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