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 66

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 58 mihad
//    flush_in,         // not used
62 21 mihad
    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 58 mihad
//input flush_in ;      // not used
87 2 mihad
 
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 59 mihad
wire empty ;
131
wire full ;
132 2 mihad
 
133
// registered almost_empty and almost_full flags
134 59 mihad
wire almost_empty ;
135
wire almost_full ;
136 2 mihad
 
137
// write allow wire - writes are allowed when fifo is not full
138 59 mihad
wire wallow = wenable_in && !full ;
139 2 mihad
 
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 59 mihad
assign almost_full_out  = almost_full && !full ;
151 2 mihad
 
152
// clear generation for FFs and registers
153 58 mihad
wire clear = reset_in /*|| flush_in*/ ;     // flush not used for write fifo
154 2 mihad
 
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 59 mihad
wire stretched_empty ;
165 2 mihad
 
166 59 mihad
wire stretched_empty_flop_i = empty && ~wclock_nempty_detect ;
167
 
168
meta_flop #(1) i_meta_flop_stretched_empty
169
(
170
    .rst_i      (clear),
171
    .clk_i      (rclock_in),
172
    .ld_i       (1'b0),
173
    .ld_val_i   (1'b0),
174
    .en_i       (1'b1),
175
    .d_i        (stretched_empty_flop_i),
176
    .meta_q_o   (stretched_empty)
177
) ;
178
 
179 21 mihad
// empty output is actual empty + 1 read clock cycle ( stretched empty )
180
assign empty_out = empty  || stretched_empty ;
181 2 mihad
 
182 21 mihad
//rallow generation
183 59 mihad
assign rallow = renable_in && !empty && !stretched_empty ; // reads allowed if read enable is high and FIFO is not empty
184 2 mihad
 
185 21 mihad
// rallow output assignment
186
assign rallow_out = rallow ;
187 2 mihad
 
188 21 mihad
// almost empty output assignment
189 59 mihad
assign almost_empty_out = almost_empty && !empty && !stretched_empty ;
190 2 mihad
 
191 21 mihad
// 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 2 mihad
 
195
 
196 21 mihad
// read address mux - when read is performed, next address is driven, so next data is available immediately after read
197
// this is convenient for zero wait stait bursts
198
assign raddr_out = rallow ? raddr_plus_one : raddr ;
199 2 mihad
 
200 21 mihad
always@(posedge rclock_in or posedge clear)
201
begin
202
    if (clear)
203 2 mihad
    begin
204 21 mihad
        // initial value is one more than initial value of read address - 6
205
        raddr_plus_one <= #`FF_DELAY 6 ;
206 2 mihad
    end
207 21 mihad
    else if (rallow)
208
        raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
209
end
210 2 mihad
 
211 21 mihad
// raddr is filled with raddr_plus_one on rising read clock edge when rallow is high
212
always@(posedge rclock_in or posedge clear)
213
begin
214
    if (clear)
215
        // initial value is 5
216
    raddr <= #`FF_DELAY 5 ;
217
    else if (rallow)
218
        raddr <= #`FF_DELAY raddr_plus_one ;
219
end
220 2 mihad
 
221
/*-----------------------------------------------------------------------------------------------
222
Read address control consists of Read address counter and Grey Address pipeline
223 21 mihad
There are 5 Grey addresses:
224 2 mihad
    - rgrey_minus3 is Grey Code of address three before current address
225
    - rgrey_minus2 is Grey Code of address two before current address
226
    - rgrey_minus1 is Grey Code of address one before current address
227
    - rgrey_addr is Grey Code of current read address
228
    - rgrey_next is Grey Code of next read address
229
--------------------------------------------------------------------------------------------------*/
230
 
231
// grey code register for three before read address
232
always@(posedge rclock_in or posedge clear)
233
begin
234 21 mihad
    if (clear)
235 2 mihad
    begin
236 21 mihad
        // initial value is 0
237
        rgrey_minus3 <= #`FF_DELAY 0 ;
238 2 mihad
    end
239 21 mihad
    else
240
    if (rallow)
241
        rgrey_minus3 <= #`FF_DELAY rgrey_minus2 ;
242 2 mihad
end
243
 
244
// grey code register for two before read address
245
always@(posedge rclock_in or posedge clear)
246
begin
247 21 mihad
    if (clear)
248 2 mihad
    begin
249 21 mihad
        // initial value is 1
250
        rgrey_minus2 <= #`FF_DELAY 1 ;
251 2 mihad
    end
252 21 mihad
    else
253
    if (rallow)
254
        rgrey_minus2 <= #`FF_DELAY rgrey_minus1 ;
255 2 mihad
end
256
 
257
// grey code register for one before read address
258
always@(posedge rclock_in or posedge clear)
259
begin
260 21 mihad
    if (clear)
261 2 mihad
    begin
262 21 mihad
        // initial value is 3 = ....011
263
        rgrey_minus1 <= #`FF_DELAY 3 ;
264 2 mihad
    end
265 21 mihad
    else
266
    if (rallow)
267
        rgrey_minus1 <= #`FF_DELAY rgrey_addr ;
268 2 mihad
end
269
 
270
// grey code register for read address - represents current Read Address
271
always@(posedge rclock_in or posedge clear)
272
begin
273 21 mihad
    if (clear)
274 2 mihad
    begin
275 21 mihad
        // initial value is 2 = ....010
276
        rgrey_addr <= #`FF_DELAY 2 ;
277 2 mihad
    end
278 21 mihad
    else
279
    if (rallow)
280
        rgrey_addr <= #`FF_DELAY rgrey_next ;
281 2 mihad
end
282
 
283 21 mihad
// grey code register for next read address - represents Grey Code of next read address
284 2 mihad
always@(posedge rclock_in or posedge clear)
285
begin
286 21 mihad
    if (clear)
287 2 mihad
    begin
288 21 mihad
        // initial value is 6 = ....110
289
        rgrey_next <= #`FF_DELAY 6 ;
290 2 mihad
    end
291 21 mihad
    else
292
    if (rallow)
293
        rgrey_next <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
294 2 mihad
end
295
 
296
/*--------------------------------------------------------------------------------------------
297
Write address control consists of write address counter and three Grey Code Registers:
298
    - wgrey_minus1 holds grey coded address of one before current write address
299
    - wgrey_addr represents current Grey Coded write address
300
    - wgrey_next represents Grey Coded next write address
301
----------------------------------------------------------------------------------------------*/
302
// grey code register for one before write address
303
always@(posedge wclock_in or posedge clear)
304
begin
305 21 mihad
    if (clear)
306 2 mihad
    begin
307 21 mihad
        // initial value is 3 = .....011
308
        wgrey_minus1 <= #`FF_DELAY 3 ;
309 2 mihad
    end
310 21 mihad
    else
311 2 mihad
    if (wallow)
312 21 mihad
        wgrey_minus1 <= #`FF_DELAY wgrey_addr ;
313 2 mihad
end
314
 
315
// grey code register for write address
316
always@(posedge wclock_in or posedge clear)
317
begin
318 21 mihad
    if (clear)
319
        // initial value is 2 = .....010
320
        wgrey_addr <= #`FF_DELAY 2 ;
321
    else
322 2 mihad
    if (wallow)
323 21 mihad
        wgrey_addr <= #`FF_DELAY wgrey_next ;
324 2 mihad
end
325
 
326
// grey code register for next write address
327
always@(posedge wclock_in or posedge clear)
328
begin
329 21 mihad
    if (clear)
330 2 mihad
    begin
331 21 mihad
        // initial value is 6 = ....0110
332
        wgrey_next <= #`FF_DELAY 6 ;
333 2 mihad
    end
334 21 mihad
    else
335 2 mihad
    if (wallow)
336
        wgrey_next <= #`FF_DELAY {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
337
end
338
 
339 21 mihad
// write address counter - nothing special except initial value
340 2 mihad
always@(posedge wclock_in or posedge clear)
341
begin
342 21 mihad
    if (clear)
343
        // initial value 5
344
        waddr <= #`FF_DELAY 5 ;
345
    else
346
    if (wallow)
347
        waddr <= #`FF_DELAY waddr + 1'b1 ;
348 2 mihad
end
349
 
350
/*------------------------------------------------------------------------------------------------------------------------------
351
Registered full control:
352
registered full is set on rising edge of wclock_in, when one location is left in fifo and another is written
353
It's kept high until something is read from FIFO, which is registered on
354
next rising write clock edge.
355
 
356
Registered almost full control:
357
registered almost full is set on rising edge of write clock when two locations are left in fifo and another is written to it.
358
it's kept high until something is read/written from/to fifo
359
 
360
Registered two left control:
361
registered two left is set on rising edge of write clock when three locations are left in fifo and another is written to it.
362
it's kept high until something is read/written from/to fifo.
363
--------------------------------------------------------------------------------------------------------------------------------*/
364
wire comb_full          = wgrey_next == rgrey_addr ;
365
wire comb_almost_full   = wgrey_addr == rgrey_minus2 ;
366
wire comb_two_left      = wgrey_next == rgrey_minus2 ;
367
wire comb_three_left    = wgrey_next == rgrey_minus3 ;
368
 
369
//combinatorial input to Registered full FlipFlop
370
wire reg_full = (wallow && comb_almost_full) || (comb_full) ;
371
 
372 59 mihad
meta_flop #(0) i_meta_flop_full
373
(
374
    .rst_i       (clear),
375
    .clk_i       (wclock_in),
376
    .ld_i        (1'b0),
377
    .ld_val_i    (1'b0),
378
    .en_i        (1'b1),
379
    .d_i         (reg_full),
380
    .meta_q_o    (full)
381
) ;
382 2 mihad
 
383
// input for almost full flip flop
384
wire reg_almost_full_in = wallow && comb_two_left || comb_almost_full ;
385
 
386 59 mihad
meta_flop #(0) i_meta_flop_almost_full
387
(
388
    .rst_i       (clear),
389
    .clk_i       (wclock_in),
390
    .ld_i        (1'b0),
391
    .ld_val_i    (1'b0),
392
    .en_i        (1'b1),
393
    .d_i         (reg_almost_full_in),
394
    .meta_q_o    (almost_full)
395
) ;
396 2 mihad
 
397
wire reg_two_left_in = wallow && comb_three_left || comb_two_left ;
398
 
399 59 mihad
meta_flop #(0) i_meta_flop_two_left
400
(
401
    .rst_i       (clear),
402
    .clk_i       (wclock_in),
403
    .ld_i        (1'b0),
404
    .ld_val_i    (1'b0),
405
    .en_i        (1'b1),
406
    .d_i         (reg_two_left_in),
407
    .meta_q_o    (two_left_out)
408
) ;
409 2 mihad
 
410
/*------------------------------------------------------------------------------------------------------------------------------
411
Registered empty control:
412 21 mihad
registered empty is set on rising edge of rclock_in,
413 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
414
the next read clock.
415
 
416
Registered almost empty control:
417
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
418
something is read/written from/to fifo.
419
--------------------------------------------------------------------------------------------------------------------------------*/
420
wire comb_almost_empty  = rgrey_next == wgrey_addr ;
421
wire comb_empty         = rgrey_addr == wgrey_addr ;
422
wire comb_two_used      = rgrey_next == wgrey_minus1 ;
423
 
424
// combinatorial input for registered emty FlipFlop
425 66 mihad
//wire reg_empty = (rallow && comb_almost_empty) || comb_empty ;
426
wire reg_empty = (rallow && almost_empty) || comb_empty ;
427 2 mihad
 
428 59 mihad
meta_flop #(1) i_meta_flop_empty
429
(
430
    .rst_i      (clear),
431
    .clk_i      (rclock_in),
432
    .ld_i       (1'b0),
433
    .ld_val_i   (1'b0),
434
    .en_i       (1'b1),
435
    .d_i        (reg_empty),
436
    .meta_q_o   (empty)
437
) ;
438 2 mihad
 
439
// input for almost empty flip flop
440
wire reg_almost_empty = rallow && comb_two_used || comb_almost_empty ;
441
 
442 59 mihad
meta_flop #(0) i_meta_flop_almost_empty
443
(
444
    .rst_i      (clear),
445
    .clk_i      (rclock_in),
446
    .ld_i       (1'b0),
447
    .ld_val_i   (1'b0),
448
    .en_i       (1'b1),
449
    .d_i        (reg_almost_empty),
450
    .meta_q_o   (almost_empty)
451
) ;
452
 
453 2 mihad
endmodule

powered by: WebSVN 2.1.0

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