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