Adding memory: state
Ask yourself a plain question: how does a circuit remember anything? Pure combinational logic can't — wire up some gates and the output is just a fresh function of whatever the inputs are *right now*. Cut the inputs and the answer vanishes, like a calculator with no memory key. To count, to hold a result, to wait for the next instruction, hardware needs a way to keep a value after the cause is gone.
That stored value has a name: state. A circuit with state is sequential — its output depends not only on the inputs now but on what happened before. Think of a light switch versus a doorbell: the doorbell sounds only while you press it (combinational), but the switch *stays* where you flipped it (state). The whole job of this guide is building that switch out of gates and giving it a disciplined moment to change.
The flip-flop, revisited
The smallest unit of state is one bit, and the device that holds it is the flip-flop — specifically the D flip-flop, the workhorse of digital design. Picture a camera with a shutter. The lens always sees the scene (the D, or *data*, input), but the photo only updates the instant the shutter clicks. A D flip-flop is exactly that: whatever value is on D gets captured at one sharp moment, then held steady on the output Q until the next click.
That 'click' is the clock edge — the moment the clock line rises from 0 to 1. Between edges, D can wiggle all it likes; the flip-flop ignores it. Only at the rising edge does Q take a fresh snapshot of D. This is the leap from combinational to sequential: the output now changes on a schedule, not continuously.
module dff(input clk, input d, output reg q);
always @(posedge clk) // at each rising clock edge...
q <= d; // ...Q snapshots D, then holds
endmoduleRegisters: holding a value
One flip-flop holds one bit — fine for a flag, useless for a number. Stack N flip-flops side by side, all sharing the same [[clock-signal|clock]], and you get a register: a row of shutters that all click at once, capturing an N-bit value in a single instant. An 8-bit register is just eight D flip-flops with their clock pins tied together. When the edge arrives, all eight snapshot their bits simultaneously — the whole byte lands as one.
In Verilog you rarely wire up eight flip-flops by hand. You declare a vector and let synthesis build the row for you. The code below describes an 8-bit register: same `posedge` capture as the single bit, just wider. One caution worth carrying past your first day: `reg` is just Verilog's name for a procedurally-assigned variable, not a promise of memory — a `reg` only becomes an actual flip-flop when you assign it on a clock edge like this. Assign the same `reg` in a combinational block and synthesis builds plain gates, no storage at all.
module reg8(input clk, input [7:0] d, output reg [7:0] q);
always @(posedge clk)
q <= d; // all 8 bits captured together on the edge
endmodulealways @(posedge clk)
This one line is the heartbeat of synchronous design, so it earns its own section. `always @(posedge clk)` tells the tools: *the hardware inside this block updates only on the rising edge of `clk`.* Everything you write here becomes sequential — it gets flip-flops. The `posedge` keyword is the camera shutter; `clk` is the finger pressing it on a steady beat.
Inside a clocked block, use the nonblocking assignment `<=`, not `=`. Here's the intuition: every `<=` in the block reads its right-hand side using the old values, and all the left-hand sides update together at the edge — exactly how real flip-flops behave, snapshotting at once. Use `=` (blocking) here and you describe a step-by-step recipe, which is the software mindset HDL is trying to break you of.
always @(posedge clk) begin q1 <= d; // all right-hand sides are read FIRST (old values), q2 <= q1; // then all left-hand sides update together at the edge end
Setup & hold: the timing handshake
Here is your first real taste of timing, and it's gentler than its reputation. A flip-flop can't reliably capture a value that's still moving — the shutter needs the scene to hold still for a brief moment. Concretely, the D input must be steady for a small window around the clock edge: a little before it, and a little after.
Those two halves of the quiet window have names. **Setup time** is how long D must be stable before the edge; **hold time** is how long it must stay stable after. Violate either — let D change inside that window — and the capture is no longer guaranteed: the flip-flop may simply latch the wrong (but clean) value, or it may land in a blurred, half-resolved state called *metastability*, where Q hovers between 0 and 1 and only settles after an unpredictable delay. Think of it as a photo snapped mid-motion: smeared, unreliable, unusable.
You don't normally compute these by hand — static timing analysis checks every flip-flop in the design for you and reports the slack (the timing margin left over). But the intuition is the whole foundation: data must be still when the camera clicks. Make the clock too fast and the signals can't settle in time — which is exactly why every chip has a maximum clock speed.
Synchronous design discipline
All these pieces converge on one professional habit: synchronous design. The rule is simple to state and worth following almost religiously — use one clock, and let every flip-flop in the design capture on the same edge of it. One shared heartbeat, and the entire chip steps forward together, one tick at a time.
Why be so strict? Because it makes timing analyzable. With a single clock, the question 'does every signal arrive in time?' has one clean answer per clock period, and timing analysis can verify the whole chip mechanically. Designs with stray clocks, or logic that reacts to signal edges willy-nilly (called *asynchronous* design), become nearly impossible to verify and notorious for bugs that appear only on certain chips, on certain days, at certain temperatures.
So the mental model for an entire synchronous chip is this: clouds of combinational logic computing the next value, separated by ranks of registers that all snapshot together on the clock edge. Compute, capture, repeat — compute during the period, capture at the edge. That heartbeat is what turns a pile of gates into a machine that moves through time.