blob: e2199db623a6bf462494d9a2abaf6fa414e91289 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001// 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
Greg Chadwickcf423082020-02-05 16:52:23 +00007`include "prim_assert.sv"
8
lowRISC Contributors802543a2019-08-31 12:12:56 +01009module prim_fifo_sync #(
Timothy Chen61e25e82019-09-13 14:04:10 -070010 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,
Scott Johnsonb7c9e3b2020-01-03 14:46:50 -080013 // derived parameter
Timothy Chen61e25e82019-09-13 14:04:10 -070014 localparam int unsigned DepthWNorm = $clog2(Depth+1),
Scott Johnsonb7c9e3b2020-01-03 14:46:50 -080015 localparam int unsigned DepthW = (DepthWNorm == 0) ? 1 : DepthWNorm
lowRISC Contributors802543a2019-08-31 12:12:56 +010016) (
17 input clk_i,
18 input rst_ni,
Michael Schaffner44242c42019-10-29 09:14:22 -070019 // synchronous clear / flush port
20 input clr_i,
lowRISC Contributors802543a2019-08-31 12:12:56 +010021 // write port
22 input wvalid,
23 output wready,
24 input [Width-1:0] wdata,
25 // read port
26 output rvalid,
27 input rready,
28 output [Width-1:0] rdata,
29 // occupancy
30 output [DepthW-1:0] depth
31);
32
Timothy Chen61e25e82019-09-13 14:04:10 -070033 // FIFO is in complete passthrough mode
34 if (Depth == 0) begin : gen_passthru_fifo
35 `ASSERT_INIT(paramCheckPass, Pass == 1)
lowRISC Contributors802543a2019-08-31 12:12:56 +010036
Timothy Chen61e25e82019-09-13 14:04:10 -070037 assign depth = 1'b0; //output is meaningless
lowRISC Contributors802543a2019-08-31 12:12:56 +010038
Timothy Chen61e25e82019-09-13 14:04:10 -070039 // devie facing
40 assign rvalid = wvalid;
41 assign rdata = wdata;
lowRISC Contributors802543a2019-08-31 12:12:56 +010042
Timothy Chen61e25e82019-09-13 14:04:10 -070043 // host facing
44 assign wready = rready;
lowRISC Contributors802543a2019-08-31 12:12:56 +010045
Michael Schaffner1ba89b82019-11-03 14:25:54 -080046 // this avoids lint warnings
47 logic unused_clr;
48 assign unused_clr = clr_i;
49
Timothy Chen61e25e82019-09-13 14:04:10 -070050 // Normal FIFO construction
51 end else begin : gen_normal_fifo
lowRISC Contributors802543a2019-08-31 12:12:56 +010052
Timothy Chen61e25e82019-09-13 14:04:10 -070053 // consider Depth == 1 case when $clog2(1) == 0
54 localparam int unsigned PTRV_W = $clog2(Depth) + ~|$clog2(Depth);
55 localparam int unsigned PTR_WIDTH = PTRV_W+1;
lowRISC Contributors802543a2019-08-31 12:12:56 +010056
Timothy Chen61e25e82019-09-13 14:04:10 -070057 logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
58 logic fifo_incr_wptr, fifo_incr_rptr, fifo_empty;
lowRISC Contributors802543a2019-08-31 12:12:56 +010059
Timothy Chen61e25e82019-09-13 14:04:10 -070060 // create the write and read pointers
61 logic full, empty;
62 logic wptr_msb;
63 logic rptr_msb;
64 logic [PTRV_W-1:0] wptr_value;
65 logic [PTRV_W-1:0] rptr_value;
lowRISC Contributors802543a2019-08-31 12:12:56 +010066
Timothy Chen61e25e82019-09-13 14:04:10 -070067 assign wptr_msb = fifo_wptr[PTR_WIDTH-1];
68 assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
69 assign wptr_value = fifo_wptr[0+:PTRV_W];
70 assign rptr_value = fifo_rptr[0+:PTRV_W];
71 assign depth = (full) ? DepthW'(Depth) :
72 (wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
73 (DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
lowRISC Contributors802543a2019-08-31 12:12:56 +010074
Timothy Chen61e25e82019-09-13 14:04:10 -070075 assign fifo_incr_wptr = wvalid & wready;
76 assign fifo_incr_rptr = rvalid & rready;
lowRISC Contributors802543a2019-08-31 12:12:56 +010077
Timothy Chen61e25e82019-09-13 14:04:10 -070078 assign wready = ~full;
79 assign rvalid = ~empty;
lowRISC Contributors802543a2019-08-31 12:12:56 +010080
Michael Schaffner44242c42019-10-29 09:14:22 -070081 always_ff @(posedge clk_i or negedge rst_ni) begin
Timothy Chen61e25e82019-09-13 14:04:10 -070082 if (!rst_ni) begin
83 fifo_wptr <= {(PTR_WIDTH){1'b0}};
Michael Schaffner44242c42019-10-29 09:14:22 -070084 end else if (clr_i) begin
85 fifo_wptr <= {(PTR_WIDTH){1'b0}};
Timothy Chen61e25e82019-09-13 14:04:10 -070086 end else if (fifo_incr_wptr) begin
87 if (fifo_wptr[PTR_WIDTH-2:0] == (Depth-1)) begin
88 fifo_wptr <= {~fifo_wptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
89 end else begin
90 fifo_wptr <= fifo_wptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
Michael Schaffner44242c42019-10-29 09:14:22 -070091 end
Timothy Chen61e25e82019-09-13 14:04:10 -070092 end
lowRISC Contributors802543a2019-08-31 12:12:56 +010093 end
94
Michael Schaffner44242c42019-10-29 09:14:22 -070095 always_ff @(posedge clk_i or negedge rst_ni) begin
Timothy Chen61e25e82019-09-13 14:04:10 -070096 if (!rst_ni) begin
97 fifo_rptr <= {(PTR_WIDTH){1'b0}};
Michael Schaffner44242c42019-10-29 09:14:22 -070098 end else if (clr_i) begin
99 fifo_rptr <= {(PTR_WIDTH){1'b0}};
Timothy Chen61e25e82019-09-13 14:04:10 -0700100 end else if (fifo_incr_rptr) begin
101 if (fifo_rptr[PTR_WIDTH-2:0] == (Depth-1)) begin
102 fifo_rptr <= {~fifo_rptr[PTR_WIDTH-1],{(PTR_WIDTH-1){1'b0}}};
103 end else begin
104 fifo_rptr <= fifo_rptr + {{(PTR_WIDTH-1){1'b0}},1'b1};
Michael Schaffner44242c42019-10-29 09:14:22 -0700105 end
Timothy Chen61e25e82019-09-13 14:04:10 -0700106 end
107 end
lowRISC Contributors802543a2019-08-31 12:12:56 +0100108
Timothy Chen61e25e82019-09-13 14:04:10 -0700109 assign full = (fifo_wptr == (fifo_rptr ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
110 assign fifo_empty = (fifo_wptr == fifo_rptr);
111
Timothy Chen61e25e82019-09-13 14:04:10 -0700112
Michael Schaffner9e2f8932019-10-16 20:24:46 -0700113 // the generate blocks below are needed to avoid lint errors due to array indexing
114 // in the where the fifo only has one storage element
Michael Schaffnerfd7d5d42020-01-22 11:46:53 -0800115 logic [Depth-1:0][Width-1:0] storage;
Michael Schaffner9e2f8932019-10-16 20:24:46 -0700116 logic [Width-1:0] storage_rdata;
117 if (Depth == 1) begin : gen_depth_eq1
118 assign storage_rdata = storage[0];
119
120 always_ff @(posedge clk_i)
121 if (fifo_incr_wptr) begin
122 storage[0] <= wdata;
123 end
124 // fifo with more than one storage element
125 end else begin : gen_depth_gt1
126 assign storage_rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
127
128 always_ff @(posedge clk_i)
129 if (fifo_incr_wptr) begin
130 storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
131 end
132 end
Timothy Chen61e25e82019-09-13 14:04:10 -0700133
134 if (Pass == 1'b1) begin : gen_pass
Michael Schaffner9e2f8932019-10-16 20:24:46 -0700135 assign rdata = (fifo_empty && wvalid) ? wdata : storage_rdata;
Timothy Chen61e25e82019-09-13 14:04:10 -0700136 assign empty = fifo_empty & ~wvalid;
Timothy Chen61e25e82019-09-13 14:04:10 -0700137 end else begin : gen_nopass
Michael Schaffner9e2f8932019-10-16 20:24:46 -0700138 assign rdata = storage_rdata;
Timothy Chen61e25e82019-09-13 14:04:10 -0700139 assign empty = fifo_empty;
Timothy Chen61e25e82019-09-13 14:04:10 -0700140 end
141
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000142 `ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth))
Timothy Chen61e25e82019-09-13 14:04:10 -0700143 end // block: gen_normal_fifo
144
lowRISC Contributors802543a2019-08-31 12:12:56 +0100145
Michael Schaffner498b1a92019-12-06 12:31:46 -0800146 //////////////////////
147 // Known Assertions //
148 //////////////////////
149
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000150 `ASSERT(DataKnown_A, rvalid |-> !$isunknown(rdata))
151 `ASSERT_KNOWN(DepthKnown_A, depth)
152 `ASSERT_KNOWN(RvalidKnown_A, rvalid)
153 `ASSERT_KNOWN(WreadyKnown_A, wready)
Michael Schaffner498b1a92019-12-06 12:31:46 -0800154
lowRISC Contributors802543a2019-08-31 12:12:56 +0100155endmodule