hw/ip/prim/rtl/prim_fifo_sync.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // Generic synchronous fifo for use in a variety of devices.
6:
7: module prim_fifo_sync #(
8: parameter int unsigned Width = 16,
9: parameter bit Pass = 1'b1, // if == 1 allow requests to pass through empty FIFO
10: parameter int unsigned Depth = 4,
11: // derived parameter
12: localparam int unsigned DepthWNorm = $clog2(Depth+1),
13: localparam int unsigned DepthW = (DepthWNorm == 0) ? 1 : DepthWNorm
14: ) (
15: input clk_i,
16: input rst_ni,
17: // synchronous clear / flush port
18: input clr_i,
19: // write port
20: input wvalid,
21: output wready,
22: input [Width-1:0] wdata,
23: // read port
24: output rvalid,
25: input rready,
26: output [Width-1:0] rdata,
27: // occupancy
28: output [DepthW-1:0] depth
29: );
30:
31: // FIFO is in complete passthrough mode
32: if (Depth == 0) begin : gen_passthru_fifo
33: `ASSERT_INIT(paramCheckPass, Pass == 1)
34:
35: assign depth = 1'b0; //output is meaningless
36:
37: // devie facing
38: assign rvalid = wvalid;
39: assign rdata = wdata;
40:
41: // host facing
42: assign wready = rready;
43:
44: // this avoids lint warnings
45: logic unused_clr;
46: assign unused_clr = clr_i;
47:
48: // Normal FIFO construction
49: end else begin : gen_normal_fifo
50:
51: // consider Depth == 1 case when $clog2(1) == 0
52: localparam int unsigned PTRV_W = $clog2(Depth) + ~|$clog2(Depth);
53: localparam int unsigned PTR_WIDTH = PTRV_W+1;
54:
55: logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
56: logic fifo_incr_wptr, fifo_incr_rptr, fifo_empty;
57:
58: // create the write and read pointers
59: logic full, empty;
60: logic wptr_msb;
61: logic rptr_msb;
62: logic [PTRV_W-1:0] wptr_value;
63: logic [PTRV_W-1:0] rptr_value;
64:
65: assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
66: assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
67: assign wptr_value = fifo_wptr[0+:PTRV_W];
68: assign rptr_value = fifo_rptr[0+:PTRV_W];
69: assign depth = (full) ? DepthW'(Depth) :
70: (wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
71: (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
72:
73: assign fifo_incr_wptr = wvalid & wready;
74: assign fifo_incr_rptr = rvalid & rready;
75:
76: assign wready = ~full;
77: assign rvalid = ~empty;
78:
79: always_ff @(posedge clk_i or negedge rst_ni) begin
80: if (!rst_ni) begin
81: fifo_wptr <= {(PTR_WIDTH){1'b0}};
82: end else if (clr_i) begin
83: fifo_wptr <= {(PTR_WIDTH){1'b0}};
84: end else if (fifo_incr_wptr) begin
85: if (fifo_wptr[PTR_WIDTH-2:0] == (Depth-1)) begin
86: fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
87: end else begin
88: fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
89: end
90: end
91: end
92:
93: always_ff @(posedge clk_i or negedge rst_ni) begin
94: if (!rst_ni) begin
95: fifo_rptr <= {(PTR_WIDTH){1'b0}};
96: end else if (clr_i) begin
97: fifo_rptr <= {(PTR_WIDTH){1'b0}};
98: end else if (fifo_incr_rptr) begin
99: if (fifo_rptr[PTR_WIDTH-2:0] == (Depth-1)) begin
100: fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
101: end else begin
102: fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
103: end
104: end
105: end
106:
107: assign full = (fifo_wptr == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
108: assign fifo_empty = (fifo_wptr == fifo_rptr);
109:
110:
111: // the generate blocks below are needed to avoid lint errors due to array indexing
112: // in the where the fifo only has one storage element
113: logic [Depth-1:0][Width-1:0] storage;
114: logic [Width-1:0] storage_rdata;
115: if (Depth == 1) begin : gen_depth_eq1
116: assign storage_rdata = storage[0];
117:
118: always_ff @(posedge clk_i)
119: if (fifo_incr_wptr) begin
120: storage[0] <= wdata;
121: end
122: // fifo with more than one storage element
123: end else begin : gen_depth_gt1
124: assign storage_rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
125:
126: always_ff @(posedge clk_i)
127: if (fifo_incr_wptr) begin
128: storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
129: end
130: end
131:
132: if (Pass == 1'b1) begin : gen_pass
133: assign rdata = (fifo_empty && wvalid) ? wdata : storage_rdata;
134: assign empty = fifo_empty & ~wvalid;
135: end else begin : gen_nopass
136: assign rdata = storage_rdata;
137: assign empty = fifo_empty;
138: end
139:
140: `ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth), clk_i, !rst_ni)
141: end // block: gen_normal_fifo
142:
143:
144: //////////////////////
145: // Known Assertions //
146: //////////////////////
147:
148: `ASSERT(DataKnown_A, rvalid |-> !$isunknown(rdata), clk_i, !rst_ni)
149: `ASSERT_KNOWN(DepthKnown_A, depth, clk_i, !rst_ni)
150: `ASSERT_KNOWN(RvalidKnown_A, rvalid, clk_i, !rst_ni)
151: `ASSERT_KNOWN(WreadyKnown_A, wready, clk_i, !rst_ni)
152:
153: endmodule
154: