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