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