Verilog & SystemVerilog DISCUSSION

Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

Started by tawonga Verilog blocking assignmentnon-blocking assignmentshift registersimulation raceclocked always block
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

tawonga Verilog & SystemVerilog Forum
#1

I wrote a two-flop synchroniser as always @(posedge clk) begin q1 = d; q2 = q1; end. In simulation q2 follows d after a single clock edge instead of two, and the synthesis report shows both registers fed directly from d. Changing the assignments to <= gives the two-stage delay I expected.

What is the actual difference between = and <= inside an always block, and is there a dependable rule for which one to use where?

Community replies 5

Re: Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

#2

A blocking assignment (=) completes before the next statement runs, like an assignment in software. So q1 = d; q2 = q1; updates q1 first and then copies that new value into q2: both end up equal to d on the same edge, which is one register stage duplicated.

A non-blocking assignment (<=) works in two steps. All right-hand sides in the block are evaluated using the values that existed at the clock edge, and the left-hand sides are updated afterwards, together. q1 <= d; q2 <= q1; therefore gives q2 the old q1, exactly what two flip-flops in series do.

Re: Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

#3

With blocking assignments the result depends on statement order: q2 = q1; q1 = d; does produce a two-stage shift, and swapping the lines silently removes a register. With non-blocking assignments the order of the two lines makes no difference.

It gets worse across blocks. If one always @(posedge clk) does q1 = d; and another does q2 = q1;, the standard does not define which block runs first, so the simulator may give either answer while synthesis builds two flops in series. That is a simulation race, and a classic source of hardware that disagrees with its simulation.

Re: Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

#4

The widely used guidelines are:

  • Clocked always blocks (flip-flops): non-blocking only.
  • Combinational always blocks: blocking only.
  • Do not mix the two kinds in one always block.
  • Do not assign the same variable from more than one always block.

Blocking suits combinational logic because intermediate results are meant to be used immediately: in always @* begin t = a & b; y = t | c; end the second line must see the new t, just as a gate output feeds the next gate without waiting for a clock.

Re: Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

#5

One consequence of non-blocking semantics catches people in counters. After count <= count + 1; any later test in the same block still sees the old value. In always @(posedge clk) begin count <= count + 1; if (count == 9) count <= 0; end the comparison uses the value before the increment, so the counter runs 0 to 9 and has a period of 10 clocks, not 9.

When two non-blocking assignments to the same variable execute in one pass, the last one wins, which is what makes this default-then-override style legal.

Re: Verilog blocking versus non-blocking assignment: why does my two-stage shift register collapse to one?

#6

It helps to know how the simulator schedules this. At a clock edge it runs all triggered blocks; blocking assignments take effect at once, while non-blocking updates are placed in a queue that is applied only after every active block has finished. Then any blocks sensitive to the changed signals run in a new pass at the same simulation time. That is why every flip-flop in the design samples the pre-edge values of all the others, however the blocks are ordered.

For the same reason, a testbench that drives inputs on the active clock edge should use non-blocking assignments too, so the design sees them one cycle later, like any registered signal.

TEP COMMUNITY