Search code examples
variablesverilogupdating

Verilog: Use of register: When are the values actually updated?


When exactly are the variables inside an always-block in Verilog updated? E.g. if the reg C is changed multiple times in an always-block: does the value of it always change? Or is the value only "physically written" to the reg at the end of the always-block?

Would it be better to use an extra intermediate register which is only actualized at the end of the always-block? Would it make any difference?

reg C;

always @(*)
C = 0;
C = A;
C = 1;
C = B;
end

Other example: If I have a module with an always block as follows, could the multiple assignments of the output exhibit sort of a glitch, where the output quickly goes to 0 before getting the value of B? Does it make a difference if I use blocking (=) or non-blocking (<=) assignments?

module example1 (output C, input A, input B);

always @(*)
begin
 C = 1’b0;
 if (A==1)
   C = B ;
end
endmodule

Example with intermediate register to avoid unwanted change of the output.

module example1 (output C, input A, input B);

reg intermediateReg;

always @(*)
begin
 intermediateReg = 1’b0;
 if (A==1)
   intermediateReg = B ;
end
   C <= intermediateReg;
endmodule

Solution

  • In the examples you provided the code behaves identically to the 'c' code. The variable gets re-assigned new values and the last one wins. In verilog this is true for blocking (=) or non-blocking (<=) assignments, but not for the mix of them.

    As in 'c' it is up to the compiler optimization technique. It can eliminate unneeded assignments, so only the last one is relevant.

    In your first example the value of 'C' will be 'B' at the end of the block. The value of 'C' in the second example will either be 0 or B, depending on A.

    Now, for the purpose of a simplicity of explanation, mixing of blocking and non-blocking assignments will cause the last 'non-blocking' assignment win. The reason is that all nba's are executed after the block is finished.

    always @(*) begin
       C <= A;
       C = B;
    end
    

    The value of C will be A at the end of the simulation cycle.

    As for the question about using intermediate values, there is no difference. You use them as needed. The simulation compiler or synthesis will optimize your code in any case. The last example is absolutely normal, except that it does not change anything at all. It behaves the same way as this, which is more explicit and more readable in my opinion. The only problem is that you incorrectly use nba assignments int combinational logic (which i fixed).

    always @(*)
    begin
     if (A==1)
       C = B ;
     else
       C = 1'b0;
    

    I guess there is another silent question in your post, will the intermediate value cause events on 'C', the answer in this case is no. There will be no events produced by the always block till it finishes its execution (or till it hits a delay or starts waiting on an event). So, only the last value is relevant.

    In a testbench code you can see a situation like that:

    always @* begin
       C = A;
       C = B;
       #5 C = D;
    end
    

    In the above case The value of C will become B. The execution of the always block will stop for #5 delays. During that time other blocks will see the value B. In #5 ticks, the value will be changed to D.