OpenCores
URL https://opencores.org/ocsvn/usb_fpga_2_14/usb_fpga_2_14/trunk

Subversion Repositories usb_fpga_2_14

[/] [usb_fpga_2_14/] [trunk/] [examples/] [memfifo/] [fpga-2.14/] [memfifo.srcs/] [sources_1/] [ip/] [mig_7series_0/] [mig_7series_0/] [user_design/] [rtl/] [controller/] [mig_7series_v2_3_bank_common.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
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              : 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
 
73
module mig_7series_v2_3_bank_common #
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
260
  mig_7series_v2_3_round_robin_arb #
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.