Property | Registered output | First-word fall-through (FWFT/show-ahead) |
|---|---|---|
When data appears | After an accepted pop | As soon as the FIFO is non-empty |
Output qualification | Pop-result valid pulse |
|
Read path | Clocked memory read | Combinational array read or a prefetch register |
Latency | One cycle from pop to result | Front word already visible |
Timing | Registered boundary | May expose memory/mux delay to the consumer |
Memory mapping | Usually block-RAM friendly | Direct combinational form may force flops/LUT RAM |
Each slot is one clock cycle. Both FIFOs hold A and B before slot 0, and both get pops in slots 1 and 3.
Slot 0: the fall-through FIFO already shows A with fwft_valid high. The registered FIFO shows nothing valid yet.
Slot 1: the pop takes A. The fall-through consumer reads A in this same slot; the registered FIFO delivers A in slot 2 with a one-cycle valid pulse.
Slot 3: the second pop takes B. The registered result arrives in slot 4.
Slot 4: the fall-through FIFO is empty, so its valid is 0 and its data is unknown. Only valid gives the data meaning.
// snippet: simple FWFT view; often not block-RAM compatible
assign dout_o = mem[rd_ptr];
assign dout_valid_o = !empty_o;
assign pop_take = pop_i && dout_valid_o;This is easy to reason about, but it creates an asynchronous memory read. It is suitable for a small flop-based queue and risky for a large FIFO intended for a synchronous SRAM macro.
Because the running FIFO targets a synchronous memory, it retains registered pop-result behavior. A separate FWFT variant would need a prefetch controller and a different consumer contract rather than a one-line output substitution.
A memory-friendly FWFT design keeps an output register filled whenever data exists. The prefetch controller reads the next word before the current front word is consumed. That preserves a registered external path but adds state for output-valid, refill, and the case where pop and refill coincide.
assign dout = mem[rd_ptr] prevent block-RAM inference?It describes an asynchronous read. Many block RAMs and ASIC SRAM macros provide a clocked read, so the tool must use distributed memory or flops to preserve the combinational behavior.
At minimum an output register and output-valid state, plus refill control that keeps the register loaded across consumes, memory latency, and simultaneous push/pop cases.