OpenCores
URL https://opencores.org/ocsvn/wbuart32/wbuart32/trunk

Subversion Repositories wbuart32

[/] [wbuart32/] [trunk/] [rtl/] [ufifo.v] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    ufifo.v
4
//
5
// Project:     wbuart32, a full featured UART with simulator
6
//
7 18 dgisselq
// Purpose:     A synchronous data FIFO, designed for supporting the Wishbone
8
//              UART.  Particular features include the ability to read and
9
//      write on the same clock, while maintaining the correct output FIFO
10
//      parameters.  Two versions of the FIFO exist within this file, separated
11
//      by the RXFIFO parameter's value.  One, where RXFIFO = 1, produces status
12
//      values appropriate for reading and checking a read FIFO from logic,
13
//      whereas the RXFIFO = 0 applies to writing to the FIFO from bus logic
14
//      and reading it automatically any time the transmit UART is idle.
15 5 dgisselq
//
16
// Creator:     Dan Gisselquist, Ph.D.
17
//              Gisselquist Technology, LLC
18
//
19
////////////////////////////////////////////////////////////////////////////////
20
//
21 26 dgisselq
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
22 5 dgisselq
//
23
// This program is free software (firmware): you can redistribute it and/or
24
// modify it under the terms of  the GNU General Public License as published
25
// by the Free Software Foundation, either version 3 of the License, or (at
26
// your option) any later version.
27
//
28
// This program is distributed in the hope that it will be useful, but WITHOUT
29
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
30
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
31
// for more details.
32
//
33
// You should have received a copy of the GNU General Public License along
34 9 dgisselq
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
35 5 dgisselq
// target there if the PDF file isn't present.)  If not, see
36
// <http://www.gnu.org/licenses/> for a copy.
37
//
38
// License:     GPL, v3, as defined and found on www.gnu.org,
39
//              http://www.gnu.org/licenses/gpl.html
40
//
41
//
42
////////////////////////////////////////////////////////////////////////////////
43
//
44
//
45 17 dgisselq
`default_nettype        none
46
//
47 9 dgisselq
module ufifo(i_clk, i_rst, i_wr, i_data, o_empty_n, i_rd, o_data, o_status, o_err);
48
        parameter       BW=8;   // Byte/data width
49
        parameter [3:0]  LGFLEN=4;
50 14 dgisselq
        parameter       RXFIFO=1'b0;
51 17 dgisselq
        input   wire            i_clk, i_rst;
52
        input   wire            i_wr;
53
        input   wire [(BW-1):0]  i_data;
54 9 dgisselq
        output  wire            o_empty_n;      // True if something is in FIFO
55 17 dgisselq
        input   wire            i_rd;
56 5 dgisselq
        output  wire [(BW-1):0]  o_data;
57
        output  wire    [15:0]   o_status;
58
        output  wire            o_err;
59
 
60
        localparam      FLEN=(1<<LGFLEN);
61
 
62
        reg     [(BW-1):0]       fifo[0:(FLEN-1)];
63 6 dgisselq
        reg     [(LGFLEN-1):0]   r_first, r_last, r_next;
64 5 dgisselq
 
65
        wire    [(LGFLEN-1):0]   w_first_plus_one, w_first_plus_two,
66
                                w_last_plus_one;
67
        assign  w_first_plus_two = r_first + {{(LGFLEN-2){1'b0}},2'b10};
68
        assign  w_first_plus_one = r_first + {{(LGFLEN-1){1'b0}},1'b1};
69 6 dgisselq
        assign  w_last_plus_one  = r_next; // r_last  + 1'b1;
70 5 dgisselq
 
71
        reg     will_overflow;
72
        initial will_overflow = 1'b0;
73
        always @(posedge i_clk)
74
                if (i_rst)
75
                        will_overflow <= 1'b0;
76
                else if (i_rd)
77
                        will_overflow <= (will_overflow)&&(i_wr);
78
                else if (i_wr)
79 17 dgisselq
                        will_overflow <= (will_overflow)||(w_first_plus_two == r_last);
80 5 dgisselq
                else if (w_first_plus_one == r_last)
81
                        will_overflow <= 1'b1;
82
 
83
        // Write
84
        reg     r_ovfl;
85
        initial r_first = 0;
86
        initial r_ovfl  = 0;
87
        always @(posedge i_clk)
88
                if (i_rst)
89
                begin
90
                        r_ovfl <= 1'b0;
91
                        r_first <= { (LGFLEN){1'b0} };
92
                end else if (i_wr)
93
                begin // Cowardly refuse to overflow
94
                        if ((i_rd)||(!will_overflow)) // (r_first+1 != r_last)
95
                                r_first <= w_first_plus_one;
96
                        else
97
                                r_ovfl <= 1'b1;
98
                end
99
        always @(posedge i_clk)
100
                if (i_wr) // Write our new value regardless--on overflow or not
101
                        fifo[r_first] <= i_data;
102
 
103
        // Reads
104
        //      Following a read, the next sample will be available on the
105
        //      next clock
106
        //      Clock   ReadCMD ReadAddr        Output
107
        //      0        0        0                fifo[0]
108
        //      1       1       0                fifo[0]
109
        //      2       0        1               fifo[1]
110
        //      3       0        1               fifo[1]
111
        //      4       1       1               fifo[1]
112
        //      5       1       2               fifo[2]
113
        //      6       0        3               fifo[3]
114
        //      7       0        3               fifo[3]
115 9 dgisselq
        reg     will_underflow;
116 5 dgisselq
        initial will_underflow = 1'b1;
117
        always @(posedge i_clk)
118
                if (i_rst)
119
                        will_underflow <= 1'b1;
120
                else if (i_wr)
121 18 dgisselq
                        will_underflow <= 1'b0;
122 5 dgisselq
                else if (i_rd)
123 17 dgisselq
                        will_underflow <= (will_underflow)||(w_last_plus_one == r_first);
124 5 dgisselq
                else
125
                        will_underflow <= (r_last == r_first);
126
 
127 9 dgisselq
        //
128
        // Don't report FIFO underflow errors.  These'll be caught elsewhere
129
        // in the system, and the logic below makes it hard to reset them.
130
        // We'll still report FIFO overflow, however.
131
        //
132
        // reg          r_unfl;
133
        // initial      r_unfl = 1'b0;
134 5 dgisselq
        initial r_last = 0;
135 18 dgisselq
        initial r_next = { {(LGFLEN-1){1'b0}}, 1'b1 };
136 5 dgisselq
        always @(posedge i_clk)
137
                if (i_rst)
138
                begin
139 6 dgisselq
                        r_last <= 0;
140
                        r_next <= { {(LGFLEN-1){1'b0}}, 1'b1 };
141 9 dgisselq
                        // r_unfl <= 1'b0;
142 5 dgisselq
                end else if (i_rd)
143
                begin
144 18 dgisselq
                        if (!will_underflow) // (r_first != r_last)
145 6 dgisselq
                        begin
146
                                r_last <= r_next;
147
                                r_next <= r_last +{{(LGFLEN-2){1'b0}},2'b10};
148 5 dgisselq
                                // Last chases first
149
                                // Need to be prepared for a possible two
150
                                // reads in quick succession
151
                                // o_data <= fifo[r_last+1];
152 9 dgisselq
                        end
153
                        // else r_unfl <= 1'b1;
154 5 dgisselq
                end
155
 
156 17 dgisselq
        reg     [(BW-1):0]       fifo_here, fifo_next, r_data;
157 5 dgisselq
        always @(posedge i_clk)
158
                fifo_here <= fifo[r_last];
159
        always @(posedge i_clk)
160 6 dgisselq
                fifo_next <= fifo[r_next];
161 5 dgisselq
        always @(posedge i_clk)
162
                r_data <= i_data;
163
 
164
        reg     [1:0]    osrc;
165
        always @(posedge i_clk)
166
                if (will_underflow)
167
                        // o_data <= i_data;
168
                        osrc <= 2'b00;
169
                else if ((i_rd)&&(r_first == w_last_plus_one))
170
                        osrc <= 2'b01;
171
                else if (i_rd)
172
                        osrc <= 2'b11;
173
                else
174
                        osrc <= 2'b10;
175
        assign o_data = (osrc[1]) ? ((osrc[0])?fifo_next:fifo_here) : r_data;
176
 
177
        // wire [(LGFLEN-1):0]  current_fill;
178
        // assign       current_fill = (r_first-r_last);
179
 
180 9 dgisselq
        reg     r_empty_n;
181
        initial r_empty_n = 1'b0;
182 5 dgisselq
        always @(posedge i_clk)
183
                if (i_rst)
184 9 dgisselq
                        r_empty_n <= 1'b0;
185 17 dgisselq
                else casez({i_wr, i_rd, will_underflow})
186
                        3'b00?: r_empty_n <= (r_first != r_last);
187 18 dgisselq
                        3'b010: r_empty_n <= (r_first != w_last_plus_one);
188 17 dgisselq
                        3'b10?: r_empty_n <= 1'b1;
189 18 dgisselq
                        3'b110: r_empty_n <= (r_first != r_last);
190
                        3'b111: r_empty_n <= 1'b1;
191 17 dgisselq
                        default: begin end
192 5 dgisselq
                endcase
193
 
194 9 dgisselq
        wire    w_full_n;
195
        assign  w_full_n = will_overflow;
196
 
197
        //
198
        // If this is a receive FIFO, the FIFO count that matters is the number
199
        // of values yet to be read.  If instead this is a transmit FIFO, then 
200
        // the FIFO count that matters is the number of empty positions that
201
        // can still be filled before the FIFO is full.
202
        //
203
        // Adjust for these differences here.
204 5 dgisselq
        reg     [(LGFLEN-1):0]   r_fill;
205 18 dgisselq
        generate
206
        if (RXFIFO != 0)
207
                initial r_fill = 0;
208
        else
209
                initial r_fill = -1;
210
        endgenerate
211
 
212 14 dgisselq
        always @(posedge i_clk)
213
                if (RXFIFO!=0) begin
214
                        // Calculate the number of elements in our FIFO
215
                        //
216
                        // Although used for receive, this is actually the more
217
                        // generic answer--should you wish to use the FIFO in
218
                        // another context.
219 9 dgisselq
                        if (i_rst)
220
                                r_fill <= 0;
221 18 dgisselq
                        else casez({(i_wr), (!will_overflow), (i_rd)&&(!will_underflow)})
222
                        3'b0?1:   r_fill <= r_first - r_next;
223
                        3'b110:   r_fill <= r_first - r_last + 1'b1;
224
                        3'b1?1:   r_fill <= r_first - r_last;
225 9 dgisselq
                        default: r_fill <= r_first - r_last;
226
                        endcase
227 14 dgisselq
                end else begin
228
                        // Calculate the number of elements that are empty and
229 17 dgisselq
                        // can be filled within our FIFO.  Hence, this is really
230
                        // not the fill, but (SIZE-1)-fill.
231 9 dgisselq
                        if (i_rst)
232
                                r_fill <= { (LGFLEN){1'b1} };
233 18 dgisselq
                        else casez({i_wr, (!will_overflow), (i_rd)&&(!will_underflow)})
234
                        3'b0?1:   r_fill <= r_fill + 1'b1;
235
                        3'b110:   r_fill <= r_fill - 1'b1;
236
                        default: r_fill  <= r_fill;
237 9 dgisselq
                        endcase
238 14 dgisselq
                end
239 5 dgisselq
 
240 9 dgisselq
        // We don't report underflow errors.  These
241
        assign o_err = (r_ovfl); //  || (r_unfl);
242 5 dgisselq
 
243
        wire    [3:0]    lglen;
244
        assign lglen = LGFLEN;
245 9 dgisselq
 
246 18 dgisselq
        wire    w_half_full;
247 9 dgisselq
        wire    [9:0]    w_fill;
248
        assign  w_fill[(LGFLEN-1):0] = r_fill;
249 14 dgisselq
        generate if (LGFLEN < 10)
250
                assign w_fill[9:(LGFLEN)] = 0;
251 9 dgisselq
        endgenerate
252
 
253
        assign  w_half_full = r_fill[(LGFLEN-1)];
254
 
255
        assign  o_status = {
256
                // Our status includes a 4'bit nibble telling anyone reading
257
                // this the size of our FIFO.  The size is then given by
258
                // 2^(this value).  Hence a 4'h4 in this position means that the
259
                // FIFO has 2^4 or 16 values within it.
260
                lglen,
261
                // The FIFO fill--for a receive FIFO the number of elements
262
                // left to be read, and for a transmit FIFO the number of
263
                // empty elements within the FIFO that can yet be filled.
264
                w_fill,
265
                // A '1' here means a half FIFO length can be read (receive
266
                // FIFO) or written to (not a receive FIFO).
267
                // receive FIFO), or be written to (if it isn't).
268
                (RXFIFO!=0)?w_half_full:w_half_full,
269
                // A '1' here means the FIFO can be read from (if it is a
270
                // receive FIFO), or be written to (if it isn't).
271 24 dgisselq
                (RXFIFO!=0)?r_empty_n:!w_full_n
272 9 dgisselq
        };
273
 
274
        assign  o_empty_n = r_empty_n;
275 18 dgisselq
 
276
//
277
//
278
//
279
// FORMAL METHODS
280
//
281
//
282
//
283
`ifdef  FORMAL
284
 
285
`ifdef  UFIFO
286
`define ASSUME  assume
287
`else
288
`define ASSUME  assert
289
`endif
290
 
291
//
292
// Assumptions about our input(s)
293
//
294
//
295
        reg     f_past_valid, f_last_clk;
296
 
297
        //
298
        // Underflows are a very real possibility, should the user wish to
299
        // read from this FIFO while it is empty.  Our parent module will need
300
        // to deal with this.
301
        //
302
        // always @(posedge i_clk)
303
        //      `ASSUME((!will_underflow)||(!i_rd)||(i_rst));
304
//
305
// Assertions about our outputs
306
//
307
//
308
 
309
        initial f_past_valid = 1'b0;
310
        always @(posedge i_clk)
311
                f_past_valid <= 1'b1;
312
 
313
        wire    [(LGFLEN-1):0]   f_fill, f_next, f_empty;
314
        assign  f_fill = r_first - r_last;
315
        assign  f_empty = {(LGFLEN){1'b1}} -f_fill;
316
        assign  f_next = r_last + 1'b1;
317
        always @(posedge i_clk)
318
        begin
319
                if (RXFIFO)
320
                        assert(f_fill == r_fill);
321
                else
322
                        assert(f_empty== r_fill);
323
                if (f_fill == 0)
324
                begin
325
                        assert(will_underflow);
326
                        assert(!o_empty_n);
327
                end else begin
328
                        assert(!will_underflow);
329
                        assert(o_empty_n);
330
                end
331
 
332
                if (f_fill == {(LGFLEN){1'b1}})
333
                        assert(will_overflow);
334
                else
335
                        assert(!will_overflow);
336
 
337
                assert(r_next == f_next);
338
        end
339
 
340
        always @(posedge i_clk)
341
        if (f_past_valid)
342
        begin
343
                if ($past(i_rst))
344
                        assert(!o_err);
345
                else begin
346
                        // No underflow detection in this core
347
                        //
348
                        // if (($past(i_rd))&&($past(r_fill == 0)))
349
                        //      assert(o_err);
350
                        //
351
                        // We do, though, have overflow detection
352
                        if (($past(i_wr))&&(!$past(i_rd))
353
                                        &&($past(will_overflow)))
354
                                assert(o_err);
355
                end
356
        end
357
 
358 23 dgisselq
        always @(posedge i_clk)
359
        if (RXFIFO)
360
        begin
361
                assert(o_status[0] == (f_fill != 0));
362
                assert(o_status[1] == (f_fill[LGFLEN-1]));
363
        end
364
 
365
        always @(posedge i_clk)
366
        if (!RXFIFO) // Transmit FIFO interrupt flags
367
        begin
368 24 dgisselq
                assert(o_status[0] == (!w_full_n));
369 23 dgisselq
                assert(o_status[1] == (!f_fill[LGFLEN-1]));
370
        end
371
 
372 18 dgisselq
`endif
373 5 dgisselq
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.