Storage elements, registers and counters
- Distinguish latches from flip-flops
- Explain synchronous and asynchronous controls
- Trace registers, shift registers, and counter types
- Choose safe clock-enable, reset, and state-retention behavior
↑ clock
Explanation
Sequential logic remembers state
Combinational logic answers from current inputs. Sequential logic also depends on stored state. A clock usually defines when that state may change.
Latches and flip-flops
A latch is level-sensitive. While its enable is active, changes at the data input can pass to the output. When enable becomes inactive, it retains the last value.
A flip-flop is edge-triggered. A positive-edge D flip-flop samples D at a rising clock edge and holds that sampled value at Q until another active edge or control event.
| Element | Sampling window | Common concern |
|---|---|---|
| D latch | Entire active enable level | Transparency and time-borrowing analysis |
| D flip-flop | Active clock edge | Setup, hold, clock-to-Q timing |
| SR storage | Set/reset commands | Forbidden or priority combinations |
| JK flip-flop | Active edge | Toggles when J=K=1 |
| T flip-flop | Active edge | Toggles when T=1 |
Modern RTL commonly models behavior with D flip-flops. Latches can be intentional, but accidental latches from incomplete combinational assignments are defects.
Synchronous and asynchronous controls
A synchronous reset affects state only at the active clock edge. It is timed like other data. An asynchronous reset can assert without a clock, which is useful for forcing a known condition during startup or failure.
Asynchronous reset deassertion near a clock edge can violate recovery or removal timing and release different flops inconsistently. A common policy asynchronously asserts reset but synchronizes its deassertion within each clock domain. The reset strategy must match library, power, DFT, and system requirements.
Reset every bit only when needed. Some datapath registers can become valid through control sequencing, while control and externally visible state usually need deliberate reset values. Excessive reset can increase routing, area, and timing pressure.
Registers and enables
A register is a group of flip-flops storing a word. A clock enable preserves the old value when no update is requested:
if reset: q_next = RESET_VALUE
else if enable: q_next = d
else: q_next = q
In RTL, a clock enable generally allows synthesis to use a flop enable or safe data mux. Creating a clock with ordinary logic can introduce glitches, skew, and untestable paths. Power-driven clock gating uses dedicated integrated clock-gating cells and an approved implementation methodology.
Shift registers
A shift register moves stored bits left or right each enabled clock. Uses include serialization, delay lines, sequence history, and simple pipelines. Define:
- shift direction;
- serial input and output;
- fill value;
- behavior when disabled;
- reset value;
- number of cycles from input to output.
Counters
A synchronous binary counter updates all bits from the same clock edge. A ripple counter clocks one stage from another stage's output; its transitions ripple in time and are unsuitable for many synchronous control uses.
Common counter forms include:
- up, down, and up/down counters;
- modulo-N counters that wrap at a specified terminal count;
- Gray counters where adjacent codes differ by one bit;
- ring counters where one active bit circulates;
- Johnson counters where an inverted end bit feeds the beginning.
A modulo-N counter needs ceil(log2(N)) bits, but unused binary states still physically exist unless the implementation prevents them. Define recovery if an unused state occurs.
Nonblocking state-update reasoning
All flip-flops conceptually sample old values at the same edge, then update. For two registers:
always_ff @(posedge clk) begin
a <= b;
b <= a;
end
The values swap. b receives the old a, not the newly assigned a. This is why clocked RTL normally uses nonblocking assignments.
State review checklist
- What clock edge updates state?
- Is each control synchronous or asynchronous, and what is its polarity?
- What is the reset or initialization value?
- What happens when enable is low?
- What occurs at terminal count or an unused state?
- Are widths and modulo behavior correct?
- Is a derived clock being created accidentally?
Worked example
Specify a modulo-10 up counter with active-low asynchronous reset and synchronous enable.
| Condition | Next count |
|---|---|
reset_n=0 |
0 immediately |
reset_n=1, rising edge, enable=0 |
retain count |
rising edge, enable=1, count 0–8 |
count + 1 |
rising edge, enable=1, count 9 |
0 |
| rising edge, count 10–15 | 0 as a recovery policy |
Four bits are required because three bits provide only eight states. Six bit patterns are unused. Explicit recovery makes simulation, verification, and fault behavior deterministic.
A useful manual test holds reset low, releases it away from an edge, checks disabled retention, counts through 8→9→0, and injects an unused state in a verification environment to check recovery.
Check yourself
What is the behavioral difference between a latch and an edge-triggered flip-flop? Why should asynchronous reset deassertion be controlled within each clock domain?