AMC13
Firmwares for the different applications of the AMC13 uTCA board made at Boston University
 All Classes Variables
mig_7series_v1_9_bank_common.v
1  //*****************************************************************************
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 : bank_common.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 // Common block for the bank machines. Bank_common computes various
67 // items that cross all of the bank machines. These values are then
68 // fed back to all of the bank machines. Most of these values have
69 // to do with a row machine figuring out where it belongs in a queue.
70 
71 `timescale 1 ps / 1 ps
72 
74  (
75  parameter TCQ = 100,
76  parameter BM_CNT_WIDTH = 2,
77  parameter LOW_IDLE_CNT = 1,
78  parameter nBANK_MACHS = 4,
79  parameter nCK_PER_CLK = 2,
80  parameter nOP_WAIT = 0,
81  parameter nRFC = 44,
82  parameter nXSDLL = 512,
83  parameter RANK_WIDTH = 2,
84  parameter RANKS = 4,
85  parameter CWL = 5,
86  parameter tZQCS = 64
87  )
88  (/*AUTOARG**/
89  // Outputs
90  accept_internal_r, accept_ns, accept, periodic_rd_insert,
91  periodic_rd_ack_r, accept_req, rb_hit_busy_cnt, idle, idle_cnt, order_cnt,
92  adv_order_q, bank_mach_next, op_exit_grant, low_idle_cnt_r, was_wr,
93  was_priority, maint_wip_r, maint_idle, insert_maint_r,
94  // Inputs
95  clk, rst, idle_ns, init_calib_complete, periodic_rd_r, use_addr,
96  rb_hit_busy_r, idle_r, ordered_r, ordered_issued, head_r, end_rtp,
97  passing_open_bank, op_exit_req, start_pre_wait, cmd, hi_priority, maint_req_r,
98  maint_zq_r, maint_sre_r, maint_srx_r, maint_hit, bm_end,
99  slot_0_present, slot_1_present
100  );
101 
102  function integer clogb2 (input integer size); // ceiling logb2
103  begin
104  size = size - 1;
105  for (clogb2=1; size>1; clogb2=clogb2+1)
106  size = size >> 1;
107  end
108  endfunction // clogb2
109 
110  localparam ZERO = 0;
111  localparam ONE = 1;
112  localparam [BM_CNT_WIDTH-1:0] BM_CNT_ZERO = ZERO[0+:BM_CNT_WIDTH];
113  localparam [BM_CNT_WIDTH-1:0] BM_CNT_ONE = ONE[0+:BM_CNT_WIDTH];
114 
115  input clk;
116  input rst;
117 
118  input [nBANK_MACHS-1:0] idle_ns;
119  input init_calib_complete;
120  wire accept_internal_ns = init_calib_complete && |idle_ns;
121  output reg accept_internal_r;
122  always @(posedge clk) accept_internal_r <= accept_internal_ns;
123  wire periodic_rd_ack_ns;
124  wire accept_ns_lcl = accept_internal_ns && ~periodic_rd_ack_ns;
125  output wire accept_ns;
126  assign accept_ns = accept_ns_lcl;
127  reg accept_r;
128  always @(posedge clk) accept_r <= #TCQ accept_ns_lcl;
129 
130 // Wire to user interface informing user that the request has been accepted.
131  output wire accept;
132  assign accept = accept_r;
133 
134 `ifdef MC_SVA
135  property none_idle;
136  @(posedge clk) (init_calib_complete && ~|idle_r);
137  endproperty
138 
139  all_bank_machines_busy: cover property (none_idle);
140 `endif
141 
142 // periodic_rd_insert tells everyone to mux in the periodic read.
143  input periodic_rd_r;
144  reg periodic_rd_ack_r_lcl;
145  reg periodic_rd_cntr_r ;
146  always @(posedge clk) begin
147  if (rst) periodic_rd_cntr_r <= #TCQ 1'b0;
148  else if (periodic_rd_r && periodic_rd_ack_r_lcl)
149  periodic_rd_cntr_r <= #TCQ ~periodic_rd_cntr_r;
150  end
151 
152  wire internal_periodic_rd_ack_r_lcl = (periodic_rd_cntr_r && periodic_rd_ack_r_lcl);
153 
154  // wire periodic_rd_insert_lcl = periodic_rd_r && ~periodic_rd_ack_r_lcl;
155  wire periodic_rd_insert_lcl = periodic_rd_r && ~internal_periodic_rd_ack_r_lcl;
156  output wire periodic_rd_insert;
157  assign periodic_rd_insert = periodic_rd_insert_lcl;
158 
159 // periodic_rd_ack_r acknowledges that the read has been accepted
160 // into the queue.
161  assign periodic_rd_ack_ns = periodic_rd_insert_lcl && accept_internal_ns;
162  always @(posedge clk) periodic_rd_ack_r_lcl <= #TCQ periodic_rd_ack_ns;
163  output wire periodic_rd_ack_r;
164  assign periodic_rd_ack_r = periodic_rd_ack_r_lcl;
165 
166 // accept_req tells all q entries that a request has been accepted.
167  input use_addr;
168  wire accept_req_lcl = periodic_rd_ack_r_lcl || (accept_r && use_addr);
169  output wire accept_req;
170  assign accept_req = accept_req_lcl;
171 
172 // Count how many non idle bank machines hit on the rank and bank.
173  input [nBANK_MACHS-1:0] rb_hit_busy_r;
174  output reg [BM_CNT_WIDTH-1:0] rb_hit_busy_cnt;
175  integer i;
176  always @(/*AS**/rb_hit_busy_r) begin
177  rb_hit_busy_cnt = BM_CNT_ZERO;
178  for (i = 0; i < nBANK_MACHS; i = i + 1)
179  if (rb_hit_busy_r[i]) rb_hit_busy_cnt = rb_hit_busy_cnt + BM_CNT_ONE;
180  end
181 
182 // Count the number of idle bank machines.
183  input [nBANK_MACHS-1:0] idle_r;
184  output reg [BM_CNT_WIDTH-1:0] idle_cnt;
185  always @(/*AS**/idle_r) begin
186  idle_cnt = BM_CNT_ZERO;
187  for (i = 0; i < nBANK_MACHS; i = i + 1)
188  if (idle_r[i]) idle_cnt = idle_cnt + BM_CNT_ONE;
189  end
190 
191 // Report an overall idle status
192  output idle;
193  assign idle = init_calib_complete && &idle_r;
194 
195 // Count the number of bank machines in the ordering queue.
196  input [nBANK_MACHS-1:0] ordered_r;
197  output reg [BM_CNT_WIDTH-1:0] order_cnt;
198  always @(/*AS**/ordered_r) begin
199  order_cnt = BM_CNT_ZERO;
200  for (i = 0; i < nBANK_MACHS; i = i + 1)
201  if (ordered_r[i]) order_cnt = order_cnt + BM_CNT_ONE;
202  end
203 
204  input [nBANK_MACHS-1:0] ordered_issued;
205  output wire adv_order_q;
206  assign adv_order_q = |ordered_issued;
207 
208 // Figure out which bank machine is going to accept the next request.
209  input [nBANK_MACHS-1:0] head_r;
210  wire [nBANK_MACHS-1:0] next = idle_r & head_r;
211  output reg[BM_CNT_WIDTH-1:0] bank_mach_next;
212  always @(/*AS**/next) begin
213  bank_mach_next = BM_CNT_ZERO;
214  for (i = 0; i <= nBANK_MACHS-1; i = i + 1)
215  if (next[i]) bank_mach_next = i[BM_CNT_WIDTH-1:0];
216  end
217 
218  input [nBANK_MACHS-1:0] end_rtp;
219  input [nBANK_MACHS-1:0] passing_open_bank;
220  input [nBANK_MACHS-1:0] op_exit_req;
221  output wire [nBANK_MACHS-1:0] op_exit_grant;
222  output reg low_idle_cnt_r = 1'b0;
223  input [nBANK_MACHS-1:0] start_pre_wait;
224 
225  generate
226 // In support of open page mode, the following logic
227 // keeps track of how many "idle" bank machines there
228 // are. In this case, idle means a bank machine is on
229 // the idle list, or is in the process of precharging and
230 // will soon be idle.
231  if (nOP_WAIT == 0) begin : op_mode_disabled
232  assign op_exit_grant = {nBANK_MACHS{1'b0}};
233  end
234 
235  else begin : op_mode_enabled
236  reg [BM_CNT_WIDTH:0] idle_cnt_r;
237  reg [BM_CNT_WIDTH:0] idle_cnt_ns;
238  always @(/*AS**/accept_req_lcl or idle_cnt_r or passing_open_bank
239  or rst or start_pre_wait)
240  if (rst) idle_cnt_ns = nBANK_MACHS;
241  else begin
242  idle_cnt_ns = idle_cnt_r - accept_req_lcl;
243  for (i = 0; i <= nBANK_MACHS-1; i = i + 1) begin
244  idle_cnt_ns = idle_cnt_ns + passing_open_bank[i];
245  end
246  idle_cnt_ns = idle_cnt_ns + |start_pre_wait;
247  end
248  always @(posedge clk) idle_cnt_r <= #TCQ idle_cnt_ns;
249  wire low_idle_cnt_ns = (idle_cnt_ns <= LOW_IDLE_CNT[0+:BM_CNT_WIDTH]);
250  always @(posedge clk) low_idle_cnt_r <= #TCQ low_idle_cnt_ns;
251 
252 // This arbiter determines which bank machine should transition
253 // from open page wait to precharge. Ideally, this process
254 // would take the oldest waiter, but don't have any reasonable
255 // way to implement that. Instead, just use simple round robin
256 // arb with the small enhancement that the most recent bank machine
257 // to enter open page wait is given lowest priority in the arbiter.
258 
259  wire upd_last_master = |end_rtp; // should be one bit set at most
261  (.WIDTH (nBANK_MACHS))
262  op_arb0
263  (.grant_ns (op_exit_grant[nBANK_MACHS-1:0]),
264  .grant_r (),
265  .upd_last_master (upd_last_master),
266  .current_master (end_rtp[nBANK_MACHS-1:0]),
267  .clk (clk),
268  .rst (rst),
269  .req (op_exit_req[nBANK_MACHS-1:0]),
270  .disable_grant (1'b0));
271 
272  end
273  endgenerate
274 
275 // Register some command information. This information will be used
276 // by the bank machines to figure out if there is something behind it
277 // in the queue that require hi priority.
278 
279  input [2:0] cmd;
280  output reg was_wr;
281  always @(posedge clk) was_wr <= #TCQ
282  cmd[0] && ~(periodic_rd_r && ~periodic_rd_ack_r_lcl);
283 
284  input hi_priority;
285  output reg was_priority;
286  always @(posedge clk) begin
287  if (hi_priority)
288  was_priority <= #TCQ 1'b1;
289  else
290  was_priority <= #TCQ 1'b0;
291  end
292 
293 
294 // DRAM maintenance (refresh and ZQ) and self-refresh controller
295 
296  input maint_req_r;
297  reg maint_wip_r_lcl;
298  output wire maint_wip_r;
299  assign maint_wip_r = maint_wip_r_lcl;
300  wire maint_idle_lcl;
301  output wire maint_idle;
302  assign maint_idle = maint_idle_lcl;
303  input maint_zq_r;
304  input maint_sre_r;
305  input maint_srx_r;
306  input [nBANK_MACHS-1:0] maint_hit;
307  input [nBANK_MACHS-1:0] bm_end;
308  wire start_maint;
309  wire maint_end;
310 
311  generate begin : maint_controller
312 
313 // Idle when not (maintenance work in progress (wip), OR maintenance
314 // starting tick).
315  assign maint_idle_lcl = ~(maint_req_r || maint_wip_r_lcl);
316 
317 // Maintenance work in progress starts with maint_reg_r tick, terminated
318 // with maint_end tick. maint_end tick is generated by the RFC/ZQ/XSDLL timer
319 // below.
320  wire maint_wip_ns =
321  ~rst && ~maint_end && (maint_wip_r_lcl || maint_req_r);
322  always @(posedge clk) maint_wip_r_lcl <= #TCQ maint_wip_ns;
323 
324 // Keep track of which bank machines hit on the maintenance request
325 // when the request is made. As bank machines complete, an assertion
326 // of the bm_end signal clears the correspoding bit in the
327 // maint_hit_busies_r vector. Eventually, all bits should clear and
328 // the maintenance operation will proceed. ZQ and self-refresh hit on all
329 // non idle banks. Refresh hits only on non idle banks with the same rank as
330 // the refresh request.
331  wire [nBANK_MACHS-1:0] clear_vector = {nBANK_MACHS{rst}} | bm_end;
332  wire [nBANK_MACHS-1:0] maint_zq_hits = {nBANK_MACHS{maint_idle_lcl}} &
333  (maint_hit | {nBANK_MACHS{maint_zq_r}}) & ~idle_ns;
334  wire [nBANK_MACHS-1:0] maint_sre_hits = {nBANK_MACHS{maint_idle_lcl}} &
335  (maint_hit | {nBANK_MACHS{maint_sre_r}}) & ~idle_ns;
336  reg [nBANK_MACHS-1:0] maint_hit_busies_r;
337  wire [nBANK_MACHS-1:0] maint_hit_busies_ns =
338  ~clear_vector & (maint_hit_busies_r | maint_zq_hits | maint_sre_hits);
339  always @(posedge clk) maint_hit_busies_r <= #TCQ maint_hit_busies_ns;
340 
341 // Queue is clear of requests conflicting with maintenance.
342  wire maint_clear = ~maint_idle_lcl && ~|maint_hit_busies_ns;
343 
344 // Ready to start sending maintenance commands.
345  wire maint_rdy = maint_clear;
346  reg maint_rdy_r1;
347  reg maint_srx_r1;
348  always @(posedge clk) maint_rdy_r1 <= #TCQ maint_rdy;
349  always @(posedge clk) maint_srx_r1 <= #TCQ maint_srx_r;
350  assign start_maint = maint_rdy && ~maint_rdy_r1 || maint_srx_r && ~maint_srx_r1;
351 
352  end // block: maint_controller
353  endgenerate
354 
355 
356 // Figure out how many maintenance commands to send, and send them.
357  input [7:0] slot_0_present;
358  input [7:0] slot_1_present;
359  reg insert_maint_r_lcl;
360  output wire insert_maint_r;
361  assign insert_maint_r = insert_maint_r_lcl;
362 
363  generate begin : generate_maint_cmds
364 
365 // Count up how many slots are occupied. This tells
366 // us how many ZQ, SRE or SRX commands to send out.
367  reg [RANK_WIDTH:0] present_count;
368  wire [7:0] present = slot_0_present | slot_1_present;
369  always @(/*AS**/present) begin
370  present_count = {RANK_WIDTH{1'b0}};
371  for (i=0; i<8; i=i+1)
372  present_count = present_count + {{RANK_WIDTH{1'b0}}, present[i]};
373  end
374 
375 // For refresh, there is only a single command sent. For
376 // ZQ, SRE and SRX, each rank present will receive a command. The counter
377 // below counts down the number of ranks present.
378  reg [RANK_WIDTH:0] send_cnt_ns;
379  reg [RANK_WIDTH:0] send_cnt_r;
380  always @(/*AS**/maint_zq_r or maint_sre_r or maint_srx_r or present_count
381  or rst or send_cnt_r or start_maint)
382  if (rst) send_cnt_ns = 4'b0;
383  else begin
384  send_cnt_ns = send_cnt_r;
385  if (start_maint && (maint_zq_r || maint_sre_r || maint_srx_r)) send_cnt_ns = present_count;
386  if (|send_cnt_ns)
387  send_cnt_ns = send_cnt_ns - ONE[RANK_WIDTH-1:0];
388  end
389  always @(posedge clk) send_cnt_r <= #TCQ send_cnt_ns;
390 
391 // Insert a maintenance command for start_maint, or when the sent count
392 // is not zero.
393  wire insert_maint_ns = start_maint || |send_cnt_r;
394 
395  always @(posedge clk) insert_maint_r_lcl <= #TCQ insert_maint_ns;
396  end // block: generate_maint_cmds
397  endgenerate
398 
399 
400 // RFC ZQ XSDLL timer. Generates delay from refresh, self-refresh exit or ZQ
401 // command until the end of the maintenance operation.
402 
403 // Compute values for RFC, ZQ and XSDLL periods.
404  localparam nRFC_CLKS = (nCK_PER_CLK == 1) ?
405  nRFC :
406  (nCK_PER_CLK == 2) ?
407  ((nRFC/2) + (nRFC%2)) :
408  // (nCK_PER_CLK == 4)
409  ((nRFC/4) + ((nRFC%4) ? 1 : 0));
410 
411  localparam nZQCS_CLKS = (nCK_PER_CLK == 1) ?
412  tZQCS :
413  (nCK_PER_CLK == 2) ?
414  ((tZQCS/2) + (tZQCS%2)) :
415  // (nCK_PER_CLK == 4)
416  ((tZQCS/4) + ((tZQCS%4) ? 1 : 0));
417 
418  localparam nXSDLL_CLKS = (nCK_PER_CLK == 1) ?
419  nXSDLL :
420  (nCK_PER_CLK == 2) ?
421  ((nXSDLL/2) + (nXSDLL%2)) :
422  // (nCK_PER_CLK == 4)
423  ((nXSDLL/4) + ((nXSDLL%4) ? 1 : 0));
424 
425  localparam RFC_ZQ_TIMER_WIDTH = clogb2(nXSDLL_CLKS + 1);
426 
427  localparam THREE = 3;
428 
429  generate begin : rfc_zq_xsdll_timer
430 
431  reg [RFC_ZQ_TIMER_WIDTH-1:0] rfc_zq_xsdll_timer_ns;
432  reg [RFC_ZQ_TIMER_WIDTH-1:0] rfc_zq_xsdll_timer_r;
433 
434  always @(/*AS**/insert_maint_r_lcl or maint_zq_r or maint_sre_r or maint_srx_r
435  or rfc_zq_xsdll_timer_r or rst) begin
436  rfc_zq_xsdll_timer_ns = rfc_zq_xsdll_timer_r;
437  if (rst) rfc_zq_xsdll_timer_ns = {RFC_ZQ_TIMER_WIDTH{1'b0}};
438  else if (insert_maint_r_lcl) rfc_zq_xsdll_timer_ns = maint_zq_r ?
439  nZQCS_CLKS :
440  maint_sre_r ?
441  {RFC_ZQ_TIMER_WIDTH{1'b0}} :
442  maint_srx_r ?
443  nXSDLL_CLKS :
444  nRFC_CLKS;
445  else if (|rfc_zq_xsdll_timer_r) rfc_zq_xsdll_timer_ns =
446  rfc_zq_xsdll_timer_r - ONE[RFC_ZQ_TIMER_WIDTH-1:0];
447  end
448  always @(posedge clk) rfc_zq_xsdll_timer_r <= #TCQ rfc_zq_xsdll_timer_ns;
449 
450 // Based on rfc_zq_xsdll_timer_r, figure out when to release any bank
451 // machines waiting to send an activate. Need to add two to the end count.
452 // One because the counter starts a state after the insert_refresh_r, and
453 // one more because bm_end to insert_refresh_r is one state shorter
454 // than bm_end to rts_row.
455  assign maint_end = (rfc_zq_xsdll_timer_r == THREE[RFC_ZQ_TIMER_WIDTH-1:0]);
456  end // block: rfc_zq_xsdll_timer
457  endgenerate
458 
459 
460 endmodule // bank_common