Search code examples
verilogregister-transfer-level

Output comes 1 clock cycle later than expected


I want to test a simple Verilog module that outputs 1 if the minterms 2, 3, 5 or 7 are found in a 3-variable input.

The module looks like this:

module modified_prime_detector(
  input [2:0] in,
  input clk,
  output reg out
);
  
  always @ (posedge clk)
  begin
    out <= (~in[2] && in[1] && ~in[0]) || (~in[2] && in[1] && in[0]) || (in[2] && ~in[1] && in[0]) || (in[2] && in[1] && in[0]);
   end
endmodule

I have also developed a testbench in order to run my simulation using EDA Playground:

module modified_prime_detector_tb();
    reg [2:0] in;
    reg clk;
    wire out;

    modified_prime_detector uut (
        .clk(clk),
        .in(in),
        .out(out)
    );

    always #5 clk = ~clk;

    always @(posedge clk) begin
        if (in == 3'b111)
            in <= 3'b000;
        else
            in <= in + 1'b1;
    end
  
  always @ (posedge clk) begin
        $display("Time: %t, in: %b, out: %b", $time, in, out);
  end

    initial begin
        $dumpfile("dump.vcd");
        $dumpvars(1, modified_prime_detector_tb);
      
        clk = 0;
        in = 0;
      
        #5;
        #100;
        $finish;
    end

endmodule

Basically, I'm increasing the 3-bit value of in on each clock cycle. I then expect to see the out's value set to 1 for the values: 010, 011, 101 and 111.

However, I see that the module outputs 1 for these values: 011, 100, 110 and 000? I'm not sure why it works like that. I think it might have to do with the simulation, because this is how the waveforms look like:

enter image description here

It seems that the output is "right-shifted" by one, at it also seems like my module gives no output for the input 000. Unfortunately, I'm not sure why this happens and how to further investigate this issue.

What might be the problem?


Solution

  • There is no issue in the output, it is correct but your intuition is wrong. In your module you are using the non-blocking statement <= and that is the standard behavior of the non-blocking statement that the output occurs after one clock cycle. This is the same reason as to why you cannot see output at 000 condition because output will arrive one cycle later.

    If you want your output to occur upon arrival of input then you should use the combinational logic by replacing the posedge clk in the sensitivity list with in and use =.

    always @ (in) begin
        out = (~in[2] && in[1] && ~in[0]) || (~in[2] && in[1] && in[0]) || (in[2] && ~in[1] && in[0]) || (in[2] && in[1] && in[0]);
    end
    

    Now if you do this, the your logic is no longer depends on the clock. Secondly I have noticed that your input is 3-bit and in the test bench you are checking if in == 3'b111 and then you reset it to in <= 3'b000, but there is no need to check this. Because if you add 1 in 3'b111, it will automatically become '0'. So you can simply write this in your test bench:

    always @(posedge clk) begin
         in <= in + 1'b1;
    end