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