OpenCores
URL https://opencores.org/ocsvn/pci/pci/trunk

Subversion Repositories pci

[/] [pci/] [tags/] [rel_7/] [rtl/] [verilog/] [pci_pciw_fifo_control.v] - Blame information for rev 104

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 77 mihad
//////////////////////////////////////////////////////////////////////
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 104 mihad
// $Log: not supported by cvs2svn $
45 77 mihad
//
46
 
47
/* FIFO_CONTROL module provides read/write address and status generation for
48
   FIFOs implemented with standard dual port SRAM cells in ASIC or FPGA designs */
49
`include "pci_constants.v"
50
// synopsys translate_off
51
`include "timescale.v"
52
// synopsys translate_on
53
 
54
module pci_pciw_fifo_control
55
(
56
    rclock_in,
57
    wclock_in,
58
    renable_in,
59
    wenable_in,
60
    reset_in,
61
    almost_full_out,
62
    full_out,
63
    almost_empty_out,
64
    empty_out,
65
    waddr_out,
66
    raddr_out,
67
    rallow_out,
68
    wallow_out,
69
    two_left_out
70
);
71
 
72
parameter ADDR_LENGTH = 7 ;
73
 
74
// independent clock inputs - rclock_in = read clock, wclock_in = write clock
75
input  rclock_in, wclock_in;
76
 
77
// enable inputs - read address changes on rising edge of rclock_in when reads are allowed
78
//                 write address changes on rising edge of wclock_in when writes are allowed
79
input  renable_in, wenable_in;
80
 
81
// reset input
82
input  reset_in;
83
 
84
// almost full and empy status outputs
85
output almost_full_out, almost_empty_out;
86
 
87
// full and empty status outputs
88
output full_out, empty_out;
89
 
90
// read and write addresses outputs
91
output [(ADDR_LENGTH - 1):0] waddr_out, raddr_out;
92
 
93
// read and write allow outputs
94
output rallow_out, wallow_out ;
95
 
96
// two locations left output indicator
97
output two_left_out ;
98
 
99
// read address register
100
reg [(ADDR_LENGTH - 1):0] raddr ;
101
 
102
// write address register
103
reg [(ADDR_LENGTH - 1):0] waddr;
104
assign waddr_out = waddr ;
105
 
106
// grey code registers
107
// grey code pipeline for write address
108 104 mihad
reg [(ADDR_LENGTH - 1):0] wgrey_minus1 ; // previous
109
reg [(ADDR_LENGTH - 1):0] wgrey_addr   ; // current
110
reg [(ADDR_LENGTH - 1):0] wgrey_next   ; // next
111 77 mihad
 
112
// next write gray address calculation - bitwise xor between address and shifted address
113
wire [(ADDR_LENGTH - 2):0] calc_wgrey_next  = waddr[(ADDR_LENGTH - 1):1] ^ waddr[(ADDR_LENGTH - 2):0] ;
114
 
115
// grey code pipeline for read address
116
reg [(ADDR_LENGTH - 1):0] rgrey_minus2 ; // two before current
117
reg [(ADDR_LENGTH - 1):0] rgrey_minus1 ; // one before current
118
reg [(ADDR_LENGTH - 1):0] rgrey_addr ; // current
119
reg [(ADDR_LENGTH - 1):0] rgrey_next ; // next
120
 
121
// next read gray address calculation - bitwise xor between address and shifted address
122
wire [(ADDR_LENGTH - 2):0] calc_rgrey_next  = raddr[(ADDR_LENGTH - 1):1] ^ raddr[(ADDR_LENGTH - 2):0] ;
123
 
124 104 mihad
// write allow - writes are allowed when fifo is not full
125
assign wallow_out = wenable_in & ~full_out ;
126 77 mihad
 
127
// clear generation for FFs and registers
128 104 mihad
wire clear = reset_in ;
129 77 mihad
 
130
//rallow generation
131 104 mihad
assign rallow_out = renable_in & ~empty_out ; // reads allowed if read enable is high and FIFO is not empty
132 77 mihad
 
133
// at any clock edge that rallow is high, this register provides next read address, so wait cycles are not necessary
134
// when FIFO is empty, this register provides actual read address, so first location can be read
135
reg [(ADDR_LENGTH - 1):0] raddr_plus_one ;
136
 
137
 
138
// read address mux - when read is performed, next address is driven, so next data is available immediately after read
139
// this is convenient for zero wait stait bursts
140 104 mihad
assign raddr_out = rallow_out ? raddr_plus_one : raddr ;
141 77 mihad
 
142
always@(posedge rclock_in or posedge clear)
143
begin
144
    if (clear)
145
    begin
146
        // initial values seem a bit odd - they are this way to allow easier grey pipeline implementation and to allow min fifo size of 8
147
        raddr_plus_one <= #`FF_DELAY 5 ;
148
        raddr          <= #`FF_DELAY 4 ;
149
    end
150 104 mihad
    else if (rallow_out)
151 77 mihad
    begin
152
        raddr_plus_one <= #`FF_DELAY raddr_plus_one + 1'b1 ;
153
        raddr          <= #`FF_DELAY raddr_plus_one ;
154
    end
155
end
156
 
157
/*-----------------------------------------------------------------------------------------------
158
Read address control consists of Read address counter and Grey Address pipeline
159
There are 4 Grey addresses:
160
    - rgrey_minus2 is Grey Code of address two before current address
161
    - rgrey_minus1 is Grey Code of address one before current address
162
    - rgrey_addr is Grey Code of current read address
163
    - rgrey_next is Grey Code of next read address
164
--------------------------------------------------------------------------------------------------*/
165
// grey coded address pipeline for status generation in read clock domain
166
always@(posedge rclock_in or posedge clear)
167
begin
168
    if (clear)
169
    begin
170 104 mihad
        rgrey_minus2 <= #1 0 ;
171 77 mihad
        rgrey_minus1 <= #`FF_DELAY 1 ;
172 104 mihad
        rgrey_addr   <= #1 3 ;
173 77 mihad
        rgrey_next   <= #`FF_DELAY 2 ;
174
    end
175
    else
176 104 mihad
    if (rallow_out)
177 77 mihad
    begin
178 104 mihad
        rgrey_minus2 <= #1 rgrey_minus1 ;
179 77 mihad
        rgrey_minus1 <= #`FF_DELAY rgrey_addr ;
180 104 mihad
        rgrey_addr   <= #1 rgrey_next ;
181 77 mihad
        rgrey_next   <= #`FF_DELAY {raddr[ADDR_LENGTH - 1], calc_rgrey_next} ;
182
    end
183
end
184
 
185
/*--------------------------------------------------------------------------------------------
186 104 mihad
Write address control consists of write address counter and 3 Grey Code Registers:
187
    - wgrey_minus1 represents previous Grey coded write address
188
    - wgrey_addr   represents current Grey Coded write address
189
    - wgrey_next   represents Grey Coded next write address
190 77 mihad
----------------------------------------------------------------------------------------------*/
191
// grey coded address pipeline for status generation in write clock domain
192
always@(posedge wclock_in or posedge clear)
193
begin
194
    if (clear)
195
    begin
196 104 mihad
        wgrey_minus1 <= #`FF_DELAY 1 ;
197
        wgrey_addr   <= #1 3 ;
198 77 mihad
        wgrey_next   <= #`FF_DELAY 2 ;
199
    end
200
    else
201 104 mihad
    if (wallow_out)
202 77 mihad
    begin
203 104 mihad
        wgrey_minus1 <= #`FF_DELAY wgrey_addr ;
204
        wgrey_addr   <= #1 wgrey_next ;
205 77 mihad
        wgrey_next   <= #`FF_DELAY {waddr[(ADDR_LENGTH - 1)], calc_wgrey_next} ;
206
    end
207
end
208
 
209
// write address counter - nothing special except initial value
210
always@(posedge wclock_in or posedge clear)
211
begin
212
    if (clear)
213
        // initial value 5
214
        waddr <= #`FF_DELAY 4 ;
215
    else
216 104 mihad
    if (wallow_out)
217 77 mihad
        waddr <= #`FF_DELAY waddr + 1'b1 ;
218
end
219
 
220
/*------------------------------------------------------------------------------------------------------------------------------
221 104 mihad
Gray coded address of read address decremented by two is synchronized to write clock domain and compared to:
222
- previous grey coded write address - if they are equal, the fifo is full
223 77 mihad
 
224 104 mihad
- gray coded write address. If they are equal, fifo is almost full.
225 77 mihad
 
226 104 mihad
- grey coded next write address. If they are equal, the fifo has two free locations left.
227 77 mihad
--------------------------------------------------------------------------------------------------------------------------------*/
228
wire [(ADDR_LENGTH - 1):0] wclk_sync_rgrey_minus2 ;
229
reg  [(ADDR_LENGTH - 1):0] wclk_rgrey_minus2 ;
230
 
231 88 mihad
synchronizer_flop #(ADDR_LENGTH, 0) i_synchronizer_reg_rgrey_minus2
232
(
233
    .data_in        (rgrey_minus2),
234
    .clk_out        (wclock_in),
235
    .sync_data_out  (wclk_sync_rgrey_minus2),
236
    .async_reset    (clear)
237
) ;
238
 
239
always@(posedge wclock_in or posedge clear)
240 77 mihad
begin
241 88 mihad
    if (clear)
242
    begin
243
        wclk_rgrey_minus2 <= #`FF_DELAY 0 ;
244
    end
245
    else
246
    begin
247
        wclk_rgrey_minus2 <= #`FF_DELAY wclk_sync_rgrey_minus2 ;
248
    end
249 77 mihad
end
250
 
251 104 mihad
assign full_out        = (wgrey_minus1 == wclk_rgrey_minus2) ;
252
assign almost_full_out = (wgrey_addr   == wclk_rgrey_minus2) ;
253
assign two_left_out = (wgrey_next   == wclk_rgrey_minus2) ;
254 77 mihad
 
255
/*------------------------------------------------------------------------------------------------------------------------------
256
Empty control:
257
Gray coded write address pointer is synchronized to read clock domain and compared to Gray coded read address pointer.
258
If they are equal, fifo is empty.
259
 
260
Almost empty control:
261
Synchronized write pointer is also compared to Gray coded next read address. If these two are
262
equal, fifo is almost empty.
263
--------------------------------------------------------------------------------------------------------------------------------*/
264
wire [(ADDR_LENGTH - 1):0] rclk_sync_wgrey_addr ;
265
reg  [(ADDR_LENGTH - 1):0] rclk_wgrey_addr ;
266 88 mihad
synchronizer_flop #(ADDR_LENGTH, 3) i_synchronizer_reg_wgrey_addr
267 77 mihad
(
268
    .data_in        (wgrey_addr),
269
    .clk_out        (rclock_in),
270
    .sync_data_out  (rclk_sync_wgrey_addr),
271 88 mihad
    .async_reset    (clear)
272 77 mihad
) ;
273
 
274 88 mihad
always@(posedge rclock_in or posedge clear)
275 77 mihad
begin
276 88 mihad
    if (clear)
277
        rclk_wgrey_addr <= #`FF_DELAY 3 ;
278
    else
279
        rclk_wgrey_addr <= #`FF_DELAY rclk_sync_wgrey_addr ;
280 77 mihad
end
281
 
282 104 mihad
assign almost_empty_out = (rgrey_next == rclk_wgrey_addr) ;
283
assign empty_out        = (rgrey_addr == rclk_wgrey_addr) ;
284 77 mihad
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.