High-Yield Rapid Revision & Master Formula Vault
This volume teaches nothing new. It is the compression of Volumes 01-09 into a form you can work through the night before an interview - every closed-form equation on one page, the comparison tables that get asked verbatim, ten bugs to spot under time pressure, and fifty questions to test recall rather than recognition.
10.1 The master formula sheet
Timing & metastability
T in the left box and its absence from the right box explains why setup and
hold are fixed by completely different actions.
─────────────────
T₀ · f_clk · f_data
exponential in t_r, linear in f
FIFOs & memory
effective rates; round reads DOWN
full = (wptr[AW] != rptr[AW])
&& (wptr[AW-1:0] == rptr[AW-1:0])
full = (wgray ==
{~rgray_s2[AW:AW-1],
rgray_s2[AW-2:0]})
Arithmetic & logic
A - B = A + ~B + 1
signed A<B = sum[MSB] ^ V
unsigned A<B = ~C_out
The complexity ladder
10.2 The golden comparison matrices
These get asked almost verbatim. Each row is a question an interviewer can ask on its own.
Blocking = | Non-blocking <= |
|---|---|
| Updates immediately | Updates in the NBA region |
| Later statements see the NEW value | Later statements see the OLD value |
| Combinational logic | Sequential logic |
always @(*) / always_comb | always @(posedge clk) / always_ff |
| 3 assignments → 1 flop | 3 assignments → 3 flops |
| Setup violation | Hold violation | |
|---|---|---|
| Data is… | Too slow | Too fast |
| Involves Tclk? | Yes | No |
| Slower clock fixes it? | Yes | Never |
| Fix | Pipeline, restructure, upsize | Insert buffers, reduce skew |
| Skew effect | Positive skew helps | Positive skew hurts |
| Sign-off corner | Slow / low-V / hot | Fast / high-V / cold |
| Ships as… | A lower speed grade | Scrap |
| Moore | Mealy | Medvedev | |
|---|---|---|---|
| Output depends on | State | State + inputs | Is the state |
| States needed | More | Fewer | Most |
| Reacts | 1 cycle later | Same cycle | 1 cycle later |
| Glitches | From decode | Follows input | None |
| Input→output path | None | Combinational | None |
| Synchronous reset | Asynchronous reset | |
|---|---|---|
| In sensitivity list? | No | Yes |
| Works without a clock? | No | Yes |
| Glitch immune? | Yes | No |
| Timing checks | Ordinary setup/hold | Recovery / removal |
| Area | MUX per D pin | Dedicated reset pin |
| Correct answer: assert asynchronously, de-assert synchronously (AASD). | ||
| Binary | Gray | One-hot | |
|---|---|---|---|
| Flops for N states | ⌈log₂N⌉ | ⌈log₂N⌉ | N |
| Decode cost | Wide AND | Wide AND | One wire |
| Bits changing per step | Up to all | Exactly 1 | 2 |
| Best for | ASIC, small FSMs | CDC pointers | FPGA, fast decode |
wire | reg | logic | |
|---|---|---|---|
| Continuous assign | Yes | No | Yes |
| Procedural assign | No | Yes | Yes |
| Multiple drivers | Allowed | Illegal | Compile error |
| Use for | Tri-state nets only | Legacy code | Everything else |
| Crossing | Correct technique |
|---|---|
| Single-bit level, slow → fast | 2-FF synchronizer |
| Single-bit pulse, fast → slow | Toggle synchronizer + edge detect |
| Multi-bit, increments by one | Gray code |
| Multi-bit, arbitrary, low rate | Handshake (data held stable) |
| Multi-bit, high throughput | Asynchronous FIFO |
| Reset | AASD reset synchronizer, one per clock domain |
| They all do the same thing: reduce the crossing to a single bit. | |
| Code coverage | Functional coverage | |
|---|---|---|
| Written by | The tool, automatically | You, from the test plan |
| Measures | Lines, branches, toggles, FSM states | Scenarios you care about |
| Answers | "What did I fail to execute?" | "What did I fail to try?" |
| 100% means | Very little on its own | The plan was covered |
| 100% code + 50% functional coverage ships bugs. Both are required. | ||
10.3 Spot the silicon bug - ten drills
Each block contains exactly one defect. Find it before opening the answer. These are the failure modes that appear most often in real code review.
always @(posedge clk) begin
q1 = d;
q2 = q1;
q3 = q2;
end
1 Reveal the bug
Blocking assignments in sequential logic. Each statement sees the value
the previous one just wrote, so all three collapse - d reaches
q3 in a single cycle and synthesis infers one flip-flop
instead of a three-stage shift register. It also races any other block reading
q1.
Fix: use <= in every clocked block.
→ Volume 1.4
always @(*) begin
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
endcase
end
2 Reveal the bug
Inferred latch. sel is two bits, so 2'b11 is
reachable and leaves y unassigned. The only hardware that can "not change"
y is a transparent latch.
Fix: add default: y = 1'b0;, or assign
a default before the case. Better still, use always_comb so the tool errors.
→ Volume 1.5
// count_a is a 4-bit counter in the clk_a domain
always @(posedge clk_b) begin
sync1 <= count_a;
sync2 <= sync1;
end
assign count_b = sync2;
3 Reveal the bug
A multi-bit bus through per-bit synchronizers. Each of the four bits
resolves its metastability independently, so bits that changed together in
clk_a can land on different clk_b edges. Crossing
0111 → 1000 can be sampled as 1111 - a value the counter never
produced.
Fix: Gray-code the counter, or use a handshake or asynchronous FIFO. → Volume 5.3
assign gated_clk = clk & enable;
always @(posedge gated_clk)
q <= d;
4 Reveal the bug
Combinational clock gating glitch. If enable changes while
clk is high, gated_clk produces a spurious edge that clocks the
whole downstream logic. The AND gate is also not on the clock tree, so it adds
uncontrolled skew.
Fix: use a clock enable on the flop
(if (en) q <= d;), or a proper integrated clock-gating cell that latches the
enable on the opposite phase.
→ Volume 3.5
// arst_n comes directly from a chip pin
always @(posedge clk or negedge arst_n)
if (!arst_n) state <= IDLE;
else state <= next_state;
5 Reveal the bug
Unsynchronized reset release. Assertion is fine - that is the point of
an asynchronous reset. De-assertion is not: if arst_n rises near a
clock edge it violates recovery/removal and the flop can go metastable. Because reset
reaches thousands of flops with different delays, part of the design can leave reset a
cycle later than the rest.
Fix: pass arst_n through an AASD reset
synchronizer - one per clock domain.
→ Volume 3.2
// Intent: assert tick once every N clocks. N is a power of two, e.g. 16.
localparam N = 16;
reg [$clog2(N)-1:0] cnt;
always @(posedge clk)
if (cnt == N) begin cnt <= 0; tick <= 1'b1; end
else begin cnt <= cnt + 1'b1; tick <= 1'b0; end
6 Reveal the bug
Two bugs, and the second one is fatal.
Off-by-one: counting 0 … N inclusive is N+1 states, so even when it
works the period is 17, not 16.
The comparison can never be true: $clog2(16) is 4, so
cnt is [3:0] and holds 0-15. The value 16 does not fit.
cnt == N is always false, tick never asserts,
and the counter free-runs forever.
Fix: compare against N-1, and size the
counter deliberately rather than trusting $clog2 to leave room for the
terminal value.
→ Volume 3.3
always @(*) begin
if (enable)
count = count + 1'b1;
end
7 Reveal the bug
Combinational feedback loop. count is both read and written
in an unclocked block, so its output feeds its own input through an adder with no
register to break the path. In simulation it can loop forever at one timestep; in silicon
it oscillates. (It also infers a latch, because count is unassigned when
enable is low.)
Fix: it is a counter - it belongs in a clocked
block. always_ff @(posedge clk) if (enable) count <= count + 1'b1;
→ Volume 3.3
always @(posedge clk) begin
#0 q <= d;
end
8 Reveal the bug
The #0 anti-pattern. #0 defers to the Inactive
region to "fix" an ordering problem. It does not fix anything: if two processes both use
#0, their relative order is undefined again. Delays are also not
synthesizable, so simulation and silicon can disagree.
Fix: delete the #0. A non-blocking
assignment already schedules into the NBA region, which is exactly the ordering guarantee
the author was reaching for. This is Cummings' Golden Rule 8.
→ Volume 1.2
class BaseDriver;
function void drive(Transaction t);
$display("base drive");
endfunction
endclass
class MyDriver extends BaseDriver;
function void drive(Transaction t);
$display("my drive");
endfunction
endclass
BaseDriver drv = MyDriver::new();
drv.drive(t);
9 Reveal the bug
Missing virtual. Without it the method is chosen from the
handle type (BaseDriver), not the object type. This prints
"base drive". Your derived driver is constructed, connected, and never
called.
The failure mode is what makes it dangerous: no error, no warning, and the test reports a pass while exercising the base behaviour.
Fix: declare virtual function void drive(...)
in the base class. In UVM, nearly everything is virtual for exactly this reason.
→ Volume 9.2
int values[];
values = new[8];
for (int i = 0; i <= 8; i++)
values[i] = i * 2;
10 Reveal the bug
Out-of-bounds write on a dynamic array. new[8] allocates
indices 0-7, but i <= 8 runs the loop nine times and writes
values[8]. Depending on the simulator this is a runtime error, a silently
ignored write, or memory corruption - and it is a classic fence-post mistake.
Fix: i < 8, or better
i < values.size() so the bound cannot drift from the allocation. A
foreach (values[i]) loop removes the possibility entirely.
→ Volume 9.2
10.4 Fifty active-recall flashcards
Cover the answers. Say yours out loud before revealing - the gap between "I recognise that" and "I can state that" is exactly what an interview measures.
Volume 01 - foundations
01 Why don't software loops become clock cycles?
for loop is unrolled at elaboration into parallel hardware - one copy of the body per iteration. It costs area, not time. Sequencing needs an explicit FSM or counter.02 Which event-queue region do non-blocking assignments update in?
03 X versus Z?
X = unknown or conflicting drivers. Z = nothing driving the net at all. X is the simulator refusing to guess; silicon has neither.04 Does reg mean register?
05 What causes an inferred latch?
if, missing default, or an output absent from one branch.Volume 02 - combinational datapaths
06 Depth of an N:1 MUX as a tree versus a cascade?
log₂(N) levels. Cascade: N-1 levels. Same MUX count, very different delay.07 Why casez and never casex?
casex treats X on the input as a wildcard, so one uninitialised bit can match a branch it should not - a simulation-synthesis mismatch. casez only wildcards Z.08 Full adder carry-out equation?
C_out = A·B + C_in·(A ⊕ B). It deliberately reuses the A ⊕ B term the sum already needs.09 Carry lookahead generate and propagate?
G = A·B (makes a carry regardless), P = A ⊕ B (passes one through). Both depend only on inputs, so all bits compute them simultaneously.10 Signed overflow condition?
V = C_in(MSB) ⊕ C_out(MSB). Equivalently: same-signed operands producing the opposite sign. C_out alone signals unsigned overflow only.11 How do you subtract with an adder?
A - B = A + ~B + 1. Implemented as a + (b ^ {W{sub}}) + sub - one XOR row, no second adder.Volume 03 - sequential design
12 What is a flip-flop actually made of?
13 Can slowing the clock fix a hold violation?
T_clk does not appear in the hold equation, so it fails at every frequency including DC. Fix with buffers or less skew.14 Recovery and removal times?
15 What does an AASD reset synchronizer do?
16 Binary to Gray conversion?
gray = bin ^ (bin >> 1). One XOR per bit, no carry chain.17 Why does an LFSR lock up, and where?
2ⁿ-1, not 2ⁿ.Volume 04 - finite state machines
18 Moore versus Mealy output dependency?
19 Which FSM coding style do production teams prefer, and why?
20 In style 3, decode the output from state or next_state?
next_state. Decoding from state puts the output a cycle behind the state it describes.21 What does one-hot encoding buy?
22 Why is full_case dangerous?
23 How do you derive a sequence detector under pressure?
Volume 05 - clock domain crossing
24 Why two flops in a synchronizer?
25 The MTBF equation?
MTBF = e^(t_r/τ) / (T₀ · f_clk · f_data)26 Is MTBF linear or exponential in resolution time?
t_r, but only linear in frequency. That asymmetry is why one extra flop turns milliseconds into millions of years.27 Why does a 2-FF synchronizer fail on a bus?
28 How do you cross a one-cycle pulse from fast to slow?
29 How long must a level be stable to cross reliably?
30 Can reset domain crossing happen within one clock domain?
Volume 06 - memory & FIFOs
31 Why does a FIFO pointer need one extra bit?
32 Synchronous FIFO full and empty conditions?
33 Asynchronous FIFO full condition?
wgray == {~rgray_s2[AW:AW-1], rgray_s2[AW-2:0]} - the top two Gray bits inverted, because Gray is a reflected code.34 Why Gray-code the pointers?
35 Are stale synchronized pointers dangerous?
36 FIFO depth for a burst?
Depth = B × (1 - F_read / F_write) using effective rates. Round reads down, add margin, round up to a power of two for a Gray-pointer FIFO.Volume 07 - static timing analysis
37 Setup slack equation?
T + skew - t_su - t_unc - t_cq - t_comb(max)38 Hold slack equation?
t_cq + t_comb(min) - t_h - skew - t_unc. Note what is missing: the clock period.39 Does clock skew help or hurt?
40 What sets a design's maximum frequency?
f_max by nothing.41 Which corners are setup and hold signed off at?
42 An N-cycle setup multicycle path needs what hold constraint?
(N-1)-cycle hold. Without it the hold check drifts an edge and demands a full cycle of data delay - producing thousands of impossible violations.Volume 08-09 - SystemVerilog
43 What does logic forbid that wire allows?
logic is a compile error, caught before any test runs.44 When must you still use wire?
45 Three things always_comb gives you over always @(*)?
46 Packed versus unpacked struct?
47 Why specify an enum's base type?
enum logic [2:0] it defaults to a 32-bit 2-state int - wasteful, and it loses X propagation on your state register.48 What does $cast add over a static cast?
state_e'(raw) converts blindly and can leave an enum holding a value its own type says cannot exist.49 Without virtual, what picks which method runs?
50 What does solve … before change?
a -> b == 0 case it moves P(a=1) from 1/257 to 1/2.