Search code examples
verilogquartustest-benchdigital-logicregister-transfer-level

Capturing the right posedge clock in Quartus waveform


I am using Quartus Prime Lite 19.1.0.

module memory_address_register1 #(
    parameter                       ADDR_WIDTH = 4
)(
    input                           clk, rst, load,
    input       [ADDR_WIDTH-1:0]    add_in,
    output reg     [ADDR_WIDTH-1:0]    add_out
);


    always @(posedge clk) begin
        if (rst) begin
            add_out <= 4'b0000;
        end else if (load) begin
            add_out <= add_in;
        end else begin
            add_out <= add_out;
        end
    end
    
endmodule

module mmr_tb();
    reg clk, rst, load;
    reg [3:0] add_in;
    wire [3:0] add_out;
    
    initial begin
        clk <= 1'b0;
        rst <= 1'b0;
        load <= 1'b0;
    end
    
    memory_address_register1 mmr (.clk(clk), .rst(rst), .load(load), .add_in(add_in), .add_out(add_out));
    
    always #10 clk = ~clk;
    
    initial begin
        #20 add_in <= 4'd2;
        #10 add_in <= 4'd3;
        load <= 1'b1;
        #30 add_in <= 4'd6;
        #10 load <= 1'b1;
        
    end

endmodule

It the output (add_out) accurate? Should the output (add_out) at t=70.0ns be "6" or "7"?

  1. If the expected output is "6", can anyone explain why is that?

img1: posedge clk output value from previous clk cycle

img2: posedge clk output value from previous clk cycle

I ran the testbench using modelsim, and I am able to get the expected output I wanted (output on the exact clock edge), but is it expected? https://i.sstatic.net/GVmKO.jpg


Solution

  • You have potential race conditions in your testbench code. You should drive all your inputs in the testbench the same way you drive them in the design:

    1. Use nonblocking assignments (<=) instead of blocking assignments (=)
    2. Use @(posedge clk) instead of # delays

    This will guarantee that your inputs will be synchronous to the clock. This also assures that pulsewidths of your inputs are a multiple of the clock period. Some of your signals are half a period wide or 1.5 periods wide.

    module mmr_tb();
        reg clk, rst, load;
        reg [3:0] add_in;
        wire [3:0] add_out;
        
        initial begin
            clk    <= 0;
            rst    <= 1;
            load   <= 0;
            add_in <= 0;
            repeat (2) @(posedge clk);
            rst <= 0;
            forever @(posedge clk) begin
                add_in <= add_in + 1;
            end
        end
        
        memory_address_register1 mmr (.clk(clk), .rst(rst), .load(load), .add_in(add_in), .add_out(add_out));
        
        always #10 clk = ~clk;
        
        initial begin
            repeat (4) @(posedge clk); load <= ~load;
            repeat (1) @(posedge clk); load <= ~load;
            repeat (4) @(posedge clk); load <= ~load;
            repeat (1) @(posedge clk); load <= ~load;
            repeat (3) @(posedge clk); $finish;
        end
    endmodule
    

    waves