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

Subversion Repositories pci

[/] [pci/] [tags/] [working_demo/] [rtl/] [verilog/] [pciw_fifo_control.v] - Blame information for rev 154

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

powered by: WebSVN 2.1.0

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