1 //////////////////////////////////////////////////////////////////////
3 //// File name "wbw_fifo_control.v" ////
5 //// This file is part of the "PCI bridge" project ////
6 //// http://www.opencores.org/cores/pci/ ////
9 //// - Miha Dolenc (mihad@opencores.org) ////
11 //// All additional information is avaliable in the README ////
15 //////////////////////////////////////////////////////////////////////
17 //// Copyright (C) 2001 Miha Dolenc, mihad@opencores.org ////
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. ////
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. ////
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 ////
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 ////
40 //////////////////////////////////////////////////////////////////////
42 // CVS Revision History
44 // $Log: pci_wbw_fifo_control.v,v $
45 // Revision 1.1 2007-03-20 17:50:56 sithglan
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.
53 // Revision 1.4 2003/08/14 13:06:03 simons
54 // synchronizer_flop replaced with pci_synchronizer_flop, artisan ram instance updated.
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.
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.
65 // Revision 1.1 2003/01/27 16:49:31 mihad
66 // Changed module and file names. Updated scripts accordingly. FIFO synchronizations changed.
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.
73 // Revision 1.5 2002/09/30 16:03:04 mihad
74 // Added meta flop module for easier meta stable FF identification during synthesis
76 // Revision 1.4 2002/09/25 15:53:52 mihad
77 // Removed all logic from asynchronous reset network
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
82 // Revision 1.2 2001/10/05 08:14:30 mihad
83 // Updated all files with inclusion of timescale file for simulation purposes.
85 // Revision 1.1.1.1 2001/10/02 15:33:47 mihad
86 // New project directory structure
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
97 module pci_wbw_fifo_control
111 half_full_out ////Robert, burst issue
114 parameter ADDR_LENGTH = 7;
116 // independent clock inputs - rclock_in = read clock, wclock_in = write clock
117 input rclock_in, wclock_in;
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 ;
127 // input flush_in ; // not used
129 // almost full and empy status outputs
130 output almost_full_out ;
132 // full and empty status outputs
133 output full_out, empty_out;
135 // read and write addresses outputs
136 output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out;
138 // read and write allow outputs
139 output rallow_out, wallow_out ;
141 output half_full_out;
143 // read address register
144 reg [(ADDR_LENGTH - 1):0] raddr ;
146 // write address register
147 reg [(ADDR_LENGTH - 1):0] waddr;
148 assign waddr_out = waddr ;
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
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] ;
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
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] ;
166 // write allow wire - writes are allowed when fifo is not full
167 assign wallow_out = wenable_in & ~full_out ;
169 // clear generation for FFs and registers
170 wire clear = reset_in ;
173 assign rallow_out = renable_in & ~empty_out ; // reads allowed if read enable is high and FIFO is not empty
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 ;
180 wire [ADDR_LENGTH :0] fifo_fullness; //Robert, burst issue
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
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 ;
192 always@(posedge rclock_in or posedge clear)
196 raddr_plus_one <= #`FF_DELAY 4 ;
197 raddr <= #`FF_DELAY 3 ;
201 raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
202 raddr <= #`FF_DELAY raddr_plus_one ;
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)
218 // initial value is 0
219 rgrey_minus1 <= #1 0 ;
221 rgrey_next <= #`FF_DELAY 3 ;
226 rgrey_minus1 <= #1 rgrey_addr ;
227 rgrey_addr <= #1 rgrey_next ;
228 rgrey_next <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
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)
240 wgrey_addr <= #`FF_DELAY 1 ;
246 wgrey_addr <= #`FF_DELAY wgrey_next ;
247 wgrey_next <= #1 {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
251 // write address counter - nothing special - initial value is important though
252 always@(posedge wclock_in or posedge clear)
256 waddr <= #`FF_DELAY 3 ;
259 waddr <= #`FF_DELAY waddr + 1'b1 ;
262 /*------------------------------------------------------------------------------------------------------------------------------
263 Gray coded address of read address decremented by 1 is synchronized to write clock domain and compared to:
265 - Gray coded write address. If they are equal, fifo is full.
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 ;
272 pci_synchronizer_flop #(ADDR_LENGTH, 0) i_synchronizer_reg_rgrey_minus1
274 .data_in (rgrey_minus1),
275 .clk_out (wclock_in),
276 .sync_data_out (wclk_sync_rgrey_minus1),
280 always@(posedge wclock_in or posedge clear)
284 wclk_rgrey_minus1 <= #`FF_DELAY 0 ;
288 wclk_rgrey_minus1 <= #`FF_DELAY wclk_sync_rgrey_minus1 ;
292 assign full_out = (wgrey_addr == wclk_rgrey_minus1) ;
293 assign almost_full_out = (wgrey_next == wclk_rgrey_minus1) ;
295 /*------------------------------------------------------------------------------------------------------------------------------
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
304 .data_in (wgrey_next),
305 .clk_out (rclock_in),
306 .sync_data_out (rclk_sync_wgrey_next),
310 always@(posedge rclock_in or posedge clear)
313 rclk_wgrey_next <= #`FF_DELAY 3 ;
315 rclk_wgrey_next <= #`FF_DELAY rclk_sync_wgrey_next ;
318 assign empty_out = (rgrey_next == rclk_wgrey_next) ;