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

Subversion Repositories pci

[/] [pci/] [tags/] [rel_3/] [rtl/] [verilog/] [pciw_fifo_control.v] - Blame information for rev 2

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

Line No. Rev Author Line
1 2 mihad
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  File name "pciw_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
45
//
46
 
47
/* FIFO_CONTROL module provides read/write address and status generation for
48
   FIFOs implemented with standard dual port SRAM cells in ASIC or FPGA designs */
49
`include "constants.v"
50
`ifdef FPGA
51
    // fifo design in FPGA will be synchronous
52
    `ifdef SYNCHRONOUS
53
    `else
54
        `define SYNCHRONOUS
55
    `endif
56
`endif
57
module PCIW_FIFO_CONTROL
58
(
59
    rclock_in,
60
    wclock_in,
61
    renable_in,
62
    wenable_in,
63
    reset_in,
64
    flush_in,
65
    almost_full_out,
66
    full_out,
67
    almost_empty_out,
68
    empty_out,
69
    waddr_out,
70
    raddr_out,
71
    rallow_out,
72
    wallow_out,
73
    two_left_out
74
);
75
 
76
parameter ADDR_LENGTH = 7 ;
77
 
78
// independent clock inputs - rclock_in = read clock, wclock_in = write clock
79
input  rclock_in, wclock_in;
80
 
81
// enable inputs - read address changes on rising edge of rclock_in when reads are allowed
82
//                 write address changes on rising edge of wclock_in when writes are allowed
83
input  renable_in, wenable_in;
84
 
85
// reset input
86
input  reset_in;
87
 
88
// flush input
89
input flush_in ;
90
 
91
// almost full and empy status outputs
92
output almost_full_out, almost_empty_out;
93
 
94
// full and empty status outputs
95
output full_out, empty_out;
96
 
97
// read and write addresses outputs
98
output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out;
99
 
100
// read and write allow outputs
101
output rallow_out, wallow_out ;
102
 
103
// two locations left output indicator
104
output two_left_out ;
105
 
106
// read address register
107
reg [(ADDR_LENGTH - 1):0] raddr ;
108
 
109
// write address register
110
reg [(ADDR_LENGTH - 1):0] waddr;
111
assign waddr_out = waddr ;
112
 
113
// grey code registers
114
// grey code pipeline for write address
115
reg [(ADDR_LENGTH - 1):0] wgrey_minus1 ; // current
116
reg [(ADDR_LENGTH - 1):0] wgrey_addr ; // current
117
reg [(ADDR_LENGTH - 1):0] wgrey_next ; // next
118
 
119
// next write gray address calculation - bitwise xor between address and shifted address
120
wire [(ADDR_LENGTH - 2):0] calc_wgrey_next  = waddr[(ADDR_LENGTH - 1):1] ^ waddr[(ADDR_LENGTH - 2):0] ;
121
 
122
// grey code pipeline for read address
123
reg [(ADDR_LENGTH - 1):0] rgrey_minus3 ; // three before current
124
reg [(ADDR_LENGTH - 1):0] rgrey_minus2 ; // two before current
125
reg [(ADDR_LENGTH - 1):0] rgrey_minus1 ; // one before current
126
reg [(ADDR_LENGTH - 1):0] rgrey_addr ; // current
127
reg [(ADDR_LENGTH - 1):0] rgrey_next ; // next
128
 
129
// next read gray address calculation - bitwise xor between address and shifted address
130
wire [(ADDR_LENGTH - 2):0] calc_rgrey_next  = raddr[(ADDR_LENGTH - 1):1] ^ raddr[(ADDR_LENGTH - 2):0] ;
131
 
132
// FFs for registered empty and full flags
133
reg empty ;
134
reg full ;
135
 
136
// registered almost_empty and almost_full flags
137
reg almost_empty ;
138
reg almost_full ;
139
 
140
// write allow wire - writes are allowed when fifo is not full
141
wire wallow = wenable_in && ~full ;
142
 
143
// write allow output assignment
144
assign wallow_out = wallow ;
145
 
146
// read allow wire
147
wire rallow ;
148
 
149
// full output assignment
150
assign full_out  = full ;
151
 
152
// almost full output assignment
153
assign almost_full_out  = almost_full && ~full ;
154
 
155
// clear generation for FFs and registers
156
wire clear = reset_in || flush_in ;
157
 
158
`ifdef SYNCHRONOUS
159
 
160
    reg wclock_nempty_detect ;
161
    always@(posedge reset_in or posedge wclock_in)
162
    begin
163
        if (reset_in)
164
            wclock_nempty_detect <= #`FF_DELAY 1'b0 ;
165
        else
166
            wclock_nempty_detect <= #`FF_DELAY (rgrey_addr != wgrey_addr) ;
167
    end
168
 
169
    // special synchronizing mechanism for different implementations - in synchronous imp., empty is prolonged for 1 clock edge if no write clock comes after initial write
170
    reg stretched_empty ;
171
    always@(posedge rclock_in or posedge clear)
172
    begin
173
        if(clear)
174
            stretched_empty <= #`FF_DELAY 1'b1 ;
175
        else
176
            stretched_empty <= #`FF_DELAY empty && ~wclock_nempty_detect ;
177
    end
178
 
179
    // empty output is actual empty + 1 read clock cycle ( stretched empty )
180
    assign empty_out = empty  || stretched_empty ;
181
 
182
    //rallow generation    
183
    assign rallow = renable_in && ~empty && ~stretched_empty ; // reads allowed if read enable is high and FIFO is not empty
184
 
185
    // rallow output assignment
186
    assign rallow_out = rallow ;
187
 
188
    // almost empty output assignment
189
    assign almost_empty_out = almost_empty && ~empty && ~stretched_empty ;
190
 
191
    // at any clock edge that rallow is high, this register provides next read address, so wait cycles are not necessary
192
    // when FIFO is empty, this register provides actual read address, so first location can be read
193
    reg [(ADDR_LENGTH - 1):0] raddr_plus_one ;
194
 
195
    // address output mux - when FIFO is empty, current actual address is driven out, when it is non - empty next address is driven out
196
    // done for zero wait state burst
197
    assign raddr_out = empty_out ? raddr : raddr_plus_one ;
198
 
199
    // enable for this register
200
    wire raddr_plus_one_en = rallow ;
201
    always@(posedge rclock_in or posedge clear)
202
    begin
203
        if (clear)
204
        begin
205
            raddr_plus_one[(ADDR_LENGTH - 1):1] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0}} ;
206
            raddr_plus_one[0] <= #`FF_DELAY 1'b1 ;
207
        end
208
        else if (raddr_plus_one_en)
209
            raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
210
    end
211
 
212
    // raddr is filled with raddr_plus_one on rising read clock edge when rallow is high
213
    always@(posedge rclock_in or posedge clear)
214
    begin
215
            if (clear)
216
            // initial value is 000......00
217
                    raddr <= #`FF_DELAY { ADDR_LENGTH{1'b0}} ;
218
            else if (rallow)
219
                raddr <= #`FF_DELAY raddr_plus_one ;
220
    end
221
 
222
`else
223
    // asynchronous RAM storage for FIFOs - somewhat simpler control logic
224
    //rallow generation    
225
    assign rallow = renable_in && ~empty ;
226
 
227
    assign rallow_out = rallow;
228
 
229
    assign almost_empty_out = almost_empty && ~empty ;
230
 
231
    // read address counter - normal counter, nothing to it
232
    // for asynchronous implementation, there is no need for pointing to next address.
233
    // On clock edge that read is performed, read address will change and on the next clock edge
234
    // asynchronous memory will provide next data
235
    always@(posedge rclock_in or posedge clear)
236
    begin
237
            if (clear)
238
            // initial value is 000......00
239
                    raddr <= #`FF_DELAY { ADDR_LENGTH{1'b0}} ;
240
            else if (rallow)
241
                    raddr <= #`FF_DELAY raddr + 1'b1 ;
242
    end
243
 
244
    assign empty_out = empty ;
245
    assign raddr_out = raddr ;
246
`endif
247
 
248
/*-----------------------------------------------------------------------------------------------
249
Read address control consists of Read address counter and Grey Address pipeline
250
There are 5 Grey addresses:
251
    - rgrey_minus3 is Grey Code of address three before current address
252
    - rgrey_minus2 is Grey Code of address two before current address
253
    - rgrey_minus1 is Grey Code of address one before current address
254
    - rgrey_addr is Grey Code of current read address
255
    - rgrey_next is Grey Code of next read address
256
--------------------------------------------------------------------------------------------------*/
257
 
258
// grey code register for three before read address
259
always@(posedge rclock_in or posedge clear)
260
begin
261
        if (clear)
262
    begin
263
        // initial value is 100......110
264
                rgrey_minus3[(ADDR_LENGTH - 1)]    <= #`FF_DELAY 1'b1 ;
265
        rgrey_minus3[(ADDR_LENGTH  - 2):3] <= #`FF_DELAY { (ADDR_LENGTH  - 4){1'b0} } ;
266
        rgrey_minus3[2:0] <= #`FF_DELAY 3'b110 ;
267
    end
268
        else
269
                if (rallow)
270
                        rgrey_minus3 <= #`FF_DELAY rgrey_minus2 ;
271
end
272
 
273
// grey code register for two before read address
274
always@(posedge rclock_in or posedge clear)
275
begin
276
        if (clear)
277
    begin
278
        // initial value is 100......010
279
                rgrey_minus2[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
280
        rgrey_minus2[(ADDR_LENGTH  - 2):2] <= #`FF_DELAY { (ADDR_LENGTH  - 3){1'b0} } ;
281
        rgrey_minus2[1:0] <= #`FF_DELAY 2'b10 ;
282
    end
283
        else
284
                if (rallow)
285
                        rgrey_minus2 <= #`FF_DELAY rgrey_minus1 ;
286
end
287
 
288
// grey code register for one before read address
289
always@(posedge rclock_in or posedge clear)
290
begin
291
        if (clear)
292
    begin
293
        // initial value is 100......011
294
                rgrey_minus1[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
295
        rgrey_minus1[(ADDR_LENGTH  - 2):2] <= #`FF_DELAY { (ADDR_LENGTH  - 3){1'b0} } ;
296
        rgrey_minus1[1:0] <= #`FF_DELAY 2'b11 ;
297
    end
298
        else
299
                if (rallow)
300
                        rgrey_minus1 <= #`FF_DELAY rgrey_addr ;
301
end
302
 
303
// grey code register for read address - represents current Read Address
304
always@(posedge rclock_in or posedge clear)
305
begin
306
        if (clear)
307
    begin
308
        // initial value is 100.......01
309
                rgrey_addr[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
310
        rgrey_addr[(ADDR_LENGTH - 2):1] <= #`FF_DELAY { (ADDR_LENGTH - 2){1'b0} } ;
311
        rgrey_addr[0] <= #`FF_DELAY 1'b1 ;
312
    end
313
        else
314
                if (rallow)
315
                        rgrey_addr <= #`FF_DELAY rgrey_next ;
316
end
317
 
318
// grey code register for next read address - represents Grey Code of next read address    
319
always@(posedge rclock_in or posedge clear)
320
begin
321
        if (clear)
322
    begin
323
        // initial value is 100......00
324
                rgrey_next[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
325
        rgrey_next[(ADDR_LENGTH - 2):0] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0} } ;
326
    end
327
        else
328
                if (rallow)
329
            rgrey_next <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
330
end
331
 
332
/*--------------------------------------------------------------------------------------------
333
Write address control consists of write address counter and three Grey Code Registers:
334
    - wgrey_minus1 holds grey coded address of one before current write address
335
    - wgrey_addr represents current Grey Coded write address
336
    - wgrey_next represents Grey Coded next write address
337
----------------------------------------------------------------------------------------------*/
338
// grey code register for one before write address
339
always@(posedge wclock_in or posedge clear)
340
begin
341
        if (clear)
342
    begin
343
        // initial value is 100.....001
344
        wgrey_minus1[(ADDR_LENGTH - 1)]   <= #`FF_DELAY 1'b1 ;
345
        wgrey_minus1[(ADDR_LENGTH - 2):2] <= #`FF_DELAY { (ADDR_LENGTH - 3){1'b0} } ;
346
        wgrey_minus1[1:0] <= #`FF_DELAY 2'b11 ;
347
    end
348
        else
349
    if (wallow)
350
            wgrey_minus1 <= #`FF_DELAY wgrey_addr ;
351
end
352
 
353
// grey code register for write address
354
always@(posedge wclock_in or posedge clear)
355
begin
356
        if (clear)
357
    begin
358
        // initial value is 100.....001
359
        wgrey_addr[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
360
        wgrey_addr[(ADDR_LENGTH - 2):1] <= #`FF_DELAY { (ADDR_LENGTH - 2){1'b0} } ;
361
        wgrey_addr[0] <= #`FF_DELAY 1'b1 ;
362
    end
363
        else
364
    if (wallow)
365
            wgrey_addr <= #`FF_DELAY wgrey_next ;
366
end
367
 
368
// grey code register for next write address
369
always@(posedge wclock_in or posedge clear)
370
begin
371
        if (clear)
372
    begin
373
        // initial value is 100......00
374
                wgrey_next[(ADDR_LENGTH - 1)] <= #`FF_DELAY 1'b1 ;
375
        wgrey_next[(ADDR_LENGTH - 2):0] <= #`FF_DELAY { (ADDR_LENGTH - 1){1'b0} } ;
376
    end
377
        else
378
    if (wallow)
379
        wgrey_next <= #`FF_DELAY {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
380
end
381
 
382
// write address counter - nothing special
383
always@(posedge wclock_in or posedge clear)
384
begin
385
        if (clear)
386
        // initial value 00.........00
387
                waddr <= #`FF_DELAY { (ADDR_LENGTH){1'b0} } ;
388
        else
389
        if (wallow)
390
                waddr <= #`FF_DELAY waddr + 1'b1 ;
391
end
392
 
393
/*------------------------------------------------------------------------------------------------------------------------------
394
Registered full control:
395
registered full is set on rising edge of wclock_in, when one location is left in fifo and another is written
396
It's kept high until something is read from FIFO, which is registered on
397
next rising write clock edge.
398
 
399
Registered almost full control:
400
registered almost full is set on rising edge of write clock when two locations are left in fifo and another is written to it.
401
it's kept high until something is read/written from/to fifo
402
 
403
Registered two left control:
404
registered two left is set on rising edge of write clock when three locations are left in fifo and another is written to it.
405
it's kept high until something is read/written from/to fifo.
406
--------------------------------------------------------------------------------------------------------------------------------*/
407
reg two_left_out ;
408
wire comb_full          = wgrey_next == rgrey_addr ;
409
wire comb_almost_full   = wgrey_addr == rgrey_minus2 ;
410
wire comb_two_left      = wgrey_next == rgrey_minus2 ;
411
wire comb_three_left    = wgrey_next == rgrey_minus3 ;
412
 
413
//combinatorial input to Registered full FlipFlop
414
wire reg_full = (wallow && comb_almost_full) || (comb_full) ;
415
 
416
always@(posedge wclock_in or posedge clear)
417
begin
418
        if (clear)
419
                full <= #`FF_DELAY 1'b0 ;
420
        else
421
                full <= #`FF_DELAY reg_full ;
422
end
423
 
424
// input for almost full flip flop
425
wire reg_almost_full_in = wallow && comb_two_left || comb_almost_full ;
426
 
427
always@(posedge clear or posedge wclock_in)
428
begin
429
    if (clear)
430
        almost_full <= #`FF_DELAY 1'b0 ;
431
    else
432
        almost_full <= #`FF_DELAY reg_almost_full_in ;
433
end
434
 
435
wire reg_two_left_in = wallow && comb_three_left || comb_two_left ;
436
 
437
always@(posedge clear or posedge wclock_in)
438
begin
439
    if (clear)
440
        two_left_out <= #`FF_DELAY 1'b0 ;
441
    else
442
        two_left_out <= #`FF_DELAY reg_two_left_in ;
443
end
444
 
445
/*------------------------------------------------------------------------------------------------------------------------------
446
Registered empty control:
447
registered empty is set on rising edge of rclock_in,
448
when only one location is used in and read from fifo. It's kept high until something is written to FIFO, which is registered on
449
the next read clock.
450
 
451
Registered almost empty control:
452
almost empty is set on rising clock edge of rclock when two locations are used and one read from FIFO. It's kept high until
453
something is read/written from/to fifo.
454
--------------------------------------------------------------------------------------------------------------------------------*/
455
wire comb_almost_empty  = rgrey_next == wgrey_addr ;
456
wire comb_empty         = rgrey_addr == wgrey_addr ;
457
wire comb_two_used      = rgrey_next == wgrey_minus1 ;
458
 
459
// combinatorial input for registered emty FlipFlop
460
wire reg_empty = (rallow && comb_almost_empty) || comb_empty ;
461
 
462
always@(posedge rclock_in or posedge clear)
463
begin
464
    if (clear)
465
        empty <= #`FF_DELAY 1'b1 ;
466
        else
467
        empty <= #`FF_DELAY reg_empty ;
468
end
469
 
470
// input for almost empty flip flop
471
wire reg_almost_empty = rallow && comb_two_used || comb_almost_empty ;
472
always@(posedge clear or posedge rclock_in)
473
begin
474
    if (clear)
475
        almost_empty <= #`FF_DELAY 1'b0 ;
476
    else
477
        almost_empty <= #`FF_DELAY reg_almost_empty ;
478
end
479
 
480
endmodule

powered by: WebSVN 2.1.0

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