下一阶段的 Systemverilog 递归更新值

Systemverilog recursion update value for next stage

我正在尝试在 Systemverilog 中创建递归逻辑,但我似乎缺少将一个迭代的输出传递到下一个迭代的正确逻辑。

这里是问题的一个例子:

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

预期的拓扑结构:

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

示例输入和预期输出:

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).

测试台:

`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

如何确保 tempintt 在我从一个阶段进入下一阶段时得到更新。

您的代码中没有任何递归。您试图使用循环来解决它,但是生成块的构造非常有限,例如,您无法访问在其他生成迭代中定义的参数(但您可以访问变量或模块实例)。

所以,我们的想法是使用模块的真正递归实例化。在以下实现中,模块 rec 是递归实例化的模块。它实际上是根据您的示例构建层次结构的(我希望正确)。 由于您将其标记为系统 verilog,因此我使用了系统 verilog 语法。

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

模块第一次实例化来自 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

还有你的测试台,有点变化:

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

对于这样的小例子,使用 $display/$monitor 比转储跟踪更方便。

我没有对我创建的东西做太多测试,所以可能会有问题,但无论如何你可以从中获得基本的想法。我认为它应该适用于任何 2 的幂的 WIDTH。