Sign in on the Premium hub to save lesson progress. This lesson is open to read so the page is a complete article, not an empty login wall.
Lesson 4.2

Full and empty flag formulas

Empty: Gray pointers equal in the read domain. Full: Gray pointers match after inverting the two MSBs of the synchronized read pointer in the write domain. That is the Cummings style used in production RTL.

1

Empty — read domain

The reader knows the exact read Gray pointer. It only has a delayed copy of the write Gray pointer (rq2_wgray). If they are equal, every write the reader has heard about has already been consumed → empty.

If a write just happened but has not yet come through the 2FF, the reader still sees empty. That is conservative: you wait extra rd_clk cycles, you do not underflow.

empty
assign empty = (rgray == rq2_wgray);

Using rgray_next (combinational empty) is an alternative that goes empty on the cycle you pop the last beat, but it creates a combinational loop through rd_fire. Lesson 4.3 uses registered compare — simpler to synthesize. Then rd_fire = rd_en && !empty still prevents underflow.

2

Full — write domain, invert two MSBs

Pointers are ADDR_W+1 bits. When the writer has wrapped one more time than the reader, addresses match and the extra wrap bit differs. In Gray code that condition is: synchronized read Gray equals write Gray with the upper two bits inverted (not only the single MSB — because Gray’s MSB pair encodes the wrap).

full
// PTR_W = ADDR_W + 1. Invert Gray[PTR_W-1] and Gray[PTR_W-2].
assign full = (wgray ==
  {~wq2_rgray[PTR_W-1:PTR_W-2], wq2_rgray[PTR_W-3:0]});

Worked DEPTH=4, PTR_W=3. After 4 writes, wgray is Gray(4)=110 (bin 100). rptr still 000 → Gray 000. Invert two MSBs of 000 → 110. 110 == 110 → full. Correct.

After 4 reads, rptr=100, rgray=110. Synced into write domain. Invert two MSBs of 110 = 000. wptr also wrapped or not depending on more writes — check equal-pointer empty on read side separately.

Do not invert only one bit

Binary extra-MSB full is {~rptr[MSB], rptr[rest]} (one bit). Gray full inverts two MSBs. Mixing the two formulas is a common whiteboard mistake.

3

Why two MSBs — short Gray reason

For an (n+1)-bit Gray code, going around the circle once flips the pattern of the top two bits in a way that a single-bit invert does not match the Gray of (binary + 2^n). The SNUG-2002 identity is: full when wgray == {~rgray[n:n-1], rgray[n-2:0]} using the synchronized rgray.

4

Waveform — conservative empty

wgray updates on wr_clk. The read domain may not see that update for two of its clocks. Until rq2 matches, empty can stay 1 even though RAM already holds data. That lag is required. It is not a drawing of two clocks on the same period.

5

DEPTH=8, PTR_W=4 — full at occupancy 8

Addresses are 3 bits. Pointers are 4-bit Gray. After reset both Grays are 0000. Eight writes take wbin from 0 to 8 (1000). Gray(8)=1100. rgray still 0000. Invert two MSBs of 0000 → 1100. wgray==1100 matches → full. One read: rbin=1, rgray=0001. When that Gray syncs to write domain, invert two MSBs of 0001 = 1101, which is not 1100, so full falls — a slot is free from the writer’s conservative view only after the 2FF, which is later than the actual read.

Empty: after eight reads matching those writes, rgray catches wgray (both Gray(8)=1100 once synced) → empty. If the writer already moved on, rq2 is stale and empty may persist for two rd_clk edges — conservative.

6

Combinational next-Gray flags (advanced)

Some listings compute empty = (rgray_next == rq2_wgray) so empty rises on the cycle you pop the last beat. Then rd_fire depends on empty which depends on rd_fire unless you carefully break the loop with a registered empty. This course’s 4.3 RTL uses registered Gray compares: simpler, one extra cycle of flag latency, still safe. Do not copy a next-state flag formula into registered RTL without redrawing the loop.

Q

Frequently asked questions

What is the async FIFO empty formula?

In the read domain: empty when the registered read Gray equals the 2FF-synchronized write Gray (rgray == rq2_wgray).

What is the async FIFO full formula?

In the write domain: full when wgray equals the synchronized read Gray with the two MSBs inverted: wgray == {~wq2_rgray[PTR_W-1:PTR_W-2], wq2_rgray[PTR_W-3:0]}.

Why invert two Gray MSBs instead of one binary MSB?

Binary extra-MSB full inverts one wrap bit. Gray’s wrap is encoded in the top two bits of the (n+1)-bit code. Inverting only one Gray bit is a common whiteboard fail.

Why register the compare instead of using gray_next?

Using next Gray for same-cycle flags can loop combinationally through wr_fire/rd_fire. Registered compares are safer to synthesize; the beat that fills the last slot is still legal.

Key takeaways

  • Empty in rd domain: registered read Gray equals 2FF-synced write Gray.
  • Full in wr domain: Gray equal after inverting two MSBs of synced rgray.
  • 2FF delay makes flags pessimistic, which is required for safety.