diff --git a/hw/ip/prim/rtl/prim_fifo_sync.sv b/hw/ip/prim/rtl/prim_fifo_sync.sv index c4c1ac429fd46a..a8e00e2af385bb 100644 --- a/hw/ip/prim/rtl/prim_fifo_sync.sv +++ b/hw/ip/prim/rtl/prim_fifo_sync.sv @@ -55,6 +55,44 @@ module prim_fifo_sync #( // No error assign err_o = 1'b 0; + // FIFO has space for a single element (and doesn't need proper counters) + end else if (Depth == 1) begin : gen_singleton_fifo + + // full_q is true if the (singleton) queue has data + logic full_d, full_q; + + assign depth_o = full_q; + assign wready_o = ~full_q; + + // We can always read from the storage if nonempty, so rvalid_o is true if full_q is true. + // Enabling pass-through mode also allows data to flow through if wvalid_i is true. + assign rvalid_o = full_q || (Pass && wvalid_i); + + // For there to be data on the next cycle, there must either be new data coming in (so !rvalid_o + // && wvalid_i) or we must be keeping the current data (so rvalid_o && !rready_i). Using + // rvalid_o instead of full_q ensures we get the right behaviour with pass-through. + // + // In either case, any stored data will be forgotten if clr_i is true. + assign full_d = (rvalid_o ? !rready_i : wvalid_i) && !clr_i; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + full_q <= 1'b0; + end else begin + full_q <= full_d; + end + end + + logic [Width-1:0] storage; + always_ff @(posedge clk_i) begin + if (wvalid_i && wready_o) storage <= wdata_i; + end + + logic [Width-1:0] rdata_int; + assign rdata_int = (full_q || Pass == 1'b0) ? storage : wdata_i; + + assign rdata_o = (OutputZeroIfEmpty && !rvalid_o) ? Width'(0) : rdata_int; + // Normal FIFO construction end else begin : gen_normal_fifo