40a1f26c |
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 |