1 |
2 |
ZTEX |
//*****************************************************************************
|
2 |
|
|
// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
3 |
|
|
//
|
4 |
|
|
// This file contains confidential and proprietary information
|
5 |
|
|
// of Xilinx, Inc. and is protected under U.S. and
|
6 |
|
|
// international copyright and other intellectual property
|
7 |
|
|
// laws.
|
8 |
|
|
//
|
9 |
|
|
// DISCLAIMER
|
10 |
|
|
// This disclaimer is not a license and does not grant any
|
11 |
|
|
// rights to the materials distributed herewith. Except as
|
12 |
|
|
// otherwise provided in a valid license issued to you by
|
13 |
|
|
// Xilinx, and to the maximum extent permitted by applicable
|
14 |
|
|
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
15 |
|
|
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
16 |
|
|
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
17 |
|
|
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
18 |
|
|
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
19 |
|
|
// (2) Xilinx shall not be liable (whether in contract or tort,
|
20 |
|
|
// including negligence, or under any other theory of
|
21 |
|
|
// liability) for any loss or damage of any kind or nature
|
22 |
|
|
// related to, arising under or in connection with these
|
23 |
|
|
// materials, including for any direct, or any indirect,
|
24 |
|
|
// special, incidental, or consequential loss or damage
|
25 |
|
|
// (including loss of data, profits, goodwill, or any type of
|
26 |
|
|
// loss or damage suffered as a result of any action brought
|
27 |
|
|
// by a third party) even if such damage or loss was
|
28 |
|
|
// reasonably foreseeable or Xilinx had been advised of the
|
29 |
|
|
// possibility of the same.
|
30 |
|
|
//
|
31 |
|
|
// CRITICAL APPLICATIONS
|
32 |
|
|
// Xilinx products are not designed or intended to be fail-
|
33 |
|
|
// safe, or for use in any application requiring fail-safe
|
34 |
|
|
// performance, such as life-support or safety devices or
|
35 |
|
|
// systems, Class III medical devices, nuclear facilities,
|
36 |
|
|
// applications related to the deployment of airbags, or any
|
37 |
|
|
// other applications that could lead to death, personal
|
38 |
|
|
// injury, or severe property or environmental damage
|
39 |
|
|
// (individually and collectively, "Critical
|
40 |
|
|
// Applications"). Customer assumes the sole risk and
|
41 |
|
|
// liability of any use of Xilinx products in Critical
|
42 |
|
|
// Applications, subject only to applicable laws and
|
43 |
|
|
// regulations governing limitations on product liability.
|
44 |
|
|
//
|
45 |
|
|
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
46 |
|
|
// PART OF THIS FILE AT ALL TIMES.
|
47 |
|
|
//
|
48 |
|
|
//*****************************************************************************
|
49 |
|
|
// ____ ____
|
50 |
|
|
// / /\/ /
|
51 |
|
|
// /___/ \ / Vendor : Xilinx
|
52 |
|
|
// \ \ \/ Version : %version
|
53 |
|
|
// \ \ Application : MIG
|
54 |
|
|
// / / Filename : ui_rd_data.v
|
55 |
|
|
// /___/ /\ Date Last Modified : $date$
|
56 |
|
|
// \ \ / \ Date Created : Tue Jun 30 2009
|
57 |
|
|
// \___\/\___\
|
58 |
|
|
//
|
59 |
|
|
//Device : 7-Series
|
60 |
|
|
//Design Name : DDR3 SDRAM
|
61 |
|
|
//Purpose :
|
62 |
|
|
//Reference :
|
63 |
|
|
//Revision History :
|
64 |
|
|
//*****************************************************************************
|
65 |
|
|
|
66 |
|
|
// User interface read buffer. Re orders read data returned from the
|
67 |
|
|
// memory controller back to the request order.
|
68 |
|
|
//
|
69 |
|
|
// Consists of a large buffer for the data, a status RAM and two counters.
|
70 |
|
|
//
|
71 |
|
|
// The large buffer is implemented with distributed RAM in 6 bit wide,
|
72 |
|
|
// 1 read, 1 write mode. The status RAM is implemented with a distributed
|
73 |
|
|
// RAM configured as 2 bits wide 1 read/write, 1 read mode.
|
74 |
|
|
//
|
75 |
|
|
// As read requests are received from the application, the data_buf_addr
|
76 |
|
|
// counter supplies the data_buf_addr sent into the memory controller.
|
77 |
|
|
// With each read request, the counter is incremented, eventually rolling
|
78 |
|
|
// over. This mechanism labels each read request with an incrementing number.
|
79 |
|
|
//
|
80 |
|
|
// When the memory controller returns read data, it echos the original
|
81 |
|
|
// data_buf_addr with the read data.
|
82 |
|
|
//
|
83 |
|
|
// The status RAM is indexed with the same address as the data buffer
|
84 |
|
|
// RAM. Each word of the data buffer RAM has an associated status bit
|
85 |
|
|
// and "end" bit. Requests of size 1 return a data burst on two consecutive
|
86 |
|
|
// states. Requests of size zero return with a single assertion of rd_data_en.
|
87 |
|
|
//
|
88 |
|
|
// Upon returning data, the status and end bits are updated for each
|
89 |
|
|
// corresponding location in the status RAM indexed by the data_buf_addr
|
90 |
|
|
// echoed on the rd_data_addr field.
|
91 |
|
|
//
|
92 |
|
|
// The other side of the status and data RAMs is indexed by the rd_buf_indx.
|
93 |
|
|
// The rd_buf_indx constantly monitors the status bit it is currently
|
94 |
|
|
// pointing to. When the status becomes set to the proper state (more on
|
95 |
|
|
// this later) read data is returned to the application, and the rd_buf_indx
|
96 |
|
|
// is incremented.
|
97 |
|
|
//
|
98 |
|
|
// At rst the rd_buf_indx is initialized to zero. Data will not have been
|
99 |
|
|
// returned from the memory controller yet, so there is nothing to return
|
100 |
|
|
// to the application. Evenutally, read requests will be made, and the
|
101 |
|
|
// memory controller will return the corresponding data. The memory
|
102 |
|
|
// controller may not return this data in the request order. In which
|
103 |
|
|
// case, the status bit at location zero, will not indicate
|
104 |
|
|
// the data for request zero is ready. Eventually, the memory controller
|
105 |
|
|
// will return data for request zero. The data is forwarded on to the
|
106 |
|
|
// application, and rd_buf_indx is incremented to point to the next status
|
107 |
|
|
// bits and data in the buffers. The status bit will be examined, and if
|
108 |
|
|
// data is valid, this data will be returned as well. This process
|
109 |
|
|
// continues until the status bit indexed by rd_buf_indx indicates data
|
110 |
|
|
// is not ready. This may be because the rd_data_buf
|
111 |
|
|
// is empty, or that some data was returned out of order. Since rd_buf_indx
|
112 |
|
|
// always increments sequentially, data is always returned to the application
|
113 |
|
|
// in request order.
|
114 |
|
|
//
|
115 |
|
|
// Some further discussion of the status bit is in order. The rd_data_buf
|
116 |
|
|
// is a circular buffer. The status bit is a single bit. Distributed RAM
|
117 |
|
|
// supports only a single write port. The write port is consumed by
|
118 |
|
|
// memory controller read data updates. If a simple '1' were used to
|
119 |
|
|
// indicate the status, when rd_data_indx rolled over it would immediately
|
120 |
|
|
// encounter a one for a request that may not be ready.
|
121 |
|
|
//
|
122 |
|
|
// This problem is solved by causing read data returns to flip the
|
123 |
|
|
// status bit, and adding hi order bit beyond the size required to
|
124 |
|
|
// index the rd_data_buf. Data is considered ready when the status bit
|
125 |
|
|
// and this hi order bit are equal.
|
126 |
|
|
//
|
127 |
|
|
// The status RAM needs to be initialized to zero after reset. This is
|
128 |
|
|
// accomplished by cycling through all rd_buf_indx valus and writing a
|
129 |
|
|
// zero to the status bits directly following deassertion of reset. This
|
130 |
|
|
// mechanism is used for similar purposes
|
131 |
|
|
// for the wr_data_buf.
|
132 |
|
|
//
|
133 |
|
|
// When ORDERING == "STRICT", read data reordering is unnecessary. For thi
|
134 |
|
|
// case, most of the logic in the block is not generated.
|
135 |
|
|
|
136 |
|
|
`timescale 1 ps / 1 ps
|
137 |
|
|
|
138 |
|
|
// User interface read data.
|
139 |
|
|
|
140 |
|
|
module mig_7series_v2_3_ui_rd_data #
|
141 |
|
|
(
|
142 |
|
|
parameter TCQ = 100,
|
143 |
|
|
parameter APP_DATA_WIDTH = 256,
|
144 |
|
|
parameter DATA_BUF_ADDR_WIDTH = 5,
|
145 |
|
|
parameter ECC = "OFF",
|
146 |
|
|
parameter nCK_PER_CLK = 2 ,
|
147 |
|
|
parameter ORDERING = "NORM"
|
148 |
|
|
)
|
149 |
|
|
(/*AUTOARG*/
|
150 |
|
|
// Outputs
|
151 |
|
|
ram_init_done_r, ram_init_addr, app_rd_data_valid, app_rd_data_end,
|
152 |
|
|
app_rd_data, app_ecc_multiple_err, rd_buf_full, rd_data_buf_addr_r,
|
153 |
|
|
// Inputs
|
154 |
|
|
rst, clk, rd_data_en, rd_data_addr, rd_data_offset, rd_data_end,
|
155 |
|
|
rd_data, ecc_multiple, rd_accepted
|
156 |
|
|
);
|
157 |
|
|
|
158 |
|
|
input rst;
|
159 |
|
|
input clk;
|
160 |
|
|
|
161 |
|
|
output wire ram_init_done_r;
|
162 |
|
|
output wire [3:0] ram_init_addr;
|
163 |
|
|
|
164 |
|
|
// rd_buf_indx points to the status and data storage rams for
|
165 |
|
|
// reading data out to the app.
|
166 |
|
|
reg [5:0] rd_buf_indx_r;
|
167 |
|
|
reg ram_init_done_r_lcl /* synthesis syn_maxfan = 10 */;
|
168 |
|
|
assign ram_init_done_r = ram_init_done_r_lcl;
|
169 |
|
|
wire app_rd_data_valid_ns;
|
170 |
|
|
wire single_data;
|
171 |
|
|
reg [5:0] rd_buf_indx_ns;
|
172 |
|
|
generate begin : rd_buf_indx
|
173 |
|
|
wire upd_rd_buf_indx = ~ram_init_done_r_lcl || app_rd_data_valid_ns;
|
174 |
|
|
// Loop through all status write addresses once after rst. Initializes
|
175 |
|
|
// the status and pointer RAMs.
|
176 |
|
|
wire ram_init_done_ns =
|
177 |
|
|
~rst && (ram_init_done_r_lcl || (rd_buf_indx_r[4:0] == 5'h1f));
|
178 |
|
|
always @(posedge clk) ram_init_done_r_lcl <= #TCQ ram_init_done_ns;
|
179 |
|
|
|
180 |
|
|
always @(/*AS*/rd_buf_indx_r or rst or single_data
|
181 |
|
|
or upd_rd_buf_indx) begin
|
182 |
|
|
rd_buf_indx_ns = rd_buf_indx_r;
|
183 |
|
|
if (rst) rd_buf_indx_ns = 6'b0;
|
184 |
|
|
else if (upd_rd_buf_indx) rd_buf_indx_ns =
|
185 |
|
|
// need to use every slot of RAMB32 if all address bits are used
|
186 |
|
|
rd_buf_indx_r + 6'h1 + (DATA_BUF_ADDR_WIDTH == 5 ? 0 : single_data);
|
187 |
|
|
end
|
188 |
|
|
always @(posedge clk) rd_buf_indx_r <= #TCQ rd_buf_indx_ns;
|
189 |
|
|
end
|
190 |
|
|
endgenerate
|
191 |
|
|
assign ram_init_addr = rd_buf_indx_r[3:0];
|
192 |
|
|
|
193 |
|
|
input rd_data_en;
|
194 |
|
|
input [DATA_BUF_ADDR_WIDTH-1:0] rd_data_addr;
|
195 |
|
|
input rd_data_offset;
|
196 |
|
|
input rd_data_end;
|
197 |
|
|
input [APP_DATA_WIDTH-1:0] rd_data;
|
198 |
|
|
output reg app_rd_data_valid /* synthesis syn_maxfan = 10 */;
|
199 |
|
|
output reg app_rd_data_end;
|
200 |
|
|
output reg [APP_DATA_WIDTH-1:0] app_rd_data;
|
201 |
|
|
input [3:0] ecc_multiple;
|
202 |
|
|
reg [2*nCK_PER_CLK-1:0] app_ecc_multiple_err_r = 'b0;
|
203 |
|
|
output wire [2*nCK_PER_CLK-1:0] app_ecc_multiple_err;
|
204 |
|
|
assign app_ecc_multiple_err = app_ecc_multiple_err_r;
|
205 |
|
|
input rd_accepted;
|
206 |
|
|
output wire rd_buf_full;
|
207 |
|
|
output wire [DATA_BUF_ADDR_WIDTH-1:0] rd_data_buf_addr_r;
|
208 |
|
|
|
209 |
|
|
// Compute dimensions of read data buffer. Depending on width of
|
210 |
|
|
// DQ bus and DRAM CK
|
211 |
|
|
// to fabric ratio, number of RAM32Ms is variable. RAM32Ms are used in
|
212 |
|
|
// single write, single read, 6 bit wide mode.
|
213 |
|
|
localparam RD_BUF_WIDTH = APP_DATA_WIDTH + (ECC == "OFF" ? 0 : 2*nCK_PER_CLK);
|
214 |
|
|
localparam FULL_RAM_CNT = (RD_BUF_WIDTH/6);
|
215 |
|
|
localparam REMAINDER = RD_BUF_WIDTH % 6;
|
216 |
|
|
localparam RAM_CNT = FULL_RAM_CNT + ((REMAINDER == 0 ) ? 0 : 1);
|
217 |
|
|
localparam RAM_WIDTH = (RAM_CNT*6);
|
218 |
|
|
generate
|
219 |
|
|
if (ORDERING == "STRICT") begin : strict_mode
|
220 |
|
|
assign app_rd_data_valid_ns = 1'b0;
|
221 |
|
|
assign single_data = 1'b0;
|
222 |
|
|
assign rd_buf_full = 1'b0;
|
223 |
|
|
reg [DATA_BUF_ADDR_WIDTH-1:0] rd_data_buf_addr_r_lcl;
|
224 |
|
|
wire [DATA_BUF_ADDR_WIDTH-1:0] rd_data_buf_addr_ns =
|
225 |
|
|
rst
|
226 |
|
|
? 0
|
227 |
|
|
: rd_data_buf_addr_r_lcl + rd_accepted;
|
228 |
|
|
always @(posedge clk) rd_data_buf_addr_r_lcl <=
|
229 |
|
|
#TCQ rd_data_buf_addr_ns;
|
230 |
|
|
assign rd_data_buf_addr_r = rd_data_buf_addr_ns;
|
231 |
|
|
// app_* signals required to be registered.
|
232 |
|
|
if (ECC == "OFF") begin : ecc_off
|
233 |
|
|
always @(/*AS*/rd_data) app_rd_data = rd_data;
|
234 |
|
|
always @(/*AS*/rd_data_en) app_rd_data_valid = rd_data_en;
|
235 |
|
|
always @(/*AS*/rd_data_end) app_rd_data_end = rd_data_end;
|
236 |
|
|
end
|
237 |
|
|
else begin : ecc_on
|
238 |
|
|
always @(posedge clk) app_rd_data <= #TCQ rd_data;
|
239 |
|
|
always @(posedge clk) app_rd_data_valid <= #TCQ rd_data_en;
|
240 |
|
|
always @(posedge clk) app_rd_data_end <= #TCQ rd_data_end;
|
241 |
|
|
always @(posedge clk) app_ecc_multiple_err_r <= #TCQ ecc_multiple;
|
242 |
|
|
end
|
243 |
|
|
end
|
244 |
|
|
else begin : not_strict_mode
|
245 |
|
|
wire rd_buf_we = ~ram_init_done_r_lcl || rd_data_en /* synthesis syn_maxfan = 10 */;
|
246 |
|
|
// In configurations where read data is returned in a single fabric cycle
|
247 |
|
|
// the offset is always zero and we can use the bit to get a deeper
|
248 |
|
|
// FIFO. The RAMB32 has 5 address bits, so when the DATA_BUF_ADDR_WIDTH
|
249 |
|
|
// is set to use them all, discard the offset. Otherwise, include the
|
250 |
|
|
// offset.
|
251 |
|
|
wire [4:0] rd_buf_wr_addr = DATA_BUF_ADDR_WIDTH == 5 ?
|
252 |
|
|
rd_data_addr :
|
253 |
|
|
{rd_data_addr, rd_data_offset};
|
254 |
|
|
wire [1:0] rd_status;
|
255 |
|
|
// Instantiate status RAM. One bit for status and one for "end".
|
256 |
|
|
begin : status_ram
|
257 |
|
|
// Turns out read to write back status is a timing path. Update
|
258 |
|
|
// the status in the ram on the state following the read. Bypass
|
259 |
|
|
// the write data into the status read path.
|
260 |
|
|
wire [4:0] status_ram_wr_addr_ns = ram_init_done_r_lcl
|
261 |
|
|
? rd_buf_wr_addr
|
262 |
|
|
: rd_buf_indx_r[4:0];
|
263 |
|
|
reg [4:0] status_ram_wr_addr_r;
|
264 |
|
|
always @(posedge clk) status_ram_wr_addr_r <=
|
265 |
|
|
#TCQ status_ram_wr_addr_ns;
|
266 |
|
|
wire [1:0] wr_status;
|
267 |
|
|
// Not guaranteed to write second status bit. If it is written, always
|
268 |
|
|
// copy in the first status bit.
|
269 |
|
|
reg wr_status_r1;
|
270 |
|
|
always @(posedge clk) wr_status_r1 <= #TCQ wr_status[0];
|
271 |
|
|
wire [1:0] status_ram_wr_data_ns =
|
272 |
|
|
ram_init_done_r_lcl
|
273 |
|
|
? {rd_data_end, ~(rd_data_offset
|
274 |
|
|
? wr_status_r1
|
275 |
|
|
: wr_status[0])}
|
276 |
|
|
: 2'b0;
|
277 |
|
|
reg [1:0] status_ram_wr_data_r;
|
278 |
|
|
always @(posedge clk) status_ram_wr_data_r <=
|
279 |
|
|
#TCQ status_ram_wr_data_ns;
|
280 |
|
|
reg rd_buf_we_r1;
|
281 |
|
|
always @(posedge clk) rd_buf_we_r1 <= #TCQ rd_buf_we;
|
282 |
|
|
RAM32M
|
283 |
|
|
#(.INIT_A(64'h0000000000000000),
|
284 |
|
|
.INIT_B(64'h0000000000000000),
|
285 |
|
|
.INIT_C(64'h0000000000000000),
|
286 |
|
|
.INIT_D(64'h0000000000000000)
|
287 |
|
|
) RAM32M0 (
|
288 |
|
|
.DOA(rd_status),
|
289 |
|
|
.DOB(),
|
290 |
|
|
.DOC(wr_status),
|
291 |
|
|
.DOD(),
|
292 |
|
|
.DIA(status_ram_wr_data_r),
|
293 |
|
|
.DIB(2'b0),
|
294 |
|
|
.DIC(status_ram_wr_data_r),
|
295 |
|
|
.DID(status_ram_wr_data_r),
|
296 |
|
|
.ADDRA(rd_buf_indx_r[4:0]),
|
297 |
|
|
.ADDRB(5'b0),
|
298 |
|
|
.ADDRC(status_ram_wr_addr_ns),
|
299 |
|
|
.ADDRD(status_ram_wr_addr_r),
|
300 |
|
|
.WE(rd_buf_we_r1),
|
301 |
|
|
.WCLK(clk)
|
302 |
|
|
);
|
303 |
|
|
end // block: status_ram
|
304 |
|
|
|
305 |
|
|
wire [RAM_WIDTH-1:0] rd_buf_out_data;
|
306 |
|
|
begin : rd_buf
|
307 |
|
|
wire [RAM_WIDTH-1:0] rd_buf_in_data;
|
308 |
|
|
if (REMAINDER == 0)
|
309 |
|
|
if (ECC == "OFF")
|
310 |
|
|
assign rd_buf_in_data = rd_data;
|
311 |
|
|
else
|
312 |
|
|
assign rd_buf_in_data = {ecc_multiple, rd_data};
|
313 |
|
|
else
|
314 |
|
|
if (ECC == "OFF")
|
315 |
|
|
assign rd_buf_in_data = {{6-REMAINDER{1'b0}}, rd_data};
|
316 |
|
|
else
|
317 |
|
|
assign rd_buf_in_data =
|
318 |
|
|
{{6-REMAINDER{1'b0}}, ecc_multiple, rd_data};
|
319 |
|
|
|
320 |
|
|
// Dedicated copy for driving distributed RAM.
|
321 |
|
|
(* keep = "true" *) reg [4:0] rd_buf_indx_copy_r /* synthesis syn_keep = 1 */;
|
322 |
|
|
always @(posedge clk) rd_buf_indx_copy_r <= #TCQ rd_buf_indx_ns[4:0];
|
323 |
|
|
|
324 |
|
|
genvar i;
|
325 |
|
|
for (i=0; i<RAM_CNT; i=i+1) begin : rd_buffer_ram
|
326 |
|
|
RAM32M
|
327 |
|
|
#(.INIT_A(64'h0000000000000000),
|
328 |
|
|
.INIT_B(64'h0000000000000000),
|
329 |
|
|
.INIT_C(64'h0000000000000000),
|
330 |
|
|
.INIT_D(64'h0000000000000000)
|
331 |
|
|
) RAM32M0 (
|
332 |
|
|
.DOA(rd_buf_out_data[((i*6)+4)+:2]),
|
333 |
|
|
.DOB(rd_buf_out_data[((i*6)+2)+:2]),
|
334 |
|
|
.DOC(rd_buf_out_data[((i*6)+0)+:2]),
|
335 |
|
|
.DOD(),
|
336 |
|
|
.DIA(rd_buf_in_data[((i*6)+4)+:2]),
|
337 |
|
|
.DIB(rd_buf_in_data[((i*6)+2)+:2]),
|
338 |
|
|
.DIC(rd_buf_in_data[((i*6)+0)+:2]),
|
339 |
|
|
.DID(2'b0),
|
340 |
|
|
.ADDRA(rd_buf_indx_copy_r[4:0]),
|
341 |
|
|
.ADDRB(rd_buf_indx_copy_r[4:0]),
|
342 |
|
|
.ADDRC(rd_buf_indx_copy_r[4:0]),
|
343 |
|
|
.ADDRD(rd_buf_wr_addr),
|
344 |
|
|
.WE(rd_buf_we),
|
345 |
|
|
.WCLK(clk)
|
346 |
|
|
);
|
347 |
|
|
end // block: rd_buffer_ram
|
348 |
|
|
end
|
349 |
|
|
|
350 |
|
|
wire rd_data_rdy = (rd_status[0] == rd_buf_indx_r[5]);
|
351 |
|
|
wire bypass = rd_data_en && (rd_buf_wr_addr[4:0] == rd_buf_indx_r[4:0]) /* synthesis syn_maxfan = 10 */;
|
352 |
|
|
assign app_rd_data_valid_ns =
|
353 |
|
|
ram_init_done_r_lcl && (bypass || rd_data_rdy);
|
354 |
|
|
wire app_rd_data_end_ns = bypass ? rd_data_end : rd_status[1];
|
355 |
|
|
always @(posedge clk) app_rd_data_valid <= #TCQ app_rd_data_valid_ns;
|
356 |
|
|
always @(posedge clk) app_rd_data_end <= #TCQ app_rd_data_end_ns;
|
357 |
|
|
|
358 |
|
|
assign single_data =
|
359 |
|
|
app_rd_data_valid_ns && app_rd_data_end_ns && ~rd_buf_indx_r[0];
|
360 |
|
|
|
361 |
|
|
wire [APP_DATA_WIDTH-1:0] app_rd_data_ns =
|
362 |
|
|
bypass
|
363 |
|
|
? rd_data
|
364 |
|
|
: rd_buf_out_data[APP_DATA_WIDTH-1:0];
|
365 |
|
|
always @(posedge clk) app_rd_data <= #TCQ app_rd_data_ns;
|
366 |
|
|
if (ECC != "OFF") begin : assign_app_ecc_multiple
|
367 |
|
|
wire [3:0] app_ecc_multiple_err_ns =
|
368 |
|
|
bypass
|
369 |
|
|
? ecc_multiple
|
370 |
|
|
: rd_buf_out_data[APP_DATA_WIDTH+:4];
|
371 |
|
|
always @(posedge clk) app_ecc_multiple_err_r <=
|
372 |
|
|
#TCQ app_ecc_multiple_err_ns;
|
373 |
|
|
end
|
374 |
|
|
|
375 |
|
|
//Added to fix timing. The signal app_rd_data_valid has
|
376 |
|
|
//a very high fanout. So making a dedicated copy for usage
|
377 |
|
|
//with the occ_cnt counter.
|
378 |
|
|
(* equivalent_register_removal = "no" *)
|
379 |
|
|
reg app_rd_data_valid_copy;
|
380 |
|
|
always @(posedge clk) app_rd_data_valid_copy <= #TCQ app_rd_data_valid_ns;
|
381 |
|
|
// Keep track of how many entries in the queue hold data.
|
382 |
|
|
wire free_rd_buf = app_rd_data_valid_copy && app_rd_data_end; //changed to use registered version
|
383 |
|
|
//of the signals in ordered to fix timing
|
384 |
|
|
reg [DATA_BUF_ADDR_WIDTH:0] occ_cnt_r;
|
385 |
|
|
wire [DATA_BUF_ADDR_WIDTH:0] occ_minus_one = occ_cnt_r - 1;
|
386 |
|
|
wire [DATA_BUF_ADDR_WIDTH:0] occ_plus_one = occ_cnt_r + 1;
|
387 |
|
|
begin : occupied_counter
|
388 |
|
|
reg [DATA_BUF_ADDR_WIDTH:0] occ_cnt_ns;
|
389 |
|
|
always @(/*AS*/free_rd_buf or occ_cnt_r or rd_accepted or rst or occ_minus_one or occ_plus_one) begin
|
390 |
|
|
occ_cnt_ns = occ_cnt_r;
|
391 |
|
|
if (rst) occ_cnt_ns = 0;
|
392 |
|
|
else case ({rd_accepted, free_rd_buf})
|
393 |
|
|
2'b01 : occ_cnt_ns = occ_minus_one;
|
394 |
|
|
2'b10 : occ_cnt_ns = occ_plus_one;
|
395 |
|
|
endcase // case ({wr_data_end, new_rd_data})
|
396 |
|
|
end
|
397 |
|
|
always @(posedge clk) occ_cnt_r <= #TCQ occ_cnt_ns;
|
398 |
|
|
assign rd_buf_full = occ_cnt_ns[DATA_BUF_ADDR_WIDTH];
|
399 |
|
|
|
400 |
|
|
`ifdef MC_SVA
|
401 |
|
|
rd_data_buffer_full: cover property (@(posedge clk) (~rst && rd_buf_full));
|
402 |
|
|
rd_data_buffer_inc_dec_15: cover property (@(posedge clk)
|
403 |
|
|
(~rst && rd_accepted && free_rd_buf && (occ_cnt_r == 'hf)));
|
404 |
|
|
rd_data_underflow: assert property (@(posedge clk)
|
405 |
|
|
(rst || !((occ_cnt_r == 'b0) && (occ_cnt_ns == 'h1f))));
|
406 |
|
|
rd_data_overflow: assert property (@(posedge clk)
|
407 |
|
|
(rst || !((occ_cnt_r == 'h10) && (occ_cnt_ns == 'h11))));
|
408 |
|
|
`endif
|
409 |
|
|
end // block: occupied_counter
|
410 |
|
|
|
411 |
|
|
|
412 |
|
|
// Generate the data_buf_address written into the memory controller
|
413 |
|
|
// for reads. Increment with each accepted read, and rollover at 0xf.
|
414 |
|
|
reg [DATA_BUF_ADDR_WIDTH-1:0] rd_data_buf_addr_r_lcl;
|
415 |
|
|
assign rd_data_buf_addr_r = rd_data_buf_addr_r_lcl;
|
416 |
|
|
begin : data_buf_addr
|
417 |
|
|
reg [DATA_BUF_ADDR_WIDTH-1:0] rd_data_buf_addr_ns;
|
418 |
|
|
always @(/*AS*/rd_accepted or rd_data_buf_addr_r_lcl or rst) begin
|
419 |
|
|
rd_data_buf_addr_ns = rd_data_buf_addr_r_lcl;
|
420 |
|
|
if (rst) rd_data_buf_addr_ns = 0;
|
421 |
|
|
else if (rd_accepted) rd_data_buf_addr_ns =
|
422 |
|
|
rd_data_buf_addr_r_lcl + 1;
|
423 |
|
|
end
|
424 |
|
|
always @(posedge clk) rd_data_buf_addr_r_lcl <=
|
425 |
|
|
#TCQ rd_data_buf_addr_ns;
|
426 |
|
|
end // block: data_buf_addr
|
427 |
|
|
end // block: not_strict_mode
|
428 |
|
|
endgenerate
|
429 |
|
|
|
430 |
|
|
endmodule // ui_rd_data
|
431 |
|
|
|
432 |
|
|
// Local Variables:
|
433 |
|
|
// verilog-library-directories:(".")
|
434 |
|
|
// End:
|