Part 8 · Senior & Interview Prep · Intermediate

Step 1: Spec Analysis & Verification Plan

The FIFO spec, feature list extraction, the verification plan table, and the corner-case inventory.

The spec as given

Everything starts from the spec — read it as a verifier: every "shall" becomes a feature row, and every silence becomes a logged question.

diagram
FIFO SPECIFICATION (v1.2)

  Parameters
    WIDTH  : data width in bits        (default 8,  range 1-64)
    DEPTH  : number of entries         (default 16, power of 2, >= 2)

  Interface (all synchronous to clk, async active-low rst_n)
    write side:  in_valid  (in)   in_ready  (out)   in_data[WIDTH]  (in)
    read  side:  out_valid (out)  out_ready (in)    out_data[WIDTH] (out)
    status:      full (out)       empty (out)

  Behavior
    1. A push occurs when in_valid && in_ready on a clk edge.
    2. A pop  occurs when out_valid && out_ready on a clk edge.
    3. in_ready  == !full;  out_valid == !empty.
    4. full  asserts when count == DEPTH; empty when count == 0.
    5. Data emerges in push order (strict FIFO), unmodified.
    6. Push at full is ignored (in_ready low blocks the handshake).
    7. Simultaneous push+pop is legal at any non-boundary fill level;
       at full: pop proceeds, push accepted ONLY if pop frees a slot
       in the same cycle (spec v1.2 clarification Q-003).
    8. rst_n clears the FIFO to empty within 1 cycle; in-flight
       data is discarded.

Ambiguities we logged (and their answers)

  • Q-003: push+pop in the same cycle at full — allowed? Answer (architect, spec updated to v1.2): pop wins, the freed slot may absorb the push that same cycle.

  • Q-004: out_data validity when empty — defined? Answer: undefined when out_valid is low; checkers must not compare it.

  • Q-005: behavior if rst_n asserts mid-handshake — Answer: transaction discarded, no partial state; flags valid 1 cycle after deassert.


Feature extraction

Three spec passes produce the feature list. Note how behavior rule 7 — one sentence in the spec — becomes three separate features , because each has a different stimulus and check.

  1. F-01 Data integrity: every pushed word pops exactly once, unmodified, in push order.

  2. F-02 full asserts exactly at count == DEPTH, deasserts on the next pop.

  3. F-03 empty asserts exactly at count == 0, deasserts on the next push.

  4. F-04 in_ready mirrors !full; out_valid mirrors !empty (combinational, same cycle).

  5. F-05 Push at full is blocked — no data loss, no corruption, count unchanged.

  6. F-06 Pop at empty is blocked — no spurious data, count unchanged.

  7. F-07 Simultaneous push+pop at intermediate fill: count unchanged, order preserved.

  8. F-08 Simultaneous push+pop at full: pop proceeds; push absorbed per Q-003.

  9. F-09 Reset mid-traffic: empty within 1 cycle, in-flight data discarded, clean restart.

  10. F-10 Backpressure: sustained out_ready == 0 fills the FIFO; release drains in order.

  11. F-11 Parameter sweep: behavior holds at DEPTH 2 (minimum) and WIDTH 1 (degenerate).


The verification plan table

diagram
VERIFICATION PLAN — fifo v1.2

  ID   │ Feature             │ Approach              │ Coverage / Check        │ Owner
  ─────┼─────────────────────┼───────────────────────┼─────────────────────────┼──────
  F-01 │ data integrity,     │ random, all tests     │ scoreboard in-order     │  SB
       │ in-order            │                       │ compare; a_data_integ   │
  F-02 │ full @ count=DEPTH  │ burst-fill directed   │ a_full_def;             │  SB
       │                     │ + random              │ cp_count.full bin       │
  F-03 │ empty @ count=0     │ drain directed        │ a_empty_def;            │  SB
       │                     │ + random              │ cp_count.empty bin      │
  F-04 │ ready/valid mirror  │ assertion, always on  │ a_ready_def, a_valid_def│  SB
  F-05 │ push @ full blocked │ stress + error test   │ a_no_push_full;         │  RK
       │                     │                       │ x_op_state full bin     │
  F-06 │ pop @ empty blocked │ stress + error test   │ a_no_pop_empty;         │  RK
       │                     │                       │ x_op_state empty bin    │
  F-07 │ push+pop mid-level  │ random mixed-rate     │ cp_simul bin            │  SB
  F-08 │ push+pop @ full     │ directed corner test  │ cp_simul_full bin       │  SB
  F-09 │ reset mid-traffic   │ reset-storm test      │ cp_reset_busy bin;      │  RK
       │                     │                       │ post-reset SB restart   │
  F-10 │ backpressure drain  │ burst/drain scenario  │ cp_backpressure bins    │  SB
  F-11 │ param corners       │ regression configs    │ DEPTH=2 + WIDTH=1 runs  │  RK

  Status column omitted here — all rows start "open".

Corner inventory — the cases that find FIFO bugs

  • Exact boundaries: the cycle full asserts, the cycle empty asserts — off-by-one heaven (count == DEPTH-1 vs DEPTH).

  • Simultaneous push+pop at empty+1, at full-1, at full (F-08) — the pointer-update ordering bugs live here.

  • Reset mid-traffic, mid-burst, and reset released directly into a push — F-09.

  • Wrap-around: pointers crossing DEPTH back to 0 repeatedly — masked when tests push fewer than DEPTH total items.

  • Sustained backpressure then sudden drain at full rate — F-10.

Key takeaways

  • One spec sentence can hide several features — extract until each row has one stimulus and one check.

  • Ambiguities (simultaneous ops at full, data validity at empty) go to the architect, never guessed from RTL.

  • The corner inventory is the FIFO bug map: boundaries, simultaneity, reset, wrap-around, backpressure.

Common pitfalls

  • Testing only deep FIFOs — DEPTH=2 exposes pointer bugs big configs hide.

  • Comparing out_data while out_valid is low — spec says undefined (Q-004).

  • Pushing fewer than DEPTH items in any test — pointer wrap-around never exercised.