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