3.5.1 · D2HDL & Digital Design Flow

Visual walkthrough — Verilog - VHDL syntax basics

1,923 words9 min readBack to topic

We build the whole idea around one tiny, famous circuit: swapping the contents of two registers on a clock edge. It is the smallest program where = and <= give different hardware, so it is the perfect microscope.


Step 1 — What is a "wire" vs a "box"? (the two atoms)

WHAT we set up: two boxes, named and , each holding one bit. WHY: everything about <= vs = is about when a box captures its new value. To talk about "when", we need boxes (things with memory) and a clock (the thing that says "now"). PICTURE: below, the blue lines are wires (instant), the yellow squares are registers (memory). The red sawtooth at the bottom is the clock — a signal that marches forever.

Figure — Verilog - VHDL syntax basics

Here and are the two register boxes. See Flip-Flops and Latches for what one box is made of — for now, "box = remembers one bit until the clock says update."


Step 2 — What does "the clock edge" mean? (the instant of update)

WHAT: we mark the exact instants where boxes are allowed to change. WHY: outside those instants, the boxes are frozen. So the whole question "does the swap work?" reduces to: at one edge, what value does each box grab? Nothing else matters. PICTURE: the red clock line has upward arrows at each rising edge. Between edges (the grey bands) every box holds still — its value is a flat plateau.

Figure — Verilog - VHDL syntax basics
  • — the event "clock just rose to 1". This is the only moment updates happen.
  • "every box samples now" — all boxes look at their inputs simultaneously. Hold onto that word simultaneously; it is the whole plot.

Step 3 — The blocking = model: a to-do list read top-to-bottom

WHAT: run the swap with blocking assignment.

always @(posedge clk) begin
    a = b;   // line 1
    b = a;   // line 2
end

WHY this is the wrong tool here: blocking behaves like ordinary software — line 1 finishes before line 2 starts. We are about to watch that ordering destroy the swap. PICTURE: trace it as a to-do list with a moving pointer. Suppose before the edge , .

Figure — Verilog - VHDL syntax basics
  • — line 1 immediately stamps 's value (7) into . The old is gone.
  • — line 2 reads , but is now , not the original . So copies .
  • Result: . Both became . The 3 vanished. This is not a swap — it is a copy. It also secretly built a shift, not a swap. This is the "accidental shift-register bug" the parent warned about; see Synthesis vs Simulation.

Step 4 — The non-blocking <= model: read everything first, then write everything

WHAT: run the same swap with non-blocking.

always @(posedge clk) begin
    a <= b;   // sample b (old)
    b <= a;   // sample a (old)
end

WHY this is the right tool: real flip-flops sharing one clock all capture their inputs at the same instant (Step 2). Non-blocking's "read-all-then-write-all" is the exact software mirror of that physical simultaneity. PICTURE: split time into two phases at the edge — a read phase (grab old values into a holding pen) and a write phase (commit them all).

Figure — Verilog - VHDL syntax basics
  • — both right sides are read before anything is written, so both see the original values.
  • — now commit. gets old-, gets old-.
  • Result: . A genuine swap. The order of the two lines no longer matters — swap them and you get the same answer.

Step 5 — Side-by-side: the same edge, two universes

WHAT: overlay both waveforms across three clock edges starting from . WHY: to prove the divergence isn't a one-time fluke — the two models drift into different behaviours edge after edge. PICTURE: top pair is the = world (both collapse to 7 and stay), bottom pair is the <= world (values ping-pong / swap each edge).

Figure — Verilog - VHDL syntax basics

Step 6 — The degenerate cases (never leave the reader stranded)

WHAT / WHY / PICTURE: four corner cases, each on its own tile of the figure.

Figure — Verilog - VHDL syntax basics
  1. already (say both 5). Swap of equal values is invisible: = and <= both leave . So this case cannot distinguish the two operators — never test your understanding on equal inputs.
  2. Self-assign a <= a;. Read old , write it back → the box holds. This is how you say "keep the value this cycle" — a deliberate no-change, not a bug.
  3. No assignment on some path (missing else). If a combinational output is left unassigned on a branch, the tool must remember the old value → it infers an unwanted latch (see Flip-Flops and Latches). For clocked <= logic, an unassigned register simply holds, which is fine and intended.
  4. The first edge (power-on, value unknown = ). Before any reset, a register holds an unknown value, written . A swap of and gives and — the unknown propagates until a reset defines it. This is why we add synchronous reset (if (rst) q <= 0;).
  • — Verilog's symbol for "unknown / not yet initialised". Not 0, not 1 — a genuine question mark on the wire.

The one-picture summary

Figure — Verilog - VHDL syntax basics

This compresses everything: one clock edge splits into read then write. Feed the same into both models. The = path chains (arrow through line 1 into line 2) and both boxes land on 7. The <= path forks (both reads from old values) and the boxes truly swap to . The clock at the bottom reminds you: all of this happens at one rising edge, and between edges everything is frozen.

Recall Feynman: the whole walkthrough in plain words

Picture two lockers, with a 3 inside and with a 7. A bell rings once (the clock edge) and you want the numbers to trade places. If you use = you're being hasty: you open locker , dump 7 in — but now the original 3 is thrown away, so when you go to fill you only find 7 to copy. Both lockers end up 7. The 3 is lost forever. If instead you use <=, you first stand back and read both lockers onto a notepad (a=3, b=7) before touching anything. Then, in one motion, you write the notepad values into the opposite lockers. Now they truly swap: and . That "read everybody first, then write everybody" is precisely how real flip-flops behave — when the bell rings, every memory box glances at its input at the very same instant, then flips together. So: bell/clock → <= (wait, read all, swap together); plain wire → = (do it now). And beware the corners: equal values hide the difference, unassigned combinational paths accidentally grow a memory latch, and before a reset everything is a big unknown .


Connections