Attention
This documentation is a work in progress. Expect to see errors and unfinished things.
fifo Source File
1// blockram based FIFO
2// exchangeable with shortfifo.v
3
4module fifo #(
5 parameter aw = 3,
6 parameter dw = 8
7) (
8 input clk,
9 input rst,
10
11 input [dw - 1: 0] din,
12 input we,
13
14 output [dw - 1: 0] dout,
15 input re,
16
17 output full,
18 output empty,
19 output last,
20
21 // -1: empty, 0: single element, 2**aw - 1: full
22 output [aw:0] count
23);
24
25localparam len = 1 << aw;
26
27reg [dw - 1: 0] mem[len - 1: 0];
28
29reg [dw - 1: 0] read = 0;
30reg [dw - 1: 0] last_write = 0;
31
32// read / write pointers (need an extra bit)
33reg [aw: 0] wr_addr = 0;
34reg [aw: 0] rd_addr = 0;
35
36// Else Vivado would not infer block ram, arrrgh
37wire [aw - 1: 0] wr_addr_ = wr_addr;
38wire [aw - 1: 0] rd_addr_ = rd_addr;
39wire [aw - 1: 0] rd_addr_next_ = rd_addr + 1;
40
41// Number of items in memory (up to len items)
42// Need 1 extra bit, else wouldn't be able to count len items
43wire [aw: 0] fill = wr_addr - rd_addr;
44assign count = fill - 1;
45
46// can only read when not empty
47wire re_ = re && !empty;
48
49// can only write when not full (except when also reading)
50wire we_ = we && (!full || re);
51
52assign empty = fill == 0;
53assign last = fill == 1;
54assign full = fill >= len;
55
56// Cannot use block-ram when there is only one element in the FIFO
57// as it has a 2 cycle latency (write and read). We need 1 cycle, so use the
58// bypass register `last_write` in this case instead.
59assign dout = last ? last_write : read;
60
61always @(posedge clk) begin
62 if (rst) begin
63 read <= 0;
64 last_write <= 0;
65 wr_addr <= 0;
66 rd_addr <= 0;
67 end else begin
68 read <= mem[rd_addr_];
69
70 if (we_) begin
71 last_write <= din;
72 mem[wr_addr_] <= din;
73 wr_addr <= wr_addr + 1;
74 end
75
76 if (re_) begin
77 rd_addr <= rd_addr + 1;
78
79 // we need to look one cycle into the future to compensate the 2 cycle
80 // latency of the Xilinx block-ram
81 read <= mem[rd_addr_next_];
82 end
83 end
84end
85
86// ---------------------------
87
88`ifdef FORMAL
89// FIFO verification exercise from:
90// https://zipcpu.com/tutorial/lsn-10-fifo.pdf
91
92reg f_past_valid = 0;
93
94// 2 magic addresses we will follow up
95(* anyconst *) reg [aw: 0] f_first_addr;
96wire [aw:0] f_second_addr = f_first_addr + 1;
97
98// address pointers are circular. read_pointer is index0 of FIFO
99// If these are < fill the addresses are valid
100wire [aw: 0] f_first_dist = f_first_addr - rd_addr;
101wire [aw: 0] f_second_dist = f_second_addr - rd_addr;
102wire f_first_valid = !empty && (f_first_dist < fill);
103wire f_second_valid = !empty && (f_second_dist < fill);
104
105// with 2 corresponding magic values
106(* anyconst *) reg [dw - 1: 0] f_first_data, f_second_data;
107
108reg [1:0] f_state = 0;
109
110always @(posedge clk) begin
111 f_past_valid <= 1;
112
113 // FIFO sequence
114 // Follow up the FIFO state transitions as 2 values enter and leave it
115 // Need to do it for 2 values to verify the correct order
116 case (f_state)
117 0: begin // IDLE state
118 // write first magic value into FIFO
119 if (we_ && (wr_addr == f_first_addr) && (din == f_first_data))
120 f_state <= 1;
121 end
122
123 1: begin // 1 value is in
124 if (re_ && (rd_addr == f_first_addr))
125 f_state <= 0; // first value was read prematurely, restart
126 else if(we_)
127 if (din == f_second_data)
128 f_state <= 2; // write second value
129 else
130 f_state <= 0; // wrote wrong second value, restart
131
132 // f_first_addr must be in the valid range of the FIFO
133 assert(f_first_valid);
134 assert(mem[f_first_addr] == f_first_data);
135 assert(wr_addr == f_second_addr);
136 end
137
138 2: begin // 2 values are in, read out first value
139 if (re_ && (rd_addr == f_first_addr))
140 f_state <= 3;
141 else
142 f_state <= 0;
143
144 assert(f_first_valid);
145 assert(f_second_valid);
146 assert(mem[f_first_addr] == f_first_data);
147 assert(mem[f_second_addr] == f_second_data);
148
149 if (rd_addr == f_first_addr)
150 assert(dout == f_first_data);
151 end
152
153 3: begin // read out second value
154 f_state <= 0;
155
156 assert(f_second_valid);
157 assert(mem[f_second_addr] == f_second_data);
158
159 assert(dout == f_second_data);
160 end
161 endcase
162
163 // Cannot go from full to empty and vice versa
164 if (f_past_valid && $past(full))
165 assert(!empty);
166 if (f_past_valid && $past(empty))
167 assert(!full);
168
169 // Read and write can happen at the same time!
170 if (f_past_valid && $past(we) && $past(re) && $past(fill > 0))
171 assert($stable(fill));
172
173 // cover mode: show 2 values entering and exiting the FIFO:
174 // cover(f_past_valid && $past(f_state) == 3 && f_state == 0);
175end
176
177// cover mode: Fill up the FIFO and empty it again
178reg f_was_full = 0;
179reg f_both = 0; // show what happens when both are high
180always @(posedge clk) begin
181 // assume(din == $past(din) + 8'h1);
182 if (full)
183 f_was_full <= 1;
184 if (we && re && !empty)
185 f_both <= 1;
186 cover(empty && f_was_full && f_both);
187end
188
189
190always @(*) begin
191 assert(fill == wr_addr - rd_addr);
192 assert(empty == (fill == 0));
193 assert(last == (fill == 1));
194 assert(full == (fill == len));
195
196 // Can't have more items than the memory holds
197 assert(fill <= len);
198
199 // Cant be full and empty at the same time
200 assert(!(full && empty));
201end
202`endif
203
204endmodule