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 : bank_queue.v
55 // /___/ /\ Date Last Modified : $date$
56 // \ \ / \ Date Created : Tue Jun 30 2009
60 //Design Name : DDR3 SDRAM
64 //*****************************************************************************
66 // Bank machine queue controller.
68 // Bank machines are always associated with a queue. When the system is
69 // idle, all bank machines are in the idle queue. As requests are
70 // received, the bank machine at the head of the idle queue accepts
71 // the request, removes itself from the idle queue and places itself
72 // in a queue associated with the rank-bank of the new request.
74 // If the new request is to an idle rank-bank, a new queue is created
75 // for that rank-bank. If the rank-bank is not idle, then the new
76 // request is added to the end of the existing rank-bank queue.
78 // When the head of the idle queue accepts a new request, all other
79 // bank machines move down one in the idle queue. When the idle queue
80 // is empty, the memory interface deasserts its accept signal.
82 // When new requests are received, the first step is to classify them
83 // as to whether the request targets an already open rank-bank, and if
84 // so, does the new request also hit on the already open page? As mentioned
85 // above, a new request places itself in the existing queue for a
86 // rank-bank hit. If it is also detected that the last entry in the
87 // existing rank-bank queue has the same page, then the current tail
88 // sets a bit telling itself to pass the open row when the column
89 // command is issued. The "passee" knows its in the head minus one
90 // position and hence takes control of the rank-bank.
92 // Requests are retired out of order to optimize DRAM array resources.
93 // However it is required that the user cannot "observe" this out of
94 // order processing as a data corruption. An ordering queue is
95 // used to enforce some ordering rules. As controlled by a paramter,
96 // there can be no ordering (RELAXED), ordering of writes only (NORM), and
97 // strict (STRICT) ordering whereby input request ordering is
98 // strictly adhered to.
100 // Note that ordering applies only to column commands. Row commands
101 // such as activate and precharge are allowed to proceed in any order
102 // with the proviso that within a rank-bank row commands are processed in
103 // the request order.
105 // When a bank machine accepts a new request, it looks at the ordering
106 // mode. If no ordering, nothing is done. If strict ordering, then
107 // it always places itself at the end of the ordering queue. If "normal"
108 // or write ordering, the row machine places itself in the ordering
109 // queue only if the new request is a write. The bank state machine
110 // looks at the ordering queue, and will only issue a column
111 // command when it sees itself at the head of the ordering queue.
113 // When a bank machine has completed its request, it must re-enter the
114 // idle queue. This is done by setting the idle_r bit, and setting q_entry_r
115 // to the idle count.
117 // There are several situations where more than one bank machine
118 // will enter the idle queue simultaneously. If two or more
119 // simply use the idle count to place themselves in the idle queue, multiple
120 // bank machines will end up at the same location in the idle queue, which
123 // Based on the bank machine instance numbers, a count is made of
124 // the number of bank machines entering idle "below" this instance. This
125 // number is added to the idle count to compute the location in
128 // There is also a single bit computed that says there were bank machines
129 // entering the idle queue "above" this instance. This is used to
130 // compute the tail bit.
132 // The word "queue" is used frequently to describe the behavior of the
133 // bank_queue block. In reality, there are no queues in the ordinary sense.
134 // As instantiated in this block, each bank machine has a q_entry_r number.
135 // This number represents the position of the bank machine in its current
136 // queue. At any given time, a bank machine may be in the idle queue,
137 // one of the dynamic rank-bank queues, or a single entry manitenance queue.
138 // A complete description of which queue a bank machine is currently in is
139 // given by idle_r, its rank-bank, mainteance status and its q_entry_r number.
141 // DRAM refresh and ZQ have a private single entry queue/channel. However,
142 // when a refresh request is made, it must be injected into the main queue
143 // properly. At the time of injection, the refresh rank is compared against
144 // all entryies in the queue. For those that match, if timing allows, and
145 // they are the tail of the rank-bank queue, then the auto_pre bit is set.
146 // Otherwise precharge is in progress. This results in a fully precharged
149 // At the time of injection, the refresh channel builds a bit
150 // vector of queue entries that hit on the refresh rank. Once all
151 // of these entries finish, the refresh is forced in at the row arbiter.
153 // New requests that come after the refresh request will notice that
154 // a refresh is in progress for their rank and wait for the refresh
155 // to finish before attempting to arbitrate to send an activate.
157 // Injection of a refresh sets the q_has_rd bit for all queues hitting
158 // on the refresh rank. This insures a starved write request will not
159 // indefinitely hold off a refresh.
161 // Periodic reads are required to compare themselves against requests
162 // that are in progress. Adding a unique compare channel for this
163 // is not worthwhile. Periodic read requests inhibit the accept
164 // signal and override any new request that might be trying to
167 // Once a periodic read has entered the queue it is nearly indistinguishable
168 // from a normal read request. The req_periodic_rd_r bit is set for
169 // queue entry. This signal is used to inhibit the rd_data_en signal.
177 parameter BM_CNT_WIDTH =
2,
178 parameter nBANK_MACHS =
4,
179 parameter ORDERING =
"NORM",
184 head_r,
tail_r,
idle_ns,
idle_r,
pass_open_bank_ns,
185 pass_open_bank_r,
auto_pre_r,
bm_end,
passing_open_bank,
186 ordered_issued,
ordered_r,
order_q_zero,
rcv_open_bank,
187 rb_hit_busies_r,
q_has_rd,
q_has_priority,
wait_for_maint_r,
189 clk,
rst,
accept_internal_r,
use_addr,
periodic_rd_ack_r,
bm_end_in,
190 idle_cnt,
rb_hit_busy_cnt,
accept_req,
rb_hit_busy_r,
maint_idle,
191 maint_hit,
row_hit_r,
pre_wait_r,
allow_auto_pre,
sending_col,
192 bank_wait_in_progress,
precharge_bm_end,
req_wr_r,
rd_wr_r,
193 adv_order_q,
order_cnt,
rb_hit_busy_ns_in,
passing_open_bank_in,
194 was_wr,
maint_req_r,
was_priority
199 localparam [
BM_CNT_WIDTH-
1:
0]
BM_CNT_ZERO =
ZERO[
0+:
BM_CNT_WIDTH];
200 localparam [
BM_CNT_WIDTH-
1:
0]
BM_CNT_ONE =
ONE[
0+:
BM_CNT_WIDTH];
205 // Decide if this bank machine should accept a new request.
208 input accept_internal_r;
209 wire bm_ready =
idle_r_lcl &&
head_r_lcl &&
accept_internal_r;
211 // Accept request in this bank machine. Could be maintenance or
214 input periodic_rd_ack_r;
215 wire accept_this_bm =
bm_ready && (
use_addr ||
periodic_rd_ack_r);
217 // Multiple machines may enter the idle queue in a single state.
218 // Based on bank machine instance number, compute how many
219 // bank machines with lower instance numbers are entering
222 input [(
nBANK_MACHS*
2)-
1:
0]
bm_end_in;
224 reg [
BM_CNT_WIDTH-
1:
0]
idlers_below;
226 always @(
/*AS**/bm_end_in)
begin
227 idlers_below =
BM_CNT_ZERO;
228 for (
i=
0;
i<
ID;
i=
i+
1)
229 idlers_below =
idlers_below +
bm_end_in[
i];
233 always @(
/*AS**/bm_end_in)
begin
235 for (
i=
ID+
1;
i<
ID+
nBANK_MACHS;
i=
i+
1)
236 idlers_above =
idlers_above ||
bm_end_in[
i];
240 bm_end_and_idlers_above: cover property (@(
posedge clk)
241 (~rst && bm_end && idlers_above));
242 bm_end_and_idlers_below: cover property (@(
posedge clk)
243 (~rst && bm_end && |idlers_below));
246 // Compute the q_entry number.
247 input [
BM_CNT_WIDTH-
1:
0]
idle_cnt;
248 input [
BM_CNT_WIDTH-
1:
0]
rb_hit_busy_cnt;
251 reg adv_queue =
1'b0;
253 reg [
BM_CNT_WIDTH-
1:
0]
q_entry_r;
254 reg [
BM_CNT_WIDTH-
1:
0]
q_entry_ns;
255 wire [
BM_CNT_WIDTH-
1:
0]
temp;
256 // always @(/*AS*/accept_req or accept_this_bm or adv_queue
257 // or bm_end_lcl or idle_cnt or idle_r_lcl or idlers_below
258 // or q_entry_r or rb_hit_busy_cnt /*or rst*/) begin
259 //// if (rst) q_entry_ns = ID[BM_CNT_WIDTH-1:0];
261 // q_entry_ns = q_entry_r;
262 // if ((~idle_r_lcl && adv_queue) ||
263 // (idle_r_lcl && accept_req && ~accept_this_bm))
264 // q_entry_ns = q_entry_r - BM_CNT_ONE;
265 // if (accept_this_bm)
266 //// q_entry_ns = rb_hit_busy_cnt - (adv_queue ? BM_CNT_ONE : BM_CNT_ZERO);
267 // q_entry_ns = adv_queue ? (rb_hit_busy_cnt - BM_CNT_ONE) : (rb_hit_busy_cnt -BM_CNT_ZERO);
268 // if (bm_end_lcl) begin
269 // q_entry_ns = idle_cnt + idlers_below;
270 // if (accept_req) q_entry_ns = q_entry_ns - BM_CNT_ONE;
274 assign temp =
idle_cnt +
idlers_below;
277 if (
accept_req &
bm_end_lcl)
278 q_entry_ns =
temp -
BM_CNT_ONE;
281 else if (
accept_this_bm)
282 q_entry_ns =
adv_queue ? (
rb_hit_busy_cnt -
BM_CNT_ONE) : (
rb_hit_busy_cnt -
BM_CNT_ZERO);
283 else if ((!
idle_r_lcl &
adv_queue) |
284 (
idle_r_lcl &
accept_req & !
accept_this_bm))
285 q_entry_ns =
q_entry_r -
BM_CNT_ONE;
287 q_entry_ns =
q_entry_r;
291 always @(
posedge clk)
293 q_entry_r <= #TCQ
ID[
BM_CNT_WIDTH-
1:
0];
295 q_entry_r <= #TCQ
q_entry_ns;
297 // Determine if this entry is the head of its queue.
299 always @(
/*AS**/accept_req or accept_this_bm or adv_queue
300 or bm_end_lcl or head_r_lcl or idle_cnt or idle_r_lcl
301 or idlers_below or q_entry_r or rb_hit_busy_cnt or rst)
begin
302 if (
rst)
head_ns = ~|
ID[
BM_CNT_WIDTH-
1:
0];
304 head_ns =
head_r_lcl;
306 head_ns = ~|(
rb_hit_busy_cnt - (
adv_queue ?
BM_CNT_ONE :
BM_CNT_ZERO));
307 if ((~
idle_r_lcl &&
adv_queue) ||
308 (
idle_r_lcl &&
accept_req && ~
accept_this_bm))
309 head_ns = ~|(
q_entry_r -
BM_CNT_ONE);
310 if (
bm_end_lcl)
begin
311 head_ns = ~|(
idle_cnt - (
accept_req ?
BM_CNT_ONE :
BM_CNT_ZERO)) &&
316 always @(
posedge clk)
head_r_lcl <= #TCQ
head_ns;
318 assign head_r =
head_r_lcl;
320 // Determine if this entry is the tail of its queue. Note that
321 // an entry can be both head and tail.
323 reg tail_r_lcl =
1'b1;
325 if (
nBANK_MACHS >
1)
begin :
compute_tail
327 always @(
accept_req or accept_this_bm
328 or bm_end_in or bm_end_lcl or idle_r_lcl
329 or idlers_above or rb_hit_busy_r or rst or tail_r_lcl)
begin
330 if (
rst)
tail_ns = (
ID ==
nBANK_MACHS);
331 // The order of the statements below is important in the case where
332 // another bank machine is retiring and this bank machine is accepting.
334 tail_ns =
tail_r_lcl;
335 if ((
accept_req &&
rb_hit_busy_r) ||
338 if (
accept_this_bm || (
bm_end_lcl && ~
idlers_above))
tail_ns =
1'b1;
341 always @(
posedge clk)
tail_r_lcl <= #TCQ
tail_ns;
342 end // if (nBANK_MACHS > 1)
345 assign tail_r =
tail_r_lcl;
347 wire clear_req =
bm_end_lcl ||
rst;
349 // Is this entry in the idle queue?
351 always @(
/*AS**/accept_this_bm or clear_req or idle_r_lcl)
begin
352 idle_ns_lcl =
idle_r_lcl;
353 if (
accept_this_bm)
idle_ns_lcl =
1'b0;
354 if (
clear_req)
idle_ns_lcl =
1'b1;
356 always @(
posedge clk)
idle_r_lcl <= #TCQ
idle_ns_lcl;
358 assign idle_ns =
idle_ns_lcl;
360 assign idle_r =
idle_r_lcl;
362 // Maintenance hitting on this active bank machine is in progress.
365 wire maint_hit_this_bm = ~
maint_idle &&
maint_hit;
367 // Does new request hit on this bank machine while it is able to pass the
371 wire pass_open_bank_eligible =
372 tail_r_lcl &&
rb_hit_busy_r &&
row_hit_r && ~
pre_wait_r;
374 // Set pass open bank bit, but not if request preceded active maintenance.
375 reg wait_for_maint_r_lcl;
376 reg pass_open_bank_r_lcl;
377 wire pass_open_bank_ns_lcl = ~
clear_req &&
378 (
pass_open_bank_r_lcl ||
379 (
accept_req &&
pass_open_bank_eligible &&
380 (~
maint_hit_this_bm ||
wait_for_maint_r_lcl)));
381 always @(
posedge clk)
pass_open_bank_r_lcl <= #TCQ
pass_open_bank_ns_lcl;
382 output wire pass_open_bank_ns;
383 assign pass_open_bank_ns =
pass_open_bank_ns_lcl;
384 output wire pass_open_bank_r;
385 assign pass_open_bank_r =
pass_open_bank_r_lcl;
388 pass_open_bank: cover property (@(
posedge clk) (~rst && pass_open_bank_ns));
389 pass_open_bank_killed_by_maint: cover property (@(
posedge clk)
390 (~rst && accept_req && pass_open_bank_eligible &&
391 maint_hit_this_bm && ~wait_for_maint_r_lcl));
392 pass_open_bank_following_maint: cover property (@(
posedge clk)
393 (~rst && accept_req && pass_open_bank_eligible &&
394 maint_hit_this_bm && wait_for_maint_r_lcl));
397 // Should the column command be sent with the auto precharge bit set? This
398 // will happen when it is detected that next request is to a different row,
399 // or the next reqest is the next request is refresh to this rank.
402 input allow_auto_pre;
403 always @(
/*AS**/accept_req or allow_auto_pre or auto_pre_r_lcl
404 or clear_req or maint_hit_this_bm or rb_hit_busy_r
405 or row_hit_r or tail_r_lcl or wait_for_maint_r_lcl)
begin
406 auto_pre_ns =
auto_pre_r_lcl;
407 if (
clear_req)
auto_pre_ns =
1'b0;
409 if (
accept_req &&
tail_r_lcl &&
allow_auto_pre &&
rb_hit_busy_r &&
410 (~
row_hit_r || (
maint_hit_this_bm && ~
wait_for_maint_r_lcl)))
413 always @(
posedge clk)
auto_pre_r_lcl <= #TCQ
auto_pre_ns;
414 output wire auto_pre_r;
415 assign auto_pre_r =
auto_pre_r_lcl;
418 auto_precharge: cover property (@(
posedge clk) (~rst && auto_pre_ns));
419 maint_triggers_auto_precharge: cover property (@(
posedge clk)
420 (~rst && auto_pre_ns && ~auto_pre_r && row_hit_r));
423 // Determine when the current request is finished.
427 wire sending_col_not_rmw_rd =
sending_col && !(
req_wr_r &&
rd_wr_r);
428 input bank_wait_in_progress;
429 input precharge_bm_end;
431 wire pre_bm_end_ns =
precharge_bm_end ||
432 (
bank_wait_in_progress &&
pass_open_bank_ns_lcl);
433 always @(
posedge clk)
pre_bm_end_r <= #TCQ
pre_bm_end_ns;
435 pre_bm_end_r || (
sending_col_not_rmw_rd &&
pass_open_bank_r_lcl);
437 assign bm_end =
bm_end_lcl;
439 // Determine that the open bank should be passed to the successor bank machine.
440 reg pre_passing_open_bank_r;
441 wire pre_passing_open_bank_ns =
442 bank_wait_in_progress &&
pass_open_bank_ns_lcl;
443 always @(
posedge clk)
pre_passing_open_bank_r <= #TCQ
444 pre_passing_open_bank_ns;
445 output wire passing_open_bank;
446 assign passing_open_bank =
447 pre_passing_open_bank_r || (
sending_col_not_rmw_rd &&
pass_open_bank_r_lcl);
450 wire set_order_q = ((
ORDERING ==
"STRICT") || ((
ORDERING ==
"NORM") &&
451 req_wr_r)) &&
accept_this_bm;
453 wire ordered_issued_lcl =
454 sending_col_not_rmw_rd && !(
req_wr_r &&
rd_wr_r) &&
455 ((
ORDERING ==
"STRICT") || ((
ORDERING ==
"NORM") &&
req_wr_r));
456 output wire ordered_issued;
457 assign ordered_issued =
ordered_issued_lcl;
460 always @(
/*AS**/ordered_issued_lcl or ordered_r_lcl or rst
461 or set_order_q)
begin
462 if (
rst)
ordered_ns =
1'b0;
464 ordered_ns =
ordered_r_lcl;
465 // Should never see accept_this_bm and adv_order_q at the same time.
466 if (
set_order_q)
ordered_ns =
1'b1;
467 if (
ordered_issued_lcl)
ordered_ns =
1'b0;
470 always @(
posedge clk)
ordered_r_lcl <= #TCQ
ordered_ns;
471 output wire ordered_r;
472 assign ordered_r =
ordered_r_lcl;
474 // Figure out when to advance the ordering queue.
476 input [
BM_CNT_WIDTH-
1:
0]
order_cnt;
477 reg [
BM_CNT_WIDTH-
1:
0]
order_q_r;
478 reg [
BM_CNT_WIDTH-
1:
0]
order_q_ns;
479 always @(
/*AS**/adv_order_q or order_cnt or order_q_r or rst
480 or set_order_q)
begin
481 order_q_ns =
order_q_r;
482 if (
rst)
order_q_ns =
BM_CNT_ZERO;
484 if (
adv_order_q)
order_q_ns =
order_cnt -
BM_CNT_ONE;
485 else order_q_ns =
order_cnt;
486 if (
adv_order_q && |
order_q_r)
order_q_ns =
order_q_r -
BM_CNT_ONE;
488 always @(
posedge clk)
order_q_r <= #TCQ
order_q_ns;
490 output wire order_q_zero;
491 assign order_q_zero = ~|
order_q_r ||
492 (
adv_order_q && (
order_q_r ==
BM_CNT_ONE)) ||
493 ((
ORDERING ==
"NORM") &&
rd_wr_r);
495 // Keep track of which other bank machine are ahead of this one in a
496 // rank-bank queue. This is necessary to know when to advance this bank
497 // machine in the queue, and when to update bank state machine counter upon
499 input [(
nBANK_MACHS*
2)-
1:
0]
rb_hit_busy_ns_in;
500 reg [(
nBANK_MACHS*
2)-
1:
0]
rb_hit_busies_r_lcl = {
nBANK_MACHS*
2{
1'b0}};
501 input [(
nBANK_MACHS*
2)-
1:
0]
passing_open_bank_in;
502 output reg rcv_open_bank =
1'b0;
505 if (
nBANK_MACHS >
1)
begin :
rb_hit_busies
507 // The clear_vector resets bits in the rb_hit_busies vector as bank machines
508 // completes requests. rst also resets all the bits.
509 wire [
nBANK_MACHS-
2:
0]
clear_vector =
512 // As this bank machine takes on a new request, capture the vector of
513 // which other bank machines are in the same queue.
520 #TCQ
rb_hit_busies_ns;
522 // Compute when to advance this queue entry based on seeing other bank machines
523 // in the same queue finish.
524 always @(
bm_end_in or rb_hit_busies_r_lcl)
528 // Decide when to receive an open bank based on knowing this bank machine is
529 // one entry from the head, and a passing_open_bank hits on the
530 // rb_hit_busies vector.
532 or passing_open_bank_in or q_entry_r
533 or rb_hit_busies_r_lcl)
rcv_open_bank =
535 && (
q_entry_r ==
BM_CNT_ONE) && ~
idle_r_lcl;
538 output wire [
nBANK_MACHS*
2-
1:
0]
rb_hit_busies_r;
539 assign rb_hit_busies_r =
rb_hit_busies_r_lcl;
542 // Keep track if the queue this entry is in has priority content.
546 wire q_has_rd_ns = ~
clear_req &&
547 (
q_has_rd_r || (
accept_req &&
rb_hit_busy_r && ~
was_wr) ||
548 (
maint_req_r &&
maint_hit && ~
idle_r_lcl));
549 always @(
posedge clk)
q_has_rd_r <= #TCQ
q_has_rd_ns;
550 output wire q_has_rd;
551 assign q_has_rd =
q_has_rd_r;
554 reg q_has_priority_r;
555 wire q_has_priority_ns = ~
clear_req &&
556 (
q_has_priority_r || (
accept_req &&
rb_hit_busy_r &&
was_priority));
557 always @(
posedge clk)
q_has_priority_r <= #TCQ
q_has_priority_ns;
558 output wire q_has_priority;
559 assign q_has_priority =
q_has_priority_r;
561 // Figure out if this entry should wait for maintenance to end.
562 wire wait_for_maint_ns = ~
rst && ~
maint_idle &&
563 (
wait_for_maint_r_lcl || (
maint_hit &&
accept_this_bm));
564 always @(
posedge clk)
wait_for_maint_r_lcl <= #TCQ
wait_for_maint_ns;
565 output wire wait_for_maint_r;
566 assign wait_for_maint_r =
wait_for_maint_r_lcl;
568 endmodule // bank_queue