Video 4 of 4 · ~8 minutes
Dr. Mike Borowczak · Electrical & Computer Engineering · CECS · UCF
Cliff Cummings's 2000 paper “Nonblocking Assignments in Verilog Synthesis” is the reference on this topic — cited in every corporate coding guideline. Nearly every lint rule in existence enforces: = only in combinational blocks, <= only in sequential blocks.
Day 4 proves this rule with waveforms. Day 5 shift registers depend on it. Day 7 FSMs require it. The rule is absolute for the rest of the course — and the rest of your career.
<= Is Not “Less Than Or Equal”“= and <= are similar — probably <= is some kind of ‘delayed’ assignment.” Or worse: “<= is a comparison.”
Inside an always block, <= means “nonblocking assignment” — a different operation entirely from =. Verilog overloaded the symbol badly. The two operators produce different simulator scheduling semantics, which in turn determine what hardware the synthesizer builds.
= and one with <= inside always @(posedge clk), produces different hardware. Not equivalent. Not interchangeable. Totally different circuits.
= BlockingEvaluate RHS, assign to LHS, immediately. Next statement in the block sees the updated value.
Use in: always @(*)
Mental model: ordinary programming assignment.
<= NonblockingEvaluate all RHS using current values, schedule the updates, apply them simultaneously at end of timestep.
Use in: always @(posedge clk)
Mental model: all flip-flops capture at once, like real silicon.
= in always @(*). <= in always @(posedge clk). Never mix.
// WRONG: blocking in sequential (not a pipeline!)
always @(posedge clk) begin
b = a; // b gets a's value NOW
c = b; // c gets b's NEW value (= a!) — both same!
end
// CORRECT: nonblocking in sequential (proper pipeline)
always @(posedge clk) begin
b <= a; // scheduled: b will become a(old)
c <= b; // scheduled: c will become b(old)
end // at end: b=a(old), c=b(old)
b = a, then c = new_b = a. Both registers end up holding the same value. The nonblocking version schedules both updates using the pre-edge values, modeling how real flip-flops behave: they all capture their D inputs simultaneously on the clock edge.
Initial values: a=1, b=2, c=3. After one clock edge, predict a, b, c:
always @(posedge clk) begin
a <= b;
b <= c;
c <= a;
end
a=2, b=3, c=1. All RHS evaluated first: a's new value = b(old) = 2, b's new = c(old) = 3, c's new = a(old) = 1. All applied simultaneously. This is a 3-element rotator.
=: a=2, b=3 (b gets c=3, but wait — b was just overwritten by... no). Let's trace: a=b=2. b=c=3. c=a=2 (a was just updated!). Final: a=2, b=3, c=2. Rotator becomes garbage.
= vs <= Side-by-Side~4 minutes
▸ COMMANDS
cd labs/week1_day03/ex4_blocking_demo/
# Two modules: shift_blocking, shift_nonblocking
make sim
make wave
# Load GTKWave .gtkw file: both traces side-by-side
▸ EXPECTED STDOUT
Cycle 1: blocking q=00 | nb q=80
Cycle 2: blocking q=00 | nb q=40
Cycle 3: blocking q=00 | nb q=20
Cycle 4: blocking q=00 | nb q=10
# blocking never shifts —
# all stages collapse to same value
▸ GTKWAVE
Two registers stacked: shift_blocking.q above shift_nonblocking.q. The nonblocking version shifts cleanly each cycle. The blocking version stays pinned — the pipeline collapsed on the first clock edge.
4-stage shift register, both coding styles:
= (bug)SB_DFF: 1 ← ONE flop
(collapses to 1 stage)
<= (correct)SB_DFF: 4 ← 4 flops
(proper 4-stage pipeline)
Ask AI: “If I use = inside an always @(posedge clk) for a 3-stage shift register, what does the synthesized hardware actually look like?”
TASK
Ask AI to describe the synthesized hardware.
BEFORE
Predict: collapses to 1 stage. All registers hold the input value after one cycle.
AFTER
Strong AI explains collapse + cites Cummings. Weak AI says “3-stage shift register” — wrong.
TAKEAWAY
If AI says “still a 3-stage shift,” it's wrong. Verify with Yosys stat.
① = (blocking) for combinational always @(*).
② <= (nonblocking) for sequential always @(posedge clk).
③ Mixing causes functional bugs — pipelines collapse.
④ The synthesizer builds what you wrote, not what you meant.
Q1: Why must you use @(*) instead of a manual sensitivity list?
@(*) automatically includes all signals read inside the block.Q2: What causes an unintentional latch?
always @(*).Q3: Name three techniques to prevent latch inference.
default in case statements.Q4: When do you use = vs <=?
= in combinational always @(*). <= in sequential always @(posedge clk). Never mix.🔗 End of Day 3
Day 4 · Clocks, flip-flops, and your first blinking LED
▸ WHY THIS MATTERS NEXT
Days 1-3 covered combinational logic — logic with no memory. Day 4 adds time: flip-flops, clocks, sequential design. You'll build a counter that turns 25 MHz into a 1 Hz LED blink, and see with your own eyes why <= is the rule.