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 21

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

powered by: WebSVN 2.1.0

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