Volume 10 Revision 4 sub-modules Built for the last 48 hours

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.

How to use this page Do not read it. Reading produces recognition, which feels like knowledge and collapses under questioning. Cover the answers, attempt each item cold, and only then reveal. Every card and drill links back to the volume that derives it - if you miss one, go read that section rather than re-reading the card.

10.1 The master formula sheet

Timing & metastability

One timing path annotated with both the setup and hold slack equations ONE PATH, TWO CHECKS LAUNCH t_cq LOGIC t_comb CAPTURE t_su / t_h t_skew = capture arrival - launch arrival SETUP (max delay) T + skew - t_su - t_unc - t_cq - t_comb(max) T appears → slow the clock to fix HOLD (min delay) t_cq + t_comb(min) - t_h - skew - t_unc no T → add buffers to fix
Figure 10.1 - If you remember one picture, make it this one. The presence of T in the left box and its absence from the right box explains why setup and hold are fixed by completely different actions.
Setup slack
T + t_skew - t_su
  - t_unc - t_cq - t_comb(max)
Hold slack
t_cq + t_comb(min)
  - t_h - t_skew - t_unc
T is absent - that is the point
Maximum frequency
T_min = t_cq + t_comb(max)
  + t_su + t_unc - t_skew
f_max = 1 / T_min
Metastability MTBF
e^(t_r / τ)
─────────────────
T₀ · f_clk · f_data
exponential in t_r, linear in f

FIFOs & memory

FIFO depth for a burst
Depth = B × (1 - F_read / F_write)
effective rates; round reads DOWN
Synchronous FIFO flags
empty = (wptr == rptr)
full  = (wptr[AW] != rptr[AW])
  && (wptr[AW-1:0] == rptr[AW-1:0])
Asynchronous FIFO flags
empty = (rgray == wgray_s2)
full  = (wgray ==
  {~rgray_s2[AW:AW-1],
   rgray_s2[AW-2:0]})
Gray code conversion
gray = bin ^ (bin >> 1)
one bit changes per increment

Arithmetic & logic

Full adder
S    = A ⊕ B ⊕ C_in
C_out = A·B + C_in·(A ⊕ B)
Carry lookahead
G_i = A_i · B_i
P_i = A_i ⊕ B_i
C_i+1 = G_i + P_i · C_i
Signed overflow & comparisons
V = C_in(MSB) ⊕ C_out(MSB)
A - B = A + ~B + 1
signed  A<B = sum[MSB] ^ V
unsigned A<B = ~C_out
LFSR
period = 2ⁿ - 1
XOR feedback → all-zeros is dead
XNOR feedback → all-ones is dead

The complexity ladder

Structures whose depth grows linearly compared with the tree equivalents that grow logarithmically THE SAME MOVE, MADE FIVE TIMES: CHAIN → TREE O(N) - A CHAIN O(log N) - A TREE Addition ripple carry carry lookahead / Kogge-Stone Selection cascaded MUXes MUX tree Shifting shift one per cycle barrel shifter Counting 1s serial accumulate balanced adder tree Multiplying add partial products Wallace tree + CPA Every one trades area for depth. Recognising the pattern is worth more than memorising the five instances.
Figure 10.2 - Volume 02's opening claim, evidenced. Almost every "fast" structure in digital design is the same transformation applied to a different operation.

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 immediatelyUpdates in the NBA region
Later statements see the NEW valueLater statements see the OLD value
Combinational logicSequential logic
always @(*) / always_combalways @(posedge clk) / always_ff
3 assignments → 1 flop3 assignments → 3 flops
Setup violationHold violation
Data is…Too slowToo fast
Involves Tclk?YesNo
Slower clock fixes it?YesNever
FixPipeline, restructure, upsizeInsert buffers, reduce skew
Skew effectPositive skew helpsPositive skew hurts
Sign-off cornerSlow / low-V / hotFast / high-V / cold
Ships as…A lower speed gradeScrap
MooreMealyMedvedev
Output depends onStateState + inputsIs the state
States neededMoreFewerMost
Reacts1 cycle laterSame cycle1 cycle later
GlitchesFrom decodeFollows inputNone
Input→output pathNoneCombinationalNone
Synchronous resetAsynchronous reset
In sensitivity list?NoYes
Works without a clock?NoYes
Glitch immune?YesNo
Timing checksOrdinary setup/holdRecovery / removal
AreaMUX per D pinDedicated reset pin
Correct answer: assert asynchronously, de-assert synchronously (AASD).
BinaryGrayOne-hot
Flops for N states⌈log₂N⌉⌈log₂N⌉N
Decode costWide ANDWide ANDOne wire
Bits changing per stepUp to allExactly 12
Best forASIC, small FSMsCDC pointersFPGA, fast decode
wirereglogic
Continuous assignYesNoYes
Procedural assignNoYesYes
Multiple driversAllowedIllegalCompile error
Use forTri-state nets onlyLegacy codeEverything else
CrossingCorrect technique
Single-bit level, slow → fast2-FF synchronizer
Single-bit pulse, fast → slowToggle synchronizer + edge detect
Multi-bit, increments by oneGray code
Multi-bit, arbitrary, low rateHandshake (data held stable)
Multi-bit, high throughputAsynchronous FIFO
ResetAASD reset synchronizer, one per clock domain
They all do the same thing: reduce the crossing to a single bit.
Code coverageFunctional coverage
Written byThe tool, automaticallyYou, from the test plan
MeasuresLines, branches, toggles, FSM statesScenarios you care about
Answers"What did I fail to execute?""What did I fail to try?"
100% meansVery little on its ownThe 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.

10 drills

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.

50 cards · Volumes 01-09

Volume 01 - foundations

01 Why don't software loops become clock cycles?
A synthesizable 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?
The NBA region, after every right-hand side in the whole design has already been sampled in the Active region.
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?
No. It means "assigned procedurally". Whether you get a flop is decided by the sensitivity list, never the keyword.
05 What causes an inferred latch?
A combinational block that fails to assign an output on every execution path - incomplete 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?
Tree: 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?
Two latches in series, clocked in opposite phase. They are never open simultaneously - that is what makes it edge-triggered rather than transparent.
13 Can slowing the clock fix a hold violation?
No. 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?
The setup and hold equivalents for asynchronous reset release. Recovery = reset must be de-asserted this long before the edge; removal = it must stay asserted this long after.
15 What does an AASD reset synchronizer do?
Asynchronous Assert, Synchronous De-assert. Resets instantly with no clock (works before the PLL locks), but releases on a clock edge so the whole domain starts together.
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?
With XOR feedback the all-zeros state is a fixed point. With XNOR it is all-ones. That is why the sequence is 2ⁿ-1, not 2ⁿ.

Volume 04 - finite state machines

18 Moore versus Mealy output dependency?
Moore: current state only. Mealy: state and current inputs - which buys a cycle of latency and costs a combinational path from input to output.
19 Which FSM coding style do production teams prefer, and why?
Style 3 (three-process). Registered outputs leave the next block a full clock period instead of burning part of it on decode logic.
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?
Every state decode becomes a single bit test instead of a wide comparator. Costs one flop per state - ideal on FPGAs where flops are plentiful.
22 Why is full_case dangerous?
It tells synthesis that unlisted values are don't-care, which lets it optimise away the recovery path from illegal states - turning a safe FSM back into one that hangs after an upset.
23 How do you derive a sequence detector under pressure?
Name each state after the longest prefix of the target the stream currently ends with. Then append each input bit and ask what the longest prefix is now. Overlap handling falls out automatically.

Volume 05 - clock domain crossing

24 Why two flops in a synchronizer?
The first may go metastable; the second gives that metastability a full clock period to decay before anything downstream reads it.
25 The MTBF equation?
MTBF = e^(t_r/τ) / (T₀ · f_clk · f_data)
26 Is MTBF linear or exponential in resolution time?
Exponential in 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?
Each bit resolves independently, so bits that left together can arrive on different edges. The destination latches a mixture - a value that never existed.
28 How do you cross a one-cycle pulse from fast to slow?
A toggle synchronizer: turn the pulse into a level change, synchronize the level, then edge-detect on the far side. Limited to one pulse per few destination clocks.
29 How long must a level be stable to cross reliably?
At least 1.5 destination clock periods; design for two or more.
30 Can reset domain crossing happen within one clock domain?
Yes - and that is why it gets missed. If two flops on the same clock have different resets, one asserting while the other does not changes a signal asynchronously to the destination's clock.

Volume 06 - memory & FIFOs

31 Why does a FIFO pointer need one extra bit?
Full and empty both place the pointers at the same address. The extra bit counts laps, which is the only thing distinguishing them.
32 Synchronous FIFO full and empty conditions?
Empty: pointers completely equal. Full: MSBs differ while every address bit matches.
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?
Only one bit changes per increment, so a mistimed sample yields the old value or the new one - never a third value that never existed.
35 Are stale synchronized pointers dangerous?
No - they make both flags pessimistic. The reader may think it is empty when data arrived; the writer may think it is full when space freed. Neither side can ever be optimistic, so it cannot overflow or underflow.
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?
Positive skew helps setup and hurts hold. There is a band of acceptable skew, not a target value.
40 What sets a design's maximum frequency?
The single worst path - the critical path. Improving anything else changes f_max by nothing.
41 Which corners are setup and hold signed off at?
Setup at slow / low voltage / hot. Hold at fast / high voltage / cold.
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?
Multiple drivers. A second driver on a logic is a compile error, caught before any test runs.
44 When must you still use wire?
Only for a genuine multi-driver net - a tri-state bus, which now lives almost exclusively at chip I/O pads.
45 Three things always_comb gives you over always @(*)?
It errors on latch inference, evaluates once at time 0, and forbids any other process from assigning the same variables. It is also sensitive to the contents of functions it calls.
46 Packed versus unpacked struct?
Packed is one contiguous bit vector - assignable whole, passable through a port, sliceable, synthesizable. Unpacked is separate variables with no bit layout. Use packed in RTL.
47 Why specify an enum's base type?
Without 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?
It checks legality and returns 0 on failure. 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?
The handle type, not the object type. Your override is silently ignored - no error, no warning, and the test still passes.
50 What does solve … before change?
Probability, never legality. It cannot make an illegal value appear. In the classic a -> b == 0 case it moves P(a=1) from 1/257 to 1/2.
If you can answer all fifty cold You are comfortably past the bar for an RTL design or DV interview at any of the companies this course targets. What remains is Volume 11 - applying it to the specific problems those companies actually set.