Start of public OpenTitan development history
Code contributors:
Alex Bradbury <asb@lowrisc.org>
Cindy Chen <chencindy@google.com>
Eunchan Kim <eunchan@google.com>
Gaurang Chitroda <gaurangg@google.com>
Mark Hayter <mark.hayter@gmail.com>
Michael Schaffner <msf@google.com>
Miguel Osorio <miguelosorio@google.com>
Nils Graf <nilsg@google.com>
Philipp Wagner <phw@lowrisc.org>
Pirmin Vogel <vogelpi@lowrisc.org>
Ram Babu Penugonda <rampenugonda@google.com>
Scott Johnson <scottdj@google.com>
Shail Kushwah <kushwahs@google.com>
Srikrishna Iyer <sriyer@google.com>
Steve Nelson <Steve.Nelson@wdc.com>
Tao Liu <taliu@google.com>
Timothy Chen <timothytim@google.com>
Tobias Wölfel <tobias.woelfel@mailbox.org>
Weicai Yang <weicai@google.com>
diff --git a/hw/ip/prim/rtl/prim_fifo_sync.sv b/hw/ip/prim/rtl/prim_fifo_sync.sv
new file mode 100644
index 0000000..185120c
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_fifo_sync.sv
@@ -0,0 +1,99 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Generic synchronous fifo for use in a variety of devices.
+
+module prim_fifo_sync #(
+ parameter int unsigned Width = 16,
+ parameter bit Pass = 1'b1, // if == 1 allow requests to pass through empty FIFO
+ parameter int unsigned Depth = 4,
+ parameter int unsigned DepthW = $clog2(Depth+1) // derived parameter
+) (
+ input clk_i,
+ input rst_ni,
+ // write port
+ input wvalid,
+ output wready,
+ input [Width-1:0] wdata,
+ // read port
+ output rvalid,
+ input rready,
+ output [Width-1:0] rdata,
+ // occupancy
+ output [DepthW-1:0] depth
+);
+
+ `ASSERT_INIT(paramCheckDepthW, DepthW == $clog2(Depth+1))
+
+ // consider Depth == 1 case when $clog2(1) == 0
+ localparam int unsigned PTRV_W = $clog2(Depth) + ~|$clog2(Depth);
+ localparam int unsigned PTR_WIDTH = PTRV_W+1;
+
+ logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
+ logic fifo_incr_wptr, fifo_incr_rptr, fifo_empty;
+
+ // create the write and read pointers
+ logic full, empty;
+ logic wptr_msb;
+ logic rptr_msb;
+ logic [PTRV_W-1:0] wptr_value;
+ logic [PTRV_W-1:0] rptr_value;
+
+ assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
+ assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
+ assign wptr_value = fifo_wptr[0+:PTRV_W];
+ assign rptr_value = fifo_rptr[0+:PTRV_W];
+ assign depth = (full) ? DepthW'(Depth) :
+ (wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
+ (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
+
+ assign fifo_incr_wptr = wvalid & wready;
+ assign fifo_incr_rptr = rvalid & rready;
+
+ assign wready = ~full;
+ assign rvalid = ~empty;
+
+ always_ff @(posedge clk_i or negedge rst_ni)
+ if (!rst_ni) begin
+ fifo_wptr <= {(PTR_WIDTH){1'b0}};
+ end else if (fifo_incr_wptr) begin
+ if (fifo_wptr[PTR_WIDTH-2:0] == (Depth-1)) begin
+ fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
+ end else begin
+ fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni)
+ if (!rst_ni) begin
+ fifo_rptr <= {(PTR_WIDTH){1'b0}};
+ end else if (fifo_incr_rptr) begin
+ if (fifo_rptr[PTR_WIDTH-2:0] == (Depth-1)) begin
+ fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
+ end else begin
+ fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
+ end
+ end
+
+ assign full = (fifo_wptr == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
+ assign fifo_empty = (fifo_wptr == fifo_rptr);
+
+ logic [Width-1:0] storage [0:Depth-1];
+
+ always_ff @(posedge clk_i)
+ if (fifo_incr_wptr) begin
+ storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
+ end
+
+ if (Pass == 1'b1) begin : gen_pass
+ assign empty = fifo_empty & ~wvalid;
+ assign rdata = (fifo_empty && wvalid) ? wdata : storage[fifo_rptr[PTR_WIDTH-2:0]];
+ end else begin : gen_nopass
+ assign empty = fifo_empty;
+ assign rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
+ end
+
+ `ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth), clk_i, !rst_ni)
+
+endmodule