AMC13
Firmwares for the different applications of the AMC13 uTCA board made at Boston University
 All Classes Variables
mig_7series_v1_9_col_mach.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 : col_mach.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 // The column machine manages the dq bus. Since there is a single DQ
67 // bus, and the column part of the DRAM is tightly coupled to this DQ
68 // bus, conceptually, the DQ bus and all of the column hardware in
69 // a multi rank DRAM array are managed as a single unit.
70 //
71 //
72 // The column machine does not "enforce" the column timing directly.
73 // It generates information and sends it to the bank machines. If the
74 // bank machines incorrectly make a request, the column machine will
75 // simply overwrite the existing request with the new request even
76 // if this would result in a timing or protocol violation.
77 //
78 // The column machine
79 // hosts the block that controls read and write data transfer
80 // to and from the dq bus.
81 //
82 // And if configured, there is provision for tracking the address
83 // of a command as it moves through the column pipeline. This
84 // address will be logged for detected ECC errors.
85 
86 `timescale 1 ps / 1 ps
87 
89  (
90  parameter TCQ = 100,
91  parameter BANK_WIDTH = 3,
92  parameter BURST_MODE = "8",
93  parameter COL_WIDTH = 12,
94  parameter CS_WIDTH = 4,
95  parameter DATA_BUF_ADDR_WIDTH = 8,
96  parameter DATA_BUF_OFFSET_WIDTH = 1,
97  parameter DELAY_WR_DATA_CNTRL = 0,
98  parameter DQS_WIDTH = 8,
99  parameter DRAM_TYPE = "DDR3",
100  parameter EARLY_WR_DATA_ADDR = "OFF",
101  parameter ECC = "OFF",
102  parameter MC_ERR_ADDR_WIDTH = 31,
103  parameter nCK_PER_CLK = 2,
104  parameter nPHY_WRLAT = 0,
105  parameter RANK_WIDTH = 2,
106  parameter ROW_WIDTH = 16
107  )
108  (/*AUTOARG**/
109  // Outputs
110  dq_busy_data, wr_data_offset, mc_wrdata_en, wr_data_en,
111  wr_data_addr, rd_rmw, ecc_err_addr, ecc_status_valid, wr_ecc_buf, rd_data_end,
112  rd_data_addr, rd_data_offset, rd_data_en, col_read_fifo_empty,
113  // Inputs
114  clk, rst, sent_col, col_size, col_wr_data_buf_addr,
115  phy_rddata_valid, col_periodic_rd, col_data_buf_addr, col_rmw,
116  col_rd_wr, col_ra, col_ba, col_row, col_a
117  );
118 
119  input clk;
120  input rst;
121 
122  input sent_col;
123  input col_rd_wr;
124 
125  output reg dq_busy_data = 1'b0;
126 
127 // The following generates a column command disable based mostly on the type
128 // of DRAM and the fabric to DRAM CK ratio.
129  generate
130  if ((nCK_PER_CLK == 1) && ((BURST_MODE == "8") || (DRAM_TYPE == "DDR3")))
131  begin : three_bumps
132  reg [1:0] granted_col_d_r;
133  wire [1:0] granted_col_d_ns = {sent_col, granted_col_d_r[1]};
134  always @(posedge clk) granted_col_d_r <= #TCQ granted_col_d_ns;
135  always @(/*AS**/granted_col_d_r or sent_col)
136  dq_busy_data = sent_col || |granted_col_d_r;
137  end
138  if (((nCK_PER_CLK == 2) && ((BURST_MODE == "8") || (DRAM_TYPE == "DDR3")))
139  || ((nCK_PER_CLK == 1) && ((BURST_MODE == "4") || (DRAM_TYPE == "DDR2"))))
140  begin : one_bump
141  always @(/*AS**/sent_col) dq_busy_data = sent_col;
142  end
143  endgenerate
144 
145 // This generates a data offset based on fabric clock to DRAM CK ratio and
146 // the size bit. Note that this is different that the dq_busy_data signal
147 // generated above.
148  reg [1:0] offset_r = 2'b0;
149  reg [1:0] offset_ns = 2'b0;
150 
151  input col_size;
152  wire data_end;
153  generate
154 
155  if(nCK_PER_CLK == 4) begin : data_valid_4_1
156 
157  // For 4:1 mode all data is transfered in a single beat so the default
158  // values of 0 for offset_r/offset_ns suffice - just tie off data_end
159  assign data_end = 1'b1;
160 
161  end
162 
163  else begin
164 
165  if(DATA_BUF_OFFSET_WIDTH == 2) begin : data_valid_1_1
166 
167  always @(col_size or offset_r or rst or sent_col) begin
168  if (rst) offset_ns = 2'b0;
169  else begin
170  offset_ns = offset_r;
171  if (sent_col) offset_ns = 2'b1;
172  else if (|offset_r && (offset_r != {col_size, 1'b1}))
173  offset_ns = offset_r + 2'b1;
174  else offset_ns = 2'b0;
175  end
176 
177  end
178 
179  always @(posedge clk) offset_r <= #TCQ offset_ns;
180  assign data_end = col_size ? (offset_r == 2'b11) : offset_r[0];
181 
182  end
183 
184  else begin : data_valid_2_1
185 
186  always @(col_size or rst or sent_col)
187  offset_ns[0] = rst ? 1'b0 : sent_col && col_size;
188  always @(posedge clk) offset_r[0] <= #TCQ offset_ns[0];
189  assign data_end = col_size ? offset_r[0] : 1'b1;
190 
191  end
192 
193  end
194 
195  endgenerate
196 
197  reg [DATA_BUF_OFFSET_WIDTH-1:0] offset_r1 = {DATA_BUF_OFFSET_WIDTH{1'b0}};
198  reg [DATA_BUF_OFFSET_WIDTH-1:0] offset_r2 = {DATA_BUF_OFFSET_WIDTH{1'b0}};
199  reg col_rd_wr_r1;
200  reg col_rd_wr_r2;
201  generate
202  if ((nPHY_WRLAT >= 1) || (DELAY_WR_DATA_CNTRL == 1)) begin : offset_pipe_0
203  always @(posedge clk) offset_r1 <=
204  #TCQ offset_r[DATA_BUF_OFFSET_WIDTH-1:0];
205  always @(posedge clk) col_rd_wr_r1 <= #TCQ col_rd_wr;
206  end
207  if(nPHY_WRLAT == 2) begin : offset_pipe_1
208  always @(posedge clk) offset_r2 <=
209  #TCQ offset_r1[DATA_BUF_OFFSET_WIDTH-1:0];
210  always @(posedge clk) col_rd_wr_r2 <= #TCQ col_rd_wr_r1;
211  end
212  endgenerate
213 
214  output wire [DATA_BUF_OFFSET_WIDTH-1:0] wr_data_offset;
215  assign wr_data_offset = (DELAY_WR_DATA_CNTRL == 1)
216  ? offset_r1[DATA_BUF_OFFSET_WIDTH-1:0]
217  : (EARLY_WR_DATA_ADDR == "OFF")
218  ? offset_r[DATA_BUF_OFFSET_WIDTH-1:0]
219  : offset_ns[DATA_BUF_OFFSET_WIDTH-1:0];
220 
221  reg sent_col_r1;
222  reg sent_col_r2;
223  always @(posedge clk) sent_col_r1 <= #TCQ sent_col;
224  always @(posedge clk) sent_col_r2 <= #TCQ sent_col_r1;
225 
226  wire wrdata_en = (nPHY_WRLAT == 0) ?
227  (sent_col || |offset_r) & ~col_rd_wr :
228  (nPHY_WRLAT == 1) ?
229  (sent_col_r1 || |offset_r1) & ~col_rd_wr_r1 :
230  //(nPHY_WRLAT >= 2) ?
231  (sent_col_r2 || |offset_r2) & ~col_rd_wr_r2;
232 
233  output wire mc_wrdata_en;
234  assign mc_wrdata_en = wrdata_en;
235 
236  output wire wr_data_en;
237  assign wr_data_en = (DELAY_WR_DATA_CNTRL == 1)
238  ? ((sent_col_r1 || |offset_r1) && ~col_rd_wr_r1)
239  : ((sent_col || |offset_r) && ~col_rd_wr);
240 
241 
242  input [DATA_BUF_ADDR_WIDTH-1:0] col_wr_data_buf_addr;
243  output wire [DATA_BUF_ADDR_WIDTH-1:0] wr_data_addr;
244  generate
245  if (DELAY_WR_DATA_CNTRL == 1) begin : delay_wr_data_cntrl_eq_1
246  reg [DATA_BUF_ADDR_WIDTH-1:0] col_wr_data_buf_addr_r;
247  always @(posedge clk) col_wr_data_buf_addr_r <=
248  #TCQ col_wr_data_buf_addr;
249  assign wr_data_addr = col_wr_data_buf_addr_r;
250  end
251  else begin : delay_wr_data_cntrl_ne_1
252  assign wr_data_addr = col_wr_data_buf_addr;
253  end
254  endgenerate
255 
256 // CAS-RD to mc_rddata_en
257 
258  wire read_data_valid = (sent_col || |offset_r) && col_rd_wr;
259 
260 function integer clogb2 (input integer size); // ceiling logb2
261  begin
262  size = size - 1;
263  for (clogb2=1; size>1; clogb2=clogb2+1)
264  size = size >> 1;
265  end
266 endfunction // clogb2
267 
268 // Implement FIFO that records reads as they are sent to the DRAM.
269 // When phy_rddata_valid is returned some unknown time later, the
270 // FIFO output is used to control how the data is interpreted.
271 
272  input phy_rddata_valid;
273  output wire rd_rmw;
274  output reg [MC_ERR_ADDR_WIDTH-1:0] ecc_err_addr;
275  output reg ecc_status_valid;
276  output reg wr_ecc_buf;
277  output reg rd_data_end;
278  output reg [DATA_BUF_ADDR_WIDTH-1:0] rd_data_addr;
279  output reg [DATA_BUF_OFFSET_WIDTH-1:0] rd_data_offset;
280  (* keep = "true", max_fanout = 10 *) output reg rd_data_en /* synthesis syn_maxfan = 10 **/;
281  output col_read_fifo_empty;
282 
283  input col_periodic_rd;
284  input [DATA_BUF_ADDR_WIDTH-1:0] col_data_buf_addr;
285  input col_rmw;
286  input [RANK_WIDTH-1:0] col_ra;
287  input [BANK_WIDTH-1:0] col_ba;
288  input [ROW_WIDTH-1:0] col_row;
289  input [ROW_WIDTH-1:0] col_a;
290 
291  // Real column address (skip A10/AP and A12/BC#). The maximum width is 12;
292  // the width will be tailored for the target DRAM downstream.
293  wire [11:0] col_a_full;
294 
295  // Minimum row width is 12; take remaining 11 bits after omitting A10/AP
296  assign col_a_full[10:0] = {col_a[11], col_a[9:0]};
297 
298  // Get the 12th bit when row address width accommodates it; omit A12/BC#
299  generate
300  if (ROW_WIDTH >= 14) begin : COL_A_FULL_11_1
301  assign col_a_full[11] = col_a[13];
302  end else begin : COL_A_FULL_11_0
303  assign col_a_full[11] = 0;
304  end
305  endgenerate
306 
307  // Extract only the width of the target DRAM
308  wire [COL_WIDTH-1:0] col_a_extracted = col_a_full[COL_WIDTH-1:0];
309 
310  localparam MC_ERR_LINE_WIDTH = MC_ERR_ADDR_WIDTH-DATA_BUF_OFFSET_WIDTH;
311  localparam FIFO_WIDTH = 1 /*data_end**/ +
312  1 /*periodic_rd**/ +
313  DATA_BUF_ADDR_WIDTH +
314  DATA_BUF_OFFSET_WIDTH +
315  ((ECC == "OFF") ? 0 : 1+MC_ERR_LINE_WIDTH);
316  localparam FULL_RAM_CNT = (FIFO_WIDTH/6);
317  localparam REMAINDER = FIFO_WIDTH % 6;
318  localparam RAM_CNT = FULL_RAM_CNT + ((REMAINDER == 0 ) ? 0 : 1);
319  localparam RAM_WIDTH = (RAM_CNT*6);
320 
321  generate
322  begin : read_fifo
323 
324  wire [MC_ERR_LINE_WIDTH:0] ecc_line;
325  if (CS_WIDTH == 1)
326  assign ecc_line = {col_rmw, col_ba, col_row, col_a_extracted};
327  else
328  assign ecc_line = {col_rmw,
329  col_ra,
330  col_ba,
331  col_row,
332  col_a_extracted};
333 
334  wire [FIFO_WIDTH-1:0] real_fifo_data;
335  if (ECC == "OFF")
336  assign real_fifo_data = {data_end,
337  col_periodic_rd,
338  col_data_buf_addr,
339  offset_r[DATA_BUF_OFFSET_WIDTH-1:0]};
340  else
341  assign real_fifo_data = {data_end,
342  col_periodic_rd,
343  col_data_buf_addr,
344  offset_r[DATA_BUF_OFFSET_WIDTH-1:0],
345  ecc_line};
346 
347  wire [RAM_WIDTH-1:0] fifo_in_data;
348  if (REMAINDER == 0)
349  assign fifo_in_data = real_fifo_data;
350  else
351  assign fifo_in_data = {{6-REMAINDER{1'b0}}, real_fifo_data};
352 
353  wire [RAM_WIDTH-1:0] fifo_out_data_ns;
354 
355  reg [4:0] head_r;
356  wire [4:0] head_ns = rst ? 5'b0 : read_data_valid
357  ? (head_r + 5'b1)
358  : head_r;
359  always @(posedge clk) head_r <= #TCQ head_ns;
360 
361 
362  reg [4:0] tail_r;
363  wire [4:0] tail_ns = rst ? 5'b0 : phy_rddata_valid
364  ? (tail_r + 5'b1)
365  : tail_r;
366  always @(posedge clk) tail_r <= #TCQ tail_ns;
367 
368  assign col_read_fifo_empty = head_r == tail_r ? 1'b1 : 1'b0;
369 
370  genvar i;
371  for (i=0; i<RAM_CNT; i=i+1) begin : fifo_ram
372  RAM32M
373  #(.INIT_A(64'h0000000000000000),
374  .INIT_B(64'h0000000000000000),
375  .INIT_C(64'h0000000000000000),
376  .INIT_D(64'h0000000000000000)
377  ) RAM32M0 (
378  .DOA(fifo_out_data_ns[((i*6)+4)+:2]),
379  .DOB(fifo_out_data_ns[((i*6)+2)+:2]),
380  .DOC(fifo_out_data_ns[((i*6)+0)+:2]),
381  .DOD(),
382  .DIA(fifo_in_data[((i*6)+4)+:2]),
383  .DIB(fifo_in_data[((i*6)+2)+:2]),
384  .DIC(fifo_in_data[((i*6)+0)+:2]),
385  .DID(2'b0),
386  .ADDRA(tail_ns),
387  .ADDRB(tail_ns),
388  .ADDRC(tail_ns),
389  .ADDRD(head_r),
390  .WE(1'b1),
391  .WCLK(clk)
392  );
393  end // block: fifo_ram
394 
395  reg [RAM_WIDTH-1:0] fifo_out_data_r;
396  always @(posedge clk) fifo_out_data_r <= #TCQ fifo_out_data_ns;
397 
398 // When ECC is ON, most of the FIFO output is delayed
399 // by one state.
400  if (ECC == "OFF") begin
401  reg periodic_rd;
402  always @(/*AS**/phy_rddata_valid or fifo_out_data_r) begin
403  {rd_data_end,
404  periodic_rd,
405  rd_data_addr,
406  rd_data_offset} = fifo_out_data_r[FIFO_WIDTH-1:0];
407  ecc_err_addr = {MC_ERR_ADDR_WIDTH{1'b0}};
408  rd_data_en = phy_rddata_valid && ~periodic_rd;
409  ecc_status_valid = 1'b0;
410  wr_ecc_buf = 1'b0;
411  end
412  assign rd_rmw = 1'b0;
413  end
414  else begin
415  wire rd_data_end_ns;
416  wire periodic_rd;
417  wire [DATA_BUF_ADDR_WIDTH-1:0] rd_data_addr_ns;
418  wire [DATA_BUF_OFFSET_WIDTH-1:0] rd_data_offset_ns;
419  wire [MC_ERR_ADDR_WIDTH-1:0] ecc_err_addr_ns;
420  assign {rd_data_end_ns,
421  periodic_rd,
422  rd_data_addr_ns,
423  rd_data_offset_ns,
424  rd_rmw,
425  ecc_err_addr_ns[DATA_BUF_OFFSET_WIDTH+:MC_ERR_LINE_WIDTH]} =
426  {fifo_out_data_r[FIFO_WIDTH-1:0]};
427  assign ecc_err_addr_ns[0+:DATA_BUF_OFFSET_WIDTH] = rd_data_offset_ns;
428  always @(posedge clk) rd_data_end <= #TCQ rd_data_end_ns;
429  always @(posedge clk) rd_data_addr <= #TCQ rd_data_addr_ns;
430  always @(posedge clk) rd_data_offset <= #TCQ rd_data_offset_ns;
431  always @(posedge clk) ecc_err_addr <= #TCQ ecc_err_addr_ns;
432  wire rd_data_en_ns = phy_rddata_valid && ~(periodic_rd || rd_rmw);
433  always @(posedge clk) rd_data_en <= rd_data_en_ns;
434  wire ecc_status_valid_ns = phy_rddata_valid && ~periodic_rd;
435  always @(posedge clk) ecc_status_valid <= #TCQ ecc_status_valid_ns;
436  wire wr_ecc_buf_ns = phy_rddata_valid && ~periodic_rd && rd_rmw;
437  always @(posedge clk) wr_ecc_buf <= #TCQ wr_ecc_buf_ns;
438  end
439  end
440  endgenerate
441 
442 endmodule