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 : rank_cntrl.v
55 // /___/ /\ Date Last Modified : $date$
56 // \ \ / \ Date Created : Tue Jun 30 2009
60 //Design Name : DDR3 SDRAM
64 //*****************************************************************************
66 //*****************************************************************************
67 // This block is responsible for managing various rank level timing
68 // parameters. For now, only Four Activate Window (FAW) and Write
69 // To Read delay are implemented here.
71 // Each rank machine generates its own inhbt_act_faw_r and inhbt_rd.
72 // These per rank machines are driven into the bank machines. Each
73 // bank machines selects the correct inhibits based on the rank
74 // of its current request.
75 //*****************************************************************************
77 `timescale 1 ps /
1 ps
81 parameter TCQ =
100,
// clk->out delay (sim only)
82 parameter BURST_MODE =
"8",
// Burst length
83 parameter DQRD2DQWR_DLY =
2,
// RD->WR DQ Bus Delay
84 parameter CL =
5,
// Read CAS latency
85 parameter CWL =
5,
// Write CAS latency
86 parameter ID =
0,
// Unique ID for each instance
87 parameter nBANK_MACHS =
4,
// # bank machines in MC
88 parameter nCK_PER_CLK =
2,
// DRAM clock : MC clock
89 parameter nFAW =
30,
// four activate window (CKs)
90 parameter nREFRESH_BANK =
8,
// # REF commands to pull-in
91 parameter nRRD =
4,
// ACT->ACT period (CKs)
92 parameter nWTR =
4,
// Internal write->read
94 parameter PERIODIC_RD_TIMER_DIV =
20,
// Maintenance prescaler divisor
95 // for periodic read timer
96 parameter RANK_BM_BV_WIDTH =
16,
// Width required to broadcast a
97 // single bit rank signal among
98 // all the bank machines
99 parameter RANK_WIDTH =
2,
// # of bits to count ranks
100 parameter RANKS =
4,
// # of ranks of DRAM
101 parameter REFRESH_TIMER_DIV =
39 // Maintenance prescaler divivor
106 // Maintenance requests
108 output periodic_rd_request,
109 output wire refresh_request,
113 output reg inhbt_act_faw_r,
122 // User maintenance requests
124 input app_periodic_rd_req,
129 input [
RANK_BM_BV_WIDTH-
1:
0]
act_this_rank_r,
130 input clear_periodic_rd_request,
132 input init_calib_complete,
133 input insert_maint_r1,
134 input maint_prescaler_tick_r,
135 input [
RANK_WIDTH-
1:
0]
maint_rank_r,
139 input [(
RANKS*
nBANK_MACHS)-
1:
0]
rank_busy_r,
141 input [
nBANK_MACHS-
1:
0]
sending_col,
142 input [
nBANK_MACHS-
1:
0]
sending_row,
143 input [
RANK_BM_BV_WIDTH-
1:
0]
rd_this_rank_r,
144 input [
RANK_BM_BV_WIDTH-
1:
0]
wr_this_rank_r
148 //***************************************************************************
149 // RRD configuration. The bank machines have a mechanism to prevent RAS to
150 // RAS on adjacent fabric CLK states to the same rank. When
151 // nCK_PER_CLK == 1, this translates to a minimum of 2 for nRRD, 4 for nRRD
152 // when nCK_PER_CLK == 2 and 8 for nRRD when nCK_PER_CLK == 4. Some of the
153 // higher clock rate DDR3 DRAMs have nRRD > 4. The additional RRD inhibit
154 // is worked into the inhbt_faw signal.
155 //***************************************************************************
157 localparam nADD_RRD =
nRRD -
159 (
nCK_PER_CLK ==
1) ?
2 :
160 (
nCK_PER_CLK ==
2) ?
4 :
161 /*(nCK_PER_CLK == 4)**/ 8
164 // divide by nCK_PER_CLK and add a cycle if there's a remainder
165 localparam nRRD_CLKS =
166 (
nCK_PER_CLK ==
1) ?
nADD_RRD :
167 (
nCK_PER_CLK ==
2) ? ((
nADD_RRD/
2)+(
nADD_RRD%
2)) :
168 /*(nCK_PER_CLK == 4)**/ ((
nADD_RRD/
4)+((
nADD_RRD%
4) ?
1 :
0));
170 // take binary log to obtain counter width and add a tick for the idle cycle
171 localparam ADD_RRD_CNTR_WIDTH =
clogb2(
nRRD_CLKS +
/* idle state **/ 1);
173 //***************************************************************************
175 //***************************************************************************
177 integer i;
// loop invariant
179 //***************************************************************************
182 // This function performs binary logarithm and rounds up
184 // size: integer to perform binary log upon
186 // clogb2: result of binary logarithm, rounded up
187 //***************************************************************************
189 function integer clogb2 (
input integer size);
194 // increment clogb2 from 1 for each bit in size
195 for (
clogb2 =
1;
size >
1;
clogb2 =
clogb2 +
1)
199 endfunction // clogb2
201 //***************************************************************************
202 // Determine if this rank has been activated. act_this_rank_r is a
203 // registered bit vector from individual bank machines indicating the
204 // corresponding bank machine is sending
205 // an activate. Timing is improved with this method.
206 //***************************************************************************
208 always @(
/*AS**/act_this_rank_r or sending_row)
begin
210 act_this_rank =
1'b0;
212 for (
i =
0;
i <
nBANK_MACHS;
i =
i +
1)
214 act_this_rank || (
sending_row[
i] &&
act_this_rank_r[(
i*
RANKS)+
ID]);
220 reg add_rrd_inhbt =
1'b0;
222 if (
nADD_RRD >
0 &&
ADD_RRD_CNTR_WIDTH >
1)
begin :
add_rdd1
223 reg[
ADD_RRD_CNTR_WIDTH-
1:
0]
add_rrd_ns;
224 reg[
ADD_RRD_CNTR_WIDTH-
1:
0]
add_rrd_r;
225 always @(
/*AS**/act_this_rank or add_rrd_r or rst)
begin
226 add_rrd_ns =
add_rrd_r;
227 if (
rst)
add_rrd_ns = {
ADD_RRD_CNTR_WIDTH{
1'b0}};
230 add_rrd_ns =
nRRD_CLKS[
0+:
ADD_RRD_CNTR_WIDTH];
231 else if (|
add_rrd_r)
add_rrd_ns =
232 add_rrd_r - {{
ADD_RRD_CNTR_WIDTH-
1{
1'b0}},
1'b1};
234 always @(
posedge clk)
add_rrd_r <= #TCQ
add_rrd_ns;
235 always @(
/*AS**/add_rrd_ns)
add_rrd_inhbt = |
add_rrd_ns;
237 else if (
nADD_RRD >
0)
begin :
add_rdd0
238 reg[
ADD_RRD_CNTR_WIDTH-
1:
0]
add_rrd_ns;
239 reg[
ADD_RRD_CNTR_WIDTH-
1:
0]
add_rrd_r;
240 always @(
/*AS**/act_this_rank or add_rrd_r or rst)
begin
241 add_rrd_ns =
add_rrd_r;
242 if (
rst)
add_rrd_ns = {
ADD_RRD_CNTR_WIDTH{
1'b0}};
245 add_rrd_ns =
nRRD_CLKS[
0+:
ADD_RRD_CNTR_WIDTH];
246 else if (|
add_rrd_r)
add_rrd_ns =
249 always @(
posedge clk)
add_rrd_r <= #TCQ
add_rrd_ns;
250 always @(
/*AS**/add_rrd_ns)
add_rrd_inhbt = |
add_rrd_ns;
255 // Compute inhbt_act_faw_r. Only allow a limited number of activates
256 // in a window. Both the number of activates and the window are
257 // configurable. This depends on the RRD mechanism to prevent
258 // two consecutive activates to the same rank.
260 // Subtract three from the specified nFAW. Subtract three because:
261 // -Zero for the delay into the SRL is really one state.
262 // -Sending_row is used to trigger the delay. Sending_row is one
263 // state delayed from the arb.
264 // -inhbt_act_faw_r is registered to make timing work, hence the
265 // generation needs to be one state early.
267 localparam nFAW_CLKS = (
nCK_PER_CLK ==
1)
269 : (
nCK_PER_CLK ==
2) ? ((
nFAW/
2) + (
nFAW%
2)) :
270 ((
nFAW/
4) + ((
nFAW%
4) ?
1 :
0));
273 begin :
inhbt_act_faw
275 wire [
4:
0]
shift_depth =
nFAW_CLKS[
4:
0] -
5'd3;
277 SRLC32E #(.
INIT(
32'h00000000) )
SRLC32E0
278 (.
Q(
act_delayed),
// SRL data output
279 .
Q31(),
// SRL cascade output pin
280 .
A(
shift_depth),
// 5-bit shift depth select input
281 .
CE(
1'b1),
// Clock enable input
282 .
CLK(
clk),
// Clock input
283 .
D(
act_this_rank)
// SRL data input
286 reg [
2:
0]
faw_cnt_ns;
288 reg inhbt_act_faw_ns;
289 always @(
/*AS**/act_delayed or act_this_rank or add_rrd_inhbt
290 or faw_cnt_r or rst)
begin
291 if (
rst)
faw_cnt_ns =
3'b0;
293 faw_cnt_ns =
faw_cnt_r;
294 if (
act_this_rank)
faw_cnt_ns =
faw_cnt_r +
3'b1;
295 if (
act_delayed)
faw_cnt_ns =
faw_cnt_ns -
3'b1;
297 inhbt_act_faw_ns = (
faw_cnt_ns ==
3'h4) ||
add_rrd_inhbt;
299 always @(
posedge clk)
faw_cnt_r <= #TCQ
faw_cnt_ns;
300 always @(
posedge clk)
inhbt_act_faw_r <= #TCQ
inhbt_act_faw_ns;
301 end // block: inhbt_act_faw
305 // In the DRAM spec, tWTR starts from CK following the end of the data
306 // burst. Since we don't directly have that spec, the wtr timer is
307 // based on when the CAS write command is sent to the DRAM.
309 // To compute the wtr timer value, first compute the time from the write command
310 // to the read command. This is CWL + data_time + nWTR.
312 // Two is subtracted from the required wtr time since the timer
313 // starts two states after the arbitration cycle.
318 localparam CASWR2CASRD =
CWL + (
BURST_MODE ==
"4" ?
2 :
4) +
nWTR;
319 localparam CASWR2CASRD_CLKS = (
nCK_PER_CLK ==
1)
322 ? ((
CASWR2CASRD /
2) + (
CASWR2CASRD %
2)) :
323 ((
CASWR2CASRD /
4) + ((
CASWR2CASRD %
4) ?
1 :
0));
324 localparam WTR_CNT_WIDTH =
clogb2(
CASWR2CASRD_CLKS);
330 always @(
/*AS**/sending_col or wr_this_rank_r)
begin
331 write_this_rank =
1'b0;
332 for (
i =
0;
i <
nBANK_MACHS;
i =
i +
1)
334 write_this_rank || (
sending_col[
i] &&
wr_this_rank_r[(
i*
RANKS)+
ID]);
337 reg [
WTR_CNT_WIDTH-
1:
0]
wtr_cnt_r;
338 reg [
WTR_CNT_WIDTH-
1:
0]
wtr_cnt_ns;
340 always @(
/*AS**/rst or write_this_rank or wtr_cnt_r)
341 if (
rst)
wtr_cnt_ns = {
WTR_CNT_WIDTH{
1'b0}};
343 wtr_cnt_ns =
wtr_cnt_r;
344 if (
write_this_rank)
wtr_cnt_ns =
345 CASWR2CASRD_CLKS[
WTR_CNT_WIDTH-
1:
0] -
ONE[
WTR_CNT_WIDTH-
1:
0];
346 else if (|
wtr_cnt_r)
wtr_cnt_ns =
wtr_cnt_r -
ONE[
WTR_CNT_WIDTH-
1:
0];
349 wire inhbt_rd_ns = |
wtr_cnt_ns;
351 always @(
posedge clk)
wtr_cnt_r <= #TCQ
wtr_cnt_ns;
352 always @(
inhbt_rd_ns)
inhbt_rd =
inhbt_rd_ns;
357 // In the DRAM spec (with AL = 0), the read-to-write command delay is implied to
358 // be CL + data_time + 2 tCK - CWL. The CL + data_time - CWL terms ensure the
359 // read and write data do not collide on the DQ bus. The 2 tCK ensures a gap
360 // between them. Here, we allow the user to tune this fixed term via the
361 // DQRD2DQWR_DLY parameter. There's a potential for optimization by relocating
362 // this to the rank_common module, since this is a DQ/DQS bus-level requirement,
363 // not a per-rank requirement.
365 localparam CASRD2CASWR =
CL + (
BURST_MODE ==
"4" ?
2 :
4) +
DQRD2DQWR_DLY -
CWL;
366 localparam CASRD2CASWR_CLKS = (
nCK_PER_CLK ==
1)
369 ? ((
CASRD2CASWR /
2) + (
CASRD2CASWR %
2)) :
370 ((
CASRD2CASWR /
4) + ((
CASRD2CASWR %
4) ?
1 :
0));
371 localparam RTW_CNT_WIDTH =
clogb2(
CASRD2CASWR_CLKS);
377 always @(
/*AS**/sending_col or rd_this_rank_r)
begin
378 read_this_rank =
1'b0;
379 for (
i =
0;
i <
nBANK_MACHS;
i =
i +
1)
381 read_this_rank || (
sending_col[
i] &&
rd_this_rank_r[(
i*
RANKS)+
ID]);
384 reg [
RTW_CNT_WIDTH-
1:
0]
rtw_cnt_r;
385 reg [
RTW_CNT_WIDTH-
1:
0]
rtw_cnt_ns;
387 always @(
/*AS**/rst or col_rd_wr or sending_col or rtw_cnt_r)
388 if (
rst)
rtw_cnt_ns = {
RTW_CNT_WIDTH{
1'b0}};
390 rtw_cnt_ns =
rtw_cnt_r;
391 if (
col_rd_wr && |
sending_col)
rtw_cnt_ns =
392 CASRD2CASWR_CLKS[
RTW_CNT_WIDTH-
1:
0] -
ONE[
RTW_CNT_WIDTH-
1:
0];
393 else if (|
rtw_cnt_r)
rtw_cnt_ns =
rtw_cnt_r -
ONE[
RTW_CNT_WIDTH-
1:
0];
396 wire inhbt_wr_ns = |
rtw_cnt_ns;
398 always @(
posedge clk)
rtw_cnt_r <= #TCQ
rtw_cnt_ns;
399 always @(
inhbt_wr_ns)
inhbt_wr =
inhbt_wr_ns;
404 // Refresh request generation. Implement a "refresh bank". Referred
405 // to as pullin-in refresh in the JEDEC spec.
406 // The refresh_rank_r counter increments when a refresh to this
407 // rank has been decoded. In the up direction, the count saturates
408 // at nREFRESH_BANK. As specified in the JEDEC spec, nREFRESH_BANK
409 // is normally eight. The counter decrements with each refresh_tick,
410 // saturating at zero. A refresh will be requests when the rank is
411 // not busy and refresh_rank_r != nREFRESH_BANK, or refresh_rank_r
414 localparam REFRESH_BANK_WIDTH =
clogb2(
nREFRESH_BANK +
1);
417 generate begin :
refresh_generation
419 always @(
/*AS**/rank_busy_r)
begin
421 for (
i=
0;
i <
nBANK_MACHS;
i=
i+
1)
422 my_rank_busy =
my_rank_busy ||
rank_busy_r[(
i*
RANKS)+
ID];
426 insert_maint_r1 && ~
maint_zq_r && ~
maint_sre_r && ~
maint_srx_r &&
427 (
maint_rank_r ==
ID[
RANK_WIDTH-
1:
0]);
429 reg [
REFRESH_BANK_WIDTH-
1:
0]
refresh_bank_r;
430 reg [
REFRESH_BANK_WIDTH-
1:
0]
refresh_bank_ns;
431 always @(
/*AS**/app_ref_req or init_calib_complete or my_refresh
432 or refresh_bank_r or refresh_tick)
433 if (~
init_calib_complete)
434 if (
REFRESH_TIMER_DIV ==
0)
435 refresh_bank_ns =
nREFRESH_BANK[
0+:
REFRESH_BANK_WIDTH];
436 else refresh_bank_ns = {
REFRESH_BANK_WIDTH{
1'b0}};
438 case ({
my_refresh,
refresh_tick,
app_ref_req})
439 3'b000,
3'b110,
3'b101,
3'b111 :
refresh_bank_ns =
refresh_bank_r;
440 3'b010,
3'b001,
3'b011 :
refresh_bank_ns =
442 refresh_bank_r -
ONE[
0+:
REFRESH_BANK_WIDTH]:
444 3'b100 :
refresh_bank_ns =
445 refresh_bank_r +
ONE[
0+:
REFRESH_BANK_WIDTH];
446 endcase // case ({my_refresh, refresh_tick})
447 always @(
posedge clk)
refresh_bank_r <= #TCQ
refresh_bank_ns;
450 refresh_bank_overflow: assert property (@(
posedge clk)
451 (rst || (refresh_bank_r <= nREFRESH_BANK)));
452 refresh_bank_underflow: assert property (@(
posedge clk)
453 (rst || ~(~|refresh_bank_r && ~my_refresh && refresh_tick)));
454 refresh_hi_priority: cover property (@(
posedge clk)
455 (rst && ~|refresh_bank_ns && (refresh_bank_r ==
456 ONE[
0+:REFRESH_BANK_WIDTH])));
457 refresh_bank_full: cover property (@(
posedge clk)
458 (rst && (refresh_bank_r ==
459 nREFRESH_BANK[
0+:REFRESH_BANK_WIDTH])));
462 assign refresh_request = init_calib_complete &&
464 ((refresh_bank_r != nREFRESH_BANK[
0+:REFRESH_BANK_WIDTH]) && ~my_rank_busy));
469 // Periodic read request generation.
471 localparam PERIODIC_RD_TIMER_WIDTH =
clogb2(
PERIODIC_RD_TIMER_DIV +
/*idle state**/ 1);
474 generate begin :
periodic_rd_generation
475 if (
PERIODIC_RD_TIMER_DIV !=
0 )
begin // enable periodic reads
477 always @(
/*AS**/rd_this_rank_r or sending_col)
begin
478 read_this_rank =
1'b0;
479 for (
i =
0;
i <
nBANK_MACHS;
i =
i +
1)
481 read_this_rank || (
sending_col[
i] &&
rd_this_rank_r[(
i*
RANKS)+
ID]);
484 reg read_this_rank_r;
485 reg read_this_rank_r1;
486 always @(
posedge clk)
read_this_rank_r <= #TCQ
read_this_rank;
487 always @(
posedge clk)
read_this_rank_r1 <= #TCQ
read_this_rank_r;
488 wire int_read_this_rank =
read_this_rank &&
489 (((
nCK_PER_CLK ==
4) &&
read_this_rank_r) ||
490 ((
nCK_PER_CLK !=
4) &&
read_this_rank_r1));
492 reg periodic_rd_cntr1_ns;
493 reg periodic_rd_cntr1_r;
494 always @(
/*AS**/clear_periodic_rd_request or periodic_rd_cntr1_r)
begin
495 periodic_rd_cntr1_ns =
periodic_rd_cntr1_r;
496 if (
clear_periodic_rd_request)
497 periodic_rd_cntr1_ns =
periodic_rd_cntr1_r +
1'b1;
499 always @(
posedge clk)
begin
500 if (
rst)
periodic_rd_cntr1_r <= #TCQ
1'b0;
501 else periodic_rd_cntr1_r <= #TCQ
periodic_rd_cntr1_ns;
504 reg [
PERIODIC_RD_TIMER_WIDTH-
1:
0]
periodic_rd_timer_r;
505 reg [
PERIODIC_RD_TIMER_WIDTH-
1:
0]
periodic_rd_timer_ns;
506 always @(
/*AS**/init_calib_complete or maint_prescaler_tick_r
507 or periodic_rd_timer_r or int_read_this_rank)
begin
508 periodic_rd_timer_ns =
periodic_rd_timer_r;
509 if (~
init_calib_complete)
510 periodic_rd_timer_ns = {
PERIODIC_RD_TIMER_WIDTH{
1'b0}};
511 else if (
int_read_this_rank)
512 periodic_rd_timer_ns =
513 PERIODIC_RD_TIMER_DIV[
0+:
PERIODIC_RD_TIMER_WIDTH];
514 else if (|
periodic_rd_timer_r &&
maint_prescaler_tick_r)
515 periodic_rd_timer_ns =
516 periodic_rd_timer_r -
ONE[
0+:
PERIODIC_RD_TIMER_WIDTH];
518 always @(
posedge clk)
periodic_rd_timer_r <= #TCQ
periodic_rd_timer_ns;
520 wire periodic_rd_timer_one =
maint_prescaler_tick_r &&
521 (
periodic_rd_timer_r ==
ONE[
0+:
PERIODIC_RD_TIMER_WIDTH]);
523 reg periodic_rd_request_r;
524 wire periodic_rd_request_ns = ~
rst &&
525 ((
app_periodic_rd_req &&
init_calib_complete) ||
526 ((
PERIODIC_RD_TIMER_DIV !=
0) && ~
init_calib_complete) ||
527 // (~(read_this_rank || clear_periodic_rd_request) &&
528 (~((
int_read_this_rank) || (
clear_periodic_rd_request &&
periodic_rd_cntr1_r)) &&
529 (
periodic_rd_request_r ||
periodic_rd_timer_one)));
530 always @(
posedge clk)
periodic_rd_request_r <=
531 #TCQ
periodic_rd_request_ns;
534 read_clears_periodic_rd_request: cover property (@(
posedge clk)
535 (rst && (periodic_rd_request_r && read_this_rank)));
538 assign periodic_rd_request = init_calib_complete && periodic_rd_request_r;
540 assign periodic_rd_request =
1'b0;
//to disable periodic reads