0

I am trying to create a recursive logic in Systemverilog but I seem to be missing the right logic to carry the output of one iteration to the next.

Here is an example of the problem:

parameter WIDTH=4;
module test_ckt #(parameter WIDTH = 4)(CK, K, Z);

input CK;
input [WIDTH-1:0] K;
output reg Z;

wire [WIDTH/2-1:0] tt;
wire [WIDTH-1:0] tempin;
assign tempin  = K;
genvar i,j;
generate
    for (j=$clog2(WIDTH); j>0; j=j-1)
    begin: outer
        wire [(2**(j-1))-1:0] tt;
        for (i=(2**j)-1; i>0; i=i-2)
        begin
            glitchy_ckt #(.WIDTH(1)) gckt (tempin[i:i], tempin[(i-1):i-1], tt[((i+1)/2)-1]);
        end
        // How do I save the value for the next iteration?
        wire [(2**(j-1))-1:0] tempin;
        assign outer[j].tempin = outer[j].tt;
    end
endgenerate

always @(posedge CK)
begin
    // How do I use the final output here?
    Z <= tt[0];
end

endmodule

module glitchy_ckt #(parameter WIDTH = 1)(A1, B1, Z1);
input [WIDTH-1:0] A1,B1;
output Z1;
assign Z1 = ~A1[0] ^ B1[0];
endmodule

Expected topology:

                S1              S2
K3--<inv>--|==
           |XOR]---<inv>----|
K2---------|==              |
                            |==
   <--gckt--->              |XOR]
                            |==
K1--<inv>--|==              |
           |XOR]------------|
K0---------|==    <-----gckt---->

Example input and expected outputs:

Expected output:

A - 1010
    ----
 S1  0 0 <- j=2 and i=3,1.
 S2    1 <- j=1 and i=1.

Actual output:

A - 1010
    ----
 S1  0 0 <- j=2 and i=3,1.
 S2    0 <- j=1 and i=1. Here, because tempin is not updated, inputs are same as (j=2 & i=1).

Test-bench:

`timescale 1 ps / 1 ps
`include "test_ckt.v"

module mytb;

reg CK;
reg [WIDTH-1:0] A;
wire Z;

test_ckt #(.WIDTH(WIDTH)) dut(.CK(CK), .K(A), .Z(Z));

always #200 CK = ~CK;
integer i;
initial begin
    $display($time, "Starting simulation");
    #0 CK = 0;
    A = 4'b1010;
    #500 $finish;
end

initial begin
    //dump waveform
    $dumpfile("test_ckt.vcd");
    $dumpvars(0,dut);
end

endmodule

How do I make sure that tempin and tt get updated as I go from one stage to the next.

6
  • you should be able to access tempin and tt from the previous iteration as outerp[j-1].tempin. Make sure that your code is compilable and provide your testbench. Commented Jul 26, 2020 at 18:25
  • I made the fixes of adding TB. I can use outerp from the second iteration, but how do I initialize it? Commented Jul 27, 2020 at 0:11
  • you do not monitor anything in your test bench. Where is your output coming from? Commented Jul 27, 2020 at 10:54
  • I was writing to a VCD to view the waveform. Commented Jul 27, 2020 at 14:33
  • and which variables did you show in your output at S1 ans S2? Commented Jul 28, 2020 at 0:57

1 Answer 1

1

Your code does not have any recursion in it. You were trying to solve it using loops, but generate blocks are very limited constructs and, for example, you cannot access parameters defined in other generate iterations (but you can access variables or module instances).

So, the idea is to use a real recursive instantiation of the module. In the following implementation the module rec is the one which is instantiated recursively. It actually builds the hierarchy from your example (I hope correctly). Since you tagged it as system verilog, I used the system verilog syntax.

module rec#(WIDTH=1) (input logic [WIDTH-1:0]source, output logic result);
   
   if (WIDTH <= 2) begin
     always_comb
       result = source; // << generating the result and exiting recursion.
   end
   else begin:blk
      localparam REC_WDT = WIDTH / 2;
      logic [REC_WDT-1:0] newSource; 
   
      always_comb // << calculation of your expression
        for (int i = 0; i < REC_WDT; i++)
          newSource[i] = source[i*2] ^ ~source[(i*2)+1]; 
   
      rec #(REC_WDT) rec(newSource, result); // << recursive instantiation with WIDTH/2
   end // else: !if(WIDTH <= 2)

   initial $display("%m: W=%0d", WIDTH);  // just my testing leftover
endmodule

The module is instantiated first time from the test_ckt:

module test_ckt #(parameter WIDTH = 4)(input logic CK, input logic [WIDTH-1:0] K, output logic Z);
   logic                 result;
   rec#(WIDTH) rec(K, result); // instantiate first time )(top)
   always_ff @(posedge CK)
     Z <= result;  // assign the results  
endmodule // test_ckt

And your testbench, a bit changed:

module mytb;

   reg CK;
   reg [WIDTH-1:0] A;
   wire        Z;

   test_ckt #(.WIDTH(WIDTH)) dut(.CK(CK), .K(A), .Z(Z));

   always #200 CK = ~CK;
   integer     i;
   initial begin
      $display($time, "Starting simulation");
      CK = 0;
      A = 4'b1010;
      #500 
      A = 4'b1000;
      #500 $finish;
   end

   initial begin
      $monitor("Z=%b", Z);     
   end
endmodule // mytb

Use of $display/$monitor is more convenient than dumping traces for such small examples.

I did not do much testing of what I created, so there could be issues, but you can get basic ideas from it in any case. I assume it should work with any WIDTH which is power of 2.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.