Say these out loud until they are automatic. Each answer is the version that survives a follow-up “are you sure?”
| Question | Model answer |
|---|---|
| Why a FIFO? | Elastic buffer for rate matching and backpressure. It does not create bandwidth. |
| Overflow vs stall? | Overflow = write still commits when occupancy is DEPTH (data lost). Stall = wr_en high, full high, wr_fire=0. Same idea for underflow vs empty. |
| How do you prove none? | Golden queue of DEPTH + SVA: never wr_fire at occ==DEPTH, never rd_fire at occ==0. |
| Sync vs async? | One clock vs two. Async: dual-port RAM, Gray pointers, 2FF, full in wr domain, empty in rd domain. |
| Why not 2FF a data bus? | Reconvergent multi-bit CDC — bits sampled at different times invent illegal vectors. |
| Why Gray for pointers? | Adjacent counts differ by one bit. Synchronizer captures old or new, both legal. |
| Why not Gray the data? | Payload is not a unit-distance counter. Keep data in RAM; only pointers cross. |
| Empty formula? | In rd domain: (next) read Gray equals 2FF-synced write Gray. |
| Full formula? | In wr domain: (next) write Gray equals synced read Gray with two MSBs inverted. |
| Binary full vs Gray full? | Binary extra-MSB inverts one bit. Gray inverts two MSBs. Do not mix. |
| XOR then flop or flop then XOR? | Convert bin_next to gray_next, then register. CDC the flop output. |
| DEPTH? | Power of two for this Gray style. Size from worst-case burst plus CDC pointer latency. |
| Reset? | Clear both pointer engines and both 2FF chains. Sync deassert per domain. |
| Why conservative flags? | 2FF delay hides recent opposite-side traffic. Prefer false full/empty over overflow/underflow. |
bin2gray = x^(x>>1) and the two flag equations.full.In the simulator, implement only bin2gray and the full comparator for PTR_W=4. Stimulus: walk wbin 0..16 with rbin=0; full must rise exactly when occupancy hits 8 for DEPTH=8 (PTR_W=4, 2^3=8).
2 min: “Async FIFO is a dual-clock queue. Data sits in dual-port RAM. I Gray-code extra-wide pointers, 2FF them, generate full where I write and empty where I read.”
5 min: Add binary CDC failure (7→8), Gray unit distance, conservative flags, power-of-two depth.
15 min: Derive empty and two-MSB full, reset, almost-full via gray2bin, SVA $onehot0(gray ^ $past(gray)), and why registered Gray matters.
“Show me occupancy=3, DEPTH=8, in Gray.” Walk wbin and rbin, convert both, explain empty/full are both 0. “What if wr_clk is 10× faster?” Apparent depth shrinks because empty lags; you may need more RAM or almost-full sooner. “FWFT?” Output register in rd domain. “Non-power-of-two?” Don’t fake Gray wrap — use 16 deep or a vendor FIFO. “Can I false-path the RAM?” No. Only the Gray-to-FF1 path.
You name the failure (multi-bit CDC) before the solution (Gray). You put full in the write domain without being prompted. You say stall ≠ overflow. You invert two Gray MSBs. You mention reset of both 2FF chains. If you only say “we use a FIFO IP,” expect a follow-up to draw the IP’s internals.
Dual-clock queue. Data in dual-port RAM. Extra-wide pointers Gray-coded, 2FF’d, full where you write, empty where you read. Conservative because of synchronizer delay.
Binary extra-MSB inverts one wrap bit. Gray full inverts two MSBs of the synced read Gray. Mixing them is a frequent fail.
Golden queue of DEPTH plus SVA: never wr_fire at occ==DEPTH, never rd_fire at occ==0. Stall is allowed; commit past the limit is not.
Combinational Gray can glitch multiple bits. The synchronizer must see a flopped unit-distance bus.