Skip to content

Commit

Permalink
[prim_fifo_sync,rtl] Specialize for Depth == 1
Browse files Browse the repository at this point in the history
This case is pretty simple to reason about, and avoids needing proper
read and write addresses (because there is only one element).

Signed-off-by: Rupert Swarbrick <[email protected]>
  • Loading branch information
rswarbrick committed Dec 2, 2024
1 parent 16b5876 commit 76bb460
Showing 1 changed file with 48 additions and 20 deletions.
68 changes: 48 additions & 20 deletions hw/ip/prim/rtl/prim_fifo_sync.sv
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,49 @@ 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 full_o = full_q;
assign depth_o = full_q;
assign wready_o = ~full_q;

// We can always read from the storage if it contains something, 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;

// The err_o signal is only used for larger depths, where there are redundant counters that get
// checked.
assign err_o = 1'b0;

// Normal FIFO construction
end else begin : gen_normal_fifo

Expand Down Expand Up @@ -100,30 +143,15 @@ module prim_fifo_sync #(
assign fifo_incr_wptr = wvalid_i & wready_o & ~under_rst;
assign fifo_incr_rptr = rvalid_o & rready_i & ~under_rst;

// the generate blocks below are needed to avoid lint errors due to array indexing
// in the where the fifo only has one storage element
logic [Depth-1:0][Width-1:0] storage;
logic [Width-1:0] storage_rdata;
if (Depth == 1) begin : gen_depth_eq1
assign storage_rdata = storage[0];

always_ff @(posedge clk_i)
if (fifo_incr_wptr) begin
storage[0] <= wdata_i;
end

logic unused_ptrs;
assign unused_ptrs = ^{fifo_wptr, fifo_rptr};

// fifo with more than one storage element
end else begin : gen_depth_gt1
assign storage_rdata = storage[fifo_rptr];
assign storage_rdata = storage[fifo_rptr];

always_ff @(posedge clk_i)
if (fifo_incr_wptr) begin
storage[fifo_wptr] <= wdata_i;
end
end
always_ff @(posedge clk_i)
if (fifo_incr_wptr) begin
storage[fifo_wptr] <= wdata_i;
end

logic [Width-1:0] rdata_int;
if (Pass == 1'b1) begin : gen_pass
Expand Down

0 comments on commit 76bb460

Please sign in to comment.