A stream of data words cannot cross with bit-wise synchronisers (see the bus lesson). A handshake works but moves one word per round trip, costing several cycles of both clocks.
An asynchronous FIFO moves up to one word per cycle of the slower clock. Data never crosses a synchroniser: it waits in memory until the pointers mark it valid.
Method | Throughput | Latency | Area | Use for |
|---|---|---|---|---|
2FF per bit | n/a (unsafe for related bits) | – | tiny | Independent single bits only |
Handshake with stable data | 1 word per round trip (about 9 source cycles per word in the lesson's testbench; depends on the two clock ratios) | Medium | Small | Control and configuration, low rates |
Gray pointer for a counter | 1 value per sample | 2 to 3 cycles | Tiny | Counters and pointers |
Asynchronous FIFO | Up to 1 word per slower clock | A few cycles | Memory + pointers | Streams and bursts, rate matching |
Read each row along the same 18 source cycles; one box is one word delivered.
The handshake spends about 9 source cycles on each word: request across, acknowledge back, then both return to zero.
The FIFO overlaps those crossings. With both sides ready, it delivers one word per cycle of the slower clock, here the 10 ns source.
The FIFO pays for that with memory and two pointer synchronisers, so the handshake is still the right choice for rare configuration writes.
Safe multi-bit transfer: data sits in memory; only single-bit-changing pointers cross.
Rate matching and bursts: it absorbs short mismatches between the producer and consumer rates.
Clean interface: winc/wfull on one side, rinc/rempty on the other, both simple synchronous handshakes.
Reusable: the structure is the same for any data width and any power-of-two depth of 2 or more.
Latency: a word written becomes visible to the reader only after its write pointer crosses (2 or 3 read-clock cycles).
Depth: it must be deep enough to cover the worst burst imbalance plus the pointer crossing delay.
Pessimistic flags: full and empty are decided from stale information, so the FIFO can report full or empty a few entries early.
For an explicit workload envelope, bound Q(t) = Q0 + A(t) − C(t), where A counts accepted arrivals and C counts reads that can actually occur (including startup/empty visibility and consumer pauses). Choose power-of-two depth at least the largest Q over every allowed phase/pause trace, including post-warning writes. If sizing from offered arrivals, either guarantee enough capacity for all offers or explicitly budget stalls. Full always gates acceptance; almost-full reserves capacity for a producer that cannot stop immediately.
Illustrative trace (not a measured run) | Occupancy bound |
|---|---|
Q0=8, 100 arrivals at 200 MHz; 100 MHz consumer continuously available | Steady-rate increase 50; phase/visibility can reduce service below 50 reads |
First 100 ns of the 500 ns burst has no consumer service; minimum service in remaining 400 ns is 40 reads | 8 + 100 − 40 = 68; depth 64 is insufficient |
After the warning, at most 6 more arrivals with no guaranteed reads | Reserve at least 6 slots at the warning; include these arrivals in A if outside the original burst |
100 × max(0, 1 − 100/200) = 50 words, so 64 is the next power-of-two depth. Prefill, pauses, start phase and reaction latency require a separate worst-case bound.
The occupancy trace in the sizing table is illustrative; it is not a measured run.