13Implementation
Make a FIFO track how full it is
Problem
Intended behavior. sync_fifo stores up to DEPTH words of WIDTH bits in
arrival order. At each rising edge, push writes din behind the stored words
and pop removes the oldest word; dout always shows the oldest word while the
FIFO is not empty. count is the number of stored words, full is 1 exactly
when count equals DEPTH, and empty is 1 exactly when count is 0. A push
while full and a pop while empty are ignored. When both arrive at one edge, each
one that is allowed takes effect: one word in and one word out leaves count
unchanged. Reset is synchronous and active-high and empties the FIFO.
Current behavior. The storage and both pointers already work, and
do_push and do_pop already consult full and empty. But count never
changes and both flags are tied to 0. In the public output count stays 0,
empty is 0 even right after reset, the pop in cycle 0 moves the read pointer
of an empty FIFO so dout later shows 20 instead of 10, and the pushes of 50
and 60 in cycles 5 and 6 overwrite 10 and 20.
Your task. Replace the two TODO parts: the count update inside the
clocked block and the two flag assignments. Keep the storage, the pointers,
do_push, do_pop, the ports, the parameters, and the public testbench.
Predict the trace first
Each line is one cycle: the inputs driven during it and the outputs visible
before the rising edge that ends it, so a push in cycle n shows up in the
count of cycle n + 1. Before editing, write the expected count, full
and empty for all thirteen cycles of a correct FIFO with DEPTH = 4:
- In which cycle does
fullfirst read 1, and what happens to the pushes of50and60? - In cycle 6,
pushandpopare both 1 while the FIFO is full. What iscountin cycle 7? - In cycle 11 both are 1 while the FIFO is empty. Which one takes effect?
Fix, run, and check
Run your version and compare it with your table line by line. Then open the
waveform: count should change only at rising edges. full and empty
should reflect the updated count without an extra cycle of delay; a flag changes
only when count enters or leaves the corresponding full or empty condition. dout may show an old
value while empty is 1; nothing may rely on it then.
Completion check
countalways equals the number of stored words, including whenpushandpoparrive together, when the FIFO is full, and when it is empty.fullandemptyfollowcountin the same cycle.doutreturns the words in the order they were pushed, and no word is lost or repeated.- The design works for positive
WIDTHvalues andDEPTHvalues from 1 to 16, including depths that are not powers of two. The existing 4-bit pointers limit the depth to 16; your added logic must not assume a depth of 4. - Reset empties the FIFO, even when it was full.
Progressive hints
Hint 1
count changes by the number of words that actually entered minus the number
that actually left at this edge. The design already has a name for "a word
actually entered" and one for "a word actually left".
Hint 2
do_push and do_pop are 1-bit values, and both can be 1 at the same edge.
One assignment can handle all four combinations if it adds one and subtracts
the other.
Hint 3
Write both flags as comparisons of count with a parameter or a constant.
Comparing with DEPTH - 1 makes the FIFO report full one word early, and
comparing with the literal 4 breaks every other depth.
Transfer experiment
Change count to be computed from the pointers instead of stored: keep
wr_ptr and rd_ptr as they are and try full = (wr_ptr == rd_ptr). Predict
first why this cannot tell a full FIFO from an empty one, then find the cycle
in the waveform where both readings would claim the same pointers. Explain what
one extra bit per pointer, or the stored count you just wrote, adds.