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

Subversion Repositories pci

[/] [pci/] [tags/] [rel_3/] [rtl/] [verilog/] [fifo_control.v] - Blame information for rev 6

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 mihad
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  File name "fifo_control.v"                                  ////
4
////                                                              ////
5
////  This file is part of the "PCI bridge" project               ////
6
////  http://www.opencores.org/cores/pci/                         ////
7
////                                                              ////
8
////  Author(s):                                                  ////
9
////      - Miha Dolenc (mihad@opencores.org)                     ////
10
////                                                              ////
11
////  All additional information is avaliable in the README       ////
12
////  file.                                                       ////
13
////                                                              ////
14
////                                                              ////
15
//////////////////////////////////////////////////////////////////////
16
////                                                              ////
17
//// Copyright (C) 2001 Miha Dolenc, mihad@opencores.org          ////
18
////                                                              ////
19
//// This source file may be used and distributed without         ////
20
//// restriction provided that this copyright statement is not    ////
21
//// removed from the file and that any derivative work contains  ////
22
//// the original copyright notice and the associated disclaimer. ////
23
////                                                              ////
24
//// This source file is free software; you can redistribute it   ////
25
//// and/or modify it under the terms of the GNU Lesser General   ////
26
//// Public License as published by the Free Software Foundation; ////
27
//// either version 2.1 of the License, or (at your option) any   ////
28
//// later version.                                               ////
29
////                                                              ////
30
//// This source is distributed in the hope that it will be       ////
31
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
32
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
33
//// PURPOSE.  See the GNU Lesser General Public License for more ////
34
//// details.                                                     ////
35
////                                                              ////
36
//// You should have received a copy of the GNU Lesser General    ////
37
//// Public License along with this source; if not, download it   ////
38
//// from http://www.opencores.org/lgpl.shtml                     ////
39
////                                                              ////
40
//////////////////////////////////////////////////////////////////////
41
//
42
// CVS Revision History
43
//
44
// $Log: not supported by cvs2svn $
45 6 mihad
// Revision 1.1.1.1  2001/10/02 15:33:46  mihad
46
// New project directory structure
47 2 mihad
//
48 6 mihad
//
49 2 mihad
 
50
/* FIFO_CONTROL module provides read/write address and status generation for
51
   FIFOs implemented with standard dual port SRAM cells in ASIC or FPGA designs */
52
 
53
`include "constants.v"
54
`ifdef FPGA
55
    // fifo design in FPGA will be synchronous
56
    `ifdef SYNCHRONOUS
57
    `else
58
        `define SYNCHRONOUS
59
    `endif
60
`endif
61 6 mihad
 
62
`include "timescale.v"
63
 
64 2 mihad
module FIFO_CONTROL
65
(
66
    rclock_in,
67
    wclock_in,
68
    renable_in,
69
    wenable_in,
70
    reset_in,
71
    flush_in,
72
    almost_full_out,
73
    full_out,
74
    almost_empty_out,
75
    empty_out,
76
    waddr_out,
77
    raddr_out,
78
    rallow_out,
79
    wallow_out
80
);
81
 
82
// address length parameter - depends on fifo depth
83
parameter ADDR_LENGTH = 7 ;
84
 
85
// independent clock inputs - rclock_in = read clock, wclock_in = write clock
86
input  rclock_in, wclock_in;
87
 
88
// enable inputs - read address changes on rising edge of rclock_in when reads are allowed
89
//                 write address changes on rising edge of wclock_in when writes are allowed
90
input  renable_in, wenable_in;
91
 
92
// reset input
93
input  reset_in;
94
 
95
// flush input
96
input flush_in ;
97
 
98
// almost full and empy status outputs
99
output almost_full_out, almost_empty_out;
100
 
101
// full and empty status outputs
102
output full_out, empty_out;
103
 
104
// read and write addresses outputs
105
output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out;
106
 
107
// read and write allow outputs
108
output rallow_out, wallow_out ;
109
 
110
// read address register
111
reg [(ADDR_LENGTH - 1):0] raddr ;
112
 
113
// write address register
114
reg [(ADDR_LENGTH - 1):0] waddr;
115
assign waddr_out = waddr ;
116
 
117
// grey code registers
118
// grey code pipeline for write address
119
reg [(ADDR_LENGTH - 1):0] wgrey_minus1 ; // one before current grey coded write address
120
reg [(ADDR_LENGTH - 1):0] wgrey_addr ; // current grey coded write address
121
reg [(ADDR_LENGTH - 1):0] wgrey_next ; // next grey coded write address
122
 
123
// next write gray address calculation - bitwise xor between address and shifted address
124
wire [(ADDR_LENGTH - 2):0] calc_wgrey_next  = waddr[(ADDR_LENGTH - 1):1] ^ waddr[(ADDR_LENGTH - 2):0] ;
125
 
126
// grey code pipeline for read address
127
reg [(ADDR_LENGTH - 1):0] rgrey_minus2 ; // two before current
128
reg [(ADDR_LENGTH - 1):0] rgrey_minus1 ; // one before current
129
reg [(ADDR_LENGTH - 1):0] rgrey_addr ; // current
130
reg [(ADDR_LENGTH - 1):0] rgrey_next ; // next
131
 
132
// next read gray address calculation - bitwise xor between address and shifted address
133
wire [(ADDR_LENGTH - 2):0] calc_rgrey_next  = raddr[(ADDR_LENGTH - 1):1] ^ raddr[(ADDR_LENGTH - 2):0] ;
134
 
135
// FFs for registered empty and full flags
136
reg empty ;
137
reg full ;
138
 
139
// almost_empty and almost_full tag - implemented as latches
140
reg almost_empty ;
141
reg almost_full ;
142
 
143
// write allow wire - writes are allowed when fifo is not full
144
wire wallow = wenable_in && ~full ;
145
 
146
// write allow output assignment
147
assign wallow_out = wallow ;
148
 
149
// read allow wire
150
wire rallow ;
151
 
152
// full output assignment
153
assign full_out  = full ;
154
 
155
// almost full output assignment
156
assign almost_full_out  = almost_full && ~full ;
157
 
158
// clear generation for FFs and registers
159
wire clear = reset_in || flush_in ;
160
 
161
`ifdef SYNCHRONOUS
162
 
163
    reg wclock_nempty_detect ;
164
    always@(posedge reset_in or posedge wclock_in)
165
    begin
166
        if (reset_in)
167
            wclock_nempty_detect <= #`FF_DELAY 1'b0 ;
168
        else
169
            wclock_nempty_detect <= #`FF_DELAY (rgrey_addr != wgrey_addr) ;
170
    end
171
 
172
    // special synchronizing mechanism for different implementations - in synchronous imp., empty is prolonged for 1 clock edge if no write clock comes after initial write
173
    reg stretched_empty ;
174
    always@(posedge rclock_in or posedge clear)
175
    begin
176
        if(clear)
177
            stretched_empty <= #`FF_DELAY 1'b1 ;
178
        else
179
            stretched_empty <= #`FF_DELAY empty && ~wclock_nempty_detect ;
180
    end
181
 
182
    // empty output is actual empty + 1 read clock cycle ( stretched empty )
183
    assign empty_out = empty || stretched_empty ;
184
 
185
    //rallow generation    
186
    assign rallow = renable_in && ~empty && ~stretched_empty ; // reads allowed if read enable is high and FIFO is not empty
187
 
188
    // rallow output assignment
189
    assign rallow_out = rallow ;
190
 
191
    // almost empty output assignment
192
    assign almost_empty_out = almost_empty && ~empty && ~stretched_empty ;
193
 
194
    // at any clock edge that rallow is high, this register provides next read address, so wait cycles are not necessary
195
    // when FIFO is empty, this register provides actual read address, so first location can be read
196
    reg [(ADDR_LENGTH - 1):0] raddr_plus_one ;
197
 
198
    // address output mux - when FIFO is empty, current actual address is driven out, when it is non - empty next address is driven out
199
    // done for zero wait state burst
200
    assign raddr_out = empty_out ? raddr : raddr_plus_one ;
201
 
202
    // enable for this register
203
    wire raddr_plus_one_en = rallow ;
204
    always@(posedge rclock_in or posedge clear)
205
    begin
206
        if (clear)
207
        begin
208
            raddr_plus_one[(ADDR_LENGTH - 1):1] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0}} ;
209
            raddr_plus_one[0] <= #`FF_DELAY 1'b1 ;
210
        end
211
        else if (raddr_plus_one_en)
212
            raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
213
    end
214
 
215
    // raddr is filled with raddr_plus_one on rising read clock edge when rallow is high
216
    always@(posedge rclock_in or posedge clear)
217
    begin
218
            if (clear)
219
            // initial value is 000......00
220
                    raddr <= #`FF_DELAY { ADDR_LENGTH{1'b0}} ;
221
            else if (rallow)
222
                raddr <= #`FF_DELAY raddr_plus_one ;
223
    end
224
 
225
`else
226
    // asynchronous RAM storage for FIFOs - somewhat simpler control logic
227
    //rallow generation    
228
    assign rallow = renable_in && ~empty ;
229
 
230
    assign rallow_out = rallow;
231
 
232
    assign almost_empty_out = almost_empty && ~empty ;
233
 
234
    // read address counter - normal counter, nothing to it
235
    // for asynchronous implementation, there is no need for pointing to next address.
236
    // On clock edge that read is performed, read address will change and on the next clock edge
237
    // asynchronous memory will provide next data
238
    always@(posedge rclock_in or posedge clear)
239
    begin
240
            if (clear)
241
            // initial value is 000......00
242
                    raddr <= #`FF_DELAY { ADDR_LENGTH{1'b0}} ;
243
            else if (rallow)
244
                    raddr <= #`FF_DELAY raddr + 1'b1 ;
245
    end
246
 
247
    assign empty_out = empty ;
248
    assign raddr_out = raddr ;
249
`endif
250
 
251
/*-----------------------------------------------------------------------------------------------
252
Read address control consists of Read address counter and Grey Address pipeline
253
There are 4 Grey addresses:
254
    - rgrey_minus2 is Grey Code of address two before current address
255
    - rgrey_minus1 is Grey Code of address one before current address
256
    - rgrey_addr is Grey Code of current read address
257
    - rgrey_next is Grey Code of next read address
258
--------------------------------------------------------------------------------------------------*/
259
// grey code register for two before read address
260
always@(posedge rclock_in or posedge clear)
261
begin
262
        if (clear)
263
    begin
264
        // initial value is 100......010
265
                rgrey_minus2[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
266
        rgrey_minus2[(ADDR_LENGTH  - 2):2] <= #`FF_DELAY { (ADDR_LENGTH  - 3){1'b0} } ;
267
        rgrey_minus2[1:0] <= #`FF_DELAY 2'b10 ;
268
    end
269
        else
270
                if (rallow)
271
                        rgrey_minus2 <= #`FF_DELAY rgrey_minus1 ;
272
end
273
 
274
// grey code register for one before read address
275
always@(posedge rclock_in or posedge clear)
276
begin
277
        if (clear)
278
    begin
279
        // initial value is 100......011
280
                rgrey_minus1[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
281
        rgrey_minus1[(ADDR_LENGTH  - 2):2] <= #`FF_DELAY { (ADDR_LENGTH  - 3){1'b0} } ;
282
        rgrey_minus1[1:0] <= #`FF_DELAY 2'b11 ;
283
    end
284
        else
285
                if (rallow)
286
                        rgrey_minus1 <= #`FF_DELAY rgrey_addr ;
287
end
288
 
289
// grey code register for read address - represents current Read Address
290
always@(posedge rclock_in or posedge clear)
291
begin
292
        if (clear)
293
    begin
294
        // initial value is 100.......01
295
                rgrey_addr[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
296
        rgrey_addr[(ADDR_LENGTH - 2):1] <= #`FF_DELAY { (ADDR_LENGTH - 2){1'b0} } ;
297
        rgrey_addr[0] <= #`FF_DELAY 1'b1 ;
298
    end
299
        else
300
                if (rallow)
301
                        rgrey_addr <= #`FF_DELAY rgrey_next ;
302
end
303
 
304
// grey code register for next read address - represents Grey Code of next read address    
305
always@(posedge rclock_in or posedge clear)
306
begin
307
        if (clear)
308
    begin
309
        // initial value is 100......00
310
                rgrey_next[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
311
        rgrey_next[(ADDR_LENGTH - 2):0] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0} } ;
312
    end
313
        else
314
                if (rallow)
315
            rgrey_next <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
316
end
317
 
318
/*--------------------------------------------------------------------------------------------
319
Write address control consists of write address counter and three Grey Code Registers:
320
    - wgrey_minus1 represents Grey Coded address of location one before current write address
321
    - wgrey_addr represents current Grey Coded write address
322
    - wgrey_next represents Grey Coded next write address
323
----------------------------------------------------------------------------------------------*/
324
// grey code register for one before write address
325
always@(posedge wclock_in or posedge clear)
326
begin
327
        if (clear)
328
    begin
329
        // initial value is 100.....001
330
        wgrey_minus1[(ADDR_LENGTH - 1)]   <= #`FF_DELAY 1'b1 ;
331
        wgrey_minus1[(ADDR_LENGTH - 2):2] <= #`FF_DELAY { (ADDR_LENGTH - 3){1'b0} } ;
332
        wgrey_minus1[1:0] <= #`FF_DELAY 2'b11 ;
333
    end
334
        else
335
    if (wallow)
336
            wgrey_minus1 <= #`FF_DELAY wgrey_addr ;
337
end
338
 
339
// grey code register for write address
340
always@(posedge wclock_in or posedge clear)
341
begin
342
        if (clear)
343
    begin
344
        // initial value is 100.....001
345
        wgrey_addr[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
346
        wgrey_addr[(ADDR_LENGTH - 2):1] <= #`FF_DELAY { (ADDR_LENGTH - 2){1'b0} } ;
347
        wgrey_addr[0] <= #`FF_DELAY 1'b1 ;
348
    end
349
        else
350
    if (wallow)
351
            wgrey_addr <= #`FF_DELAY wgrey_next ;
352
end
353
 
354
// grey code register for next write address
355
always@(posedge wclock_in or posedge clear)
356
begin
357
        if (clear)
358
    begin
359
        // initial value is 100......00
360
                wgrey_next[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
361
        wgrey_next[(ADDR_LENGTH - 2):0] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0} } ;
362
    end
363
        else
364
    if (wallow)
365
        wgrey_next <= #`FF_DELAY {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
366
end
367
 
368
// write address counter - nothing special
369
always@(posedge wclock_in or posedge clear)
370
begin
371
        if (clear)
372
        // initial value 00.........00
373
                waddr <= #`FF_DELAY { (ADDR_LENGTH){1'b0} } ;
374
        else
375
        if (wallow)
376
                waddr <= #`FF_DELAY waddr + 1'b1 ;
377
end
378
 
379
/*------------------------------------------------------------------------------------------------------------------------------
380
Registered full control:
381
registered full is set on rising edge of wclock_in, when fifo is almost full and something gets written to it.
382
It's kept high until something is read from FIFO, which is registered on next rising write clock edge.
383
 
384
Registered almost full control:
385
Almost full flag is set on rising write clock edge whenever two free locations are left in fifo and another entry is written to it.
386
It remains set if nothing is read/written from/to fifo. All operations are synchronized on write clock.
387
--------------------------------------------------------------------------------------------------------------------------------*/
388
wire comb_full          = wgrey_next == rgrey_addr ;
389
wire comb_almost_full   = wgrey_addr == rgrey_minus2 ;
390
wire comb_two_left      = wgrey_next == rgrey_minus2 ;
391
 
392
//combinatorial input to Registered full FlipFlop
393
wire reg_full = (wallow && comb_almost_full) || (comb_full) ;
394
 
395
always@(posedge wclock_in or posedge clear)
396
begin
397
        if (clear)
398
                full <= #`FF_DELAY 1'b0 ;
399
        else
400
                full <= #`FF_DELAY reg_full ;
401
end
402
 
403
// input for almost full flip flop
404
wire reg_almost_full_in = wallow && comb_two_left || comb_almost_full ;
405
 
406
always@(posedge clear or posedge wclock_in)
407
begin
408
    if (clear)
409
        almost_full <= #`FF_DELAY 1'b0 ;
410
    else
411
        almost_full <= #`FF_DELAY reg_almost_full_in ;
412
end
413
 
414
/*------------------------------------------------------------------------------------------------------------------------------
415
Registered empty control:
416
registered empty is set on rising edge of rclock_in when one location is occupied and read from it. It remains set until
417
something is written to fifo which is detected on next read clock edge.
418
 
419
Registered almost empty control:
420
Almost empty is set on rising clock edge of read clock when two locations are used in fifo and one of them is read from it.
421
It remains set until something is read/written from/to fifo. All operations are detected on rising edge of read clock.
422
--------------------------------------------------------------------------------------------------------------------------------*/
423
wire comb_almost_empty  = rgrey_next == wgrey_addr ;
424
wire comb_empty         = rgrey_addr == wgrey_addr ;
425
wire comb_two_used      = rgrey_next == wgrey_minus1 ;
426
 
427
// combinatorial input for registered emty FlipFlop
428
wire reg_empty = (rallow && comb_almost_empty) || comb_empty ;
429
 
430
always@(posedge rclock_in or posedge clear)
431
begin
432
    if (clear)
433
        empty <= #`FF_DELAY 1'b1 ;
434
        else
435
        empty <= #`FF_DELAY reg_empty ;
436
end
437
 
438
// input for almost empty flip flop
439
wire reg_almost_empty = rallow && comb_two_used || comb_almost_empty ;
440
always@(posedge clear or posedge rclock_in)
441
begin
442
    if (clear)
443
        almost_empty <= #`FF_DELAY 1'b0 ;
444
    else
445
        almost_empty <= #`FF_DELAY reg_almost_empty ;
446
end
447
 
448
endmodule

powered by: WebSVN 2.1.0

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