40a1f26c |
1 | ////////////////////////////////////////////////////////////////////// |
2 | //// //// |
3 | //// File name "wbw_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_wbw_fifo_control.v,v $ |
45 | // Revision 1.1 2007-03-20 17:50:56 sithglan |
46 | // add shit |
47 | // |
48 | // Revision 1.5 2006/07/04 13:16:19 mihad |
49 | // Write burst performance patch applied. |
50 | // Not tested. Everything should be backwards |
51 | // compatible, since functional code is ifdefed. |
52 | // |
53 | // Revision 1.4 2003/08/14 13:06:03 simons |
54 | // synchronizer_flop replaced with pci_synchronizer_flop, artisan ram instance updated. |
55 | // |
56 | // Revision 1.3 2003/07/29 08:20:11 mihad |
57 | // Found and simulated the problem in the synchronization logic. |
58 | // Repaired the synchronization logic in the FIFOs. |
59 | // |
60 | // Revision 1.2 2003/03/26 13:16:18 mihad |
61 | // Added the reset value parameter to the synchronizer flop module. |
62 | // Added resets to all synchronizer flop instances. |
63 | // Repaired initial sync value in fifos. |
64 | // |
65 | // Revision 1.1 2003/01/27 16:49:31 mihad |
66 | // Changed module and file names. Updated scripts accordingly. FIFO synchronizations changed. |
67 | // |
68 | // Revision 1.6 2002/11/27 20:36:13 mihad |
69 | // Changed the code a bit to make it more readable. |
70 | // Functionality not changed in any way. |
71 | // More robust synchronization in fifos is still pending. |
72 | // |
73 | // Revision 1.5 2002/09/30 16:03:04 mihad |
74 | // Added meta flop module for easier meta stable FF identification during synthesis |
75 | // |
76 | // Revision 1.4 2002/09/25 15:53:52 mihad |
77 | // Removed all logic from asynchronous reset network |
78 | // |
79 | // Revision 1.3 2002/02/01 15:25:14 mihad |
80 | // Repaired a few bugs, updated specification, added test bench files and design document |
81 | // |
82 | // Revision 1.2 2001/10/05 08:14:30 mihad |
83 | // Updated all files with inclusion of timescale file for simulation purposes. |
84 | // |
85 | // Revision 1.1.1.1 2001/10/02 15:33:47 mihad |
86 | // New project directory structure |
87 | // |
88 | // |
89 | |
90 | /* FIFO_CONTROL module provides read/write address and status generation for |
91 | FIFOs implemented with standard dual port SRAM cells in ASIC or FPGA designs */ |
92 | `include "pci_constants.v" |
93 | // synopsys translate_off |
94 | `include "timescale.v" |
95 | // synopsys translate_on |
96 | |
97 | module pci_wbw_fifo_control |
98 | ( |
99 | rclock_in, |
100 | wclock_in, |
101 | renable_in, |
102 | wenable_in, |
103 | reset_in, |
104 | almost_full_out, |
105 | full_out, |
106 | empty_out, |
107 | waddr_out, |
108 | raddr_out, |
109 | rallow_out, |
110 | wallow_out, |
111 | half_full_out ////Robert, burst issue |
112 | ); |
113 | |
114 | parameter ADDR_LENGTH = 7; |
115 | |
116 | // independent clock inputs - rclock_in = read clock, wclock_in = write clock |
117 | input rclock_in, wclock_in; |
118 | |
119 | // enable inputs - read address changes on rising edge of rclock_in when reads are allowed |
120 | // write address changes on rising edge of wclock_in when writes are allowed |
121 | input renable_in, wenable_in ; |
122 | |
123 | // reset input |
124 | input reset_in; |
125 | |
126 | // flush input |
127 | // input flush_in ; // not used |
128 | |
129 | // almost full and empy status outputs |
130 | output almost_full_out ; |
131 | |
132 | // full and empty status outputs |
133 | output full_out, empty_out; |
134 | |
135 | // read and write addresses outputs |
136 | output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out; |
137 | |
138 | // read and write allow outputs |
139 | output rallow_out, wallow_out ; |
140 | |
141 | output half_full_out; |
142 | |
143 | // read address register |
144 | reg [(ADDR_LENGTH - 1):0] raddr ; |
145 | |
146 | // write address register |
147 | reg [(ADDR_LENGTH - 1):0] waddr; |
148 | assign waddr_out = waddr ; |
149 | |
150 | // grey code registers |
151 | reg [(ADDR_LENGTH - 1):0] wgrey_addr ; // current |
152 | // grey code register for next write address |
153 | reg [(ADDR_LENGTH - 1):0] wgrey_next ; // next |
154 | |
155 | // next write gray address calculation - bitwise xor between address and shifted address |
156 | wire [(ADDR_LENGTH - 2):0] calc_wgrey_next = waddr[(ADDR_LENGTH - 1):1] ^ waddr[(ADDR_LENGTH - 2):0] ; |
157 | |
158 | // grey code pipeline for read address |
159 | reg [(ADDR_LENGTH - 1):0] rgrey_minus1 ; // one before current |
160 | reg [(ADDR_LENGTH - 1):0] rgrey_addr ; // current |
161 | reg [(ADDR_LENGTH - 1):0] rgrey_next ; // next |
162 | |
163 | // next read gray address calculation - bitwise xor between address and shifted address |
164 | wire [(ADDR_LENGTH - 2):0] calc_rgrey_next = raddr[(ADDR_LENGTH - 1):1] ^ raddr[(ADDR_LENGTH - 2):0] ; |
165 | |
166 | // write allow wire - writes are allowed when fifo is not full |
167 | assign wallow_out = wenable_in & ~full_out ; |
168 | |
169 | // clear generation for FFs and registers |
170 | wire clear = reset_in ; |
171 | |
172 | //rallow generation |
173 | assign rallow_out = renable_in & ~empty_out ; // reads allowed if read enable is high and FIFO is not empty |
174 | |
175 | // at any clock edge that rallow is high, this register provides next read address, so wait cycles are not necessary |
176 | // when FIFO is empty, this register provides actual read address, so first location can be read |
177 | reg [(ADDR_LENGTH - 1):0] raddr_plus_one ; |
178 | |
179 | |
180 | wire [ADDR_LENGTH :0] fifo_fullness; //Robert, burst issue |
181 | |
182 | //Robert, burst issue |
183 | assign fifo_fullness = (waddr > raddr) ? ({1'b0, waddr} - {1'b0, raddr}) : ({1'b1, waddr} - {1'b0, raddr}); |
184 | assign half_full_out = fifo_fullness[(ADDR_LENGTH - 1)] ; |
185 | //Robert, burst issue |
186 | |
187 | |
188 | // address output mux - when FIFO is empty, current actual address is driven out, when it is non - empty next address is driven out |
189 | // done for zero wait state burst |
190 | assign raddr_out = rallow_out ? raddr_plus_one : raddr ; |
191 | |
192 | always@(posedge rclock_in or posedge clear) |
193 | begin |
194 | if (clear) |
195 | begin |
196 | raddr_plus_one <= #`FF_DELAY 4 ; |
197 | raddr <= #`FF_DELAY 3 ; |
198 | end |
199 | else if (rallow_out) |
200 | begin |
201 | raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ; |
202 | raddr <= #`FF_DELAY raddr_plus_one ; |
203 | end |
204 | end |
205 | |
206 | /*----------------------------------------------------------------------------------------------- |
207 | Read address control consists of Read address counter and Grey Address pipeline |
208 | There are 3 Grey addresses: |
209 | - rgrey_minus1 is Grey Code of address one before current address |
210 | - rgrey_addr is Grey Code of current read address |
211 | - rgrey_next is Grey Code of next read address |
212 | --------------------------------------------------------------------------------------------------*/ |
213 | // grey coded address pipeline for status generation in read clock domain |
214 | always@(posedge rclock_in or posedge clear) |
215 | begin |
216 | if (clear) |
217 | begin |
218 | // initial value is 0 |
219 | rgrey_minus1 <= #1 0 ; |
220 | rgrey_addr <= #1 1 ; |
221 | rgrey_next <= #`FF_DELAY 3 ; |
222 | end |
223 | else |
224 | if (rallow_out) |
225 | begin |
226 | rgrey_minus1 <= #1 rgrey_addr ; |
227 | rgrey_addr <= #1 rgrey_next ; |
228 | rgrey_next <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ; |
229 | end |
230 | end |
231 | |
232 | /*-------------------------------------------------------------------------------------------- |
233 | Write address control consists of write address counter and Grey Code Register |
234 | ----------------------------------------------------------------------------------------------*/ |
235 | // grey coded address pipeline for status generation in write clock domain |
236 | always@(posedge wclock_in or posedge clear) |
237 | begin |
238 | if (clear) |
239 | begin |
240 | wgrey_addr <= #`FF_DELAY 1 ; |
241 | wgrey_next <= #1 3 ; |
242 | end |
243 | else |
244 | if (wallow_out) |
245 | begin |
246 | wgrey_addr <= #`FF_DELAY wgrey_next ; |
247 | wgrey_next <= #1 {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ; |
248 | end |
249 | end |
250 | |
251 | // write address counter - nothing special - initial value is important though |
252 | always@(posedge wclock_in or posedge clear) |
253 | begin |
254 | if (clear) |
255 | // initial value 4 |
256 | waddr <= #`FF_DELAY 3 ; |
257 | else |
258 | if (wallow_out) |
259 | waddr <= #`FF_DELAY waddr + 1'b1 ; |
260 | end |
261 | |
262 | /*------------------------------------------------------------------------------------------------------------------------------ |
263 | Gray coded address of read address decremented by 1 is synchronized to write clock domain and compared to: |
264 | |
265 | - Gray coded write address. If they are equal, fifo is full. |
266 | |
267 | - Gray coded next write address. If they are equal, fifo is almost full. |
268 | --------------------------------------------------------------------------------------------------------------------------------*/ |
269 | wire [(ADDR_LENGTH - 1):0] wclk_sync_rgrey_minus1 ; |
270 | reg [(ADDR_LENGTH - 1):0] wclk_rgrey_minus1 ; |
271 | |
272 | pci_synchronizer_flop #(ADDR_LENGTH, 0) i_synchronizer_reg_rgrey_minus1 |
273 | ( |
274 | .data_in (rgrey_minus1), |
275 | .clk_out (wclock_in), |
276 | .sync_data_out (wclk_sync_rgrey_minus1), |
277 | .async_reset (clear) |
278 | ) ; |
279 | |
280 | always@(posedge wclock_in or posedge clear) |
281 | begin |
282 | if (clear) |
283 | begin |
284 | wclk_rgrey_minus1 <= #`FF_DELAY 0 ; |
285 | end |
286 | else |
287 | begin |
288 | wclk_rgrey_minus1 <= #`FF_DELAY wclk_sync_rgrey_minus1 ; |
289 | end |
290 | end |
291 | |
292 | assign full_out = (wgrey_addr == wclk_rgrey_minus1) ; |
293 | assign almost_full_out = (wgrey_next == wclk_rgrey_minus1) ; |
294 | |
295 | /*------------------------------------------------------------------------------------------------------------------------------ |
296 | Empty control: |
297 | Gray coded address of next write address is synchronized to read clock domain and compared to Gray coded next read address. |
298 | If they are equal, fifo is empty. |
299 | --------------------------------------------------------------------------------------------------------------------------------*/ |
300 | wire [(ADDR_LENGTH - 1):0] rclk_sync_wgrey_next ; |
301 | reg [(ADDR_LENGTH - 1):0] rclk_wgrey_next ; |
302 | pci_synchronizer_flop #(ADDR_LENGTH, 3) i_synchronizer_reg_wgrey_next |
303 | ( |
304 | .data_in (wgrey_next), |
305 | .clk_out (rclock_in), |
306 | .sync_data_out (rclk_sync_wgrey_next), |
307 | .async_reset (clear) |
308 | ) ; |
309 | |
310 | always@(posedge rclock_in or posedge clear) |
311 | begin |
312 | if (clear) |
313 | rclk_wgrey_next <= #`FF_DELAY 3 ; |
314 | else |
315 | rclk_wgrey_next <= #`FF_DELAY rclk_sync_wgrey_next ; |
316 | end |
317 | |
318 | assign empty_out = (rgrey_next == rclk_wgrey_next) ; |
319 | |
320 | endmodule |