15 / 37 · Concept
Nonblocking assignments and simultaneous state updates
Separate old and next values to interpret pipeline and counter RTL correctly.
Lessons are free to read. Enroll to save your learning progress.
Evaluate right-hand sides from the previous state
In a clocked sequential block, <= evaluates its right-hand expression and applies the result during the nonblockingNonblocking assignment An assignment written as <= in sequential RTL. It evaluates the right-hand side and schedules the update, allowing registers at the same edge to compute from the previous state. update phase. This lets multiple registersRegister A circuit that stores multiple bits of state. The synchronous registers in this course store their specified inputs at a clock edge. Learn more update on the same edge without new values cascading through them merely because of source-code order.
always_ff @(posedge clk) begin
if (rst) begin
a <= 8'd0;
b <= 8'd0;
end else begin
a <= d;
b <= a;
end
endStarting with a=b=0 and inputs 5, 9, 2, the post-edge pairs (a,b) are (5,0), (9,5), (2,9). Interpreting the second line as reading the updated a effectively removes a pipelinePipeline A structure that divides computation into register-separated stages and overlaps processing of multiple inputs. Data, valid and control signals must be aligned by stage. Learn more stage.
Each column below records a rising edgeRising edge The instant at which the clock changes from 0 to 1. Distinguish it from a level, which refers to the entire interval during which CLK=1. Learn more. Inputs are pre-edge; states labeled “after” are post-update. Alignment shows sample order, not physical propagation delayPropagation delay The time from an input change until the output settles to the correct value. Logical equivalence and timing behavior are separate properties. Learn more. Starting at a=b=0, a stores new d while b stores old a, so the two rows are offset by one stage.
View waveform data
| Signal | Wave | Bus values |
|---|---|---|
| edge | 234 | E0 → E1 → E2 |
| d | 234 | 5 → 9 → 2 |
| a after | 234 | 5 → 9 → 2 |
| b after | 234 | 0 → 5 → 9 |
Why switching to blocking can be dangerous
Replacing the code with a=d; b=a; lets b use the a already updated within that block. Scheduling with other sequential blocks can also create races. Use blocking for combinational computation and nonblocking for state storage as the default rule; make exceptions only when you can explain their event semantics.
Avoid multiple assignments to the same register
If several nonblocking assignments to q execute within one procedure, the last executed assignment can determine the result. Express priority with if / else if / else or an explicit next-state variable, instead of hiding it in independent if statements. Avoid driving a register from multiple blocks.
During RTL review, write one next-state equation per register. Two competing equations or a condition with no definition is a signal to revisit control priority.
Try it yourself
Starting with a=1 and b=4, execute a<=b; b<=a; in the same clocked block. What are the states after one and two edges?
Read the explanation
After one edge, (a,b)=(4,1); after two, (1,4). Both assignments read the same old state, so the values swap. With a=b; b=a;, execution order can make both become the old b; that is not equivalent.