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_wr_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 write data buffer. Consists of four counters,
|
67 |
|
|
// a pointer RAM and the write data storage RAM.
|
68 |
|
|
//
|
69 |
|
|
// All RAMs are implemented with distributed RAM.
|
70 |
|
|
//
|
71 |
|
|
// Whe ordering is set to STRICT or NORM, data moves through
|
72 |
|
|
// the write data buffer in strictly FIFO order. In RELAXED
|
73 |
|
|
// mode, data may be retired from the write data RAM in any
|
74 |
|
|
// order relative to the input order. This implementation
|
75 |
|
|
// supports all ordering modes.
|
76 |
|
|
//
|
77 |
|
|
// The pointer RAM stores a list of pointers to the write data storage RAM.
|
78 |
|
|
// This is a list of vacant entries. As data is written into the RAM, a
|
79 |
|
|
// pointer is pulled from the pointer RAM and used to index the write
|
80 |
|
|
// operation. In a semi autonomously manner, pointers are also pulled, in
|
81 |
|
|
// the same order, and provided to the command port as the data_buf_addr.
|
82 |
|
|
//
|
83 |
|
|
// When the MC reads data from the write data buffer, it uses the
|
84 |
|
|
// data_buf_addr provided with the command to extract the data from the
|
85 |
|
|
// write data buffer. It also writes this pointer into the end
|
86 |
|
|
// of the pointer RAM.
|
87 |
|
|
//
|
88 |
|
|
// The occupancy counter keeps track of how many entries are valid
|
89 |
|
|
// in the write data storage RAM. app_wdf_rdy and app_rdy will be
|
90 |
|
|
// de-asserted when there is no more storage in the write data buffer.
|
91 |
|
|
//
|
92 |
|
|
// Three sequentially incrementing counters/indexes are used to maintain
|
93 |
|
|
// and use the contents of the pointer RAM.
|
94 |
|
|
//
|
95 |
|
|
// The write buffer write data address index generates the pointer
|
96 |
|
|
// used to extract the write data address from the pointer RAM. It
|
97 |
|
|
// is incremented with each buffer write. The counter is actually one
|
98 |
|
|
// ahead of the current write address so that the actual data buffer
|
99 |
|
|
// write address can be registered to give a full state to propagate to
|
100 |
|
|
// the write data distributed RAMs.
|
101 |
|
|
//
|
102 |
|
|
// The data_buf_addr counter is used to extract the data_buf_addr for
|
103 |
|
|
// the command port. It is incremented as each command is written
|
104 |
|
|
// into the MC.
|
105 |
|
|
//
|
106 |
|
|
// The read data index points to the end of the list of free
|
107 |
|
|
// buffers. When the MC fetches data from the write data buffer, it
|
108 |
|
|
// provides the buffer address. The buffer address is used to fetch
|
109 |
|
|
// the data, but is also written into the pointer at the location indicated
|
110 |
|
|
// by the read data index.
|
111 |
|
|
//
|
112 |
|
|
// Enter and exiting a buffer full condition generates corner cases. Upon
|
113 |
|
|
// entering a full condition, incrementing the write buffer write data
|
114 |
|
|
// address index must be inhibited. When exiting the full condition,
|
115 |
|
|
// the just arrived pointer must propagate through the pointer RAM, then
|
116 |
|
|
// indexed by the current value of the write buffer write data
|
117 |
|
|
// address counter, the value is registered in the write buffer write
|
118 |
|
|
// data address register, then the counter can be advanced.
|
119 |
|
|
//
|
120 |
|
|
// The pointer RAM must be initialized with valid data after reset. This is
|
121 |
|
|
// accomplished by stepping through each pointer RAM entry and writing
|
122 |
|
|
// the locations address into the pointer RAM. For the FIFO modes, this means
|
123 |
|
|
// that buffer address will always proceed in a sequential order. In the
|
124 |
|
|
// RELAXED mode, the original write traversal will be in sequential
|
125 |
|
|
// order, but once the MC begins to retire out of order, the entries in
|
126 |
|
|
// the pointer RAM will become randomized. The ui_rd_data module provides
|
127 |
|
|
// the control information for the initialization process.
|
128 |
|
|
|
129 |
|
|
`timescale 1 ps / 1 ps
|
130 |
|
|
|
131 |
|
|
module mig_7series_v2_3_ui_wr_data #
|
132 |
|
|
(
|
133 |
|
|
parameter TCQ = 100,
|
134 |
|
|
parameter APP_DATA_WIDTH = 256,
|
135 |
|
|
parameter APP_MASK_WIDTH = 32,
|
136 |
|
|
parameter ECC = "OFF",
|
137 |
|
|
parameter nCK_PER_CLK = 2 ,
|
138 |
|
|
parameter ECC_TEST = "OFF",
|
139 |
|
|
parameter CWL = 5
|
140 |
|
|
)
|
141 |
|
|
(/*AUTOARG*/
|
142 |
|
|
// Outputs
|
143 |
|
|
app_wdf_rdy, wr_req_16, wr_data_buf_addr, wr_data, wr_data_mask,
|
144 |
|
|
raw_not_ecc,
|
145 |
|
|
// Inputs
|
146 |
|
|
rst, clk, app_wdf_data, app_wdf_mask, app_raw_not_ecc, app_wdf_wren,
|
147 |
|
|
app_wdf_end, wr_data_offset, wr_data_addr, wr_data_en, wr_accepted,
|
148 |
|
|
ram_init_done_r, ram_init_addr
|
149 |
|
|
);
|
150 |
|
|
|
151 |
|
|
input rst;
|
152 |
|
|
input clk;
|
153 |
|
|
|
154 |
|
|
input [APP_DATA_WIDTH-1:0] app_wdf_data;
|
155 |
|
|
input [APP_MASK_WIDTH-1:0] app_wdf_mask;
|
156 |
|
|
input [2*nCK_PER_CLK-1:0] app_raw_not_ecc;
|
157 |
|
|
input app_wdf_wren;
|
158 |
|
|
input app_wdf_end;
|
159 |
|
|
|
160 |
|
|
reg [APP_DATA_WIDTH-1:0] app_wdf_data_r1;
|
161 |
|
|
reg [APP_MASK_WIDTH-1:0] app_wdf_mask_r1;
|
162 |
|
|
reg [2*nCK_PER_CLK-1:0] app_raw_not_ecc_r1 = 4'b0;
|
163 |
|
|
reg app_wdf_wren_r1;
|
164 |
|
|
reg app_wdf_end_r1;
|
165 |
|
|
|
166 |
|
|
reg app_wdf_rdy_r;
|
167 |
|
|
|
168 |
|
|
//Adding few copies of the app_wdf_rdy_r signal in order to meet
|
169 |
|
|
//timing. This is signal has a very high fanout. So grouped into
|
170 |
|
|
//few functional groups and alloted one copy per group.
|
171 |
|
|
(* equivalent_register_removal = "no" *)
|
172 |
|
|
reg app_wdf_rdy_r_copy1;
|
173 |
|
|
(* equivalent_register_removal = "no" *)
|
174 |
|
|
reg app_wdf_rdy_r_copy2;
|
175 |
|
|
(* equivalent_register_removal = "no" *)
|
176 |
|
|
reg app_wdf_rdy_r_copy3;
|
177 |
|
|
(* equivalent_register_removal = "no" *)
|
178 |
|
|
reg app_wdf_rdy_r_copy4;
|
179 |
|
|
|
180 |
|
|
wire [APP_DATA_WIDTH-1:0] app_wdf_data_ns1 =
|
181 |
|
|
~app_wdf_rdy_r_copy2 ? app_wdf_data_r1 : app_wdf_data;
|
182 |
|
|
wire [APP_MASK_WIDTH-1:0] app_wdf_mask_ns1 =
|
183 |
|
|
~app_wdf_rdy_r_copy2 ? app_wdf_mask_r1 : app_wdf_mask;
|
184 |
|
|
wire app_wdf_wren_ns1 =
|
185 |
|
|
~rst && (~app_wdf_rdy_r_copy2 ? app_wdf_wren_r1 : app_wdf_wren);
|
186 |
|
|
wire app_wdf_end_ns1 =
|
187 |
|
|
~rst && (~app_wdf_rdy_r_copy2 ? app_wdf_end_r1 : app_wdf_end);
|
188 |
|
|
|
189 |
|
|
generate
|
190 |
|
|
if (ECC_TEST != "OFF") begin : ecc_on
|
191 |
|
|
always @(app_raw_not_ecc) app_raw_not_ecc_r1 = app_raw_not_ecc;
|
192 |
|
|
end
|
193 |
|
|
endgenerate
|
194 |
|
|
|
195 |
|
|
// Be explicit about the latch enable on these registers.
|
196 |
|
|
always @(posedge clk) begin
|
197 |
|
|
app_wdf_data_r1 <= #TCQ app_wdf_data_ns1;
|
198 |
|
|
app_wdf_mask_r1 <= #TCQ app_wdf_mask_ns1;
|
199 |
|
|
app_wdf_wren_r1 <= #TCQ app_wdf_wren_ns1;
|
200 |
|
|
app_wdf_end_r1 <= #TCQ app_wdf_end_ns1;
|
201 |
|
|
end
|
202 |
|
|
|
203 |
|
|
// The signals wr_data_addr and wr_data_offset come at different
|
204 |
|
|
// times depending on ECC and the value of CWL. The data portion
|
205 |
|
|
// always needs to look a the raw wires, the control portion needs
|
206 |
|
|
// to look at a delayed version when ECC is on and CWL != 8. The
|
207 |
|
|
// currently supported write data delays do not require this
|
208 |
|
|
// functionality, but preserve for future use.
|
209 |
|
|
input wr_data_offset;
|
210 |
|
|
input [3:0] wr_data_addr;
|
211 |
|
|
reg wr_data_offset_r;
|
212 |
|
|
reg [3:0] wr_data_addr_r;
|
213 |
|
|
generate
|
214 |
|
|
if (ECC == "OFF" || CWL >= 0) begin : pass_wr_addr
|
215 |
|
|
always @(wr_data_offset) wr_data_offset_r = wr_data_offset;
|
216 |
|
|
always @(wr_data_addr) wr_data_addr_r = wr_data_addr;
|
217 |
|
|
end
|
218 |
|
|
else begin : delay_wr_addr
|
219 |
|
|
always @(posedge clk) wr_data_offset_r <= #TCQ wr_data_offset;
|
220 |
|
|
always @(posedge clk) wr_data_addr_r <= #TCQ wr_data_addr;
|
221 |
|
|
end
|
222 |
|
|
endgenerate
|
223 |
|
|
|
224 |
|
|
// rd_data_cnt is the pointer RAM index for data read from the write data
|
225 |
|
|
// buffer. Ie, its the data on its way out to the DRAM.
|
226 |
|
|
input wr_data_en;
|
227 |
|
|
wire new_rd_data = wr_data_en && ~wr_data_offset_r;
|
228 |
|
|
reg [3:0] rd_data_indx_r;
|
229 |
|
|
reg rd_data_upd_indx_r;
|
230 |
|
|
generate begin : read_data_indx
|
231 |
|
|
reg [3:0] rd_data_indx_ns;
|
232 |
|
|
always @(/*AS*/new_rd_data or rd_data_indx_r or rst) begin
|
233 |
|
|
rd_data_indx_ns = rd_data_indx_r;
|
234 |
|
|
if (rst) rd_data_indx_ns = 5'b0;
|
235 |
|
|
else if (new_rd_data) rd_data_indx_ns = rd_data_indx_r + 5'h1;
|
236 |
|
|
end
|
237 |
|
|
always @(posedge clk) rd_data_indx_r <= #TCQ rd_data_indx_ns;
|
238 |
|
|
always @(posedge clk) rd_data_upd_indx_r <= #TCQ new_rd_data;
|
239 |
|
|
end
|
240 |
|
|
endgenerate
|
241 |
|
|
|
242 |
|
|
// data_buf_addr_cnt generates the pointer for the pointer RAM on behalf
|
243 |
|
|
// of data buf address that comes with the wr_data_en.
|
244 |
|
|
// The data buf address is written into the memory
|
245 |
|
|
// controller along with the command and address.
|
246 |
|
|
input wr_accepted;
|
247 |
|
|
reg [3:0] data_buf_addr_cnt_r;
|
248 |
|
|
generate begin : data_buf_address_counter
|
249 |
|
|
|
250 |
|
|
reg [3:0] data_buf_addr_cnt_ns;
|
251 |
|
|
always @(/*AS*/data_buf_addr_cnt_r or rst or wr_accepted) begin
|
252 |
|
|
data_buf_addr_cnt_ns = data_buf_addr_cnt_r;
|
253 |
|
|
if (rst) data_buf_addr_cnt_ns = 4'b0;
|
254 |
|
|
else if (wr_accepted) data_buf_addr_cnt_ns =
|
255 |
|
|
data_buf_addr_cnt_r + 4'h1;
|
256 |
|
|
end
|
257 |
|
|
always @(posedge clk) data_buf_addr_cnt_r <= #TCQ data_buf_addr_cnt_ns;
|
258 |
|
|
|
259 |
|
|
end
|
260 |
|
|
endgenerate
|
261 |
|
|
|
262 |
|
|
// Control writing data into the write data buffer.
|
263 |
|
|
wire wdf_rdy_ns;
|
264 |
|
|
always @( posedge clk ) begin
|
265 |
|
|
app_wdf_rdy_r_copy1 <= #TCQ wdf_rdy_ns;
|
266 |
|
|
app_wdf_rdy_r_copy2 <= #TCQ wdf_rdy_ns;
|
267 |
|
|
app_wdf_rdy_r_copy3 <= #TCQ wdf_rdy_ns;
|
268 |
|
|
app_wdf_rdy_r_copy4 <= #TCQ wdf_rdy_ns;
|
269 |
|
|
end
|
270 |
|
|
wire wr_data_end = app_wdf_end_r1 && app_wdf_rdy_r_copy1 && app_wdf_wren_r1;
|
271 |
|
|
wire [3:0] wr_data_pntr;
|
272 |
|
|
wire [4:0] wb_wr_data_addr;
|
273 |
|
|
wire [4:0] wb_wr_data_addr_w;
|
274 |
|
|
reg [3:0] wr_data_indx_r;
|
275 |
|
|
generate begin : write_data_control
|
276 |
|
|
|
277 |
|
|
wire wr_data_addr_le = (wr_data_end && wdf_rdy_ns) ||
|
278 |
|
|
(rd_data_upd_indx_r && ~app_wdf_rdy_r_copy1);
|
279 |
|
|
|
280 |
|
|
// For pointer RAM. Initialize to one since this is one ahead of
|
281 |
|
|
// what's being registered in wb_wr_data_addr. Assumes pointer RAM
|
282 |
|
|
// has been initialized such that address equals contents.
|
283 |
|
|
reg [3:0] wr_data_indx_ns;
|
284 |
|
|
always @(/*AS*/rst or wr_data_addr_le or wr_data_indx_r) begin
|
285 |
|
|
wr_data_indx_ns = wr_data_indx_r;
|
286 |
|
|
if (rst) wr_data_indx_ns = 4'b1;
|
287 |
|
|
else if (wr_data_addr_le) wr_data_indx_ns = wr_data_indx_r + 4'h1;
|
288 |
|
|
end
|
289 |
|
|
always @(posedge clk) wr_data_indx_r <= #TCQ wr_data_indx_ns;
|
290 |
|
|
|
291 |
|
|
// Take pointer from pointer RAM and set into the write data address.
|
292 |
|
|
// Needs to be split into zeroth bit and everything else because synthesis
|
293 |
|
|
// tools don't always allow assigning bit vectors seperately. Bit zero of the
|
294 |
|
|
// address is computed via an entirely different algorithm.
|
295 |
|
|
reg [4:1] wb_wr_data_addr_ns;
|
296 |
|
|
reg [4:1] wb_wr_data_addr_r;
|
297 |
|
|
always @(/*AS*/rst or wb_wr_data_addr_r or wr_data_addr_le
|
298 |
|
|
or wr_data_pntr) begin
|
299 |
|
|
wb_wr_data_addr_ns = wb_wr_data_addr_r;
|
300 |
|
|
if (rst) wb_wr_data_addr_ns = 4'b0;
|
301 |
|
|
else if (wr_data_addr_le) wb_wr_data_addr_ns = wr_data_pntr;
|
302 |
|
|
end
|
303 |
|
|
always @(posedge clk) wb_wr_data_addr_r <= #TCQ wb_wr_data_addr_ns;
|
304 |
|
|
|
305 |
|
|
// If we see the first getting accepted, then
|
306 |
|
|
// second half is unconditionally accepted.
|
307 |
|
|
reg wb_wr_data_addr0_r;
|
308 |
|
|
wire wb_wr_data_addr0_ns = ~rst &&
|
309 |
|
|
((app_wdf_rdy_r_copy3 && app_wdf_wren_r1 && ~app_wdf_end_r1) ||
|
310 |
|
|
(wb_wr_data_addr0_r && ~app_wdf_wren_r1));
|
311 |
|
|
always @(posedge clk) wb_wr_data_addr0_r <= #TCQ wb_wr_data_addr0_ns;
|
312 |
|
|
|
313 |
|
|
assign wb_wr_data_addr = {wb_wr_data_addr_r, wb_wr_data_addr0_r};
|
314 |
|
|
assign wb_wr_data_addr_w = {wb_wr_data_addr_ns, wb_wr_data_addr0_ns};
|
315 |
|
|
|
316 |
|
|
end
|
317 |
|
|
endgenerate
|
318 |
|
|
|
319 |
|
|
// Keep track of how many entries in the queue hold data.
|
320 |
|
|
input ram_init_done_r;
|
321 |
|
|
output wire app_wdf_rdy;
|
322 |
|
|
generate begin : occupied_counter
|
323 |
|
|
//reg [4:0] occ_cnt_ns;
|
324 |
|
|
//reg [4:0] occ_cnt_r;
|
325 |
|
|
//always @(/*AS*/occ_cnt_r or rd_data_upd_indx_r or rst
|
326 |
|
|
// or wr_data_end) begin
|
327 |
|
|
// occ_cnt_ns = occ_cnt_r;
|
328 |
|
|
// if (rst) occ_cnt_ns = 5'b0;
|
329 |
|
|
// else case ({wr_data_end, rd_data_upd_indx_r})
|
330 |
|
|
// 2'b01 : occ_cnt_ns = occ_cnt_r - 5'b1;
|
331 |
|
|
// 2'b10 : occ_cnt_ns = occ_cnt_r + 5'b1;
|
332 |
|
|
// endcase // case ({wr_data_end, rd_data_upd_indx_r})
|
333 |
|
|
//end
|
334 |
|
|
//always @(posedge clk) occ_cnt_r <= #TCQ occ_cnt_ns;
|
335 |
|
|
//assign wdf_rdy_ns = !(rst || ~ram_init_done_r || occ_cnt_ns[4]);
|
336 |
|
|
//always @(posedge clk) app_wdf_rdy_r <= #TCQ wdf_rdy_ns;
|
337 |
|
|
//assign app_wdf_rdy = app_wdf_rdy_r;
|
338 |
|
|
reg [15:0] occ_cnt;
|
339 |
|
|
always @(posedge clk) begin
|
340 |
|
|
if ( rst )
|
341 |
|
|
occ_cnt <= #TCQ 16'h0000;
|
342 |
|
|
else case ({wr_data_end, rd_data_upd_indx_r})
|
343 |
|
|
2'b01 : occ_cnt <= #TCQ {1'b0,occ_cnt[15:1]};
|
344 |
|
|
2'b10 : occ_cnt <= #TCQ {occ_cnt[14:0],1'b1};
|
345 |
|
|
endcase // case ({wr_data_end, rd_data_upd_indx_r})
|
346 |
|
|
end
|
347 |
|
|
assign wdf_rdy_ns = !(rst || ~ram_init_done_r || (occ_cnt[14] && wr_data_end && ~rd_data_upd_indx_r) || (occ_cnt[15] && ~rd_data_upd_indx_r));
|
348 |
|
|
always @(posedge clk) app_wdf_rdy_r <= #TCQ wdf_rdy_ns;
|
349 |
|
|
assign app_wdf_rdy = app_wdf_rdy_r;
|
350 |
|
|
|
351 |
|
|
`ifdef MC_SVA
|
352 |
|
|
wr_data_buffer_full: cover property (@(posedge clk)
|
353 |
|
|
(~rst && ~app_wdf_rdy_r));
|
354 |
|
|
// wr_data_buffer_inc_dec_15: cover property (@(posedge clk)
|
355 |
|
|
// (~rst && wr_data_end && rd_data_upd_indx_r && (occ_cnt_r == 5'hf)));
|
356 |
|
|
// wr_data_underflow: assert property (@(posedge clk)
|
357 |
|
|
// (rst || !((occ_cnt_r == 5'b0) && (occ_cnt_ns == 5'h1f))));
|
358 |
|
|
// wr_data_overflow: assert property (@(posedge clk)
|
359 |
|
|
// (rst || !((occ_cnt_r == 5'h10) && (occ_cnt_ns == 5'h11))));
|
360 |
|
|
`endif
|
361 |
|
|
end // block: occupied_counter
|
362 |
|
|
endgenerate
|
363 |
|
|
|
364 |
|
|
// Keep track of how many write requests are in the memory controller. We
|
365 |
|
|
// must limit this to 16 because we only have that many data_buf_addrs to
|
366 |
|
|
// hand out. Since the memory controller queue and the write data buffer
|
367 |
|
|
// queue are distinct, the number of valid entries can be different.
|
368 |
|
|
// Throttle request acceptance once there are sixteen write requests in
|
369 |
|
|
// the memory controller. Note that there is still a requirement
|
370 |
|
|
// for a write reqeusts corresponding write data to be written into the
|
371 |
|
|
// write data queue with two states of the request.
|
372 |
|
|
output wire wr_req_16;
|
373 |
|
|
generate begin : wr_req_counter
|
374 |
|
|
reg [4:0] wr_req_cnt_ns;
|
375 |
|
|
reg [4:0] wr_req_cnt_r;
|
376 |
|
|
always @(/*AS*/rd_data_upd_indx_r or rst or wr_accepted
|
377 |
|
|
or wr_req_cnt_r) begin
|
378 |
|
|
wr_req_cnt_ns = wr_req_cnt_r;
|
379 |
|
|
if (rst) wr_req_cnt_ns = 5'b0;
|
380 |
|
|
else case ({wr_accepted, rd_data_upd_indx_r})
|
381 |
|
|
2'b01 : wr_req_cnt_ns = wr_req_cnt_r - 5'b1;
|
382 |
|
|
2'b10 : wr_req_cnt_ns = wr_req_cnt_r + 5'b1;
|
383 |
|
|
endcase // case ({wr_accepted, rd_data_upd_indx_r})
|
384 |
|
|
end
|
385 |
|
|
always @(posedge clk) wr_req_cnt_r <= #TCQ wr_req_cnt_ns;
|
386 |
|
|
assign wr_req_16 = (wr_req_cnt_ns == 5'h10);
|
387 |
|
|
|
388 |
|
|
`ifdef MC_SVA
|
389 |
|
|
wr_req_mc_full: cover property (@(posedge clk) (~rst && wr_req_16));
|
390 |
|
|
wr_req_mc_full_inc_dec_15: cover property (@(posedge clk)
|
391 |
|
|
(~rst && wr_accepted && rd_data_upd_indx_r && (wr_req_cnt_r == 5'hf)));
|
392 |
|
|
wr_req_underflow: assert property (@(posedge clk)
|
393 |
|
|
(rst || !((wr_req_cnt_r == 5'b0) && (wr_req_cnt_ns == 5'h1f))));
|
394 |
|
|
wr_req_overflow: assert property (@(posedge clk)
|
395 |
|
|
(rst || !((wr_req_cnt_r == 5'h10) && (wr_req_cnt_ns == 5'h11))));
|
396 |
|
|
`endif
|
397 |
|
|
end // block: wr_req_counter
|
398 |
|
|
endgenerate
|
399 |
|
|
|
400 |
|
|
|
401 |
|
|
|
402 |
|
|
// Instantiate pointer RAM. Made up of RAM32M in single write, two read
|
403 |
|
|
// port mode, 2 bit wide mode.
|
404 |
|
|
input [3:0] ram_init_addr;
|
405 |
|
|
output wire [3:0] wr_data_buf_addr;
|
406 |
|
|
localparam PNTR_RAM_CNT = 2;
|
407 |
|
|
generate begin : pointer_ram
|
408 |
|
|
wire pointer_we = new_rd_data || ~ram_init_done_r;
|
409 |
|
|
wire [3:0] pointer_wr_data = ram_init_done_r
|
410 |
|
|
? wr_data_addr_r
|
411 |
|
|
: ram_init_addr;
|
412 |
|
|
wire [3:0] pointer_wr_addr = ram_init_done_r
|
413 |
|
|
? rd_data_indx_r
|
414 |
|
|
: ram_init_addr;
|
415 |
|
|
genvar i;
|
416 |
|
|
for (i=0; i<PNTR_RAM_CNT; i=i+1) begin : rams
|
417 |
|
|
RAM32M
|
418 |
|
|
#(.INIT_A(64'h0000000000000000),
|
419 |
|
|
.INIT_B(64'h0000000000000000),
|
420 |
|
|
.INIT_C(64'h0000000000000000),
|
421 |
|
|
.INIT_D(64'h0000000000000000)
|
422 |
|
|
) RAM32M0 (
|
423 |
|
|
.DOA(),
|
424 |
|
|
.DOB(wr_data_buf_addr[i*2+:2]),
|
425 |
|
|
.DOC(wr_data_pntr[i*2+:2]),
|
426 |
|
|
.DOD(),
|
427 |
|
|
.DIA(2'b0),
|
428 |
|
|
.DIB(pointer_wr_data[i*2+:2]),
|
429 |
|
|
.DIC(pointer_wr_data[i*2+:2]),
|
430 |
|
|
.DID(2'b0),
|
431 |
|
|
.ADDRA(5'b0),
|
432 |
|
|
.ADDRB({1'b0, data_buf_addr_cnt_r}),
|
433 |
|
|
.ADDRC({1'b0, wr_data_indx_r}),
|
434 |
|
|
.ADDRD({1'b0, pointer_wr_addr}),
|
435 |
|
|
.WE(pointer_we),
|
436 |
|
|
.WCLK(clk)
|
437 |
|
|
);
|
438 |
|
|
end // block : rams
|
439 |
|
|
end // block: pointer_ram
|
440 |
|
|
endgenerate
|
441 |
|
|
|
442 |
|
|
|
443 |
|
|
// Instantiate write data buffer. Depending on width of DQ bus and
|
444 |
|
|
// DRAM CK to fabric ratio, number of RAM32Ms is variable. RAM32Ms are
|
445 |
|
|
// used in single write, single read, 6 bit wide mode.
|
446 |
|
|
localparam WR_BUF_WIDTH =
|
447 |
|
|
APP_DATA_WIDTH + APP_MASK_WIDTH + (ECC_TEST == "OFF" ? 0 : 2*nCK_PER_CLK);
|
448 |
|
|
localparam FULL_RAM_CNT = (WR_BUF_WIDTH/6);
|
449 |
|
|
localparam REMAINDER = WR_BUF_WIDTH % 6;
|
450 |
|
|
localparam RAM_CNT = FULL_RAM_CNT + ((REMAINDER == 0 ) ? 0 : 1);
|
451 |
|
|
localparam RAM_WIDTH = (RAM_CNT*6);
|
452 |
|
|
wire [RAM_WIDTH-1:0] wr_buf_out_data_w;
|
453 |
|
|
reg [RAM_WIDTH-1:0] wr_buf_out_data;
|
454 |
|
|
generate
|
455 |
|
|
begin : write_buffer
|
456 |
|
|
wire [RAM_WIDTH-1:0] wr_buf_in_data;
|
457 |
|
|
if (REMAINDER == 0)
|
458 |
|
|
if (ECC_TEST == "OFF")
|
459 |
|
|
assign wr_buf_in_data = {app_wdf_mask_ns1, app_wdf_data_ns1};
|
460 |
|
|
else
|
461 |
|
|
assign wr_buf_in_data =
|
462 |
|
|
{app_raw_not_ecc_r1, app_wdf_mask_ns1, app_wdf_data_ns1};
|
463 |
|
|
else
|
464 |
|
|
if (ECC_TEST == "OFF")
|
465 |
|
|
assign wr_buf_in_data =
|
466 |
|
|
{{6-REMAINDER{1'b0}}, app_wdf_mask_ns1, app_wdf_data_ns1};
|
467 |
|
|
else
|
468 |
|
|
assign wr_buf_in_data = {{6-REMAINDER{1'b0}}, app_raw_not_ecc_r1,//app_raw_not_ecc_r1 is not ff
|
469 |
|
|
app_wdf_mask_ns1, app_wdf_data_ns1};
|
470 |
|
|
|
471 |
|
|
wire [4:0] rd_addr_w;
|
472 |
|
|
|
473 |
|
|
assign rd_addr_w = {wr_data_addr, wr_data_offset};
|
474 |
|
|
always @(posedge clk) wr_buf_out_data <= #TCQ wr_buf_out_data_w;
|
475 |
|
|
genvar i;
|
476 |
|
|
for (i=0; i<RAM_CNT; i=i+1) begin : wr_buffer_ram
|
477 |
|
|
RAM32M
|
478 |
|
|
#(.INIT_A(64'h0000000000000000),
|
479 |
|
|
.INIT_B(64'h0000000000000000),
|
480 |
|
|
.INIT_C(64'h0000000000000000),
|
481 |
|
|
.INIT_D(64'h0000000000000000)
|
482 |
|
|
) RAM32M0 (
|
483 |
|
|
.DOA(wr_buf_out_data_w[((i*6)+4)+:2]),
|
484 |
|
|
.DOB(wr_buf_out_data_w[((i*6)+2)+:2]),
|
485 |
|
|
.DOC(wr_buf_out_data_w[((i*6)+0)+:2]),
|
486 |
|
|
.DOD(),
|
487 |
|
|
.DIA(wr_buf_in_data[((i*6)+4)+:2]),
|
488 |
|
|
.DIB(wr_buf_in_data[((i*6)+2)+:2]),
|
489 |
|
|
.DIC(wr_buf_in_data[((i*6)+0)+:2]),
|
490 |
|
|
.DID(2'b0),
|
491 |
|
|
.ADDRA(rd_addr_w),
|
492 |
|
|
.ADDRB(rd_addr_w),
|
493 |
|
|
.ADDRC(rd_addr_w),
|
494 |
|
|
.ADDRD(wb_wr_data_addr_w),
|
495 |
|
|
.WE(wdf_rdy_ns),
|
496 |
|
|
.WCLK(clk)
|
497 |
|
|
);
|
498 |
|
|
end // block: wr_buffer_ram
|
499 |
|
|
end
|
500 |
|
|
endgenerate
|
501 |
|
|
|
502 |
|
|
output [APP_DATA_WIDTH-1:0] wr_data;
|
503 |
|
|
output [APP_MASK_WIDTH-1:0] wr_data_mask;
|
504 |
|
|
assign {wr_data_mask, wr_data} = wr_buf_out_data[WR_BUF_WIDTH-1:0];
|
505 |
|
|
output [2*nCK_PER_CLK-1:0] raw_not_ecc;
|
506 |
|
|
generate
|
507 |
|
|
if (ECC_TEST == "OFF") assign raw_not_ecc = {2*nCK_PER_CLK{1'b0}};
|
508 |
|
|
else assign raw_not_ecc = wr_buf_out_data[WR_BUF_WIDTH-1-:(2*nCK_PER_CLK)];
|
509 |
|
|
endgenerate
|
510 |
|
|
|
511 |
|
|
endmodule // ui_wr_data
|
512 |
|
|
|
513 |
|
|
// Local Variables:
|
514 |
|
|
// verilog-library-directories:(".")
|
515 |
|
|
// End:
|