Simple combinatorial logic assignment fails

114 Views Asked by At

I wrote a simple dummy module in Verilog. It basically copies the value from inputs to the outputs.

module dummy (
    input clk,
    input [7:0] vector1 [3:0],
    output reg [7:0] vector2 [3:0]
);

always @* begin
    for (integer i = 0; i < 4; i = i + 1) begin
        vector2[i] = vector1[i];
    end
end

endmodule

Then I had the testbench file:

module tb0;

    // Inputs
    reg clk;
    reg [7:0] data_in1 [3:0];

    wire [7:0] result [3:0];

    // Instantiate the module under test
    dummy uut (
        .clk(clk),
        .vector1(data_in1),
        .vector2(result)
    );

    // Clock generation
    always begin
        #5 clk = ~clk;
    end

    initial begin
        clk = 0;
        data_in1[0] = 8'h00;
        data_in1[1] = 8'h00;
        data_in1[2] = 8'h00;
        data_in1[3] = 8'h00;

        #10 data_in1[0] = 8'h0f;
        #10 data_in1[1] = 8'h04;
        #10 data_in1[2] = 8'h0e;
        #10 data_in1[3] = 8'h0a;

        $monitor("Time = %d: data_in1[1] = %d, data_out[1] = %d", $time, data_in1[1], result[1]); 

        #20 $finish;
    end
    endmodule

If I understand correctly, say the value data_out[1] should be zero initially, and then change to 8'h04 after 20 time units. But, when I run my Verilog testbench, I get data_out[1] fixed to zero. Why is that?

Updated: I have updated my script to the following:

module tb0;
    // Inputs
    reg clk;
    reg [7:0] data_in1 [3:0];

    // Output
    wire [7:0] result [3:0];

    // Instantiate the module under test
    dummy uut (
        .clk(clk),
        .vector1(data_in1),
        .vector2(result)
    );

    // Clock generation
    always begin
        #5 clk = ~clk; // Toggle clock every 5 ns
    end

    initial begin
        $monitor("Time = %d: data_in1[1] = %d, data_out[1] = %d", $time, data_in1[1], result[1]); 
        
        clk = 0;
        data_in1[0] = 8'h00;
        data_in1[1] = 8'h00;
        data_in1[2] = 8'h00;
        data_in1[3] = 8'h00;

        #11 data_in1[0] = 8'h0f;
        #11 data_in1[1] = 8'h04;
        #11 data_in1[2] = 8'h0e;
        #11 data_in1[3] = 8'h0a;
        
        #20 $finish;
    end
endmodule

And I still get the following as output:

Time =                    0: data_in1[1] =   0, data_out[1] =   0
Time =                    5: data_in1[1] =   0, data_out[1] =   0
Time =                    5: data_in1[1] =   0, data_out[1] =   0
Time =                   10: data_in1[1] =   0, data_out[1] =   0
Time =                   10: data_in1[1] =   0, data_out[1] =   0
Time =                   11: data_in1[1] =   0, data_out[1] =   0
Time =                   11: data_in1[1] =   0, data_out[1] =   0
Time =                   15: data_in1[1] =   0, data_out[1] =   0
Time =                   15: data_in1[1] =   0, data_out[1] =   0
Time =                   20: data_in1[1] =   0, data_out[1] =   0
Time =                   20: data_in1[1] =   0, data_out[1] =   0
Time =                   22: data_in1[1] =   4, data_out[1] =   0
Time =                   22: data_in1[1] =   4, data_out[1] =   0
Time =                   25: data_in1[1] =   4, data_out[1] =   0
...

I am using Verilator.

1

There are 1 best solutions below

0
toolic On

When I run the simulation, I see the following output:

Time =                   40: data_in1[1] =   4, data_out[1] =   4

I get a different output from you (data_out[1] is 4, not 0). This may indicate a bug in your simulator tool (Verilator).

Notice that the time is 40 because you call $monitor after 4 delays of 10 time units (#10).

It is more common to call $monitor at time 0, like this:

initial begin
    $monitor("Time = %d: data_in1[1] = %d, data_out[1] = %d", $time, data_in1[1], result[1]); 
    clk = 0;
    data_in1[0] = 8'h00;
    data_in1[1] = 8'h00;
    data_in1[2] = 8'h00;
    data_in1[3] = 8'h00;

    #10 data_in1[0] = 8'h0f;
    #10 data_in1[1] = 8'h04;
    #10 data_in1[2] = 8'h0e;
    #10 data_in1[3] = 8'h0a;
    #20 $finish;
end

This is the output I get, which may be more of what you were expecting:

Time =                    0: data_in1[1] =   0, data_out[1] =   0
Time =                   20: data_in1[1] =   4, data_out[1] =   4

Another approach is to call $display instead of $monitor, and call it at a time when the signals are stable (not at the edges):

always @(posedge clk) $display("Time = %d: data_in1[1] = %d, data_out[1] = %d", $time, data_in1[1], result[1]); 

Output:

Time =                    5: data_in1[1] =   0, data_out[1] =   0
Time =                   15: data_in1[1] =   0, data_out[1] =   0
Time =                   25: data_in1[1] =   4, data_out[1] =   4
Time =                   35: data_in1[1] =   4, data_out[1] =   4
Time =                   45: data_in1[1] =   4, data_out[1] =   4
Time =                   55: data_in1[1] =   4, data_out[1] =   4

Run it on EDA playground. You can see the waveforms as well.

I was going to recommend you submit a bug report, but I see you have already done so. It looks like Verilator has now been fixed to support your syntax.