1 //*****************************************************************************
2 // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
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
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.
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.
45 // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
46 // PART OF THIS FILE AT ALL TIMES.
48 //*****************************************************************************
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
60 //Design Name : DDR3 SDRAM
64 //*****************************************************************************
66 // User interface write data buffer. Consists of four counters,
67 // a pointer RAM and the write data storage RAM.
69 // All RAMs are implemented with distributed RAM.
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.
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.
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.
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.
92 // Three sequentially incrementing counters/indexes are used to maintain
93 // and use the contents of the pointer RAM.
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.
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
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.
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.
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.
129 `timescale 1 ps /
1 ps
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",
143 app_wdf_rdy,
wr_req_16,
wr_data_buf_addr,
wr_data,
wr_data_mask,
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
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;
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;
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;
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);
190 if (
ECC_TEST !=
"OFF")
begin :
ecc_on
191 always @(
app_raw_not_ecc)
app_raw_not_ecc_r1 =
app_raw_not_ecc;
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;
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;
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;
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;
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.
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;
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;
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.
247 reg [
3:
0]
data_buf_addr_cnt_r;
248 generate begin :
data_buf_address_counter
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;
257 always @(
posedge clk)
data_buf_addr_cnt_r <= #TCQ
data_buf_addr_cnt_ns;
262 // Control writing data into the write data buffer.
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;
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
277 wire wr_data_addr_le = (
wr_data_end &&
wdf_rdy_ns) ||
278 (
rd_data_upd_indx_r && ~
app_wdf_rdy_r_copy1);
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;
289 always @(
posedge clk)
wr_data_indx_r <= #TCQ
wr_data_indx_ns;
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;
303 always @(
posedge clk)
wb_wr_data_addr_r <= #TCQ
wb_wr_data_addr_ns;
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;
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};
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})
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;
339 always @(
posedge clk)
begin
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})
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;
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))));
361 end // block: occupied_counter
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})
385 always @(
posedge clk)
wr_req_cnt_r <= #TCQ
wr_req_cnt_ns;
386 assign wr_req_16 = (
wr_req_cnt_ns ==
5'h10);
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))));
397 end // block: wr_req_counter
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
412 wire [
3:
0]
pointer_wr_addr =
ram_init_done_r
416 for (
i=
0;
i<
PNTR_RAM_CNT;
i=
i+
1)
begin :
rams
418 #(.
INIT_A(
64'h0000000000000000),
419 .
INIT_B(
64'h0000000000000000),
420 .
INIT_C(
64'h0000000000000000),
421 .
INIT_D(
64'h0000000000000000)
424 .
DOB(
wr_data_buf_addr[
i*
2+:
2]),
425 .
DOC(
wr_data_pntr[
i*
2+:
2]),
428 .
DIB(
pointer_wr_data[
i*
2+:
2]),
429 .
DIC(
pointer_wr_data[
i*
2+:
2]),
432 .
ADDRB({
1'b0,
data_buf_addr_cnt_r}),
433 .
ADDRC({
1'b0,
wr_data_indx_r}),
434 .
ADDRD({
1'b0,
pointer_wr_addr}),
439 end // block: pointer_ram
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;
456 wire [
RAM_WIDTH-
1:
0]
wr_buf_in_data;
458 if (
ECC_TEST ==
"OFF")
459 assign wr_buf_in_data = {
app_wdf_mask_ns1,
app_wdf_data_ns1};
461 assign wr_buf_in_data =
462 {
app_raw_not_ecc_r1,
app_wdf_mask_ns1,
app_wdf_data_ns1};
464 if (
ECC_TEST ==
"OFF")
465 assign wr_buf_in_data =
466 {{
6-
REMAINDER{
1'b0}},
app_wdf_mask_ns1,
app_wdf_data_ns1};
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};
471 wire [
4:
0]
rd_addr_w;
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;
476 for (
i=
0;
i<
RAM_CNT;
i=
i+
1)
begin :
wr_buffer_ram
478 #(.
INIT_A(
64'h0000000000000000),
479 .
INIT_B(
64'h0000000000000000),
480 .
INIT_C(
64'h0000000000000000),
481 .
INIT_D(
64'h0000000000000000)
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]),
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]),
494 .
ADDRD(
wb_wr_data_addr_w),
498 end // block: wr_buffer_ram
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;
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-:
4];
511 endmodule // ui_wr_data
514 // verilog-library-directories:(".")