FIFO depth from burst arithmetic
Size a FIFO from the burst, the consumer's rate and its stall, check the arithmetic against the words a bench counts, and see why no depth fixes a rate mismatch.
- Lesson
- R5.3
- Time
- 30 min
- Runs on
- Your browser
- Check
- 5 questions
A producer wrote bursts of 64 words, one per cycle, into a consumer that took one word every two cycles. The FIFO between them was 16 deep, sized "to be safe". On the first burst it refused the 32nd word, and 17 words were lost.
used is the count register after each edge.- Cycle 0
Cycle 26: two words arrive for every one that leaves, so
usedclimbs by one every two cycles. - Cycle 4
Cycle 30: the 31st word makes 16. The FIFO is full.
- Cycle 5
Cycle 31: the 32nd word arrives while a word leaves. The FIFO decides from the count before the edge, so it takes the read and refuses the write.
- Cycle 8
From cycle 31 every second word is lost, 17 in all, and
overflowstays 1 until reset.
Measured with a probe of the lesson's design at DEPTH 16.
Arrivals minus departures
A FIFO absorbs the difference between how fast words arrive and how fast they leave. The words it holds at any moment are the arrivals so far minus the departures so far. The depth must cover the largest value that difference reaches.
- Burst
For B cycles a word arrives every cycle. The consumer takes one every C cycles, so the count climbs by B - B / C over the burst.
- Peak
The count peaks when the last word arrives. After that the FIFO only drains.
- Last word
If the FIFO is full before the edge where the last word arrives, the accept logic refuses it, even when a word leaves at that edge.
Read the diagram as text
- Producer: B words, one per cycle
- FIFO: DEPTH slots
- Consumer: waits S, then one per C cycles
- Accept logic: full and empty before the edge
- Producer → FIFO: write
- FIFO → Consumer: read
- FIFO → Accept logic: count
The depth covers the peak of arrivals minus departures, plus what the accept rule needs.
Take a burst of B words at one per cycle, and a consumer that reads one word every C cycles. During the B cycles of the burst, the consumer takes B / C words, so the FIFO peaks at B - B / C. For the hook: 64 - 32 = 32 words.
- Cycle 1
Cycle 1: a word leaves for the first time. Every two cycles, two arrive and one leaves.
- Cycle 15
Cycle 15: the last of 16 words arrives while the eighth word leaves. The peak is 8, which is 16 - 16 / 2.
- Cycle 23
Cycle 23: with no arrivals, the FIFO drains one word every two cycles. It is empty at cycle 31.
Measured with a probe of the lesson's design at DEPTH 16. No word is lost.
A stall of S cycles before the consumer starts leaves fewer reads inside the burst: (B - S) / C of them. The peak becomes B - (B - S) / C. With C = 2, a stall of 8 cycles costs 4 words of depth, not 8.
One more word than the peak
The arithmetic gives the peak, with (B - S) / C rounded down. On this FIFO the depth to set is one more whenever the last word of the burst arrives in a cycle with a read. Every pattern on this page does that. Look at cycle 15 of the ramp: the last word arrives in the same cycle a word leaves. If the FIFO were full before that edge, it would refuse the arriving word. When the last word arrives in a cycle with no read, the peak itself is enough.
Both decisions use the count before the edge, the rule of R5.2 and of the FIFO the SystemVerilog track verifies. So a slot freed by a read is free only after the edge, one cycle late for a word arriving at the same edge.
| Burst B | Read every C | Stall S | B - (B - S) / C | Most held, measured | Smallest DEPTH with no loss |
|---|---|---|---|---|---|
| 64 | 2 | 0 | 32 | 32 | 33 |
| 16 | 4 | 0 | 12 | 12 | 13 |
| 32 | 2 | 8 | 20 | 20 | 21 |
| 8 | 2 | 0 | 4 | 4 | 5 |
Measured on the lab bench: most held at a DEPTH with no loss, and the depth found by trying it and the depth below it. One depth less loses exactly one word in each row.
What depth cannot fix
The formula assumes the burst ends and the FIFO drains before the next one. Over a long run, if words arrive faster than they leave, the backlog grows by the difference every burst. No finite depth holds it.
| Bursts of 8 words, one every | Arrive per burst | Leave per burst | Held at the end of bursts 1, 2, ... 10 |
|---|---|---|---|
| 16 cycles | 8 | 8 | 4 every time |
| 14 cycles | 8 | 7 | 4, 5, 6, ... 13: one more per burst |
| 12 cycles | 8 | 6 | 4, 6, 8, ... 22: two more per burst |
Measured with a probe of the lesson's design at DEPTH 64, consumer reading every second cycle, ten bursts.
Depth also has costs. Measured at DEPTH 16, 33 and 64: 448, 1000 and 1666 cells, with 151, 292 and 541 flops. A deep FIFO adds latency too: in the hook's burst at DEPTH 33, the last word arrives at cycle 63 and leaves at cycle 127.
The lab: size the FIFO
| Port | Direction | Width | Meaning |
|---|---|---|---|
| clk | input | 1 | clock |
| rst_n | input | 1 | reset, asynchronous, active-low |
| write_en | input | 1 | as in R5.2 |
| write_data | input | [WIDTH-1:0] | as in R5.2 |
| read_en | input | 1 | as in R5.2 |
| read_data | output | [WIDTH-1:0] | as in R5.2 |
| read_valid | output | 1 | as in R5.2 |
| full | output | 1 | as in R5.2 |
| empty | output | 1 | as in R5.2 |
| overflow | output | 1 | 1 from the first edge where a write is offered while full, until reset |
- Throughput
- a burst of B words, one per cycle; the consumer waits S cycles, then reads in the last cycle of every C
- Parameters
DEPTHwords, any value from 2 up, 16 shipped;WIDTH8. Patterns: B 64, C 2, S 0; B 16, C 4, S 0; B 32, C 2, S 8- Corner cases
- the last word arriving as a word leaves; a stall at the start; a DEPTH one below the need. Rule: at full, a write and a read together: the read is accepted, the write refused
Run the lab. At DEPTH 16 the first and third patterns lose words and report most held 16; the second fits, with a peak of 12. Work out the depth for each pattern, set DEPTH to the largest, and run again.
At DEPTH 33 every pattern fits, with peaks of 32, 12 and 20. Try 32: the first pattern loses one word. Synthesize at 16 and at 33: 448 cells, 151 flops, 13 levels of logic, then 1000 cells, 292 flops, 14 levels.
Asked in interviews
How do you size a FIFO?
Find the largest value of arrivals minus departures over the worst burst. Count a consumer stall in the departures: a stall of S cycles removes S / C reads from the burst, never S words. Add one word if the FIFO refuses a write at full in the cycle it is read.
A producer bursts 64 words at line rate into a half-rate consumer: what depth?
The consumer takes 32 during the burst, so the peak is 32. A FIFO that decides from the count before the edge needs 33.
Why can no FIFO fix a rate mismatch?
If words arrive faster than they leave over the long run, the backlog grows every burst. A FIFO only smooths bursts; the average rates must match or the producer must be slowed.
Try it
Each line is one pattern, after a reset. most held is the largest count the bench saw after any edge, and lost counts writes offered while full. A FIFO that reports most held equal to its DEPTH has been full, and may have lost words.
At DEPTH 33 the lines read most held 32, 12 and 20, with no loss. At DEPTH 32 the first line reads most held 32, lost 1.
Synthesize the design to measure its cells and inspect the mapped gates.
burst 64, read every 2, stall 0: most held 16, lost 17, overflow=1 burst 16, read every 4, stall 0: most held 12, lost 0, overflow=0 burst 32, read every 2, stall 8: most held 16, lost 5, overflow=1Original design · 448 cells · 151 flip-flops · 0 latches · 13 logic levels. Synthesis uses Yosys; counts depend on the toolchain.
Read included file: tb.sv
`timescale 1ns/1ps
module tb;
logic clk = 0;
always #5 clk = ~clk; // rising edges at 5, 15, 25, ...
logic rst_n = 1; // falls at 1 ns: a real edge, so an asynchronous reset acts before any clock
int edge_n = -1;
always @(posedge clk) edge_n = edge_n + 1;
logic write_en = 0, read_en = 0;
logic [7:0] write_data = 0, read_data;
logic read_valid, full, empty, overflow;
// One traffic pattern: a burst of b words, one per cycle from cycle 0; the consumer waits s
// cycles, then reads in the last cycle of every c. The bench counts what the FIFO holds.
int held, most, lost;
task automatic pattern(input int b, input int c, input int s);
int t;
bit wf, re_ok;
rst_n = 0; #1 rst_n = 1; // empty the FIFO and clear overflow
held = 0; most = 0; lost = 0; t = 0;
while (t < b || held > 0) begin
write_en = (t < b); write_data = 8'(t);
read_en = (t >= s) && ((t - s) % c == c - 1);
wf = full; re_ok = read_en && !empty; // the flags before the edge
tick();
if (write_en && wf) lost++;
held = held + (write_en && !wf) - re_ok;
if (held > most) most = held;
t++;
end
write_en = 0; read_en = 0;
endtask
task automatic run(input int b, input int c, input int s);
pattern(b, c, s);
$display("burst %0d, read every %0d, stall %0d: most held %0d, lost %0d, overflow=%b",
b, c, s, most, lost, overflow);
endtask
sync_fifo dut (.clk(clk), .rst_n(rst_n), .write_en(write_en), .write_data(write_data), .read_en(read_en),
.read_data(read_data), .read_valid(read_valid), .full(full), .empty(empty), .overflow(overflow));
// Advance to the next rising edge, wait for the design to settle, then print one line.
task automatic tick();
@(posedge clk); #1;
endtask
initial begin
#1 rst_n = 0; tick(); tick(); rst_n = 1; // asserted at 1 ns, edges 0 and 1 in reset, released 1 ns after edge 1
run(64, 2, 0);
run(16, 4, 0);
run(32, 2, 8);
$finish(0); // quiet: no "$finish called" line
end
endmodule
Check yourself
Remember
- The words a FIFO holds are the arrivals so far minus the departures so far; the depth must cover the largest value over the worst burst.
- A burst of B words at one per cycle into a consumer that waits S cycles, then reads every C, peaks at B - (B - S) / C.
- When both accept decisions use the count before the edge, a full FIFO refuses a write in the cycle it is read, so set the depth one above the peak whenever the last word of the burst arrives in a read cycle.
- If the long-run arrival rate exceeds the departure rate, the backlog grows every burst and no depth is enough.