Search code examples
verilogcpu-architecturesystem-verilog

Question about the behaviour of registers


I am an engineer new to verilog and system verilog. I was trying to make a module that is tend to implement a ram memory. However, the behaviour of the module was not what I was expecting. After debugging, I found that the behaviour of registers in verilog is not exactly what I thought of. Then I have written a testing module to test the behaviour of registers. The following is the code for the module.

`timescale 1ns/1ps

module reg_behve(
    input       clk,
    input       rst_n,
    input       write_flag,
    input       d_in,
    output      d_out
);

reg     d_out_r;

always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        d_out_r <= 0;
    end
    else if(write_flag)begin
        d_out_r <= d_in;
    end
end

assign d_out = d_out_r;

endmodule

The following is the test bench of the module.

`timescale 1ns/1ps

module reg_behve_tb();
reg     clk;
reg     rst_n;
reg     write_flag_a;
reg     write_flag_b;
reg     d_in;
wire    d_out_a;
wire    d_out_b;

reg_behve uut_1(
    .clk                (clk),
    .rst_n              (rst_n),
    .write_flag         (write_flag_a),
    .d_in               (d_in),
    .d_out              (d_out_a)
);

reg_behve uut_2(
    .clk                (clk),
    .rst_n              (rst_n),
    .write_flag         (write_flag_b),
    .d_in               (d_in),
    .d_out              (d_out_b)
);
integer i;
initial begin
    clk = 0;
    rst_n = 1;
    @(posedge clk)
    rst_n = 0;
    write_flag_a = 0;
    write_flag_b = 0;
    d_in = 0;
    @(posedge clk)
    rst_n = 1;
    @(posedge clk)
    d_in = 1;
    write_flag_a = 1;
    @(posedge clk)
    write_flag_a = 0;
    for(i = 0; i < 5; i = i + 1)begin
        @(posedge clk);
    end
    $finish;
end

always @(posedge clk) begin
    write_flag_b <= write_flag_a;
end

initial begin
    $recordfile("sim/result.trn", "compress");
    $recordvars();
end

always #1 clk = ~clk;

endmodule

The following is the waveform of the module.

waveform of the module

The main purpose of the module is to put the value in d_in into the register d_out_r if the write_flag rise. I used to know that any changes to the register will be updated in the next cycle. However, in the simulation result, we can see that for the uut_1, the d_out_r rise at the same time as the write_flag. I am very confused about this behaviour and cannot explain it with my current knowledge. I tried to search it up online but I found it difficult to find the right keyword and answer for this particular problem. The strange thing is that, when I use a register to delay the write_flag_b in test bench for uut_2, the behaviour of the module 2 is what I expected. The d_out_r will update its value at the next clock cycle. It would be really helpful if someone can help me with this problem. If anyone need more information about the problem, I will be pleased to provide other necessary information! Thank you so much!

I tried to work on a module that shows the behaviour of a register in verilog. I expect the register will update its value in the next cycle. However, it update the value immediately after it was triggered.


Solution

  • Your coding is quite good given that you have just started. Now about the issue, you have to use the non blocking statement <= in your test bench, in the initial block. <= Non-blocking statement in test bench is used to synchronize the logic with the respective clock edge.

    initial begin
        clk = 0;
        rst_n <= 1;
        @(posedge clk)
        rst_n <= 0;
        write_flag_a <= 0;
        write_flag_b <= 0;
        d_in <= 0;
        @(posedge clk)
        rst_n <= 1;
        @(posedge clk)
        d_in <= 1;
        write_flag_a <= 1;
        @(posedge clk)
        write_flag_a <= 0;
        for(i = 0; i < 5; i = i + 1)begin
            @(posedge clk);
        end
        $finish;
    end
    
    

    Alternatively, you can provide clk = 1; in the beginning to offset your stimulus.

    Most people are aware of the non blocking and blocking statement usage in Verilog modules i.e. for sequential and combinational logics respectively. But use of these statement is quite often neglected in the test bench.

    You can check here for more details.