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

Subversion Repositories pci

[/] [pci/] [tags/] [rel_7/] [rtl/] [verilog/] [pci_pciw_fifo_control.v] - Blame information for rev 108

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

Line No. Rev Author Line
1 77 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 104 mihad
// $Log: not supported by cvs2svn $
45 108 tadejm
// Revision 1.3  2003/07/29 08:20:11  mihad
46
// Found and simulated the problem in the synchronization logic.
47
// Repaired the synchronization logic in the FIFOs.
48 77 mihad
//
49 108 tadejm
//
50 77 mihad
 
51
/* FIFO_CONTROL module provides read/write address and status generation for
52
   FIFOs implemented with standard dual port SRAM cells in ASIC or FPGA designs */
53
`include "pci_constants.v"
54
// synopsys translate_off
55
`include "timescale.v"
56
// synopsys translate_on
57
 
58
module pci_pciw_fifo_control
59
(
60
    rclock_in,
61
    wclock_in,
62
    renable_in,
63
    wenable_in,
64
    reset_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 108 tadejm
    three_left_out,
74 77 mihad
    two_left_out
75
);
76
 
77
parameter ADDR_LENGTH = 7 ;
78
 
79
// independent clock inputs - rclock_in = read clock, wclock_in = write clock
80
input  rclock_in, wclock_in;
81
 
82
// enable inputs - read address changes on rising edge of rclock_in when reads are allowed
83
//                 write address changes on rising edge of wclock_in when writes are allowed
84
input  renable_in, wenable_in;
85
 
86
// reset input
87
input  reset_in;
88
 
89
// almost full and empy status outputs
90
output almost_full_out, almost_empty_out;
91
 
92
// full and empty status outputs
93
output full_out, empty_out;
94
 
95
// read and write addresses outputs
96
output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out;
97
 
98
// read and write allow outputs
99
output rallow_out, wallow_out ;
100
 
101 108 tadejm
// three and two locations left output indicator
102
output three_left_out ;
103 77 mihad
output two_left_out ;
104
 
105
// read address register
106
reg [(ADDR_LENGTH - 1):0] raddr ;
107
 
108
// write address register
109
reg [(ADDR_LENGTH - 1):0] waddr;
110 108 tadejm
reg [(ADDR_LENGTH - 1):0] waddr_plus1;
111 77 mihad
assign waddr_out = waddr ;
112
 
113
// grey code registers
114
// grey code pipeline for write address
115 104 mihad
reg [(ADDR_LENGTH - 1):0] wgrey_minus1 ; // previous
116
reg [(ADDR_LENGTH - 1):0] wgrey_addr   ; // current
117
reg [(ADDR_LENGTH - 1):0] wgrey_next   ; // next
118 77 mihad
 
119 108 tadejm
reg [(ADDR_LENGTH - 1):0] wgrey_next_plus1   ; // next plus 1
120
 
121
 
122 77 mihad
// next write gray address calculation - bitwise xor between address and shifted address
123
wire [(ADDR_LENGTH - 2):0] calc_wgrey_next  = waddr[(ADDR_LENGTH - 1):1] ^ waddr[(ADDR_LENGTH - 2):0] ;
124 108 tadejm
wire [(ADDR_LENGTH - 2):0] calc_wgrey_next_plus1  = waddr_plus1[(ADDR_LENGTH - 1):1] ^ waddr_plus1[(ADDR_LENGTH - 2):0] ;
125 77 mihad
 
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 104 mihad
// write allow - writes are allowed when fifo is not full
136
assign wallow_out = wenable_in & ~full_out ;
137 77 mihad
 
138
// clear generation for FFs and registers
139 104 mihad
wire clear = reset_in ;
140 77 mihad
 
141
//rallow generation
142 104 mihad
assign rallow_out = renable_in & ~empty_out ; // reads allowed if read enable is high and FIFO is not empty
143 77 mihad
 
144
// at any clock edge that rallow is high, this register provides next read address, so wait cycles are not necessary
145
// when FIFO is empty, this register provides actual read address, so first location can be read
146
reg [(ADDR_LENGTH - 1):0] raddr_plus_one ;
147
 
148
 
149
// read address mux - when read is performed, next address is driven, so next data is available immediately after read
150
// this is convenient for zero wait stait bursts
151 104 mihad
assign raddr_out = rallow_out ? raddr_plus_one : raddr ;
152 77 mihad
 
153
always@(posedge rclock_in or posedge clear)
154
begin
155
    if (clear)
156
    begin
157
        // initial values seem a bit odd - they are this way to allow easier grey pipeline implementation and to allow min fifo size of 8
158
        raddr_plus_one <= #`FF_DELAY 5 ;
159
        raddr          <= #`FF_DELAY 4 ;
160 108 tadejm
//        raddr_plus_one <= #`FF_DELAY 6 ;
161
//        raddr          <= #`FF_DELAY 5 ;
162 77 mihad
    end
163 104 mihad
    else if (rallow_out)
164 77 mihad
    begin
165
        raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
166
        raddr          <= #`FF_DELAY raddr_plus_one ;
167
    end
168
end
169
 
170
/*-----------------------------------------------------------------------------------------------
171
Read address control consists of Read address counter and Grey Address pipeline
172
There are 4 Grey addresses:
173
    - rgrey_minus2 is Grey Code of address two before current address
174
    - rgrey_minus1 is Grey Code of address one before current address
175
    - rgrey_addr is Grey Code of current read address
176
    - rgrey_next is Grey Code of next read address
177
--------------------------------------------------------------------------------------------------*/
178
// grey coded address pipeline for status generation in read clock domain
179
always@(posedge rclock_in or posedge clear)
180
begin
181
    if (clear)
182
    begin
183 104 mihad
        rgrey_minus2 <= #1 0 ;
184 77 mihad
        rgrey_minus1 <= #`FF_DELAY 1 ;
185 104 mihad
        rgrey_addr   <= #1 3 ;
186 77 mihad
        rgrey_next   <= #`FF_DELAY 2 ;
187
    end
188
    else
189 104 mihad
    if (rallow_out)
190 77 mihad
    begin
191 104 mihad
        rgrey_minus2 <= #1 rgrey_minus1 ;
192 77 mihad
        rgrey_minus1 <= #`FF_DELAY rgrey_addr ;
193 104 mihad
        rgrey_addr   <= #1 rgrey_next ;
194 77 mihad
        rgrey_next   <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
195
    end
196
end
197
 
198
/*--------------------------------------------------------------------------------------------
199 104 mihad
Write address control consists of write address counter and 3 Grey Code Registers:
200
    - wgrey_minus1 represents previous Grey coded write address
201
    - wgrey_addr   represents current Grey Coded write address
202 108 tadejm
    - wgrey_next   represents next Grey Coded write address
203
 
204
    - wgrey_next_plus1 represents second next Grey Coded write address
205
 
206 77 mihad
----------------------------------------------------------------------------------------------*/
207
// grey coded address pipeline for status generation in write clock domain
208
always@(posedge wclock_in or posedge clear)
209
begin
210
    if (clear)
211
    begin
212 104 mihad
        wgrey_minus1 <= #`FF_DELAY 1 ;
213 108 tadejm
        wgrey_addr   <= #`FF_DELAY 3 ;
214 77 mihad
        wgrey_next   <= #`FF_DELAY 2 ;
215 108 tadejm
 
216
        wgrey_next_plus1 <= #`FF_DELAY 6;
217
 
218 77 mihad
    end
219
    else
220 104 mihad
    if (wallow_out)
221 77 mihad
    begin
222 104 mihad
        wgrey_minus1 <= #`FF_DELAY wgrey_addr ;
223 108 tadejm
        wgrey_addr   <= #`FF_DELAY wgrey_next ;
224
 
225 77 mihad
        wgrey_next   <= #`FF_DELAY {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
226 108 tadejm
//        wgrey_next   <= #`FF_DELAY wgrey_next_plus1 ;
227
        wgrey_next_plus1 <= #`FF_DELAY {waddr_plus1[(ADDR_LENGTH - 1)], calc_wgrey_next_plus1} ;
228
 
229 77 mihad
    end
230
end
231
 
232
// write address counter - nothing special except initial value
233
always@(posedge wclock_in or posedge clear)
234
begin
235
    if (clear)
236 108 tadejm
    begin
237 77 mihad
        // initial value 5
238 108 tadejm
 
239 77 mihad
        waddr <= #`FF_DELAY 4 ;
240 108 tadejm
        waddr_plus1 <= #`FF_DELAY 5 ;
241
    end
242 77 mihad
    else
243 104 mihad
    if (wallow_out)
244 108 tadejm
    begin
245 77 mihad
        waddr <= #`FF_DELAY waddr + 1'b1 ;
246 108 tadejm
        waddr_plus1 <= #`FF_DELAY waddr_plus1 + 1'b1 ;
247
    end
248 77 mihad
end
249
 
250
/*------------------------------------------------------------------------------------------------------------------------------
251 104 mihad
Gray coded address of read address decremented by two is synchronized to write clock domain and compared to:
252
- previous grey coded write address - if they are equal, the fifo is full
253 77 mihad
 
254 104 mihad
- gray coded write address. If they are equal, fifo is almost full.
255 77 mihad
 
256 104 mihad
- grey coded next write address. If they are equal, the fifo has two free locations left.
257 77 mihad
--------------------------------------------------------------------------------------------------------------------------------*/
258
wire [(ADDR_LENGTH - 1):0] wclk_sync_rgrey_minus2 ;
259
reg  [(ADDR_LENGTH - 1):0] wclk_rgrey_minus2 ;
260
 
261 88 mihad
synchronizer_flop #(ADDR_LENGTH, 0) i_synchronizer_reg_rgrey_minus2
262
(
263
    .data_in        (rgrey_minus2),
264
    .clk_out        (wclock_in),
265
    .sync_data_out  (wclk_sync_rgrey_minus2),
266
    .async_reset    (clear)
267
) ;
268
 
269
always@(posedge wclock_in or posedge clear)
270 77 mihad
begin
271 88 mihad
    if (clear)
272
    begin
273
        wclk_rgrey_minus2 <= #`FF_DELAY 0 ;
274
    end
275
    else
276
    begin
277
        wclk_rgrey_minus2 <= #`FF_DELAY wclk_sync_rgrey_minus2 ;
278
    end
279 77 mihad
end
280
 
281 104 mihad
assign full_out        = (wgrey_minus1 == wclk_rgrey_minus2) ;
282
assign almost_full_out = (wgrey_addr   == wclk_rgrey_minus2) ;
283 108 tadejm
assign two_left_out    = (wgrey_next   == wclk_rgrey_minus2) ;
284 77 mihad
 
285 108 tadejm
assign three_left_out  = (wgrey_next_plus1 == wclk_rgrey_minus2) ;
286
 
287
 
288 77 mihad
/*------------------------------------------------------------------------------------------------------------------------------
289
Empty control:
290
Gray coded write address pointer is synchronized to read clock domain and compared to Gray coded read address pointer.
291
If they are equal, fifo is empty.
292
 
293
Almost empty control:
294
Synchronized write pointer is also compared to Gray coded next read address. If these two are
295
equal, fifo is almost empty.
296
--------------------------------------------------------------------------------------------------------------------------------*/
297
wire [(ADDR_LENGTH - 1):0] rclk_sync_wgrey_addr ;
298
reg  [(ADDR_LENGTH - 1):0] rclk_wgrey_addr ;
299 88 mihad
synchronizer_flop #(ADDR_LENGTH, 3) i_synchronizer_reg_wgrey_addr
300 77 mihad
(
301
    .data_in        (wgrey_addr),
302
    .clk_out        (rclock_in),
303
    .sync_data_out  (rclk_sync_wgrey_addr),
304 88 mihad
    .async_reset    (clear)
305 77 mihad
) ;
306
 
307 88 mihad
always@(posedge rclock_in or posedge clear)
308 77 mihad
begin
309 88 mihad
    if (clear)
310
        rclk_wgrey_addr <= #`FF_DELAY 3 ;
311
    else
312
        rclk_wgrey_addr <= #`FF_DELAY rclk_sync_wgrey_addr ;
313 77 mihad
end
314
 
315 104 mihad
assign almost_empty_out = (rgrey_next == rclk_wgrey_addr) ;
316
assign empty_out        = (rgrey_addr == rclk_wgrey_addr) ;
317 77 mihad
endmodule

powered by: WebSVN 2.1.0

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