URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2/boards/xilinx/ml501/rtl
- from Rev 412 to Rev 69
- ↔ Reverse comparison
Rev 412 → Rev 69
/verilog/orpsoc_top/orpsoc_top.v
File deleted
/verilog/arbiter/arbiter_dbus.v
File deleted
/verilog/arbiter/arbiter_bytebus.v
File deleted
/verilog/arbiter/arbiter_ibus.v
File deleted
/verilog/gpio/README
File deleted
/verilog/gpio/gpio.v
File deleted
/verilog/xilinx_ssram/xilinx_ssram.v
File deleted
/verilog/include/orpsoc-params.v
File deleted
/verilog/include/uart_defines.v
File deleted
/verilog/include/xilinx_ddr2_params.v
File deleted
/verilog/include/dbg_defines.v
File deleted
/verilog/include/ethmac_defines.v
File deleted
\ No newline at end of file
/verilog/include/i2c_master_slave_defines.v
File deleted
/verilog/include/orpsoc-defines.v
File deleted
/verilog/include/dbg_cpu_defines.v
File deleted
/verilog/include/or1200_defines.v
File deleted
/verilog/include/tap_defines.v
File deleted
/verilog/include/dbg_wb_defines.v
File deleted
/verilog/clkgen/clkgen.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_io.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_ctl_io.v
File deleted
/verilog/xilinx_ddr2/xilinx_ddr2_if.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_calib.v
File deleted
/verilog/xilinx_ddr2/ddr2_idelay_ctrl.v
File deleted
/verilog/xilinx_ddr2/ddr2_usr_top.v
File deleted
\ No newline at end of file
/verilog/xilinx_ddr2/ddr2_usr_rd.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_dqs_iob.v
File deleted
/verilog/xilinx_ddr2/ddr2_top.v
File deleted
/verilog/xilinx_ddr2/ddr2_ctrl.v
File deleted
/verilog/xilinx_ddr2/ddr2_usr_addr_fifo.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_dm_iob.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_write.v
File deleted
/verilog/xilinx_ddr2/xilinx_ddr2.v
File deleted
/verilog/xilinx_ddr2/ddr2_mig.v
File deleted
/verilog/xilinx_ddr2/xilinx_ddr2_if_cache.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_dq_iob.v
File deleted
/verilog/xilinx_ddr2/ddr2_chipscope.v
File deleted
\ No newline at end of file
/verilog/xilinx_ddr2/README
File deleted
/verilog/xilinx_ddr2/ddr2_mem_if_top.v
File deleted
/verilog/xilinx_ddr2/ddr2_infrastructure.v
File deleted
/verilog/xilinx_ddr2/ddr2_usr_wr.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_top.v
File deleted
/verilog/xilinx_ddr2/ddr2_phy_init.v
File deleted
/verilog/lfsr/lfsr.v
File deleted
/eth_defines.v
0,0 → 1,340
////////////////////////////////////////////////////////////////////// |
//// //// |
//// eth_defines.v //// |
//// //// |
//// This file is part of the Ethernet IP core project //// |
//// http://www.opencores.org/projects/ethmac/ //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorM@opencores.org) //// |
//// //// |
//// All additional information is available in the Readme.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001, 2002 Authors //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: eth_defines.v,v $ |
// Revision 1.34 2005/02/21 12:48:06 igorm |
// Warning fixes. |
// |
// Revision 1.33 2003/11/12 18:24:58 tadejm |
// WISHBONE slave changed and tested from only 32-bit accesss to byte access. |
// |
// Revision 1.32 2003/10/17 07:46:13 markom |
// mbist signals updated according to newest convention |
// |
// Revision 1.31 2003/08/14 16:42:58 simons |
// Artisan ram instance added. |
// |
// Revision 1.30 2003/06/13 11:55:37 mohor |
// Define file in eth_cop.v is changed to eth_defines.v. Some defines were |
// moved from tb_eth_defines.v to eth_defines.v. |
// |
// Revision 1.29 2002/11/19 18:13:49 mohor |
// r_MiiMRst is not used for resetting the MIIM module. wb_rst used instead. |
// |
// Revision 1.28 2002/11/15 14:27:15 mohor |
// Since r_Rst bit is not used any more, default value is changed to 0xa000. |
// |
// Revision 1.27 2002/11/01 18:19:34 mohor |
// Defines fixed to use generic RAM by default. |
// |
// Revision 1.26 2002/10/24 18:53:03 mohor |
// fpga define added. |
// |
// Revision 1.3 2002/10/11 16:57:54 igorm |
// eth_defines.v tagged with rel_5 used. |
// |
// Revision 1.25 2002/10/10 16:47:44 mohor |
// Defines changed to have ETH_ prolog. |
// ETH_WISHBONE_B# define added. |
// |
// Revision 1.24 2002/10/10 16:33:11 mohor |
// Bist added. |
// |
// Revision 1.23 2002/09/23 18:22:48 mohor |
// Virtual Silicon RAM might be used in the ASIC implementation of the ethernet |
// core. |
// |
// Revision 1.22 2002/09/04 18:36:49 mohor |
// Defines for control registers added (ETH_TXCTRL and ETH_RXCTRL). |
// |
// Revision 1.21 2002/08/16 22:09:47 mohor |
// Defines for register width added. mii_rst signal in MIIMODER register |
// changed. |
// |
// Revision 1.20 2002/08/14 19:31:48 mohor |
// Register TX_BD_NUM is changed so it contains value of the Tx buffer descriptors. No |
// need to multiply or devide any more. |
// |
// Revision 1.19 2002/07/23 15:28:31 mohor |
// Ram , used for BDs changed from generic_spram to eth_spram_256x32. |
// |
// Revision 1.18 2002/05/03 10:15:50 mohor |
// Outputs registered. Reset changed for eth_wishbone module. |
// |
// Revision 1.17 2002/04/24 08:52:19 mohor |
// Compiler directives added. Tx and Rx fifo size incremented. A "late collision" |
// bug fixed. |
// |
// Revision 1.16 2002/03/19 12:53:29 mohor |
// Some defines that are used in testbench only were moved to tb_eth_defines.v |
// file. |
// |
// Revision 1.15 2002/02/26 16:11:32 mohor |
// Number of interrupts changed |
// |
// Revision 1.14 2002/02/16 14:03:44 mohor |
// Registered trimmed. Unused registers removed. |
// |
// Revision 1.13 2002/02/16 13:06:33 mohor |
// EXTERNAL_DMA used instead of WISHBONE_DMA. |
// |
// Revision 1.12 2002/02/15 10:58:31 mohor |
// Changed that were lost with last update put back to the file. |
// |
// Revision 1.11 2002/02/14 20:19:41 billditt |
// Modified for Address Checking, |
// addition of eth_addrcheck.v |
// |
// Revision 1.10 2002/02/12 17:01:19 mohor |
// HASH0 and HASH1 registers added. |
|
// Revision 1.9 2002/02/08 16:21:54 mohor |
// Rx status is written back to the BD. |
// |
// Revision 1.8 2002/02/05 16:44:38 mohor |
// Both rx and tx part are finished. Tested with wb_clk_i between 10 and 200 |
// MHz. Statuses, overrun, control frame transmission and reception still need |
// to be fixed. |
// |
// Revision 1.7 2002/01/23 10:28:16 mohor |
// Link in the header changed. |
// |
// Revision 1.6 2001/12/05 15:00:16 mohor |
// RX_BD_NUM changed to TX_BD_NUM (holds number of TX descriptors |
// instead of the number of RX descriptors). |
// |
// Revision 1.5 2001/12/05 10:21:37 mohor |
// ETH_RX_BD_ADR register deleted. ETH_RX_BD_NUM is used instead. |
// |
// Revision 1.4 2001/11/13 14:23:56 mohor |
// Generic memory model is used. Defines are changed for the same reason. |
// |
// Revision 1.3 2001/10/18 12:07:11 mohor |
// Status signals changed, Adress decoding changed, interrupt controller |
// added. |
// |
// Revision 1.2 2001/09/24 15:02:56 mohor |
// Defines changed (All precede with ETH_). Small changes because some |
// tools generate warnings when two operands are together. Synchronization |
// between two clocks domains in eth_wishbonedma.v is changed (due to ASIC |
// demands). |
// |
// Revision 1.1 2001/08/06 14:44:29 mohor |
// A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). |
// Include files fixed to contain no path. |
// File names and module names changed ta have a eth_ prologue in the name. |
// File eth_timescale.v is used to define timescale |
// All pin names on the top module are changed to contain _I, _O or _OE at the end. |
// Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O |
// and Mdo_OE. The bidirectional signal must be created on the top level. This |
// is done due to the ASIC tools. |
// |
// Revision 1.1 2001/07/30 21:23:42 mohor |
// Directory structure changed. Files checked and joind together. |
// |
// |
// |
// |
// |
|
|
|
//`define ETH_BIST // Bist for usage with Virtual Silicon RAMS |
|
`define ETH_MBIST_CTRL_WIDTH 3 // width of MBIST control bus |
|
// Ethernet implemented in Xilinx Chips (uncomment following lines) |
// `define ETH_FIFO_XILINX // Use Xilinx distributed ram for tx and rx fifo |
// `define ETH_XILINX_RAMB4 // Selection of the used memory for Buffer descriptors |
// Core is going to be implemented in Virtex FPGA and contains Virtex |
// specific elements. |
|
// Ethernet implemented in Altera Chips (uncomment following lines) |
//`define ETH_ALTERA_ALTSYNCRAM |
|
// Ethernet implemented in ASIC with Virtual Silicon RAMs |
// `define ETH_VIRTUAL_SILICON_RAM // Virtual Silicon RAMS used storing buffer decriptors (ASIC implementation) |
|
// Ethernet implemented in ASIC with Artisan RAMs |
// `define ETH_ARTISAN_RAM // Artisan RAMS used storing buffer decriptors (ASIC implementation) |
|
// Uncomment when Avalon bus is used |
//`define ETH_AVALON_BUS |
|
`define ETH_MODER_ADR 8'h0 // 0x0 |
`define ETH_INT_SOURCE_ADR 8'h1 // 0x4 |
`define ETH_INT_MASK_ADR 8'h2 // 0x8 |
`define ETH_IPGT_ADR 8'h3 // 0xC |
`define ETH_IPGR1_ADR 8'h4 // 0x10 |
`define ETH_IPGR2_ADR 8'h5 // 0x14 |
`define ETH_PACKETLEN_ADR 8'h6 // 0x18 |
`define ETH_COLLCONF_ADR 8'h7 // 0x1C |
`define ETH_TX_BD_NUM_ADR 8'h8 // 0x20 |
`define ETH_CTRLMODER_ADR 8'h9 // 0x24 |
`define ETH_MIIMODER_ADR 8'hA // 0x28 |
`define ETH_MIICOMMAND_ADR 8'hB // 0x2C |
`define ETH_MIIADDRESS_ADR 8'hC // 0x30 |
`define ETH_MIITX_DATA_ADR 8'hD // 0x34 |
`define ETH_MIIRX_DATA_ADR 8'hE // 0x38 |
`define ETH_MIISTATUS_ADR 8'hF // 0x3C |
`define ETH_MAC_ADDR0_ADR 8'h10 // 0x40 |
`define ETH_MAC_ADDR1_ADR 8'h11 // 0x44 |
`define ETH_HASH0_ADR 8'h12 // 0x48 |
`define ETH_HASH1_ADR 8'h13 // 0x4C |
`define ETH_TX_CTRL_ADR 8'h14 // 0x50 |
`define ETH_RX_CTRL_ADR 8'h15 // 0x54 |
|
|
`define ETH_MODER_DEF_0 8'h00 |
`define ETH_MODER_DEF_1 8'hA0 |
`define ETH_MODER_DEF_2 1'h0 |
`define ETH_INT_MASK_DEF_0 7'h0 |
`define ETH_IPGT_DEF_0 7'h12 |
`define ETH_IPGR1_DEF_0 7'h0C |
`define ETH_IPGR2_DEF_0 7'h12 |
`define ETH_PACKETLEN_DEF_0 8'h00 |
`define ETH_PACKETLEN_DEF_1 8'h06 |
`define ETH_PACKETLEN_DEF_2 8'h40 |
`define ETH_PACKETLEN_DEF_3 8'h00 |
`define ETH_COLLCONF_DEF_0 6'h3f |
`define ETH_COLLCONF_DEF_2 4'hF |
`define ETH_TX_BD_NUM_DEF_0 8'h40 |
`define ETH_CTRLMODER_DEF_0 3'h0 |
`define ETH_MIIMODER_DEF_0 8'h64 |
`define ETH_MIIMODER_DEF_1 1'h0 |
`define ETH_MIIADDRESS_DEF_0 5'h00 |
`define ETH_MIIADDRESS_DEF_1 5'h00 |
`define ETH_MIITX_DATA_DEF_0 8'h00 |
`define ETH_MIITX_DATA_DEF_1 8'h00 |
`define ETH_MIIRX_DATA_DEF 16'h0000 // not written from WB |
`define ETH_MAC_ADDR0_DEF_0 8'h00 |
`define ETH_MAC_ADDR0_DEF_1 8'h00 |
`define ETH_MAC_ADDR0_DEF_2 8'h00 |
`define ETH_MAC_ADDR0_DEF_3 8'h00 |
`define ETH_MAC_ADDR1_DEF_0 8'h00 |
`define ETH_MAC_ADDR1_DEF_1 8'h00 |
`define ETH_HASH0_DEF_0 8'h00 |
`define ETH_HASH0_DEF_1 8'h00 |
`define ETH_HASH0_DEF_2 8'h00 |
`define ETH_HASH0_DEF_3 8'h00 |
`define ETH_HASH1_DEF_0 8'h00 |
`define ETH_HASH1_DEF_1 8'h00 |
`define ETH_HASH1_DEF_2 8'h00 |
`define ETH_HASH1_DEF_3 8'h00 |
`define ETH_TX_CTRL_DEF_0 8'h00 // |
`define ETH_TX_CTRL_DEF_1 8'h00 // |
`define ETH_TX_CTRL_DEF_2 1'h0 // |
`define ETH_RX_CTRL_DEF_0 8'h00 |
`define ETH_RX_CTRL_DEF_1 8'h00 |
|
|
`define ETH_MODER_WIDTH_0 8 |
`define ETH_MODER_WIDTH_1 8 |
`define ETH_MODER_WIDTH_2 1 |
`define ETH_INT_SOURCE_WIDTH_0 7 |
`define ETH_INT_MASK_WIDTH_0 7 |
`define ETH_IPGT_WIDTH_0 7 |
`define ETH_IPGR1_WIDTH_0 7 |
`define ETH_IPGR2_WIDTH_0 7 |
`define ETH_PACKETLEN_WIDTH_0 8 |
`define ETH_PACKETLEN_WIDTH_1 8 |
`define ETH_PACKETLEN_WIDTH_2 8 |
`define ETH_PACKETLEN_WIDTH_3 8 |
`define ETH_COLLCONF_WIDTH_0 6 |
`define ETH_COLLCONF_WIDTH_2 4 |
`define ETH_TX_BD_NUM_WIDTH_0 8 |
`define ETH_CTRLMODER_WIDTH_0 3 |
`define ETH_MIIMODER_WIDTH_0 8 |
`define ETH_MIIMODER_WIDTH_1 1 |
`define ETH_MIICOMMAND_WIDTH_0 3 |
`define ETH_MIIADDRESS_WIDTH_0 5 |
`define ETH_MIIADDRESS_WIDTH_1 5 |
`define ETH_MIITX_DATA_WIDTH_0 8 |
`define ETH_MIITX_DATA_WIDTH_1 8 |
`define ETH_MIIRX_DATA_WIDTH 16 // not written from WB |
`define ETH_MIISTATUS_WIDTH 3 // not written from WB |
`define ETH_MAC_ADDR0_WIDTH_0 8 |
`define ETH_MAC_ADDR0_WIDTH_1 8 |
`define ETH_MAC_ADDR0_WIDTH_2 8 |
`define ETH_MAC_ADDR0_WIDTH_3 8 |
`define ETH_MAC_ADDR1_WIDTH_0 8 |
`define ETH_MAC_ADDR1_WIDTH_1 8 |
`define ETH_HASH0_WIDTH_0 8 |
`define ETH_HASH0_WIDTH_1 8 |
`define ETH_HASH0_WIDTH_2 8 |
`define ETH_HASH0_WIDTH_3 8 |
`define ETH_HASH1_WIDTH_0 8 |
`define ETH_HASH1_WIDTH_1 8 |
`define ETH_HASH1_WIDTH_2 8 |
`define ETH_HASH1_WIDTH_3 8 |
`define ETH_TX_CTRL_WIDTH_0 8 |
`define ETH_TX_CTRL_WIDTH_1 8 |
`define ETH_TX_CTRL_WIDTH_2 1 |
`define ETH_RX_CTRL_WIDTH_0 8 |
`define ETH_RX_CTRL_WIDTH_1 8 |
|
|
// Outputs are registered (uncomment when needed) |
`define ETH_REGISTERED_OUTPUTS |
|
// Settings for TX FIFO |
//`define ETH_TX_FIFO_CNT_WIDTH 5 |
//`define ETH_TX_FIFO_DEPTH 16 |
// Settings for TX FIFO buffer for a while ethernet packet (1500 bytes) |
`define ETH_TX_FIFO_CNT_WIDTH 9 |
`define ETH_TX_FIFO_DEPTH 375 |
`define ETH_TX_FIFO_DATA_WIDTH 32 |
|
// Settings for RX FIFO |
`define ETH_RX_FIFO_CNT_WIDTH 5 |
`define ETH_RX_FIFO_DEPTH 16 |
`define ETH_RX_FIFO_DATA_WIDTH 32 |
|
// Burst length |
`define ETH_BURST_LENGTH 4 // Change also ETH_BURST_CNT_WIDTH |
`define ETH_BURST_CNT_WIDTH 3 // The counter must be width enough to count to ETH_BURST_LENGTH |
|
// WISHBONE interface is Revision B3 compliant (uncomment when needed) |
`define ETH_WISHBONE_B3 |
|
// TXBuffer Polling enable |
`define POLL_TXBDS |
/ml501_mc.v
0,0 → 1,295
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx ML501 Memory controller Wishbone Interface //// |
//// //// |
//// Description //// |
//// Module which can instantiate the different external memory //// |
//// control modules, as well as the internal BRAMS. //// |
//// //// |
//// To Do: //// |
//// Fix the addressing (letting internal SRAMs take lowest //// |
//// addresses, followed by next biggest memory server, ect) //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
/* Memory and memory control module for ml501 board */ |
`include "ml501_defines.v" |
module ml501_mc |
( |
input [31:0] wb_adr_i, |
input wb_stb_i, |
input wb_cyc_i, |
input wb_we_i, |
input [3:0] wb_sel_i, |
input [31:0] wb_dat_i, |
output [31:0] wb_dat_o, |
output wb_ack_o, |
|
`ifdef ML501_MEMORY_SSRAM |
output sram_clk, |
input sram_clk_fb, |
output [21:1] sram_addr, |
inout [31:0] sram_dq_io, |
output sram_ce_l, |
output sram_oe_l, |
output sram_we_l, |
output [3:0] sram_bw_l, |
output sram_adv_ld_l, |
output sram_mode, |
`endif // `ifdef ML501_MEMORY_SSRAM |
|
`ifdef ML501_MEMORY_DDR2 |
|
output [12:0] ddr2_a, |
output [1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output [1:0] ddr2_cs_n, |
output [1:0] ddr2_odt, |
output [1:0] ddr2_cke, |
output [7:0] ddr2_dm, |
|
inout [63:0] ddr2_dq, |
inout [7:0] ddr2_dqs, |
inout [7:0] ddr2_dqs_n, |
output [1:0] ddr2_ck, |
output [1:0] ddr2_ck_n, |
|
input ddr2_if_clk, |
`endif // `ifdef ML501_MEMORY_DDR2 |
|
input clk_200, |
input wb_clk, |
input wb_rst); |
|
`ifdef ML501_MEMORY_STARTUP |
parameter startup_size = `ML501_MEMORY_STARTUP_ADDR_SPAN; |
`else |
parameter startup_size = 0; |
`endif |
|
wire [31:0] wbs_strtup_dat_o; |
wire [31:0] wbs_strtup_dat_i; |
wire [31:0] wbs_strtup_adr_i; |
wire [3:0] wbs_strtup_sel_i; |
wire wbs_strtup_stb_i; |
wire wbs_strtup_cyc_i; |
wire wbs_strtup_ack_o; |
parameter wbs_strtup_err_o = 1'b0; |
|
wire [31:0] wbs_mc_dat_o; |
wire [31:0] wbs_mc_dat_i; |
wire [31:0] wbs_mc_adr_i; |
wire [3:0] wbs_mc_sel_i; |
wire [2:0] wbs_mc_cti_i; |
wire wbs_mc_stb_i; |
wire wbs_mc_cyc_i; |
wire wbs_mc_ack_o; |
parameter wbs_mc_err_o = 1'b0; |
|
wire mem_sel; |
|
// In to startup memory |
assign wbs_strtup_adr_i = wb_adr_i; |
assign wbs_strtup_dat_i = wb_dat_i; |
assign wbs_strtup_sel_i = wb_sel_i; |
assign wbs_strtup_cyc_i = wb_cyc_i; |
assign wbs_strtup_we_i = wb_we_i; |
|
// In to larger memory controller |
assign wbs_mc_adr_i = wb_adr_i; |
assign wbs_mc_dat_i = wb_dat_i; |
assign wbs_mc_sel_i = wb_sel_i; |
assign wbs_mc_cyc_i = wb_cyc_i; |
assign wbs_mc_we_i = wb_we_i; |
assign wbs_mc_cti_i = 0; |
|
assign mem_sel = ( wb_adr_i >= startup_size); |
|
// Assign signals according to which memory should be used |
assign wbs_strtup_stb_i = mem_sel ? 0 : wb_stb_i; |
assign wbs_mc_stb_i = mem_sel ? wb_stb_i : 0; |
|
assign wb_ack_o = mem_sel ? wbs_mc_ack_o : wbs_strtup_ack_o; |
assign wb_dat_o = mem_sel ? wbs_mc_dat_o : wbs_strtup_dat_o; |
|
`ifdef ML501_MEMORY_STARTUP |
/* On-chip startup RAM */ |
ml501_startup ml501_startup0 |
( |
.wb_adr_i(wbs_strtup_adr_i), |
.wb_stb_i(wbs_strtup_stb_i), |
.wb_cyc_i(wbs_strtup_cyc_i), |
.wb_we_i(wbs_strtup_we_i), |
.wb_sel_i(wbs_strtup_sel_i), |
.wb_dat_o(wbs_strtup_dat_o), |
.wb_dat_i(wbs_strtup_dat_i), |
.wb_ack_o(wbs_strtup_ack_o), |
.wb_clk(wb_clk), |
.wb_rst(wb_rst) |
); |
defparam ml501_startup0.mem_span = startup_size; |
defparam ml501_startup0.adr_width = `ML501_MEMORY_STARTUP_ADDR_WIDTH; |
`else // !`ifdef ML501_MEMORY_STARTUP |
assign wbs_strtup_dat_o = 0; |
assign wb_strtup_ack_o = 0; |
`endif // !`ifdef ML501_MEMORY_STARTUP |
|
`ifdef ML501_MEMORY_ONCHIP |
parameter ram_wb_dat_width = 32; |
// From board defines |
parameter ram_wb_adr_width = `ML501_MEMORY_ONCHIP_ADDRESS_WIDTH; |
parameter ram_wb_mem_size = ((`ML501_MEMORY_ONCHIP_SIZE_BYTES)/4); |
|
ram_wb |
# |
( |
.dat_width(ram_wb_dat_width), |
.adr_width(ram_wb_adr_width), |
.mem_size(ram_wb_mem_size) |
) |
ram_wb0 |
( |
.dat_i(wbs_mc_dat_i), |
.dat_o(wbs_mc_dat_o), |
.sel_i(wbs_mc_sel_i), |
.adr_i(wbs_mc_adr_i[ram_wb_adr_width-1:2]), |
.we_i (wbs_mc_we_i), |
.cti_i(wbs_mc_cti_i), |
.stb_i(wbs_mc_stb_i), |
.cyc_i(wbs_mc_cyc_i), |
.ack_o(wbs_mc_ack_o), |
.clk_i(wb_clk), |
.rst_i(wb_rst) |
); |
`else // !`ifdef ML501_MEMORY_ONCHIP |
`ifdef ML501_MEMORY_SSRAM |
|
/* ZBT SSRAM controller */ |
|
ssram_controller ssram_controller0 |
( |
// Outputs |
.wb_dat_o (wbs_mc_dat_o), |
.wb_ack_o (wbs_mc_ack_o), |
.sram_clk (sram_clk), |
.sram_addr (sram_addr), |
.sram_ce_l (sram_ce_l), |
.sram_oe_l (sram_oe_l), |
.sram_we_l (sram_we_l), |
.sram_bw_l (sram_bw_l), |
.sram_adv_ld_l (sram_adv_ld_l), |
.sram_mode (sram_mode), |
// Inouts |
.sram_dq_io (sram_dq_io), |
// Inputs |
.wb_adr_i (wbs_mc_adr_i), |
.wb_stb_i (wbs_mc_stb_i), |
.wb_cyc_i (wbs_mc_cyc_i), |
.wb_we_i (wbs_mc_we_i), |
.wb_sel_i (wbs_mc_sel_i), |
.wb_dat_i (wbs_mc_dat_i), |
.wb_clk (wb_clk), |
.wb_rst (wb_rst), |
.clk_200 (clk_200), |
.sram_clk_fb (sram_clk_fb)); |
|
`else |
`ifdef ML501_MEMORY_DDR2 |
|
/* DDR2 SDRAM controller */ |
|
/* ml501_ddr2_wb_if AUTO_TEMPLATE */ |
|
ml501_ddr2_wb_if ml501_ddr2_wb_if0 |
( |
|
.wb_dat_o (wbs_mc_dat_o[31:0]), |
.wb_ack_o (wbs_mc_ack_o), |
.wb_adr_i (wbs_mc_adr_i[31:0]), |
.wb_stb_i (wbs_mc_stb_i), |
.wb_cyc_i (wbs_mc_cyc_i), |
.wb_we_i (wbs_mc_we_i), |
.wb_sel_i (wbs_mc_sel_i[3:0]), |
.wb_dat_i (wbs_mc_dat_i[31:0]), |
|
.ddr2_a (ddr2_a[12:0]), |
.ddr2_ba (ddr2_ba[1:0]), |
.ddr2_ras_n (ddr2_ras_n), |
.ddr2_cas_n (ddr2_cas_n), |
.ddr2_we_n (ddr2_we_n), |
.ddr2_cs_n (ddr2_cs_n), |
.ddr2_odt (ddr2_odt), |
.ddr2_cke (ddr2_cke), |
.ddr2_dm (ddr2_dm[7:0]), |
.ddr2_ck (ddr2_ck[1:0]), |
.ddr2_ck_n (ddr2_ck_n[1:0]), |
.ddr2_dq (ddr2_dq[63:0]), |
.ddr2_dqs (ddr2_dqs[7:0]), |
.ddr2_dqs_n (ddr2_dqs_n[7:0]), |
|
.ddr2_if_clk (clk_200), |
.idly_clk_200 (clk_200), |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
`else |
|
/* No memory controller*/ |
dummy_slave |
# ( .value(32'h00000000)) |
mc_ds |
( |
.dat_o(wbs_mc_dat_o), |
.stb_i(wbs_mc_stb_i), |
.cyc_i(wbs_mc_cyc_i), |
.ack_o(wbs_mc_ack_o), |
.clk(wb_clk), |
.rst(wb_rst) |
); |
|
always @(posedge wb_clk) |
if (wbs_mc_stb_i & wbs_mc_cyc_i & wbs_mc_ack_o) |
begin |
$display("* Warning - access to non-existent memory location, 0x%x\n",wb_adr_i); |
end |
|
|
`endif |
`endif // !`ifdef ML501_MEMORY_SSRAM |
`endif // !`ifdef ML501_MEMORY_ONCHIP |
endmodule // ml501_mem_ctrl |
|
// Local Variables: |
// verilog-library-directories:(".") |
// verilog-library-extensions:(".v" ".h") |
// End: |
/ml501_ddr2_wb_if.v
0,0 → 1,486
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx ML501 DDR2 controller Wishbone Interface //// |
//// //// |
//// Description //// |
//// Simple interface to the Xilinx MIG generated DDR2 controller//// |
//// //// |
//// To Do: //// |
//// Increase usage of cache BRAM to maximum (currently only //// |
//// 256 bytes out of about 8192) //// |
//// Make this a Wishbone B3 registered feedback burst friendly //// |
//// server. //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
/* |
* The controller is design to stream lots of data out at the DDR2 controller's |
* rate. All we implement here is enough to do the simplest accesses into a |
* small cache, which eases the domain crossing headaches. |
* |
* This was originally written to handle a DDR2 part which is doing burst length |
* of 4 as a minimum via a databus which is 64-bits wide. |
* |
* This means the smallest accesses is 4*64=256-bits or 32-bytes. |
* |
* We are bridging to a 32-bit wide system bus, so this means we must handle |
* accesses in 8-word lots. |
* |
* A simple cache mechanism has been implemented, meaning we check if the cached |
* data has been written to, and therefore needs writing back to the main memory |
* before any other access can occur. |
* |
* Cache memory: |
* The cache memory is a core-generated module, instantiating something out |
* of the XilinxCoreLib. The reason is because an arrangement or RAMB36s with |
* different sized A and B data in/out ports can't be instantiated directly |
* for some reason. |
* What we have is side A with 32-bits, and side B with 128-bits wide. |
* |
* TODO: |
* This only supports 8-words for now but can easily be expanded, although |
* multiple way/associativity caching will require some extra work to handle |
* multiple cached addresses. |
* |
* But it should be easy enough to make this thing cache as much as its RAMB |
* resources allow (4-RAMB16s becuase due to the 128-bit DDR2-side interface) |
* which is about 8Kbyte. |
* |
* Multi-cycle paths: |
* Write: |
* To indicate that a writeback is occuring, a system-bus domain (wishbone, in |
* this case) signal is set, and then sampled in the controller domain whenever |
* a system-bus domain clock edge is detected. This register is "do_writeback" |
* and then the controller domain register "ddr2_write_done" is asserted when |
* the data has been written out of the RAMs and into the controller's fifos. |
* "ddr2_write_done" is then sampled by the system-bus domain and "do_writeback" |
* So there are paths between: |
* ( register -> (sampled by) -> register ) |
* wb_clk:do_writeback -> ddr2_clk:do_writeback_ddr2_shifter |
* wb_clk:do_writeback -> ddr2_clk:ddr2_write_done |
* ddr2_clk:ddr2_write_done -> wb_clk:do_writeback |
* |
* Read: |
* The only signal crossing we have here is the one indicating the read data |
* has arrived into the cache RAM from the controller. The controller domain |
* register "ddr2_read_done" is set, and sampled in the system-bus domain by the |
* logic controlling the "do_readfrom" register. "ddr2_read_done" is cleared |
* when the controller domain sees that "do_readfrom" has been de-asserted. |
* So there are paths between: |
* ( register -> (sampled by) -> register ) |
* ddr2_clk:ddr2_read_done -> wb_clk:do_readfrom |
* wb_clk:do_readfrom -> ddr2_clk:ddr2_read_done |
* |
*/ |
module ml501_ddr2_wb_if ( |
input [31:0] wb_adr_i, |
input wb_stb_i, |
input wb_cyc_i, |
input wb_we_i, |
input [3:0] wb_sel_i, |
input [31:0] wb_dat_i, |
output [31:0] wb_dat_o, |
output reg wb_ack_o, |
|
output [12:0] ddr2_a, |
output [1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output [1:0] ddr2_cs_n, |
output [1:0] ddr2_odt, |
output [1:0] ddr2_cke, |
output [7:0] ddr2_dm, |
|
inout [63:0] ddr2_dq, |
inout [7:0] ddr2_dqs, |
inout [7:0] ddr2_dqs_n, |
output [1:0] ddr2_ck, |
output [1:0] ddr2_ck_n, |
|
input ddr2_if_clk, |
input idly_clk_200, |
|
input wb_clk, |
input wb_rst); |
|
`include "ml501_ddr2_params.vh" |
|
wire ddr2_clk; // DDR2 iface domain clock. |
wire ddr2_rst; // reset from the ddr2 module |
|
wire wb_req; |
reg wb_req_r; |
reg wb_ack_o_r; |
|
wire wb_req_new; |
reg wb_req_new_r; |
|
reg wb_req_addr_hit; |
|
reg cached_addr_valid; |
|
reg [31:5] cached_addr; |
|
wire cache_hit; |
|
reg cache_dirty; |
|
reg [2:0] wb_req_cache_word_addr; |
|
wire wb_cache_en; |
|
reg do_writeback, do_writeback_r; |
wire do_writeback_start, do_writeback_finished; |
wire doing_writeback; |
|
reg do_readfrom, do_readfrom_r; |
wire do_readfrom_start, do_readfrom_finished; |
wire doing_readfrom; |
|
|
// Domain crossing logic |
reg wb_clk_r; |
reg wb_clk_in_ddr2_clk; |
|
reg wb_clk_in_ddr2_clk_r; |
wire wb_clk_edge; |
reg [2:0] ddr2_clk_phase; |
// Sample when clk phase is 0 |
reg [3:0] do_writeback_ddr2_shifter; |
reg [3:0] do_writeback_ddr2_shifter_r; |
reg do_writeback_ddr2_fifo_we; |
reg ddr2_write_done; |
|
// Currently, ddr2-side of cache is address is a single bit |
reg ddr2_cache_addr; |
wire [127:0] ddr2_cache_data_o; |
reg rd_data_valid_r; |
reg ddr2_read_done; |
|
// DDR2 MIG interface wires |
wire app_af_afull; |
wire app_wdf_afull; |
wire app_wdf_wren; |
wire app_af_wren; |
wire [30:0] app_af_addr; |
wire [2:0] app_af_cmd; |
wire [(APPDATA_WIDTH)-1:0] app_wdf_data; |
wire [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data; |
wire rd_data_valid; |
wire [(APPDATA_WIDTH)-1:0] rd_data_fifo_out; |
wire phy_init_done; |
|
|
assign cache_hit = (cached_addr == wb_adr_i[31:5]) & cached_addr_valid; |
|
// Wishbone request detection |
assign wb_req = wb_stb_i & wb_cyc_i & phy_init_done; |
|
always @(posedge wb_clk) |
wb_req_r <= wb_req; |
|
assign wb_req_new = wb_req & !wb_req_r; |
|
always @(posedge wb_clk) |
wb_req_new_r <= wb_req_new; |
|
// Register whether it's a hit or not |
// As more lines are added, add them to this check. |
always @(posedge wb_clk) |
if (wb_rst) |
wb_req_addr_hit <= 0; |
else |
wb_req_addr_hit <= wb_req & cache_hit & cached_addr_valid; |
|
always @(posedge wb_clk) |
if (wb_rst) |
wb_ack_o <= 0; |
else |
wb_ack_o <= wb_req_addr_hit & !wb_ack_o & !wb_ack_o_r; |
|
always @(posedge wb_clk) |
wb_ack_o_r <= wb_ack_o; |
|
// Address valid logic |
always @(posedge wb_clk) |
if (wb_rst) |
cached_addr_valid <= 0; |
else if (do_readfrom_finished) |
cached_addr_valid <= 1; |
else if ( do_writeback_finished ) // Data written back, cache not valid |
cached_addr_valid <= 0; |
else if (wb_req & !cache_hit & cached_addr_valid & !cache_dirty) |
// Invalidate cache so a readfrom begins |
cached_addr_valid <= 0; |
|
// Address cacheing |
always @(posedge wb_clk) |
if (wb_rst) |
cached_addr <= 0; |
else if (do_readfrom_start) |
cached_addr <= wb_adr_i[31:5]; |
|
// Cache dirty signal |
always @(posedge wb_clk) |
if (wb_rst) |
cache_dirty <= 0; |
else if (wb_req & wb_we_i & wb_req_addr_hit & wb_ack_o) |
cache_dirty <= 1; |
else if (!cached_addr_valid & cache_dirty) |
cache_dirty <= 0; |
|
// Wishbone side of cache enable. Important! |
// 1. Enable on first access, if it's not a write |
// 2. Enable if we've just refreshed the cache |
// 3. Enable on ACK'ing for a write |
assign wb_cache_en = (wb_req_new & !wb_we_i) | do_readfrom_finished | |
(wb_req_addr_hit & wb_stb_i & !wb_we_i & !wb_ack_o) | |
(wb_ack_o & wb_we_i); |
|
// Writeback detect logic |
always @(posedge wb_clk) |
if (wb_rst) |
do_writeback <= 0; |
else if (ddr2_write_done) // DDR2 domain signal |
do_writeback <= 0; |
else if (wb_req & !cache_hit & cached_addr_valid & !doing_writeback & cache_dirty) |
do_writeback <= 1; |
|
|
always @(posedge wb_clk) |
do_writeback_r <= do_writeback; |
|
assign do_writeback_start = do_writeback & !do_writeback_r; |
assign do_writeback_finished = !do_writeback & do_writeback_r; |
assign doing_writeback = do_writeback | do_writeback_r; |
|
// DDR2 Read detect logic |
always @(posedge wb_clk) |
if (wb_rst) |
do_readfrom <= 0; |
else if (ddr2_read_done) // DDR2 domain signal |
do_readfrom <= 0; |
else if (wb_req & !cache_hit & !cached_addr_valid & !doing_readfrom & !cache_dirty) |
do_readfrom <= 1; |
|
always @(posedge wb_clk) |
do_readfrom_r <= do_readfrom; |
|
assign do_readfrom_start = do_readfrom & !do_readfrom_r; |
assign do_readfrom_finished = !do_readfrom & do_readfrom_r; |
assign doing_readfrom = do_readfrom | do_readfrom_r; |
|
// Address fifo signals |
assign app_af_wren = (do_writeback_finished | do_readfrom_start); |
assign app_af_cmd[0] = do_readfrom_start; // 1 - read, 0 - write |
assign app_af_cmd[2:1] = 0; |
assign app_af_addr = do_readfrom_start ? {2'd0, wb_adr_i[31:5],2'd0} : |
{2'd0,cached_addr,2'd0}; |
|
assign app_wdf_wren = do_writeback_ddr2_fifo_we; |
assign app_wdf_data = ddr2_cache_data_o; |
assign app_wdf_mask_data = 0; |
|
always @(posedge wb_clk) if (wb_rst) wb_clk_r <= 0; else wb_clk_r <= ~wb_clk_r; |
always @(posedge ddr2_clk) wb_clk_in_ddr2_clk <= wb_clk_r; |
always @(posedge ddr2_clk) wb_clk_in_ddr2_clk_r <= wb_clk_in_ddr2_clk; |
|
assign wb_clk_edge = wb_clk_in_ddr2_clk & !wb_clk_in_ddr2_clk_r; |
|
always @(posedge ddr2_clk) |
if (ddr2_rst) |
ddr2_clk_phase <= 0; |
else if (wb_clk_edge) |
ddr2_clk_phase <= 0; |
else |
ddr2_clk_phase <= ddr2_clk_phase + 1; |
|
always @(posedge ddr2_clk) |
do_writeback_ddr2_fifo_we <= (do_writeback_ddr2_shifter_r[0]) | |
(do_writeback_ddr2_shifter_r[2]); |
|
// Kick off counting when we see that the wb_clk domain is |
// doing a writeback. |
always @(posedge ddr2_clk) |
if (ddr2_rst) |
do_writeback_ddr2_shifter <= 4'h0; |
else if (|do_writeback_ddr2_shifter) |
do_writeback_ddr2_shifter <= {do_writeback_ddr2_shifter[2:0], 1'b0}; |
else if (!(|ddr2_clk_phase) & do_writeback) // sample WB domain |
do_writeback_ddr2_shifter <= 4'h1; |
|
|
|
always @(posedge ddr2_clk) |
do_writeback_ddr2_shifter_r <= do_writeback_ddr2_shifter; |
|
always @(posedge ddr2_clk) |
if (ddr2_rst) |
ddr2_write_done <= 0; |
else if (do_writeback_ddr2_shifter[3]) |
ddr2_write_done <= 1; |
else if ((!(|ddr2_clk_phase)) & !do_writeback) // sample WB domain |
ddr2_write_done <= 0; |
|
always @(posedge ddr2_clk) |
if (ddr2_rst) |
ddr2_cache_addr <= 0; |
else if (rd_data_valid | do_writeback_ddr2_fifo_we) |
ddr2_cache_addr <= ~ddr2_cache_addr; |
|
always @(posedge ddr2_clk) |
rd_data_valid_r <= rd_data_valid; |
|
// Read done signaling to WB domain |
always @(posedge ddr2_clk) |
if (ddr2_rst) |
ddr2_read_done <= 0; |
else if (!rd_data_valid & rd_data_valid_r) // Detect read data valid falling edge |
ddr2_read_done <= 1; |
else if (!(|ddr2_clk_phase) & !do_readfrom) // Read WB domain |
ddr2_read_done <= 0; |
|
wire [2:0] wb_cache_adr; |
assign wb_cache_adr = wb_adr_i[4:2]; |
wire [3:0] wb_cache_sel_we; |
assign wb_cache_sel_we = {4{wb_we_i}} & wb_sel_i; |
wire ddr2_cache_en; |
wire [15:0] ddr2_cache_we; |
assign ddr2_cache_en = rd_data_valid | (|do_writeback_ddr2_shifter); |
assign ddr2_cache_we = {16{rd_data_valid}}; |
|
|
// Xilinx Coregen true dual-port RAMB array. |
// Wishbone side : 32-bit |
// DDR2 side : 128-bit |
ml501_ddr2_wb_if_cache cache_mem0 |
( |
// Wishbone side |
.clka(wb_clk), |
.ena(wb_cache_en), |
.wea(wb_cache_sel_we), |
.addra(wb_cache_adr), |
.dina(wb_dat_i), |
.douta(wb_dat_o), |
|
// DDR2 controller side |
.clkb(ddr2_clk), |
.enb(ddr2_cache_en), |
.web(ddr2_cache_we), |
.addrb(ddr2_cache_addr), |
.dinb(rd_data_fifo_out), |
.doutb(ddr2_cache_data_o)); |
|
ddr2_mig # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.CLK_WIDTH (CLK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.CS_BITS (CS_BITS), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQ_BITS (DQ_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.DQS_BITS (DQS_BITS), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.MULTI_BANK_EN (MULTI_BANK_EN), |
.ODT_TYPE (ODT_TYPE), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TREFI_NS (TREFI_NS), |
.TRAS (TRAS), |
.TRCD (TRCD), |
.TRFC (TRFC), |
.TRP (TRP), |
.TRTP (TRTP), |
.TWR (TWR), |
.TWTR (TWTR), |
.SIM_ONLY (SIM_ONLY), |
.RST_ACT_LOW (RST_ACT_LOW), |
.CLK_TYPE (CLK_TYPE), |
.DLL_FREQ_MODE (DLL_FREQ_MODE), |
.CLK_PERIOD (CLK_PERIOD) |
) |
ddr2_mig0 |
( |
.sys_clk (ddr2_if_clk), |
.idly_clk_200 (idly_clk_200), |
.sys_rst_n (wb_rst), |
.ddr2_ras_n (ddr2_ras_n), |
.ddr2_cas_n (ddr2_cas_n), |
.ddr2_we_n (ddr2_we_n), |
.ddr2_cs_n (ddr2_cs_n), |
.ddr2_cke (ddr2_cke), |
.ddr2_odt (ddr2_odt), |
.ddr2_dm (ddr2_dm), |
.ddr2_dq (ddr2_dq), |
.ddr2_dqs (ddr2_dqs), |
.ddr2_dqs_n (ddr2_dqs_n), |
.ddr2_ck (ddr2_ck), |
.ddr2_ck_n (ddr2_ck_n), |
.ddr2_ba (ddr2_ba), |
.ddr2_a (ddr2_a), |
|
.clk0_tb (ddr2_clk), |
.rst0_tb (ddr2_rst), |
.usr_clk (wb_clk), |
.app_af_afull (app_af_afull), |
.app_wdf_afull (app_wdf_afull), |
.rd_data_valid (rd_data_valid), |
.rd_data_fifo_out (rd_data_fifo_out), |
.app_af_wren (app_af_wren), |
.app_af_cmd (app_af_cmd), |
.app_af_addr (app_af_addr), |
.app_wdf_wren (app_wdf_wren), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.phy_init_done (phy_init_done) |
); |
|
|
endmodule // ml501_ddr2_wb_if |
// Local Variables: |
// verilog-library-directories:("." "ddr2_mig") |
// verilog-library-extensions:(".v" ".h") |
// End: |
/ml501_startup.v
0,0 → 1,152
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx ML501 Startup Memory //// |
//// //// |
//// Description //// |
//// Describes inferrable memory slave. //// |
//// //// |
//// To Do: //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
/* Memory containing memory addresses 0x0 up to mem_span */ |
module ml501_startup |
( wb_adr_i, wb_stb_i, wb_cyc_i, wb_we_i, wb_sel_i, wb_dat_i, |
wb_dat_o, wb_ack_o, |
wb_clk, wb_rst |
); |
|
/* Make this memory span up to this value */ |
parameter mem_span = 12'h800; |
parameter adr_width = 11; // log2(mem_span) |
parameter mem_span_word_address_width = (adr_width-2); |
|
input [adr_width-1:0] wb_adr_i; |
input wb_stb_i; |
input wb_cyc_i; |
input wb_we_i; |
input [3:0] wb_sel_i; |
input [31:0] wb_dat_i; |
output [31:0] wb_dat_o; |
output wb_ack_o; |
input wb_clk; |
input wb_rst; |
|
|
|
// synthesis attribute ram_style of mem is block |
reg [31:0] mem [0:(mem_span/4)-1] /* synthesis ram_style = no_rw_check */; |
reg [mem_span_word_address_width-1:0] adr; |
|
|
parameter memory_file = "sram.vmem"; |
|
initial |
begin |
$readmemh(memory_file, mem); |
end |
|
|
wire [31:0] wr_data; |
|
// mux for data to ram, RMW on part sel != 4'hf |
assign wr_data[31:24] = wb_sel_i[3] ? wb_dat_i[31:24] : wb_dat_o[31:24]; |
assign wr_data[23:16] = wb_sel_i[2] ? wb_dat_i[23:16] : wb_dat_o[23:16]; |
assign wr_data[15: 8] = wb_sel_i[1] ? wb_dat_i[15: 8] : wb_dat_o[15: 8]; |
assign wr_data[ 7: 0] = wb_sel_i[0] ? wb_dat_i[ 7: 0] : wb_dat_o[ 7: 0]; |
|
always @(posedge wb_clk or posedge wb_rst) |
begin |
if (wb_rst) |
adr <= 0; |
else |
if (wb_cyc_i & wb_stb_i) |
adr <= wb_adr_i[(mem_span_word_address_width+2)-1:2]; |
end |
|
// Define REG_READS to have registered reads |
//`define REG_READS |
|
reg [31:0] wb_dat_o_r; |
|
`ifdef REG_READS |
// Registered read |
assign wb_dat_o = wb_dat_o_r; |
`else |
// Unregistered read |
assign wb_dat_o = mem[adr]; |
`endif |
|
always @ (posedge wb_clk) |
begin |
if (wb_we_i & wb_ack_o) |
mem[adr] <= wb_dat_i; |
`ifdef REG_READS |
// Registered read |
wb_dat_o_r <= mem[adr]; |
`endif |
end |
|
|
// ack_o |
|
reg wb_ack_o_r, wb_ack_o_r2; |
|
`ifdef REG_READS |
// Use the following for registered reads |
assign wb_ack_o = wb_ack_o_r2; |
`else |
// Use the following for UNregistered reads |
assign wb_ack_o = wb_ack_o_r; |
`endif |
|
always @ (posedge wb_clk or posedge wb_rst) |
if (wb_rst) |
wb_ack_o_r <= 1'b0; |
else |
if (!wb_ack_o_r) |
begin |
if (wb_cyc_i & wb_stb_i |
`ifdef REG_READS |
& !wb_ack_o_r2 |
`endif |
) |
wb_ack_o_r <= 1'b1; |
end |
else |
wb_ack_o_r <= 1'b0; |
|
always @ (posedge wb_clk) |
wb_ack_o_r2 <= wb_ack_o_r; |
|
|
endmodule |
/ml501_defines.v
0,0 → 1,72
/////////////////////////////////////////////////////////////////////////// |
// ML501 ORPSoCv2 build defines |
/////////////////////////////////////////////////////////////////////////// |
// |
// Uncomment the `defines to enable them |
// |
// Note the synthesis scripts may need to be altered (mainly the UCF for |
// place and route) depending on the configuration. |
// |
/////////////////////////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////// |
// Memory |
/////////////////////////////////////////////////////////////////////////// |
// |
// Memory configuration options: |
// |
// On-Chip startup/low memory RAM is optional |
// The main memory controllers are mutually exclusive (ie. only one enabled at a time) |
// |
// Main memory options (select only of the following): |
// |
// On-Chip Xilinx RAMBs (~64KByte, resource use depending) |
// ZBT SSRAM (1MByte, 200Mhz) |
// DDR2 SDRAM (256MByte, 266Mhz) |
// It is recommended the startup memory is used with only the ZBT SSRAM or DDR2 |
// |
// See the RTL file, boards/xilinx/ml501/rtl/ml501_mc.v, for specifics |
// |
/////////////////////////////////////////////////////////////////////////// |
|
// Use on-chip memory as a boot-ROM |
`define ML501_MEMORY_STARTUP |
`ifdef ML501_MEMORY_STARTUP |
// Define the size of the onchip low/startup memory |
// 4KByte |
//`define ML501_MEMORY_STARTUP_ADDR_SPAN 16'h1000 |
//`define ML501_MEMORY_STARTUP_ADDR_WIDTH 12 |
// 8KByte |
//`define ML501_MEMORY_STARTUP_ADDR_SPAN 16'h2000 |
//`define ML501_MEMORY_STARTUP_ADDR_WIDTH 13 |
// 32KByte |
`define ML501_MEMORY_STARTUP_ADDR_SPAN 16'h8000 |
`define ML501_MEMORY_STARTUP_ADDR_WIDTH 15 |
`endif |
|
// Main memory configuration |
|
// On-chip SRAM (Xilinx RAMB36s) |
//`define ML501_MEMORY_ONCHIP |
`ifdef ML501_MEMORY_ONCHIP |
// 64KByte = 16 on-chip RAMs (4KByte per RAMB36) of the xc5vlx50's 48 BlockRAMs |
`define ML501_MEMORY_ONCHIP_SIZE_BYTES (64*1024) |
`define ML501_MEMORY_ONCHIP_ADDRESS_WIDTH 16 |
`endif |
|
// Use the ZBT SSRAM controller |
//`define ML501_MEMORY_SSRAM |
`ifdef ML501_MEMORY_SSRAM |
`define tsramtrace #750 /* 1500ps roundtrip */ |
`endif |
|
// Use the DDR2 SDRAM controller |
`define ML501_MEMORY_DDR2 |
|
/////////////////////////////////////////////////////////////////////////// |
// Peripherals |
/////////////////////////////////////////////////////////////////////////// |
|
// Include the OpenCores Ethernet MAC |
`define USE_ETHERNET |
|
/ml501.v
0,0 → 1,1005
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ORPSoC on Xilinx ML501 //// |
//// //// |
//// Description //// |
//// ORPSoC on Xilinx ML501 board toplevel file //// |
//// //// |
//// To Do: //// |
//// Check to see if system works with both SSRAM and DDR2 RAM //// |
//// are enabled. //// |
//// Add ethernet MAC controller. //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
// ml501 board toplevel RTL |
`timescale 1ps/1ps |
`include "ml501_defines.v" |
module ml501 |
( |
// Clocks and reset |
input sys_clk_in_p, // 200Mhz diff. pair |
input sys_clk_in_n, |
input sys_clk_in, // 100Mhz user clock |
input sys_rst_in, |
output usr_rst_out, // User controlled reset signal |
input usr_rst_in, |
|
`ifdef ML501_MEMORY_SSRAM |
// ZBT SSRAM |
output sram_clk, |
input sram_clk_fb, |
output [21:1] sram_flash_addr, |
inout [31:0] sram_flash_data, |
output sram_cen, |
output sram_flash_oe_n, |
output sram_flash_we_n, |
output [3:0] sram_bw, |
output sram_adv_ld_n, |
output sram_mode, |
`endif // `ifdef ML501_MEMORY_SSRAM |
|
`ifdef ML501_MEMORY_DDR2 |
// DDR2 SDRAM |
output [12:0] ddr2_a, |
output [1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output [1:0] ddr2_cs_n, |
output [1:0] ddr2_odt, |
output [1:0] ddr2_cke, |
output [7:0] ddr2_dm, |
|
inout [63:0] ddr2_dq, |
inout [7:0] ddr2_dqs, |
inout [7:0] ddr2_dqs_n, |
output [1:0] ddr2_ck, |
output [1:0] ddr2_ck_n, |
`endif // `ifdef ML501_MEMORY_DDR2 |
|
`ifdef USE_ETHERNET |
input phy_tx_clk, |
output [3:0] phy_tx_data, |
output phy_tx_en, |
output phy_tx_er, |
|
input phy_rx_clk, |
input [3:0] phy_rx_data, |
input phy_dv, |
input phy_rx_er, |
|
input phy_col, |
input phy_crs, |
|
output phy_smi_clk, |
inout phy_smi_data, |
|
output phy_rst_n, |
`endif // `ifdef USE_ETHERNET |
|
// JTAG debug |
input dbg_tdi_pad_i, |
input dbg_tck_pad_i, |
input dbg_tms_pad_i, |
output dbg_tdo_pad_o, |
|
// Uart |
input uart0_RX, |
output uart0_TX, |
// Duplicates of the UART signals, this time to the USB debug cable |
input uart0_RX_expheader, |
output uart0_TX_expheader, |
|
// GPIO |
inout [25:0] gpio |
) |
; |
|
wire wb_rst; |
wire wb_clk; |
wire sys_clk_in_200; |
wire clk_200; |
wire [30:0] pic_ints; |
wire uart0_irq; |
wire eth0_int_o; |
parameter [31:0] wbm_or12_i_dat_o = 32'h0; |
wire [31:0] wbm_or12_i_adr_o; |
wire [3:0] wbm_or12_i_sel_o; |
wire wbm_or12_i_we_o; |
wire [1:0] wbm_or12_i_bte_o; |
wire [2:0] wbm_or12_i_cti_o; |
wire wbm_or12_i_stb_o; |
wire wbm_or12_i_cyc_o; |
wire [31:0] wbm_or12_i_dat_i; |
wire wbm_or12_i_ack_i; |
wire wbm_or12_i_err_i; |
wire wbm_or12_i_rty_i; |
wire [31:0] wbm_or12_debug_dat_o; |
wire [31:0] wbm_or12_debug_adr_o; |
wire [3:0] wbm_or12_debug_sel_o; |
wire wbm_or12_debug_we_o; |
wire [1:0] wbm_or12_debug_bte_o; |
wire [2:0] wbm_or12_debug_cti_o; |
wire wbm_or12_debug_stb_o; |
wire wbm_or12_debug_cyc_o; |
wire [31:0] wbm_or12_debug_dat_i; |
wire wbm_or12_debug_ack_i; |
wire wbm_or12_debug_err_i; |
wire wbm_or12_debug_rty_i; |
wire [31:0] wbm_or12_d_dat_o; |
wire [31:0] wbm_or12_d_adr_o; |
wire [3:0] wbm_or12_d_sel_o; |
wire wbm_or12_d_we_o; |
wire [1:0] wbm_or12_d_bte_o; |
wire [2:0] wbm_or12_d_cti_o; |
wire wbm_or12_d_stb_o; |
wire wbm_or12_d_cyc_o; |
wire [31:0] wbm_or12_d_dat_i; |
wire wbm_or12_d_ack_i; |
wire wbm_or12_d_err_i; |
wire wbm_or12_d_rty_i; |
wire [31:0] wbm_eth1_dat_o; |
wire [31:0] wbm_eth1_adr_o; |
wire [3:0] wbm_eth1_sel_o; |
wire wbm_eth1_we_o; |
wire [1:0] wbm_eth1_bte_o; |
wire [2:0] wbm_eth1_cti_o; |
wire wbm_eth1_stb_o; |
wire wbm_eth1_cyc_o; |
wire [31:0] wbm_eth1_dat_i; |
wire wbm_eth1_ack_i; |
wire wbm_eth1_err_i; |
wire wbm_eth1_rty_i; |
wire [31:0] wbs_eth1_cfg_dat_o; |
wire [31:0] wbs_eth1_cfg_dat_i; |
wire [31:0] wbs_eth1_cfg_adr_i; |
wire [3:0] wbs_eth1_cfg_sel_i; |
wire [1:0] wbs_eth1_cfg_bte_i; |
wire [2:0] wbs_eth1_cfg_cti_i; |
wire wbs_eth1_cfg_stb_i; |
wire wbs_eth1_cfg_cyc_i; |
wire wbs_eth1_cfg_ack_o; |
wire wbs_eth1_cfg_err_o; |
parameter wbs_eth1_cfg_rty_o = 1'b0; |
wire [31:0] wbs_mc_m_dat_o; |
wire [31:0] wbs_mc_m_dat_i; |
wire [31:0] wbs_mc_m_adr_i; |
wire [3:0] wbs_mc_m_sel_i; |
wire [1:0] wbs_mc_m_bte_i; |
wire [2:0] wbs_mc_m_cti_i; |
wire wbs_mc_m_stb_i; |
wire wbs_mc_m_cyc_i; |
wire wbs_mc_m_ack_o; |
wire wbs_mc_m_err_o; |
parameter wbs_mc_m_rty_o = 1'b0; |
wire [31:0] wbs_spi_flash_dat_o; |
wire [31:0] wbs_spi_flash_dat_i; |
wire [31:0] wbs_spi_flash_adr_i; |
wire [3:0] wbs_spi_flash_sel_i; |
wire [1:0] wbs_spi_flash_bte_i; |
wire [2:0] wbs_spi_flash_cti_i; |
wire wbs_spi_flash_stb_i; |
wire wbs_spi_flash_cyc_i; |
wire wbs_spi_flash_ack_o; |
parameter wbs_spi_flash_err_o = 1'b0; |
parameter wbs_spi_flash_rty_o = 1'b0; |
wire [31:0] wbs_uart0_dat_o; |
wire [31:0] wbs_uart0_dat_i; |
wire [31:0] wbs_uart0_adr_i; |
wire [3:0] wbs_uart0_sel_i; |
wire [1:0] wbs_uart0_bte_i; |
wire [2:0] wbs_uart0_cti_i; |
wire wbs_uart0_stb_i; |
wire wbs_uart0_cyc_i; |
wire wbs_uart0_ack_o; |
parameter wbs_uart0_err_o = 1'b0; |
parameter wbs_uart0_rty_o = 1'b0; |
wire [31:0] wbs_ds1_dat_o; |
wire [31:0] wbs_ds1_dat_i; |
wire [31:0] wbs_ds1_adr_i; |
wire [3:0] wbs_ds1_sel_i; |
wire [1:0] wbs_ds1_bte_i; |
wire [2:0] wbs_ds1_cti_i; |
wire wbs_ds1_stb_i; |
wire wbs_ds1_cyc_i; |
wire wbs_ds1_ack_o; |
parameter wbs_ds1_err_o = 1'b0; |
parameter wbs_ds1_rty_o = 1'b0; |
wire [31:0] wbs_usrrst_dat_o; |
wire [31:0] wbs_usrrst_dat_i; |
wire [31:0] wbs_usrrst_adr_i; |
wire [3:0] wbs_usrrst_sel_i; |
wire [1:0] wbs_usrrst_bte_i; |
wire [2:0] wbs_usrrst_cti_i; |
wire wbs_usrrst_stb_i; |
wire wbs_usrrst_cyc_i; |
wire wbs_usrrst_ack_o; |
parameter wbs_usrrst_err_o = 1'b0; |
parameter wbs_usrrst_rty_o = 1'b0; |
wire [31:0] wbs_lfsr_dat_o; |
wire [31:0] wbs_lfsr_dat_i; |
wire [31:0] wbs_lfsr_adr_i; |
wire [3:0] wbs_lfsr_sel_i; |
wire [1:0] wbs_lfsr_bte_i; |
wire [2:0] wbs_lfsr_cti_i; |
wire wbs_lfsr_stb_i; |
wire wbs_lfsr_cyc_i; |
wire wbs_lfsr_ack_o; |
parameter wbs_lfsr_err_o = 1'b0; |
parameter wbs_lfsr_rty_o = 1'b0; |
wire [31:0] wbs_gpio_dat_o; |
wire [31:0] wbs_gpio_dat_i; |
wire [31:0] wbs_gpio_adr_i; |
wire [3:0] wbs_gpio_sel_i; |
wire [1:0] wbs_gpio_bte_i; |
wire [2:0] wbs_gpio_cti_i; |
wire wbs_gpio_stb_i; |
wire wbs_gpio_cyc_i; |
wire wbs_gpio_ack_o; |
parameter wbs_gpio_err_o = 1'b0; |
parameter wbs_gpio_rty_o = 1'b0; |
|
wire eth_clk; |
wire [1:1] eth_int; |
|
/* DCM0 wires */ |
wire dcm0_clk0_prebufg, dcm0_clk0; |
wire dcm0_clkfx_prebufg, dcm0_clkfx; |
wire dcm0_clkdv_prebufg, dcm0_clkdv; |
wire dcm0_rst, dcm0_locked; |
|
|
wb_conbus_top |
#(.s0_addr_w(4), .s0_addr(4'h0), // MC |
.s1_addr_w(4), .s1_addr(4'h8), // GPIO |
.s27_addr_w(8), |
.s2_addr(8'h92), // ETH Slave |
.s3_addr(8'hb0), // SPI |
.s4_addr(8'h90), // UART |
.s5_addr(8'hc0), // DS1 |
.s6_addr(8'he0), // User Reset |
.s7_addr(8'h1f)) // LFSR |
wb_conbus |
( |
// Master 0 |
// Inputs |
.m0_dat_i (wbm_or12_i_dat_o), |
.m0_adr_i (wbm_or12_i_adr_o), |
.m0_sel_i (wbm_or12_i_sel_o), |
.m0_we_i (wbm_or12_i_we_o), |
.m0_cyc_i (wbm_or12_i_cyc_o), |
.m0_stb_i (wbm_or12_i_stb_o), |
.m0_cab_i (1'b0), |
// Outputs |
.m0_dat_o (wbm_or12_i_dat_i), |
.m0_ack_o (wbm_or12_i_ack_i), |
.m0_err_o (wbm_or12_i_err_i), |
.m0_rty_o (wbm_or12_i_rty_i), |
|
// Master 1 |
// Inputs |
.m1_dat_i (wbm_or12_debug_dat_o), |
.m1_adr_i (wbm_or12_debug_adr_o), |
.m1_sel_i (wbm_or12_debug_sel_o), |
.m1_we_i (wbm_or12_debug_we_o), |
.m1_cyc_i (wbm_or12_debug_cyc_o), |
.m1_stb_i (wbm_or12_debug_stb_o), |
.m1_cab_i (1'b0), |
// Outputs |
.m1_dat_o (wbm_or12_debug_dat_i), |
.m1_ack_o (wbm_or12_debug_ack_i), |
.m1_err_o (wbm_or12_debug_err_i), |
.m1_rty_o (wbm_or12_debug_rty_i), |
|
// Master 2 |
// Inputs |
.m2_dat_i (wbm_or12_d_dat_o), |
.m2_adr_i (wbm_or12_d_adr_o), |
.m2_sel_i (wbm_or12_d_sel_o), |
.m2_we_i (wbm_or12_d_we_o), |
.m2_cyc_i (wbm_or12_d_cyc_o), |
.m2_stb_i (wbm_or12_d_stb_o), |
.m2_cab_i (1'b0), |
// Outputs |
.m2_dat_o (wbm_or12_d_dat_i), |
.m2_ack_o (wbm_or12_d_ack_i), |
.m2_err_o (wbm_or12_d_err_i), |
.m2_rty_o (wbm_or12_d_rty_i), |
|
// Master 3 |
// Inputs |
.m3_dat_i (wbm_eth1_dat_o), |
.m3_adr_i (wbm_eth1_adr_o), |
.m3_sel_i (wbm_eth1_sel_o), |
.m3_we_i (wbm_eth1_we_o), |
.m3_cyc_i (wbm_eth1_cyc_o), |
.m3_stb_i (wbm_eth1_stb_o), |
.m3_cab_i (1'b0), |
// Outputs |
.m3_dat_o (wbm_eth1_dat_i), |
.m3_ack_o (wbm_eth1_ack_i), |
.m3_err_o (wbm_eth1_err_i), |
.m3_rty_o (wbm_eth1_rty_i), |
|
// Master 4 |
// Inputs |
.m4_dat_i (0), |
.m4_adr_i (0), |
.m4_sel_i (4'h0), |
.m4_we_i (1'b0), |
.m4_cyc_i (1'b0), |
.m4_stb_i (1'b0), |
.m4_cab_i (1'b0), |
// Outputs |
//.m4_dat_o (), |
//.m4_ack_o (), |
//.m4_err_o (), |
//.m4_rty_o (), |
|
// Master 5 |
// Inputs |
.m5_dat_i (0), |
.m5_adr_i (0), |
.m5_sel_i (4'h0), |
.m5_we_i (1'b0), |
.m5_cyc_i (1'b0), |
.m5_stb_i (1'b0), |
.m5_cab_i (1'b0), |
// Outputs |
//.m5_dat_o (), |
//.m5_ack_o (), |
//.m5_err_o (), |
//.m5_rty_o (), |
|
// Master 6 |
// Inputs |
.m6_dat_i (0), |
.m6_adr_i (0), |
.m6_sel_i (4'h0), |
.m6_we_i (1'b0), |
.m6_cyc_i (1'b0), |
.m6_stb_i (1'b0), |
.m6_cab_i (1'b0), |
// Outputs |
//.m6_dat_o (), |
//.m6_ack_o (), |
//.m6_err_o (), |
//.m6_rty_o (), |
|
// Master 7 |
// Inputs |
.m7_dat_i (0), |
.m7_adr_i (0), |
.m7_sel_i (4'h0), |
.m7_we_i (1'b0), |
.m7_cyc_i (1'b0), |
.m7_stb_i (1'b0), |
.m7_cab_i (1'b0), |
// Outputs |
//.m7_dat_o (), |
//.m7_ack_o (), |
//.m7_err_o (), |
//.m7_rty_o (), |
|
|
// Slave 0 |
// Inputs |
.s0_dat_i (wbs_mc_m_dat_o), |
.s0_ack_i (wbs_mc_m_ack_o), |
.s0_err_i (wbs_mc_m_err_o), |
.s0_rty_i (wbs_mc_m_rty_o), |
// Outputs |
.s0_dat_o (wbs_mc_m_dat_i), |
.s0_adr_o (wbs_mc_m_adr_i), |
.s0_sel_o (wbs_mc_m_sel_i), |
.s0_we_o (wbs_mc_m_we_i), |
.s0_cyc_o (wbs_mc_m_cyc_i), |
.s0_stb_o (wbs_mc_m_stb_i), |
//.s0_cab_o (), |
|
// Slave 1 |
// Inputs |
.s1_dat_i (wbs_gpio_dat_o), |
.s1_ack_i (wbs_gpio_ack_o), |
.s1_err_i (wbs_gpio_err_o), |
.s1_rty_i (wbs_gpio_rty_o), |
// Outputs |
.s1_dat_o (wbs_gpio_dat_i), |
.s1_adr_o (wbs_gpio_adr_i), |
.s1_sel_o (wbs_gpio_sel_i), |
.s1_we_o (wbs_gpio_we_i), |
.s1_cyc_o (wbs_gpio_cyc_i), |
.s1_stb_o (wbs_gpio_stb_i), |
//.s1_cab_o (), |
|
// Slave 2 |
// Inputs |
.s2_dat_i (wbs_eth1_cfg_dat_o), |
.s2_ack_i (wbs_eth1_cfg_ack_o), |
.s2_err_i (wbs_eth1_cfg_err_o), |
.s2_rty_i (wbs_eth1_cfg_rty_o), |
// Outputs |
.s2_dat_o (wbs_eth1_cfg_dat_i), |
.s2_adr_o (wbs_eth1_cfg_adr_i), |
.s2_sel_o (wbs_eth1_cfg_sel_i), |
.s2_we_o (wbs_eth1_cfg_we_i), |
.s2_cyc_o (wbs_eth1_cfg_cyc_i), |
.s2_stb_o (wbs_eth1_cfg_stb_i), |
//.s2_cab_o (), |
|
// Slave 3 |
// Inputs |
.s3_dat_i (wbs_spi_flash_dat_o), |
.s3_ack_i (wbs_spi_flash_ack_o), |
.s3_err_i (wbs_spi_flash_err_o), |
.s3_rty_i (wbs_spi_flash_rty_o), |
// Outputs |
.s3_dat_o (wbs_spi_flash_dat_i), |
.s3_adr_o (wbs_spi_flash_adr_i), |
.s3_sel_o (wbs_spi_flash_sel_i), |
.s3_we_o (wbs_spi_flash_we_i), |
.s3_cyc_o (wbs_spi_flash_cyc_i), |
.s3_stb_o (wbs_spi_flash_stb_i), |
//.s3_cab_o (), |
|
// Slave 4 |
// Inputs |
.s4_dat_i (wbs_uart0_dat_o), |
.s4_ack_i (wbs_uart0_ack_o), |
.s4_err_i (wbs_uart0_err_o), |
.s4_rty_i (wbs_uart0_rty_o), |
// Outputs |
.s4_dat_o (wbs_uart0_dat_i), |
.s4_adr_o (wbs_uart0_adr_i), |
.s4_sel_o (wbs_uart0_sel_i), |
.s4_we_o (wbs_uart0_we_i), |
.s4_cyc_o (wbs_uart0_cyc_i), |
.s4_stb_o (wbs_uart0_stb_i), |
//.s4_cab_o (), |
|
// Slave 5 |
// Inputs |
.s5_dat_i (wbs_ds1_dat_o), |
.s5_ack_i (wbs_ds1_ack_o), |
.s5_err_i (1'b0), |
.s5_rty_i (1'b0), |
// Outputs |
.s5_dat_o (wbs_ds1_dat_i), |
.s5_adr_o (wbs_ds1_adr_i), |
.s5_sel_o (wbs_ds1_sel_i), |
.s5_we_o (wbs_ds1_we_i), |
.s5_cyc_o (wbs_ds1_cyc_i), |
.s5_stb_o (wbs_ds1_stb_i), |
.s5_cab_o (), |
|
// Slave 6 |
// Inputs |
.s6_dat_i (wbs_usrrst_dat_o), |
.s6_ack_i (wbs_usrrst_ack_o), |
.s6_err_i (1'b0), |
.s6_rty_i (1'b0), |
// Outputs |
.s6_dat_o (wbs_usrrst_dat_i), |
.s6_adr_o (wbs_usrrst_adr_i), |
.s6_sel_o (wbs_usrrst_sel_i), |
.s6_we_o (wbs_usrrst_we_i), |
.s6_cyc_o (wbs_usrrst_cyc_i), |
.s6_stb_o (wbs_usrrst_stb_i), |
.s6_cab_o (), |
|
// Slave 7 |
// Inputs |
.s7_dat_i (wbs_lfsr_dat_o), |
.s7_ack_i (wbs_lfsr_ack_o), |
.s7_err_i (1'b0), |
.s7_rty_i (1'b0), |
// Outputs |
.s7_dat_o (wbs_lfsr_dat_i), |
.s7_adr_o (wbs_lfsr_adr_i), |
.s7_sel_o (wbs_lfsr_sel_i), |
.s7_we_o (wbs_lfsr_we_i), |
.s7_cyc_o (wbs_lfsr_cyc_i), |
.s7_stb_o (wbs_lfsr_stb_i), |
.s7_cab_o (), |
|
// Inputs |
.clk_i (wb_clk), |
.rst_i (wb_rst)); |
|
// Tie all cycle type identifiers (CTI) and burst type extension (BTE) signals low |
// Not supported by this arbiter. |
assign wbs_eth1_cfg_bte_i = 0; |
assign wbs_eth1_cfg_cti_i = 0; |
|
assign wbs_gpio_bte_i = 0; |
assign wbs_gpio_cti_i = 0; |
assign wbs_spi_flash_bte_i = 0; |
assign wbs_spi_flash_cti_i = 0; |
assign wbs_mc_m_bte_i = 0; |
assign wbs_mc_m_cti_i = 0; |
assign wbs_uart0_bte_i = 0; |
assign wbs_uart0_cti_i = 0; |
assign wbs_ds1_bte_i = 0; |
assign wbs_ds1_cti_i = 0; |
assign wbs_usrrst_bte_i = 0; |
assign wbs_usrrst_cti_i = 0; |
assign wbs_lfsr_bte_i = 0; |
assign wbs_lfsr_cti_i = 0; |
|
// Programmable interrupt controller lines (aka. IRQ lines) |
assign pic_ints[30] = 1'b0; |
assign pic_ints[29] = 1'b0; |
assign pic_ints[28] = 1'b0; |
assign pic_ints[27] = 1'b0; |
assign pic_ints[26] = 1'b0; |
assign pic_ints[25] = 1'b0; |
assign pic_ints[24] = 1'b0; |
assign pic_ints[23] = 1'b0; |
assign pic_ints[22] = 1'b0; |
assign pic_ints[21] = 1'b0; |
assign pic_ints[20] = 1'b0; |
assign pic_ints[19] = 1'b0; |
assign pic_ints[18] = 1'b0; |
assign pic_ints[17] = 1'b0; |
assign pic_ints[16] = 1'b0; |
assign pic_ints[15] = 1'b0; |
assign pic_ints[14] = 1'b0; |
assign pic_ints[13] = 1'b0; |
assign pic_ints[12] = 1'b0; |
assign pic_ints[11] = 1'b0; |
assign pic_ints[10] = 1'b0; |
assign pic_ints[9] = 1'b0; |
assign pic_ints[8] = 1'b0; |
assign pic_ints[7] = 1'b0; |
assign pic_ints[6] = 1'b0; |
assign pic_ints[5] = 1'b0; |
assign pic_ints[4] = eth_int[1]; /* IRQ4, just like in Linux. Added jb 090716 */ |
assign pic_ints[3] = 1'b0; |
assign pic_ints[2] = uart0_irq; |
assign pic_ints[1] = 1'b0; |
assign pic_ints[0] = 1'b0; |
or1k_top i_or1k |
( |
.clk_i (wb_clk), |
.rst_i (wb_rst), |
.pic_ints_i (pic_ints[19:0]), |
.iwb_clk_i (wb_clk), |
.iwb_rst_i (wb_rst), |
.iwb_ack_i (wbm_or12_i_ack_i), |
.iwb_err_i (wbm_or12_i_err_i), |
.iwb_rty_i (wbm_or12_i_rty_i), |
.iwb_dat_i (wbm_or12_i_dat_i), |
.iwb_cyc_o (wbm_or12_i_cyc_o), |
.iwb_adr_o (wbm_or12_i_adr_o), |
.iwb_stb_o (wbm_or12_i_stb_o), |
.iwb_we_o (wbm_or12_i_we_o ), |
.iwb_sel_o (wbm_or12_i_sel_o), |
.iwb_cti_o (wbm_or12_i_cti_o), |
.iwb_bte_o (wbm_or12_i_bte_o), |
.dwb_clk_i (wb_clk), |
.dwb_rst_i (wb_rst), |
.dwb_ack_i (wbm_or12_d_ack_i), |
.dwb_err_i (wbm_or12_d_err_i), |
.dwb_rty_i (wbm_or12_d_rty_i), |
.dwb_dat_i (wbm_or12_d_dat_i), |
.dwb_cyc_o (wbm_or12_d_cyc_o), |
.dwb_adr_o (wbm_or12_d_adr_o), |
.dwb_stb_o (wbm_or12_d_stb_o), |
.dwb_we_o (wbm_or12_d_we_o), |
.dwb_sel_o (wbm_or12_d_sel_o), |
.dwb_dat_o (wbm_or12_d_dat_o), |
.dwb_cti_o (wbm_or12_d_cti_o), |
.dwb_bte_o (wbm_or12_d_bte_o), |
.dbgwb_clk_i (wb_clk), |
.dbgwb_rst_i (wb_rst), |
.dbgwb_ack_i (wbm_or12_debug_ack_i), |
.dbgwb_err_i (wbm_or12_debug_err_i), |
.dbgwb_dat_i (wbm_or12_debug_dat_i), |
.dbgwb_cyc_o (wbm_or12_debug_cyc_o), |
.dbgwb_adr_o (wbm_or12_debug_adr_o), |
.dbgwb_stb_o (wbm_or12_debug_stb_o), |
.dbgwb_we_o (wbm_or12_debug_we_o), |
.dbgwb_sel_o (wbm_or12_debug_sel_o), |
.dbgwb_dat_o (wbm_or12_debug_dat_o), |
.dbgwb_cti_o (wbm_or12_debug_cti_o), |
.dbgwb_bte_o (wbm_or12_debug_bte_o), |
.tms_pad_i (dbg_tms_pad_i), |
.tck_pad_i (dbg_tck), |
.tdi_pad_i (dbg_tdi_pad_i), |
.tdo_pad_o (dbg_tdo_pad_o), |
.tdo_padoe_o ( ) |
); |
|
`ifdef USE_SPI_FLASH |
|
wire spi_flash_mosi, spi_flash_miso, spi_flash_sclk; |
wire [1:0] spi_flash_ss; |
spi_flash_top # |
( |
.divider(0), |
.divider_len(2) |
) |
spi_flash_top0 |
( |
.wb_clk_i(wb_clk), |
.wb_rst_i(wb_rst), |
.wb_adr_i(wbs_spi_flash_adr_i[4:2]), |
.wb_dat_i(wbs_spi_flash_dat_i), |
.wb_dat_o(wbs_spi_flash_dat_o), |
.wb_sel_i(wbs_spi_flash_sel_i), |
.wb_we_i(wbs_spi_flash_we_i), |
.wb_stb_i(wbs_spi_flash_stb_i), |
.wb_cyc_i(wbs_spi_flash_cyc_i), |
.wb_ack_o(wbs_spi_flash_ack_o), |
.mosi_pad_o(spi_flash_mosi), |
.miso_pad_i(spi_flash_miso), |
.sclk_pad_o(spi_flash_sclk), |
.ss_pad_o(spi_flash_ss) |
); |
|
// SPI flash memory signals |
assign spi_flash_mosi_pad_o = !spi_flash_ss[0] ? spi_flash_mosi : 1'b1; |
assign spi_flash_sclk_pad_o = !spi_flash_ss[0] ? spi_flash_sclk : 1'b1; |
assign spi_flash_ss_pad_o = spi_flash_ss[0]; |
assign spi_flash_w_n_pad_o = 1'b1; |
assign spi_flash_hold_n_pad_o = 1'b1; |
assign spi_sd_mosi_pad_o = !spi_flash_ss[1] ? spi_flash_mosi : 1'b1; |
assign spi_sd_sclk_pad_o = !spi_flash_ss[1] ? spi_flash_sclk : 1'b1; |
assign spi_sd_ss_pad_o = spi_flash_ss[1]; |
assign spi_flash_miso = !spi_flash_ss[0] ? spi_flash_miso_pad_i : |
!spi_flash_ss[1] ? spi_sd_miso_pad_i : |
1'b0; |
|
`else // !`ifdef USE_SPI_FLASH |
|
|
dummy_slave |
# ( .value(32'hb0000000)) |
ds_spi |
( |
.dat_o(wbs_spi_flash_dat_o), |
.stb_i(wbs_spi_flash_stb_i), |
.cyc_i(wbs_spi_flash_cyc_i), |
.ack_o(wbs_spi_flash_ack_o), |
.clk(wb_clk), |
.rst(wb_rst) |
); |
|
`endif // !`ifdef USE_SPI_FLASH |
|
/* Memory module */ |
ml501_mc ml501_mc0 |
( |
.wb_dat_i(wbs_mc_m_dat_i), |
.wb_dat_o(wbs_mc_m_dat_o), |
.wb_sel_i(wbs_mc_m_sel_i), |
.wb_adr_i(wbs_mc_m_adr_i), |
.wb_we_i (wbs_mc_m_we_i), |
.wb_stb_i(wbs_mc_m_stb_i), |
.wb_cyc_i(wbs_mc_m_cyc_i), |
.wb_ack_o(wbs_mc_m_ack_o), |
|
`ifdef ML501_MEMORY_SSRAM |
.sram_clk(sram_clk), |
.sram_addr(sram_flash_addr), |
.sram_ce_l(sram_cen), |
.sram_oe_l(sram_flash_oe_n), |
.sram_we_l(sram_flash_we_n), |
.sram_bw_l(sram_bw), |
.sram_adv_ld_l(sram_adv_ld_n), |
.sram_mode(sram_mode), |
.sram_clk_fb(sram_clk_fb), |
.sram_dq_io(sram_flash_data), |
`endif // `ifdef ML501_MEMORY_SSRAM |
|
`ifdef ML501_MEMORY_DDR2 |
.ddr2_a(ddr2_a[12:0]), |
.ddr2_ba(ddr2_ba[1:0]), |
.ddr2_ras_n(ddr2_ras_n), |
.ddr2_cas_n(ddr2_cas_n), |
.ddr2_we_n(ddr2_we_n), |
.ddr2_cs_n(ddr2_cs_n), |
.ddr2_odt(ddr2_odt), |
.ddr2_cke(ddr2_cke), |
.ddr2_dm(ddr2_dm[7:0]), |
.ddr2_ck(ddr2_ck[1:0]), |
.ddr2_ck_n(ddr2_ck_n[1:0]), |
.ddr2_dq(ddr2_dq[63:0]), |
.ddr2_dqs(ddr2_dqs[7:0]), |
.ddr2_dqs_n(ddr2_dqs_n[7:0]), |
// .ddr2_if_clk(clk_200), |
.ddr2_if_clk(dcm0_clkfx), |
`endif // `ifdef ML501_MEMORY_DDR2 |
|
.clk_200(clk_200), |
.wb_clk(wb_clk), |
.wb_rst(wb_rst) |
); |
|
assign wbs_mc_m_err_o = 1'b0; |
|
// Wires for duplication |
wire uart_rx, uart_tx; |
assign uart_rx = uart0_RX & uart0_RX_expheader; |
|
assign uart0_TX = uart_tx; |
assign uart0_TX_expheader = uart_tx; |
|
uart_top |
#( 32, 5) |
i_uart_0_top |
( |
.wb_dat_o (wbs_uart0_dat_o), |
.wb_dat_i (wbs_uart0_dat_i), |
.wb_sel_i (wbs_uart0_sel_i), |
.wb_adr_i (wbs_uart0_adr_i[4:0]), |
.wb_we_i (wbs_uart0_we_i), |
.wb_stb_i (wbs_uart0_stb_i), |
.wb_cyc_i (wbs_uart0_cyc_i), |
.wb_ack_o (wbs_uart0_ack_o), |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst), |
.int_o (uart0_irq), |
.srx_pad_i (uart_rx), |
.stx_pad_o (uart_tx), |
.cts_pad_i (1'b0), |
.rts_pad_o ( ), |
.dtr_pad_o ( ), |
.dcd_pad_i (1'b0), |
.dsr_pad_i (1'b0), |
.ri_pad_i (1'b0) |
); |
|
|
|
`ifdef USE_ETHERNET |
|
wire phy_smi_data_i, phy_smi_data_o, phy_smi_data_dir; |
|
|
eth_top eth_top1 |
( |
.wb_clk_i(wb_clk), |
.wb_rst_i(wb_rst), |
.wb_dat_i(wbs_eth1_cfg_dat_i), |
.wb_dat_o(wbs_eth1_cfg_dat_o), |
.wb_adr_i(wbs_eth1_cfg_adr_i[11:2]), |
.wb_sel_i(wbs_eth1_cfg_sel_i), |
.wb_we_i(wbs_eth1_cfg_we_i), |
.wb_cyc_i(wbs_eth1_cfg_cyc_i), |
.wb_stb_i(wbs_eth1_cfg_stb_i), |
.wb_ack_o(wbs_eth1_cfg_ack_o), |
.wb_err_o(wbs_eth1_cfg_err_o), |
|
.m_wb_adr_o(wbm_eth1_adr_o), |
.m_wb_sel_o(wbm_eth1_sel_o), |
.m_wb_we_o(wbm_eth1_we_o), |
.m_wb_dat_o(wbm_eth1_dat_o), |
.m_wb_dat_i(wbm_eth1_dat_i), |
.m_wb_cyc_o(wbm_eth1_cyc_o), |
.m_wb_stb_o(wbm_eth1_stb_o), |
.m_wb_ack_i(wbm_eth1_ack_i), |
.m_wb_err_i(wbm_eth1_err_i), |
.m_wb_cti_o(wbm_eth1_cti_o), |
.m_wb_bte_o(wbm_eth1_bte_o), |
|
.mtx_clk_pad_i(phy_tx_clk), |
.mtxd_pad_o(phy_tx_data), |
.mtxen_pad_o(phy_tx_en), |
.mtxerr_pad_o(phy_tx_er), |
.mrx_clk_pad_i(phy_rx_clk), |
.mrxd_pad_i(phy_rx_data), |
.mrxdv_pad_i(phy_dv), |
.mrxerr_pad_i(phy_rx_er), |
.mcoll_pad_i(phy_col), |
.mcrs_pad_i(phy_crs), |
.mdc_pad_o(phy_smi_clk), |
.md_pad_i(phy_smi_data_i), |
.md_pad_o(phy_smi_data_o), |
.md_padoe_o(phy_smi_data_dir), |
.int_o(eth_int[1]) |
); |
|
// Xilinx primitive |
IOBUF iobuf_phy_smi_data |
( |
// Outputs |
.O (phy_smi_data_i), |
// Inouts |
.IO (phy_smi_data), |
// Inputs |
.I (phy_smi_data_o), |
.T (!phy_smi_data_dir)); |
|
assign phy_rst_n = !wb_rst; |
|
|
`else // !`ifdef USE_ETHERNET |
// If ethernet core is disabled, still ack anyone who tries |
// to access its config port. This allows linux to boot in |
// the verilated ORPSoC. |
|
dummy_slave |
# ( .value(32'h92000000)) |
ds_eth1_cfg |
( |
.dat_o(wbs_eth1_cfg_dat_o), |
.stb_i(wbs_eth1_cfg_stb_i), |
.cyc_i(wbs_eth1_cfg_cyc_i), |
.ack_o(wbs_eth1_cfg_ack_o), |
.clk(wb_clk), |
.rst(wb_rst) |
); |
assign wbs_eth1_cfg_err_o = 0; |
|
|
// Tie off ethernet master ctrl signals |
assign wbm_eth1_adr_o = 0; |
assign wbm_eth1_sel_o = 0; |
assign wbm_eth1_we_o = 0; |
assign wbm_eth1_dat_o = 0; |
assign wbm_eth1_cyc_o = 0; |
assign wbm_eth1_stb_o = 0; |
assign wbm_eth1_cti_o = 0; |
assign wbm_eth1_bte_o = 0; |
|
`endif // `ifdef USE_ETHERNET |
|
ml501_gpio ml501_gpio0 |
( |
// WB |
.dat_o (wbs_gpio_dat_o), |
.dat_i (wbs_gpio_dat_i), |
.ack_o (wbs_gpio_ack_o), |
.adr_i (wbs_gpio_adr_i[2:0]), |
.sel_i (wbs_gpio_sel_i[3:0]), |
.stb_i (wbs_gpio_stb_i), |
.cyc_i (wbs_gpio_cyc_i), |
.we_i (wbs_gpio_we_i), |
|
.gpio (gpio), |
// Inputs |
.clk (wb_clk), |
.rst (wb_rst)); |
|
defparam ml501_gpio0.gpio_width = 26; |
|
|
wb_lfsr lfsr0 |
( |
// Outputs |
.wb_dat_o (wbs_lfsr_dat_o), |
.wb_ack_o (wbs_lfsr_ack_o), |
// Inputs |
.wb_clk (wb_clk), |
.wb_rst (wb_rst), |
.wb_adr_i (wbs_lfsr_adr_i[2:0]), |
.wb_dat_i (wbs_lfsr_dat_i), |
.wb_cyc_i (wbs_lfsr_cyc_i), |
.wb_stb_i (wbs_lfsr_stb_i), |
.wb_we_i (wbs_lfsr_we_i)); |
|
|
dummy_slave |
# ( .value(32'hc0000000)) |
ds1 |
( |
.dat_o(wbs_ds1_dat_o), |
.stb_i(wbs_ds1_stb_i), |
.cyc_i(wbs_ds1_cyc_i), |
.ack_o(wbs_ds1_ack_o), |
.clk(wb_clk), |
.rst(wb_rst) |
); |
|
usr_rst usr_rst0 |
( |
// Outputs |
.usr_rst_out (usr_rst_out), |
// Inputs |
.wb_clk (wb_clk), |
.wb_rst (wb_rst), |
.wb_cyc_i (wbs_usrrst_cyc_i), |
.wb_stb_i (wbs_usrrst_stb_i), |
.wb_ack_o (wbs_usrrst_ack_o)); |
|
assign wbs_usrrst_dat_o = 0; |
|
/* Reset and clock stuff */ |
reset_debounce reset_debounce0 |
( |
.sys_rst_in(sys_rst_in), |
.usr_rst_in(usr_rst_in), |
.sys_clk_in(sys_clk_in), |
.dcm0_clk(dcm0_clk0), |
.dcm0_locked(dcm0_locked), |
.rst_dcm0(dcm0_rst), |
.rst(wb_rst) |
); |
|
/* DCM providing main system/Wishbone clock */ |
DCM_BASE dcm0 |
( |
// Outputs |
.CLK0 (dcm0_clk0_prebufg), |
.CLK180 (), |
.CLK270 (), |
.CLK2X180 (), |
.CLK2X (), |
.CLK90 (), |
.CLKDV (dcm0_clkdv_prebufg), |
.CLKFX180 (), |
.CLKFX (dcm0_clkfx_prebufg), |
.LOCKED (dcm0_locked), |
// Inputs |
.CLKFB (dcm0_clk0), |
.CLKIN (sys_clk_in_200), |
.RST (dcm0_rst)); |
|
// Generate 266 MHz from CLKFX |
defparam dcm0.CLKFX_MULTIPLY = 4; |
defparam dcm0.CLKFX_DIVIDE = 3; |
|
// Generate 50 MHz from CLKDV |
defparam dcm0.CLKDV_DIVIDE = 4.0; |
|
BUFG dcm0_clk0_bufg |
(// Outputs |
.O (dcm0_clk0), |
// Inputs |
.I (dcm0_clk0_prebufg)); |
|
BUFG dcm0_clkfx_bufg |
(// Outputs |
.O (dcm0_clkfx), |
// Inputs |
.I (dcm0_clkfx_prebufg)); |
|
BUFG dcm0_clkdv_bufg |
(// Outputs |
.O (dcm0_clkdv), |
// Inputs |
.I (dcm0_clkdv_prebufg)); |
|
IBUFGDS_LVPECL_25 sys_clk_in_ibufds |
( |
.O(sys_clk_in_200), |
.I(sys_clk_in_p), |
.IB(sys_clk_in_n)); |
|
assign wb_clk = dcm0_clkdv; |
assign dbg_tck = dbg_tck_pad_i; |
//assign clk_200 = sys_clk_in_200; |
assign clk_200 = dcm0_clk0; |
|
|
endmodule |
/ml501_gpio.v
0,0 → 1,125
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx ML501 GPIO controller with Wishbone Interface //// |
//// //// |
//// Description //// |
//// Wishbone interface to simple GPIO registers. //// |
//// //// |
//// To Do: //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
module ml501_gpio (adr_i, dat_i, dat_o, sel_i, stb_i, cyc_i, we_i, ack_o, clk, rst, gpio ); |
|
parameter gpio_width = 26; |
|
// WB interface |
input [2:0] adr_i; |
output [31:0] dat_o; |
input [31:0] dat_i; |
input [3:0] sel_i; |
input stb_i; |
input cyc_i; |
input we_i; |
output reg ack_o; |
input clk; |
input rst; |
|
inout [gpio_width - 1 : 0] gpio; |
|
wire [gpio_width -1 : 0] gpio_i; |
|
reg [31:0] gpio_o, gpio_o_r, gpio_dir; |
|
reg [gpio_width - 1 : 0] dat_o_r; |
|
assign dat_o[gpio_width-1: 0] = dat_o_r; |
assign dat_o[31:gpio_width] = 0; |
|
always @(posedge clk) |
if (rst) |
gpio_dir <= 0; // All in |
else |
if (stb_i & cyc_i & we_i & adr_i[2]) |
begin |
if (sel_i[3]) gpio_dir[31:24] <= dat_i[31:24]; |
if (sel_i[2]) gpio_dir[23:16] <= dat_i[23:16]; |
if (sel_i[1]) gpio_dir[15:8] <= dat_i[15:8]; |
if (sel_i[0]) gpio_dir[7:0] <= dat_i[7:0]; |
end |
|
always @(posedge clk) |
if (rst) |
ack_o <= 0; |
else if (stb_i & cyc_i & !ack_o) |
ack_o <= 1; |
else |
ack_o <= 0; |
|
|
always @(posedge clk) |
if (rst) |
gpio_o <= 0; |
else if (stb_i & cyc_i & we_i & !adr_i[2]) |
begin |
if (sel_i[3]) gpio_o[31:24] <= dat_i[31:24]; |
if (sel_i[2]) gpio_o[23:16] <= dat_i[23:16]; |
if (sel_i[1]) gpio_o[15:8] <= dat_i[15:8]; |
if (sel_i[0]) gpio_o[7:0] <= dat_i[7:0]; |
end |
|
|
genvar i; |
generate |
for (i=0; i<gpio_width; i=i+1) begin: gpio_tribuf_gen |
|
always @(posedge clk) |
if (stb_i & cyc_i & !we_i) |
if (!adr_i[2]) |
dat_o_r[i] <= gpio_dir[i] ? gpio_o_r[i] : gpio_i[i]; |
else |
dat_o_r[i] <= gpio_dir[i]; |
|
// Xilinx primitive |
IOBUF U |
( |
// Outputs |
.O (gpio_i[i]), |
// Inouts |
.IO (gpio[i]), |
// Inputs |
.I (gpio_o[i]), |
.T (!gpio_dir[i])); |
end // block: gpio_tribuf_gen |
endgenerate |
|
endmodule // ml501_gpio |
|
/wb_conbus_defines.v
0,0 → 1,11
`define dw 32 // Data bus Width |
`define aw 32 // Address bus Width |
`define sw `dw / 8 // Number of Select Lines |
`define mbusw `aw + `sw + `dw +4 //address width + byte select width + dat width + cyc + we + stb +cab , input from master interface |
`define sbusw 3 // ack + err + rty, input from slave interface |
`define mselectw 8 // number of masters |
`define sselectw 8 // number of slavers |
|
|
// Define the following to enable logic to generate the first few instructions at reset |
//`define OR1200_BOOT_LOGIC |
/or1200_defines.v
0,0 → 1,1847
////////////////////////////////////////////////////////////////////// |
//// //// |
//// OR1200's definitions //// |
//// //// |
//// This file is part of the OpenRISC 1200 project //// |
//// http://www.opencores.org/cores/or1k/ //// |
//// //// |
//// Description //// |
//// Parameters of the OR1200 core //// |
//// //// |
//// To Do: //// |
//// - add parameters that are missing //// |
//// //// |
//// Author(s): //// |
//// - Damjan Lampret, lampret@opencores.org //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: or1200_defines.v,v $ |
// Revision 1.45 2006/04/09 01:32:29 lampret |
// See OR1200_MAC_SHIFTBY in or1200_defines.v for explanation of the change. Since now no more 28 bits shift for l.macrc insns however for backward compatbility it is possible to set arbitry number of shifts. |
// |
// Revision 1.44 2005/10/19 11:37:56 jcastillo |
// Added support for RAMB16 Xilinx4/Spartan3 primitives |
// |
// Revision 1.43 2005/01/07 09:23:39 andreje |
// l.ff1 and l.cmov instructions added |
// |
// Revision 1.42 2004/06/08 18:17:36 lampret |
// Non-functional changes. Coding style fixes. |
// |
// Revision 1.41 2004/05/09 20:03:20 lampret |
// By default l.cust5 insns are disabled |
// |
// Revision 1.40 2004/05/09 19:49:04 lampret |
// Added some l.cust5 custom instructions as example |
// |
// Revision 1.39 2004/04/08 11:00:46 simont |
// Add support for 512B instruction cache. |
// |
// Revision 1.38 2004/04/05 08:29:57 lampret |
// Merged branch_qmem into main tree. |
// |
// Revision 1.35.4.6 2004/02/11 01:40:11 lampret |
// preliminary HW breakpoints support in debug unit (by default disabled). To enable define OR1200_DU_HWBKPTS. |
// |
// Revision 1.35.4.5 2004/01/15 06:46:38 markom |
// interface to debug changed; no more opselect; stb-ack protocol |
// |
// Revision 1.35.4.4 2004/01/11 22:45:46 andreje |
// Separate instruction and data QMEM decoders, QMEM acknowledge and byte-select added |
// |
// Revision 1.35.4.3 2003/12/17 13:43:38 simons |
// Exception prefix configuration changed. |
// |
// Revision 1.35.4.2 2003/12/05 00:05:03 lampret |
// Static exception prefix. |
// |
// Revision 1.35.4.1 2003/07/08 15:36:37 lampret |
// Added embedded memory QMEM. |
// |
// Revision 1.35 2003/04/24 00:16:07 lampret |
// No functional changes. Added defines to disable implementation of multiplier/MAC |
// |
// Revision 1.34 2003/04/20 22:23:57 lampret |
// No functional change. Only added customization for exception vectors. |
// |
// Revision 1.33 2003/04/07 20:56:07 lampret |
// Fixed OR1200_CLKDIV_x_SUPPORTED defines. Better description. |
// |
// Revision 1.32 2003/04/07 01:26:57 lampret |
// RFRAM defines comments updated. Altera LPM option added. |
// |
// Revision 1.31 2002/12/08 08:57:56 lampret |
// Added optional support for WB B3 specification (xwb_cti_o, xwb_bte_o). Made xwb_cab_o optional. |
// |
// Revision 1.30 2002/10/28 15:09:22 mohor |
// Previous check-in was done by mistake. |
// |
// Revision 1.29 2002/10/28 15:03:50 mohor |
// Signal scanb_sen renamed to scanb_en. |
// |
// Revision 1.28 2002/10/17 20:04:40 lampret |
// Added BIST scan. Special VS RAMs need to be used to implement BIST. |
// |
// Revision 1.27 2002/09/16 03:13:23 lampret |
// Removed obsolete comment. |
// |
// Revision 1.26 2002/09/08 05:52:16 lampret |
// Added optional l.div/l.divu insns. By default they are disabled. |
// |
// Revision 1.25 2002/09/07 19:16:10 lampret |
// If SR[CY] implemented with OR1200_IMPL_ADDC enabled, l.add/l.addi also set SR[CY]. |
// |
// Revision 1.24 2002/09/07 05:42:02 lampret |
// Added optional SR[CY]. Added define to enable additional (compare) flag modifiers. Defines are OR1200_IMPL_ADDC and OR1200_ADDITIONAL_FLAG_MODIFIERS. |
// |
// Revision 1.23 2002/09/04 00:50:34 lampret |
// Now most of the configuration registers are updatded automatically based on defines in or1200_defines.v. |
// |
// Revision 1.22 2002/09/03 22:28:21 lampret |
// As per Taylor Su suggestion all case blocks are full case by default and optionally (OR1200_CASE_DEFAULT) can be disabled to increase clock frequncy. |
// |
// Revision 1.21 2002/08/22 02:18:55 lampret |
// Store buffer has been tested and it works. BY default it is still disabled until uClinux confirms correct operation on FPGA board. |
// |
// Revision 1.20 2002/08/18 21:59:45 lampret |
// Disable SB until it is tested |
// |
// Revision 1.19 2002/08/18 19:53:08 lampret |
// Added store buffer. |
// |
// Revision 1.18 2002/08/15 06:04:11 lampret |
// Fixed Xilinx trace buffer address. REported by Taylor Su. |
// |
// Revision 1.17 2002/08/12 05:31:44 lampret |
// Added OR1200_WB_RETRY. Moved WB registered outsputs / samples inputs into lower section. |
// |
// Revision 1.16 2002/07/14 22:17:17 lampret |
// Added simple trace buffer [only for Xilinx Virtex target]. Fixed instruction fetch abort when new exception is recognized. |
// |
// Revision 1.15 2002/06/08 16:20:21 lampret |
// Added defines for enabling generic FF based memory macro for register file. |
// |
// Revision 1.14 2002/03/29 16:24:06 lampret |
// Changed comment about synopsys to _synopsys_ because synthesis was complaining about unknown directives |
// |
// Revision 1.13 2002/03/29 15:16:55 lampret |
// Some of the warnings fixed. |
// |
// Revision 1.12 2002/03/28 19:25:42 lampret |
// Added second type of Virtual Silicon two-port SRAM (for register file). Changed defines for VS STP RAMs. |
// |
// Revision 1.11 2002/03/28 19:13:17 lampret |
// Updated defines. |
// |
// Revision 1.10 2002/03/14 00:30:24 lampret |
// Added alternative for critical path in DU. |
// |
// Revision 1.9 2002/03/11 01:26:26 lampret |
// Fixed async loop. Changed multiplier type for ASIC. |
// |
// Revision 1.8 2002/02/11 04:33:17 lampret |
// Speed optimizations (removed duplicate _cyc_ and _stb_). Fixed D/IMMU cache-inhibit attr. |
// |
// Revision 1.7 2002/02/01 19:56:54 lampret |
// Fixed combinational loops. |
// |
// Revision 1.6 2002/01/19 14:10:22 lampret |
// Fixed OR1200_XILINX_RAM32X1D. |
// |
// Revision 1.5 2002/01/18 07:56:00 lampret |
// No more low/high priority interrupts (PICPR removed). Added tick timer exception. Added exception prefix (SR[EPH]). Fixed single-step bug whenreading NPC. |
// |
// Revision 1.4 2002/01/14 09:44:12 lampret |
// Default ASIC configuration does not sample WB inputs. |
// |
// Revision 1.3 2002/01/08 00:51:08 lampret |
// Fixed typo. OR1200_REGISTERED_OUTPUTS was not defined. Should be. |
// |
// Revision 1.2 2002/01/03 21:23:03 lampret |
// Uncommented OR1200_REGISTERED_OUTPUTS for FPGA target. |
// |
// Revision 1.1 2002/01/03 08:16:15 lampret |
// New prefixes for RTL files, prefixed module names. Updated cache controllers and MMUs. |
// |
// Revision 1.20 2001/12/04 05:02:36 lampret |
// Added OR1200_GENERIC_MULTP2_32X32 and OR1200_ASIC_MULTP2_32X32 |
// |
// Revision 1.19 2001/11/27 19:46:57 lampret |
// Now FPGA and ASIC target are separate. |
// |
// Revision 1.18 2001/11/23 21:42:31 simons |
// Program counter divided to PPC and NPC. |
// |
// Revision 1.17 2001/11/23 08:38:51 lampret |
// Changed DSR/DRR behavior and exception detection. |
// |
// Revision 1.16 2001/11/20 21:30:38 lampret |
// Added OR1200_REGISTERED_INPUTS. |
// |
// Revision 1.15 2001/11/19 14:29:48 simons |
// Cashes disabled. |
// |
// Revision 1.14 2001/11/13 10:02:21 lampret |
// Added 'setpc'. Renamed some signals (except_flushpipe into flushpipe etc) |
// |
// Revision 1.13 2001/11/12 01:45:40 lampret |
// Moved flag bit into SR. Changed RF enable from constant enable to dynamic enable for read ports. |
// |
// Revision 1.12 2001/11/10 03:43:57 lampret |
// Fixed exceptions. |
// |
// Revision 1.11 2001/11/02 18:57:14 lampret |
// Modified virtual silicon instantiations. |
// |
// Revision 1.10 2001/10/21 17:57:16 lampret |
// Removed params from generic_XX.v. Added translate_off/on in sprs.v and id.v. Removed spr_addr from dc.v and ic.v. Fixed CR+LF. |
// |
// Revision 1.9 2001/10/19 23:28:46 lampret |
// Fixed some synthesis warnings. Configured with caches and MMUs. |
// |
// Revision 1.8 2001/10/14 13:12:09 lampret |
// MP3 version. |
// |
// Revision 1.1.1.1 2001/10/06 10:18:36 igorm |
// no message |
// |
// Revision 1.3 2001/08/17 08:01:19 lampret |
// IC enable/disable. |
// |
// Revision 1.2 2001/08/13 03:36:20 lampret |
// Added cfg regs. Moved all defines into one defines.v file. More cleanup. |
// |
// Revision 1.1 2001/08/09 13:39:33 lampret |
// Major clean-up. |
// |
// Revision 1.2 2001/07/22 03:31:54 lampret |
// Fixed RAM's oen bug. Cache bypass under development. |
// |
// Revision 1.1 2001/07/20 00:46:03 lampret |
// Development version of RTL. Libraries are missing. |
// |
// |
|
// |
// Dump VCD |
// |
//`define OR1200_VCD_DUMP |
|
// |
// Generate debug messages during simulation |
// |
//`define OR1200_VERBOSE |
|
// `define OR1200_ASIC |
//////////////////////////////////////////////////////// |
// |
// Typical configuration for an ASIC |
// |
`ifdef OR1200_ASIC |
|
// |
// Target ASIC memories |
// |
//`define OR1200_ARTISAN_SSP |
//`define OR1200_ARTISAN_SDP |
//`define OR1200_ARTISAN_STP |
`define OR1200_VIRTUALSILICON_SSP |
//`define OR1200_VIRTUALSILICON_STP_T1 |
//`define OR1200_VIRTUALSILICON_STP_T2 |
|
// |
// Do not implement Data cache |
// |
//`define OR1200_NO_DC |
|
// |
// Do not implement Insn cache |
// |
//`define OR1200_NO_IC |
|
// |
// Do not implement Data MMU |
// |
//`define OR1200_NO_DMMU |
|
// |
// Do not implement Insn MMU |
// |
//`define OR1200_NO_IMMU |
|
// |
// Select between ASIC optimized and generic multiplier |
// |
//`define OR1200_ASIC_MULTP2_32X32 |
`define OR1200_GENERIC_MULTP2_32X32 |
|
// |
// Size/type of insn/data cache if implemented |
// |
// `define OR1200_IC_1W_512B |
// `define OR1200_IC_1W_4KB |
`define OR1200_IC_1W_8KB |
// `define OR1200_DC_1W_4KB |
`define OR1200_DC_1W_8KB |
|
`else |
|
|
///////////////////////////////////////////////////////// |
// |
// Typical configuration for an FPGA |
// |
|
// |
// Target FPGA memories |
// |
//`define OR1200_ALTERA_LPM |
`define OR1200_XILINX_RAMB16 |
//`define OR1200_XILINX_RAMB4 |
//`define OR1200_XILINX_RAM32X1D |
//`define OR1200_USE_RAM16X1D_FOR_RAM32X1D |
//`define OR1200_ACTEL |
|
// |
// Do not implement Data cache |
// |
`define OR1200_NO_DC |
|
// |
// Do not implement Insn cache |
// |
//`define OR1200_NO_IC |
|
// |
// Do not implement Data MMU |
// |
//`define OR1200_NO_DMMU |
|
// |
// Do not implement Insn MMU |
// |
//`define OR1200_NO_IMMU |
|
// |
// Select between ASIC and generic multiplier |
// |
// (Generic seems to trigger a bug in the Cadence Ncsim simulator) |
// |
//`define OR1200_ASIC_MULTP2_32X32 |
`define OR1200_GENERIC_MULTP2_32X32 |
|
// |
// Size/type of insn/data cache if implemented |
// (consider available FPGA memory resources) |
// |
//`define OR1200_IC_1W_512B |
//`define OR1200_IC_1W_4KB |
`define OR1200_IC_1W_8KB |
//`define OR1200_DC_1W_4KB |
`define OR1200_DC_1W_8KB |
|
`endif |
|
|
////////////////////////////////////////////////////////// |
// |
// Do not change below unless you know what you are doing |
// |
|
// |
// Enable RAM BIST |
// |
// At the moment this only works for Virtual Silicon |
// single port RAMs. For other RAMs it has not effect. |
// Special wrapper for VS RAMs needs to be provided |
// with scan flops to facilitate bist scan. |
// |
//`define OR1200_BIST |
|
// |
// Register OR1200 WISHBONE outputs |
// (must be defined/enabled) |
// |
`define OR1200_REGISTERED_OUTPUTS |
|
// |
// Register OR1200 WISHBONE inputs |
// |
// (must be undefined/disabled) |
// |
//`define OR1200_REGISTERED_INPUTS |
|
// |
// Disable bursts if they are not supported by the |
// memory subsystem (only affect cache line fill) |
// |
`define OR1200_NO_BURSTS |
// |
|
// |
// WISHBONE retry counter range |
// |
// 2^value range for retry counter. Retry counter |
// is activated whenever *wb_rty_i is asserted and |
// until retry counter expires, corresponding |
// WISHBONE interface is deactivated. |
// |
// To disable retry counters and *wb_rty_i all together, |
// undefine this macro. |
// |
//`define OR1200_WB_RETRY 7 |
|
// |
// WISHBONE Consecutive Address Burst |
// |
// This was used prior to WISHBONE B3 specification |
// to identify bursts. It is no longer needed but |
// remains enabled for compatibility with old designs. |
// |
// To remove *wb_cab_o ports undefine this macro. |
// |
//`define OR1200_WB_CAB |
|
// |
// WISHBONE B3 compatible interface |
// |
// This follows the WISHBONE B3 specification. |
// It is not enabled by default because most |
// designs still don't use WB b3. |
// |
// To enable *wb_cti_o/*wb_bte_o ports, |
// define this macro. |
// |
`define OR1200_WB_B3 |
|
// |
// LOG all WISHBONE accesses |
// |
`define OR1200_LOG_WB_ACCESS |
|
// |
// Enable additional synthesis directives if using |
// _Synopsys_ synthesis tool |
// |
//`define OR1200_ADDITIONAL_SYNOPSYS_DIRECTIVES |
|
// |
// Enables default statement in some case blocks |
// and disables Synopsys synthesis directive full_case |
// |
// By default it is enabled. When disabled it |
// can increase clock frequency. |
// |
`define OR1200_CASE_DEFAULT |
|
// |
// Operand width / register file address width |
// |
// (DO NOT CHANGE) |
// |
`define OR1200_OPERAND_WIDTH 32 |
`define OR1200_REGFILE_ADDR_WIDTH 5 |
|
// |
// l.add/l.addi/l.and and optional l.addc/l.addic |
// also set (compare) flag when result of their |
// operation equals zero |
// |
// At the time of writing this, default or32 |
// C/C++ compiler doesn't generate code that |
// would benefit from this optimization. |
// |
// By default this optimization is disabled to |
// save area. |
// |
//`define OR1200_ADDITIONAL_FLAG_MODIFIERS |
|
// |
// Implement l.addc/l.addic instructions |
// |
// By default implementation of l.addc/l.addic |
// instructions is enabled in case you need them. |
// If you don't use them, then disable implementation |
// to save area. |
// |
`define OR1200_IMPL_ADDC |
|
// |
// Implement carry bit SR[CY] |
// |
// By default implementation of SR[CY] is enabled |
// to be compliant with the simulator. However |
// SR[CY] is explicitly only used by l.addc/l.addic |
// instructions and if these two insns are not |
// implemented there is not much point having SR[CY]. |
// |
`define OR1200_IMPL_CY |
|
// |
// Implement optional l.div/l.divu instructions |
// |
// By default divide instructions are not implemented |
// to save area and increase clock frequency. or32 C/C++ |
// compiler can use soft library for division. |
// |
// To implement divide, multiplier needs to be implemented. |
// |
`define OR1200_IMPL_DIV |
|
// |
// Implement rotate in the ALU |
// |
// At the time of writing this, or32 |
// C/C++ compiler doesn't generate rotate |
// instructions. However or32 assembler |
// can assemble code that uses rotate insn. |
// This means that rotate instructions |
// must be used manually inserted. |
// |
// By default implementation of rotate |
// is disabled to save area and increase |
// clock frequency. |
// |
//`define OR1200_IMPL_ALU_ROTATE |
|
// |
// Type of ALU compare to implement |
// |
// Try either one to find what yields |
// higher clock frequencyin your case. |
// |
//`define OR1200_IMPL_ALU_COMP1 |
`define OR1200_IMPL_ALU_COMP2 |
|
// |
// Implement multiplier |
// |
// By default multiplier is implemented |
// |
`define OR1200_MULT_IMPLEMENTED |
|
// |
// Implement multiply-and-accumulate |
// |
// By default MAC is implemented. To |
// implement MAC, multiplier needs to be |
// implemented. |
// |
`define OR1200_MAC_IMPLEMENTED |
|
// |
// Low power, slower multiplier |
// |
// Select between low-power (larger) multiplier |
// and faster multiplier. The actual difference |
// is only AND logic that prevents distribution |
// of operands into the multiplier when instruction |
// in execution is not multiply instruction |
// |
//`define OR1200_LOWPWR_MULT |
|
|
// |
// Implement HW Single Precision FPU |
// |
//`define OR1200_FPU_IMPLEMENTED |
|
// |
// Clock ratio RISC clock versus WB clock |
// |
// If you plan to run WB:RISC clock fixed to 1:1, disable |
// both defines |
// |
// For WB:RISC 1:2 or 1:1, enable OR1200_CLKDIV_2_SUPPORTED |
// and use clmode to set ratio |
// |
// For WB:RISC 1:4, 1:2 or 1:1, enable both defines and use |
// clmode to set ratio |
// |
`define OR1200_CLKDIV_2_SUPPORTED |
//`define OR1200_CLKDIV_4_SUPPORTED |
|
// |
// Type of register file RAM |
// |
// Memory macro w/ two ports (see or1200_tpram_32x32.v) |
`define OR1200_RFRAM_TWOPORT |
// |
// Memory macro dual port (see or1200_dpram_32x32.v) |
//`define OR1200_RFRAM_DUALPORT |
|
// |
// Generic (flip-flop based) register file (see or1200_rfram_generic.v) |
//`define OR1200_RFRAM_GENERIC |
// Generic register file supports - 16 registers |
`ifdef OR1200_RFRAM_GENERIC |
// `define OR1200_RFRAM_16REG |
`endif |
|
// |
// Type of mem2reg aligner to implement. |
// |
// Once OR1200_IMPL_MEM2REG2 yielded faster |
// circuit, however with today tools it will |
// most probably give you slower circuit. |
// |
`define OR1200_IMPL_MEM2REG1 |
//`define OR1200_IMPL_MEM2REG2 |
|
// |
// ALUOPs |
// |
`define OR1200_ALUOP_WIDTH 4 |
`define OR1200_ALUOP_NOP 4'd4 |
/* Order defined by arith insns that have two source operands both in regs |
(see binutils/include/opcode/or32.h) */ |
`define OR1200_ALUOP_ADD 4'd0 |
`define OR1200_ALUOP_ADDC 4'd1 |
`define OR1200_ALUOP_SUB 4'd2 |
`define OR1200_ALUOP_AND 4'd3 |
`define OR1200_ALUOP_OR 4'd4 |
`define OR1200_ALUOP_XOR 4'd5 |
`define OR1200_ALUOP_MUL 4'd6 |
`define OR1200_ALUOP_CUST5 4'd7 |
`define OR1200_ALUOP_SHROT 4'd8 |
`define OR1200_ALUOP_DIV 4'd9 |
`define OR1200_ALUOP_DIVU 4'd10 |
/* Order not specifically defined. */ |
`define OR1200_ALUOP_IMM 4'd11 |
`define OR1200_ALUOP_MOVHI 4'd12 |
`define OR1200_ALUOP_COMP 4'd13 |
`define OR1200_ALUOP_MTSR 4'd14 |
`define OR1200_ALUOP_MFSR 4'd15 |
`define OR1200_ALUOP_CMOV 4'd14 |
`define OR1200_ALUOP_FF1 4'd15 |
// |
// MACOPs |
// |
`define OR1200_MACOP_WIDTH 2 |
`define OR1200_MACOP_NOP 2'b00 |
`define OR1200_MACOP_MAC 2'b01 |
`define OR1200_MACOP_MSB 2'b10 |
|
// |
// Shift/rotate ops |
// |
`define OR1200_SHROTOP_WIDTH 2 |
`define OR1200_SHROTOP_NOP 2'd0 |
`define OR1200_SHROTOP_SLL 2'd0 |
`define OR1200_SHROTOP_SRL 2'd1 |
`define OR1200_SHROTOP_SRA 2'd2 |
`define OR1200_SHROTOP_ROR 2'd3 |
|
// Execution cycles per instruction |
`define OR1200_MULTICYCLE_WIDTH 3 |
`define OR1200_ONE_CYCLE 3'd0 |
`define OR1200_TWO_CYCLES 3'd1 |
|
// Operand MUX selects |
`define OR1200_SEL_WIDTH 2 |
`define OR1200_SEL_RF 2'd0 |
`define OR1200_SEL_IMM 2'd1 |
`define OR1200_SEL_EX_FORW 2'd2 |
`define OR1200_SEL_WB_FORW 2'd3 |
|
// |
// BRANCHOPs |
// |
`define OR1200_BRANCHOP_WIDTH 3 |
`define OR1200_BRANCHOP_NOP 3'd0 |
`define OR1200_BRANCHOP_J 3'd1 |
`define OR1200_BRANCHOP_JR 3'd2 |
`define OR1200_BRANCHOP_BAL 3'd3 |
`define OR1200_BRANCHOP_BF 3'd4 |
`define OR1200_BRANCHOP_BNF 3'd5 |
`define OR1200_BRANCHOP_RFE 3'd6 |
|
// |
// LSUOPs |
// |
// Bit 0: sign extend |
// Bits 1-2: 00 doubleword, 01 byte, 10 halfword, 11 singleword |
// Bit 3: 0 load, 1 store |
`define OR1200_LSUOP_WIDTH 4 |
`define OR1200_LSUOP_NOP 4'b0000 |
`define OR1200_LSUOP_LBZ 4'b0010 |
`define OR1200_LSUOP_LBS 4'b0011 |
`define OR1200_LSUOP_LHZ 4'b0100 |
`define OR1200_LSUOP_LHS 4'b0101 |
`define OR1200_LSUOP_LWZ 4'b0110 |
`define OR1200_LSUOP_LWS 4'b0111 |
`define OR1200_LSUOP_LD 4'b0001 |
`define OR1200_LSUOP_SD 4'b1000 |
`define OR1200_LSUOP_SB 4'b1010 |
`define OR1200_LSUOP_SH 4'b1100 |
`define OR1200_LSUOP_SW 4'b1110 |
|
// FETCHOPs |
`define OR1200_FETCHOP_WIDTH 1 |
`define OR1200_FETCHOP_NOP 1'b0 |
`define OR1200_FETCHOP_LW 1'b1 |
|
// |
// Register File Write-Back OPs |
// |
`ifdef OR1200_FPU_IMPLEMENTED |
// Bit 0: register file write enable |
// Bits 3-1: write-back mux selects |
`define OR1200_RFWBOP_WIDTH 4 |
`define OR1200_RFWBOP_NOP 4'b0000 |
`define OR1200_RFWBOP_ALU 3'b000 |
`define OR1200_RFWBOP_LSU 3'b001 |
`define OR1200_RFWBOP_SPRS 3'b010 |
`define OR1200_RFWBOP_LR 3'b011 |
`define OR1200_RFWBOP_FPU 3'b100 |
`else |
// Bit 0: register file write enable |
// Bits 2-1: write-back mux selects |
`define OR1200_RFWBOP_WIDTH 3 |
`define OR1200_RFWBOP_NOP 3'b000 |
`define OR1200_RFWBOP_ALU 2'b00 |
`define OR1200_RFWBOP_LSU 2'b01 |
`define OR1200_RFWBOP_SPRS 2'b10 |
`define OR1200_RFWBOP_LR 2'b11 |
`endif // !`ifdef OR1200_FPU_IMPLEMENTED |
|
// Compare instructions |
`define OR1200_COP_SFEQ 3'b000 |
`define OR1200_COP_SFNE 3'b001 |
`define OR1200_COP_SFGT 3'b010 |
`define OR1200_COP_SFGE 3'b011 |
`define OR1200_COP_SFLT 3'b100 |
`define OR1200_COP_SFLE 3'b101 |
`define OR1200_COP_X 3'b111 |
`define OR1200_SIGNED_COMPARE 'd3 |
`define OR1200_COMPOP_WIDTH 4 |
|
// |
// FPU OPs |
// |
// MSbit indicates FPU operation valid |
// |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_FPUOP_WIDTH 8 |
/* FPU unit from Usselman takes 5 cycles from decode, so 4 ex. cycles */ |
`define OR1200_FPUOP_CYCLES 3'd4 |
/* FP instruction is double precision if bit 4 is set. We're a 32-bit |
implementation thus do not support double precision FP */ |
`define OR1200_FPUOP_DOUBLE_BIT 4 |
`define OR1200_FPUOP_ADD 8'b0000_0000 |
`define OR1200_FPUOP_SUB 8'b0000_0001 |
`define OR1200_FPUOP_MUL 8'b0000_0010 |
`define OR1200_FPUOP_DIV 8'b0000_0011 |
`define OR1200_FPUOP_ITOF 8'b0000_0100 |
`define OR1200_FPUOP_FTOI 8'b0000_0101 |
`define OR1200_FPUOP_REM 8'b0000_0110 |
`define OR1200_FPUOP_RESERVED 8'b0000_0111 |
// FP Compare instructions |
`define OR1200_FPCOP_SFEQ 8'b0000_1000 |
`define OR1200_FPCOP_SFNE 8'b0000_1001 |
`define OR1200_FPCOP_SFGT 8'b0000_1010 |
`define OR1200_FPCOP_SFGE 8'b0000_1011 |
`define OR1200_FPCOP_SFLT 8'b0000_1100 |
`define OR1200_FPCOP_SFLE 8'b0000_1101 |
`endif |
|
// |
// TAGs for instruction bus |
// |
`define OR1200_ITAG_IDLE 4'h0 // idle bus |
`define OR1200_ITAG_NI 4'h1 // normal insn |
`define OR1200_ITAG_BE 4'hb // Bus error exception |
`define OR1200_ITAG_PE 4'hc // Page fault exception |
`define OR1200_ITAG_TE 4'hd // TLB miss exception |
|
// |
// TAGs for data bus |
// |
`define OR1200_DTAG_IDLE 4'h0 // idle bus |
`define OR1200_DTAG_ND 4'h1 // normal data |
`define OR1200_DTAG_AE 4'ha // Alignment exception |
`define OR1200_DTAG_BE 4'hb // Bus error exception |
`define OR1200_DTAG_PE 4'hc // Page fault exception |
`define OR1200_DTAG_TE 4'hd // TLB miss exception |
|
|
////////////////////////////////////////////// |
// |
// ORBIS32 ISA specifics |
// |
|
// SHROT_OP position in machine word |
`define OR1200_SHROTOP_POS 7:6 |
|
// ALU instructions multicycle field in machine word |
`define OR1200_ALUMCYC_POS 9:8 |
|
// |
// Instruction opcode groups (basic) |
// |
`define OR1200_OR32_J 6'b000000 |
`define OR1200_OR32_JAL 6'b000001 |
`define OR1200_OR32_BNF 6'b000011 |
`define OR1200_OR32_BF 6'b000100 |
`define OR1200_OR32_NOP 6'b000101 |
`define OR1200_OR32_MOVHI 6'b000110 |
`define OR1200_OR32_XSYNC 6'b001000 |
`define OR1200_OR32_RFE 6'b001001 |
/* */ |
`define OR1200_OR32_JR 6'b010001 |
`define OR1200_OR32_JALR 6'b010010 |
`define OR1200_OR32_MACI 6'b010011 |
/* */ |
`define OR1200_OR32_LWZ 6'b100001 |
`define OR1200_OR32_LBZ 6'b100011 |
`define OR1200_OR32_LBS 6'b100100 |
`define OR1200_OR32_LHZ 6'b100101 |
`define OR1200_OR32_LHS 6'b100110 |
`define OR1200_OR32_ADDI 6'b100111 |
`define OR1200_OR32_ADDIC 6'b101000 |
`define OR1200_OR32_ANDI 6'b101001 |
`define OR1200_OR32_ORI 6'b101010 |
`define OR1200_OR32_XORI 6'b101011 |
`define OR1200_OR32_MULI 6'b101100 |
`define OR1200_OR32_MFSPR 6'b101101 |
`define OR1200_OR32_SH_ROTI 6'b101110 |
`define OR1200_OR32_SFXXI 6'b101111 |
/* */ |
`define OR1200_OR32_MTSPR 6'b110000 |
`define OR1200_OR32_MACMSB 6'b110001 |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_OR32_FLOAT 6'b110010 |
`endif |
/* */ |
`define OR1200_OR32_SW 6'b110101 |
`define OR1200_OR32_SB 6'b110110 |
`define OR1200_OR32_SH 6'b110111 |
`define OR1200_OR32_ALU 6'b111000 |
`define OR1200_OR32_SFXX 6'b111001 |
//`define OR1200_OR32_CUST5 6'b111100 |
|
///////////////////////////////////////////////////// |
// |
// Exceptions |
// |
|
// |
// Exception vectors per OR1K architecture: |
// 0xPPPPP100 - reset |
// 0xPPPPP200 - bus error |
// ... etc |
// where P represents exception prefix. |
// |
// Exception vectors can be customized as per |
// the following formula: |
// 0xPPPPPNVV - exception N |
// |
// P represents exception prefix |
// N represents exception N |
// VV represents length of the individual vector space, |
// usually it is 8 bits wide and starts with all bits zero |
// |
|
// |
// PPPPP and VV parts |
// |
// Sum of these two defines needs to be 28 |
// |
`define OR1200_EXCEPT_EPH0_P 20'h00000 |
`define OR1200_EXCEPT_EPH1_P 20'hF0000 |
`define OR1200_EXCEPT_V 8'h00 |
|
// |
// N part width |
// |
`define OR1200_EXCEPT_WIDTH 4 |
|
// |
// Definition of exception vectors |
// |
// To avoid implementation of a certain exception, |
// simply comment out corresponding line |
// |
`define OR1200_EXCEPT_UNUSED `OR1200_EXCEPT_WIDTH'hf |
`define OR1200_EXCEPT_TRAP `OR1200_EXCEPT_WIDTH'he |
//`define OR1200_EXCEPT_BREAK `OR1200_EXCEPT_WIDTH'hd |
`define OR1200_EXCEPT_FLOAT `OR1200_EXCEPT_WIDTH'hd |
`define OR1200_EXCEPT_SYSCALL `OR1200_EXCEPT_WIDTH'hc |
`define OR1200_EXCEPT_RANGE `OR1200_EXCEPT_WIDTH'hb |
`define OR1200_EXCEPT_ITLBMISS `OR1200_EXCEPT_WIDTH'ha |
`define OR1200_EXCEPT_DTLBMISS `OR1200_EXCEPT_WIDTH'h9 |
`define OR1200_EXCEPT_INT `OR1200_EXCEPT_WIDTH'h8 |
`define OR1200_EXCEPT_ILLEGAL `OR1200_EXCEPT_WIDTH'h7 |
`define OR1200_EXCEPT_ALIGN `OR1200_EXCEPT_WIDTH'h6 |
`define OR1200_EXCEPT_TICK `OR1200_EXCEPT_WIDTH'h5 |
`define OR1200_EXCEPT_IPF `OR1200_EXCEPT_WIDTH'h4 |
`define OR1200_EXCEPT_DPF `OR1200_EXCEPT_WIDTH'h3 |
`define OR1200_EXCEPT_BUSERR `OR1200_EXCEPT_WIDTH'h2 |
`define OR1200_EXCEPT_RESET `OR1200_EXCEPT_WIDTH'h1 |
`define OR1200_EXCEPT_NONE `OR1200_EXCEPT_WIDTH'h0 |
|
|
///////////////////////////////////////////////////// |
// |
// SPR groups |
// |
|
// Bits that define the group |
`define OR1200_SPR_GROUP_BITS 15:11 |
|
// Width of the group bits |
`define OR1200_SPR_GROUP_WIDTH 5 |
|
// Bits that define offset inside the group |
`define OR1200_SPR_OFS_BITS 10:0 |
|
// List of groups |
`define OR1200_SPR_GROUP_SYS 5'd00 |
`define OR1200_SPR_GROUP_DMMU 5'd01 |
`define OR1200_SPR_GROUP_IMMU 5'd02 |
`define OR1200_SPR_GROUP_DC 5'd03 |
`define OR1200_SPR_GROUP_IC 5'd04 |
`define OR1200_SPR_GROUP_MAC 5'd05 |
`define OR1200_SPR_GROUP_DU 5'd06 |
`define OR1200_SPR_GROUP_PM 5'd08 |
`define OR1200_SPR_GROUP_PIC 5'd09 |
`define OR1200_SPR_GROUP_TT 5'd10 |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_SPR_GROUP_FPU 5'd11 |
`endif |
|
///////////////////////////////////////////////////// |
// |
// System group |
// |
|
// |
// System registers |
// |
`define OR1200_SPR_CFGR 7'd0 |
`define OR1200_SPR_RF 6'd32 // 1024 >> 5 |
`define OR1200_SPR_NPC 11'd16 |
`define OR1200_SPR_SR 11'd17 |
`define OR1200_SPR_PPC 11'd18 |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_SPR_FPCSR 11'd20 |
`endif |
`define OR1200_SPR_EPCR 11'd32 |
`define OR1200_SPR_EEAR 11'd48 |
`define OR1200_SPR_ESR 11'd64 |
|
// |
// SR bits |
// |
`define OR1200_SR_WIDTH 16 |
`define OR1200_SR_SM 0 |
`define OR1200_SR_TEE 1 |
`define OR1200_SR_IEE 2 |
`define OR1200_SR_DCE 3 |
`define OR1200_SR_ICE 4 |
`define OR1200_SR_DME 5 |
`define OR1200_SR_IME 6 |
`define OR1200_SR_LEE 7 |
`define OR1200_SR_CE 8 |
`define OR1200_SR_F 9 |
`define OR1200_SR_CY 10 // Unused |
`define OR1200_SR_OV 11 // Unused |
`define OR1200_SR_OVE 12 // Unused |
`define OR1200_SR_DSX 13 // Unused |
`define OR1200_SR_EPH 14 |
`define OR1200_SR_FO 15 |
`define OR1200_SR_CID 31:28 // Unimplemented |
|
// |
// Bits that define offset inside the group |
// |
`define OR1200_SPROFS_BITS 10:0 |
|
// |
// Default Exception Prefix |
// |
// 1'b0 - OR1200_EXCEPT_EPH0_P (0x0000_0000) |
// 1'b1 - OR1200_EXCEPT_EPH1_P (0xF000_0000) |
// |
`define OR1200_SR_EPH_DEF 1'b0 |
|
// |
// FPCSR bits |
// |
`define OR1200_FPCSR_WIDTH 12 |
`define OR1200_FPCSR_FPEE 0 |
`define OR1200_FPCSR_RM 2:1 |
`define OR1200_FPCSR_OVF 3 |
`define OR1200_FPCSR_UNF 4 |
`define OR1200_FPCSR_SNF 5 |
`define OR1200_FPCSR_QNF 6 |
`define OR1200_FPCSR_ZF 7 |
`define OR1200_FPCSR_IXF 8 |
`define OR1200_FPCSR_IVF 9 |
`define OR1200_FPCSR_INF 10 |
`define OR1200_FPCSR_DZF 11 |
`define OR1200_FPCSR_RES 31:12 |
|
|
///////////////////////////////////////////////////// |
// |
// Power Management (PM) |
// |
|
// Define it if you want PM implemented |
//`define OR1200_PM_IMPLEMENTED |
|
// Bit positions inside PMR (don't change) |
`define OR1200_PM_PMR_SDF 3:0 |
`define OR1200_PM_PMR_DME 4 |
`define OR1200_PM_PMR_SME 5 |
`define OR1200_PM_PMR_DCGE 6 |
`define OR1200_PM_PMR_UNUSED 31:7 |
|
// PMR offset inside PM group of registers |
`define OR1200_PM_OFS_PMR 11'b0 |
|
// PM group |
`define OR1200_SPRGRP_PM 5'd8 |
|
// Define if PMR can be read/written at any address inside PM group |
`define OR1200_PM_PARTIAL_DECODING |
|
// Define if reading PMR is allowed |
`define OR1200_PM_READREGS |
|
// Define if unused PMR bits should be zero |
`define OR1200_PM_UNUSED_ZERO |
|
|
///////////////////////////////////////////////////// |
// |
// Debug Unit (DU) |
// |
|
// Define it if you want DU implemented |
`define OR1200_DU_IMPLEMENTED |
|
// |
// Define if you want HW Breakpoints |
// (if HW breakpoints are not implemented |
// only default software trapping is |
// possible with l.trap insn - this is |
// however already enough for use |
// with or32 gdb) |
// |
`define OR1200_DU_HWBKPTS |
|
// Number of DVR/DCR pairs, minus one, if HW breakpoints enabled |
`define OR1200_DU_DVRDCR_PAIRS 7 |
|
// Define if you want trace buffer |
//`define OR1200_DU_TB_IMPLEMENTED |
|
// |
// Address offsets of DU registers inside DU group |
// |
// To not implement a register, doq not define its address |
// |
`ifdef OR1200_DU_HWBKPTS |
`define OR1200_DU_DVR0 11'd0 |
`define OR1200_DU_DVR1 11'd1 |
`define OR1200_DU_DVR2 11'd2 |
`define OR1200_DU_DVR3 11'd3 |
`define OR1200_DU_DVR4 11'd4 |
`define OR1200_DU_DVR5 11'd5 |
`define OR1200_DU_DVR6 11'd6 |
`define OR1200_DU_DVR7 11'd7 |
`define OR1200_DU_DCR0 11'd8 |
`define OR1200_DU_DCR1 11'd9 |
`define OR1200_DU_DCR2 11'd10 |
`define OR1200_DU_DCR3 11'd11 |
`define OR1200_DU_DCR4 11'd12 |
`define OR1200_DU_DCR5 11'd13 |
`define OR1200_DU_DCR6 11'd14 |
`define OR1200_DU_DCR7 11'd15 |
`endif |
`define OR1200_DU_DMR1 11'd16 |
`ifdef OR1200_DU_HWBKPTS |
`define OR1200_DU_DMR2 11'd17 |
`define OR1200_DU_DWCR0 11'd18 |
`define OR1200_DU_DWCR1 11'd19 |
`endif |
`define OR1200_DU_DSR 11'd20 |
`define OR1200_DU_DRR 11'd21 |
`ifdef OR1200_DU_TB_IMPLEMENTED |
`define OR1200_DU_TBADR 11'h0ff |
`define OR1200_DU_TBIA 11'h1xx |
`define OR1200_DU_TBIM 11'h2xx |
`define OR1200_DU_TBAR 11'h3xx |
`define OR1200_DU_TBTS 11'h4xx |
`endif |
|
// Position of offset bits inside SPR address |
`define OR1200_DUOFS_BITS 10:0 |
|
// DCR bits |
`define OR1200_DU_DCR_DP 0 |
`define OR1200_DU_DCR_CC 3:1 |
`define OR1200_DU_DCR_SC 4 |
`define OR1200_DU_DCR_CT 7:5 |
|
// DMR1 bits |
`define OR1200_DU_DMR1_CW0 1:0 |
`define OR1200_DU_DMR1_CW1 3:2 |
`define OR1200_DU_DMR1_CW2 5:4 |
`define OR1200_DU_DMR1_CW3 7:6 |
`define OR1200_DU_DMR1_CW4 9:8 |
`define OR1200_DU_DMR1_CW5 11:10 |
`define OR1200_DU_DMR1_CW6 13:12 |
`define OR1200_DU_DMR1_CW7 15:14 |
`define OR1200_DU_DMR1_CW8 17:16 |
`define OR1200_DU_DMR1_CW9 19:18 |
`define OR1200_DU_DMR1_CW10 21:20 |
`define OR1200_DU_DMR1_ST 22 |
`define OR1200_DU_DMR1_BT 23 |
`define OR1200_DU_DMR1_DXFW 24 |
`define OR1200_DU_DMR1_ETE 25 |
|
// DMR2 bits |
`define OR1200_DU_DMR2_WCE0 0 |
`define OR1200_DU_DMR2_WCE1 1 |
`define OR1200_DU_DMR2_AWTC 11:2 |
`define OR1200_DU_DMR2_WGB 23:12 |
|
// DWCR bits |
`define OR1200_DU_DWCR_COUNT 15:0 |
`define OR1200_DU_DWCR_MATCH 31:16 |
|
// DSR bits |
`define OR1200_DU_DSR_WIDTH 14 |
`define OR1200_DU_DSR_RSTE 0 |
`define OR1200_DU_DSR_BUSEE 1 |
`define OR1200_DU_DSR_DPFE 2 |
`define OR1200_DU_DSR_IPFE 3 |
`define OR1200_DU_DSR_TTE 4 |
`define OR1200_DU_DSR_AE 5 |
`define OR1200_DU_DSR_IIE 6 |
`define OR1200_DU_DSR_IE 7 |
`define OR1200_DU_DSR_DME 8 |
`define OR1200_DU_DSR_IME 9 |
`define OR1200_DU_DSR_RE 10 |
`define OR1200_DU_DSR_SCE 11 |
`define OR1200_DU_DSR_FPE 12 |
`define OR1200_DU_DSR_TE 13 |
|
// DRR bits |
`define OR1200_DU_DRR_RSTE 0 |
`define OR1200_DU_DRR_BUSEE 1 |
`define OR1200_DU_DRR_DPFE 2 |
`define OR1200_DU_DRR_IPFE 3 |
`define OR1200_DU_DRR_TTE 4 |
`define OR1200_DU_DRR_AE 5 |
`define OR1200_DU_DRR_IIE 6 |
`define OR1200_DU_DRR_IE 7 |
`define OR1200_DU_DRR_DME 8 |
`define OR1200_DU_DRR_IME 9 |
`define OR1200_DU_DRR_RE 10 |
`define OR1200_DU_DRR_SCE 11 |
`define OR1200_DU_DRR_FPE 12 |
`define OR1200_DU_DRR_TE 13 |
|
// Define if reading DU regs is allowed |
`define OR1200_DU_READREGS |
|
// Define if unused DU registers bits should be zero |
`define OR1200_DU_UNUSED_ZERO |
|
// Define if IF/LSU status is not needed by devel i/f |
`define OR1200_DU_STATUS_UNIMPLEMENTED |
|
///////////////////////////////////////////////////// |
// |
// Programmable Interrupt Controller (PIC) |
// |
|
// Define it if you want PIC implemented |
`define OR1200_PIC_IMPLEMENTED |
|
// Define number of interrupt inputs (2-31) |
`define OR1200_PIC_INTS 20 |
|
// Address offsets of PIC registers inside PIC group |
`define OR1200_PIC_OFS_PICMR 2'd0 |
`define OR1200_PIC_OFS_PICSR 2'd2 |
|
// Position of offset bits inside SPR address |
`define OR1200_PICOFS_BITS 1:0 |
|
// Define if you want these PIC registers to be implemented |
`define OR1200_PIC_PICMR |
`define OR1200_PIC_PICSR |
|
// Define if reading PIC registers is allowed |
`define OR1200_PIC_READREGS |
|
// Define if unused PIC register bits should be zero |
`define OR1200_PIC_UNUSED_ZERO |
|
|
///////////////////////////////////////////////////// |
// |
// Tick Timer (TT) |
// |
|
// Define it if you want TT implemented |
`define OR1200_TT_IMPLEMENTED |
|
// Address offsets of TT registers inside TT group |
`define OR1200_TT_OFS_TTMR 1'd0 |
`define OR1200_TT_OFS_TTCR 1'd1 |
|
// Position of offset bits inside SPR group |
`define OR1200_TTOFS_BITS 0 |
|
// Define if you want these TT registers to be implemented |
`define OR1200_TT_TTMR |
`define OR1200_TT_TTCR |
|
// TTMR bits |
`define OR1200_TT_TTMR_TP 27:0 |
`define OR1200_TT_TTMR_IP 28 |
`define OR1200_TT_TTMR_IE 29 |
`define OR1200_TT_TTMR_M 31:30 |
|
// Define if reading TT registers is allowed |
`define OR1200_TT_READREGS |
|
|
////////////////////////////////////////////// |
// |
// MAC |
// |
`define OR1200_MAC_ADDR 0 // MACLO 0xxxxxxxx1, MACHI 0xxxxxxxx0 |
`define OR1200_MAC_SPR_WE // Define if MACLO/MACHI are SPR writable |
|
// |
// Shift {MACHI,MACLO} into destination register when executing l.macrc |
// |
// According to architecture manual there is no shift, so default value is 0. |
// |
// However the implementation has deviated in this from the arch manual and had hard coded shift by 28 bits which |
// is a useful optimization for MP3 decoding (if using libmad fixed point library). Shifts are no longer |
// default setup, but if you need to remain backward compatible, define your shift bits, which were normally |
// dest_GPR = {MACHI,MACLO}[59:28] |
`define OR1200_MAC_SHIFTBY 0 // 0 = According to arch manual, 28 = obsolete backward compatibility |
|
|
////////////////////////////////////////////// |
// |
// Data MMU (DMMU) |
// |
|
// |
// Address that selects between TLB TR and MR |
// |
`define OR1200_DTLB_TM_ADDR 7 |
|
// |
// DTLBMR fields |
// |
`define OR1200_DTLBMR_V_BITS 0 |
`define OR1200_DTLBMR_CID_BITS 4:1 |
`define OR1200_DTLBMR_RES_BITS 11:5 |
`define OR1200_DTLBMR_VPN_BITS 31:13 |
|
// |
// DTLBTR fields |
// |
`define OR1200_DTLBTR_CC_BITS 0 |
`define OR1200_DTLBTR_CI_BITS 1 |
`define OR1200_DTLBTR_WBC_BITS 2 |
`define OR1200_DTLBTR_WOM_BITS 3 |
`define OR1200_DTLBTR_A_BITS 4 |
`define OR1200_DTLBTR_D_BITS 5 |
`define OR1200_DTLBTR_URE_BITS 6 |
`define OR1200_DTLBTR_UWE_BITS 7 |
`define OR1200_DTLBTR_SRE_BITS 8 |
`define OR1200_DTLBTR_SWE_BITS 9 |
`define OR1200_DTLBTR_RES_BITS 11:10 |
`define OR1200_DTLBTR_PPN_BITS 31:13 |
|
// |
// DTLB configuration |
// |
`define OR1200_DMMU_PS 13 // 13 for 8KB page size |
`define OR1200_DTLB_INDXW 6 // 6 for 64 entry DTLB 7 for 128 entries |
`define OR1200_DTLB_INDXL `OR1200_DMMU_PS // 13 13 |
`define OR1200_DTLB_INDXH `OR1200_DMMU_PS+`OR1200_DTLB_INDXW-1 // 18 19 |
`define OR1200_DTLB_INDX `OR1200_DTLB_INDXH:`OR1200_DTLB_INDXL // 18:13 19:13 |
`define OR1200_DTLB_TAGW 32-`OR1200_DTLB_INDXW-`OR1200_DMMU_PS // 13 12 |
`define OR1200_DTLB_TAGL `OR1200_DTLB_INDXH+1 // 19 20 |
`define OR1200_DTLB_TAG 31:`OR1200_DTLB_TAGL // 31:19 31:20 |
`define OR1200_DTLBMRW `OR1200_DTLB_TAGW+1 // +1 because of V bit |
`define OR1200_DTLBTRW 32-`OR1200_DMMU_PS+5 // +5 because of protection bits and CI |
|
// |
// Cache inhibit while DMMU is not enabled/implemented |
// |
// cache inhibited 0GB-4GB 1'b1 |
// cache inhibited 0GB-2GB !dcpu_adr_i[31] |
// cache inhibited 0GB-1GB 2GB-3GB !dcpu_adr_i[30] |
// cache inhibited 1GB-2GB 3GB-4GB dcpu_adr_i[30] |
// cache inhibited 2GB-4GB (default) dcpu_adr_i[31] |
// cached 0GB-4GB 1'b0 |
// |
`define OR1200_DMMU_CI dcpu_cycstb_i && dcpu_adr_i[31] |
|
|
////////////////////////////////////////////// |
// |
// Insn MMU (IMMU) |
// |
|
// |
// Address that selects between TLB TR and MR |
// |
`define OR1200_ITLB_TM_ADDR 7 |
|
// |
// ITLBMR fields |
// |
`define OR1200_ITLBMR_V_BITS 0 |
`define OR1200_ITLBMR_CID_BITS 4:1 |
`define OR1200_ITLBMR_RES_BITS 11:5 |
`define OR1200_ITLBMR_VPN_BITS 31:13 |
|
// |
// ITLBTR fields |
// |
`define OR1200_ITLBTR_CC_BITS 0 |
`define OR1200_ITLBTR_CI_BITS 1 |
`define OR1200_ITLBTR_WBC_BITS 2 |
`define OR1200_ITLBTR_WOM_BITS 3 |
`define OR1200_ITLBTR_A_BITS 4 |
`define OR1200_ITLBTR_D_BITS 5 |
`define OR1200_ITLBTR_SXE_BITS 6 |
`define OR1200_ITLBTR_UXE_BITS 7 |
`define OR1200_ITLBTR_RES_BITS 11:8 |
`define OR1200_ITLBTR_PPN_BITS 31:13 |
|
// |
// ITLB configuration |
// |
`define OR1200_IMMU_PS 13 // 13 for 8KB page size |
`define OR1200_ITLB_INDXW 6 // 6 for 64 entry ITLB 7 for 128 entries |
`define OR1200_ITLB_INDXL `OR1200_IMMU_PS // 13 13 |
`define OR1200_ITLB_INDXH `OR1200_IMMU_PS+`OR1200_ITLB_INDXW-1 // 18 19 |
`define OR1200_ITLB_INDX `OR1200_ITLB_INDXH:`OR1200_ITLB_INDXL // 18:13 19:13 |
`define OR1200_ITLB_TAGW 32-`OR1200_ITLB_INDXW-`OR1200_IMMU_PS // 13 12 |
`define OR1200_ITLB_TAGL `OR1200_ITLB_INDXH+1 // 19 20 |
`define OR1200_ITLB_TAG 31:`OR1200_ITLB_TAGL // 31:19 31:20 |
`define OR1200_ITLBMRW `OR1200_ITLB_TAGW+1 // +1 because of V bit |
`define OR1200_ITLBTRW 32-`OR1200_IMMU_PS+3 // +3 because of protection bits and CI |
|
// |
// Cache inhibit while IMMU is not enabled/implemented |
// Note: all combinations that use icpu_adr_i cause async loop |
// |
// cache inhibited 0GB-4GB 1'b1 |
// cache inhibited 0GB-2GB !icpu_adr_i[31] |
// cache inhibited 0GB-1GB 2GB-3GB !icpu_adr_i[30] |
// cache inhibited 1GB-2GB 3GB-4GB icpu_adr_i[30] |
// cache inhibited 2GB-4GB (default) icpu_adr_i[31] |
// cached 0GB-4GB 1'b0 |
// |
`define OR1200_IMMU_CI 1'b0 |
|
|
///////////////////////////////////////////////// |
// |
// Insn cache (IC) |
// |
|
// 3 for 8 bytes, 4 for 16 bytes etc |
`define OR1200_ICLS 4 |
|
// |
// IC configurations |
// |
`ifdef OR1200_IC_1W_512B |
`define OR1200_ICSIZE 9 // 512 |
`define OR1200_ICINDX `OR1200_ICSIZE-2 // 7 |
`define OR1200_ICINDXH `OR1200_ICSIZE-1 // 8 |
`define OR1200_ICTAGL `OR1200_ICINDXH+1 // 9 |
`define OR1200_ICTAG `OR1200_ICSIZE-`OR1200_ICLS // 5 |
`define OR1200_ICTAG_W 24 |
`endif |
`ifdef OR1200_IC_1W_4KB |
`define OR1200_ICSIZE 12 // 4096 |
`define OR1200_ICINDX `OR1200_ICSIZE-2 // 10 |
`define OR1200_ICINDXH `OR1200_ICSIZE-1 // 11 |
`define OR1200_ICTAGL `OR1200_ICINDXH+1 // 12 |
`define OR1200_ICTAG `OR1200_ICSIZE-`OR1200_ICLS // 8 |
`define OR1200_ICTAG_W 21 |
`endif |
`ifdef OR1200_IC_1W_8KB |
`define OR1200_ICSIZE 13 // 8192 |
`define OR1200_ICINDX `OR1200_ICSIZE-2 // 11 |
`define OR1200_ICINDXH `OR1200_ICSIZE-1 // 12 |
`define OR1200_ICTAGL `OR1200_ICINDXH+1 // 13 |
`define OR1200_ICTAG `OR1200_ICSIZE-`OR1200_ICLS // 9 |
`define OR1200_ICTAG_W 20 |
`endif |
|
|
///////////////////////////////////////////////// |
// |
// Data cache (DC) |
// |
|
// 3 for 8 bytes, 4 for 16 bytes etc |
`define OR1200_DCLS 4 |
|
// Define to perform store refill (potential performance penalty) |
// `define OR1200_DC_STORE_REFILL |
|
// |
// DC configurations |
// |
`ifdef OR1200_DC_1W_4KB |
`define OR1200_DCSIZE 12 // 4096 |
`define OR1200_DCINDX `OR1200_DCSIZE-2 // 10 |
`define OR1200_DCINDXH `OR1200_DCSIZE-1 // 11 |
`define OR1200_DCTAGL `OR1200_DCINDXH+1 // 12 |
`define OR1200_DCTAG `OR1200_DCSIZE-`OR1200_DCLS // 8 |
`define OR1200_DCTAG_W 21 |
`endif |
`ifdef OR1200_DC_1W_8KB |
`define OR1200_DCSIZE 13 // 8192 |
`define OR1200_DCINDX `OR1200_DCSIZE-2 // 11 |
`define OR1200_DCINDXH `OR1200_DCSIZE-1 // 12 |
`define OR1200_DCTAGL `OR1200_DCINDXH+1 // 13 |
`define OR1200_DCTAG `OR1200_DCSIZE-`OR1200_DCLS // 9 |
`define OR1200_DCTAG_W 20 |
`endif |
|
///////////////////////////////////////////////// |
// |
// Store buffer (SB) |
// |
|
// |
// Store buffer |
// |
// It will improve performance by "caching" CPU stores |
// using store buffer. This is most important for function |
// prologues because DC can only work in write though mode |
// and all stores would have to complete external WB writes |
// to memory. |
// Store buffer is between DC and data BIU. |
// All stores will be stored into store buffer and immediately |
// completed by the CPU, even though actual external writes |
// will be performed later. As a consequence store buffer masks |
// all data bus errors related to stores (data bus errors |
// related to loads are delivered normally). |
// All pending CPU loads will wait until store buffer is empty to |
// ensure strict memory model. Right now this is necessary because |
// we don't make destinction between cached and cache inhibited |
// address space, so we simply empty store buffer until loads |
// can begin. |
// |
// It makes design a bit bigger, depending what is the number of |
// entries in SB FIFO. Number of entries can be changed further |
// down. |
// |
//`define OR1200_SB_IMPLEMENTED |
|
// |
// Number of store buffer entries |
// |
// Verified number of entries are 4 and 8 entries |
// (2 and 3 for OR1200_SB_LOG). OR1200_SB_ENTRIES must |
// always match 2**OR1200_SB_LOG. |
// To disable store buffer, undefine |
// OR1200_SB_IMPLEMENTED. |
// |
`define OR1200_SB_LOG 2 // 2 or 3 |
`define OR1200_SB_ENTRIES 4 // 4 or 8 |
|
|
///////////////////////////////////////////////// |
// |
// Quick Embedded Memory (QMEM) |
// |
|
// |
// Quick Embedded Memory |
// |
// Instantiation of dedicated insn/data memory (RAM or ROM). |
// Insn fetch has effective throughput 1insn / clock cycle. |
// Data load takes two clock cycles / access, data store |
// takes 1 clock cycle / access (if there is no insn fetch)). |
// Memory instantiation is shared between insn and data, |
// meaning if insn fetch are performed, data load/store |
// performance will be lower. |
// |
// Main reason for QMEM is to put some time critical functions |
// into this memory and to have predictable and fast access |
// to these functions. (soft fpu, context switch, exception |
// handlers, stack, etc) |
// |
// It makes design a bit bigger and slower. QMEM sits behind |
// IMMU/DMMU so all addresses are physical (so the MMUs can be |
// used with QMEM and QMEM is seen by the CPU just like any other |
// memory in the system). IC/DC are sitting behind QMEM so the |
// whole design timing might be worse with QMEM implemented. |
// |
//`define OR1200_QMEM_IMPLEMENTED |
|
// |
// Base address and mask of QMEM |
// |
// Base address defines first address of QMEM. Mask defines |
// QMEM range in address space. Actual size of QMEM is however |
// determined with instantiated RAM/ROM. However bigger |
// mask will reserve more address space for QMEM, but also |
// make design faster, while more tight mask will take |
// less address space but also make design slower. If |
// instantiated RAM/ROM is smaller than space reserved with |
// the mask, instatiated RAM/ROM will also be shadowed |
// at higher addresses in reserved space. |
// |
`define OR1200_QMEM_IADDR 32'h0080_0000 |
`define OR1200_QMEM_IMASK 32'hfff0_0000 // Max QMEM size 1MB |
`define OR1200_QMEM_DADDR 32'h0080_0000 |
`define OR1200_QMEM_DMASK 32'hfff0_0000 // Max QMEM size 1MB |
|
// |
// QMEM interface byte-select capability |
// |
// To enable qmem_sel* ports, define this macro. |
// |
//`define OR1200_QMEM_BSEL |
|
// |
// QMEM interface acknowledge |
// |
// To enable qmem_ack port, define this macro. |
// |
//`define OR1200_QMEM_ACK |
|
///////////////////////////////////////////////////// |
// |
// VR, UPR and Configuration Registers |
// |
// |
// VR, UPR and configuration registers are optional. If |
// implemented, operating system can automatically figure |
// out how to use the processor because it knows |
// what units are available in the processor and how they |
// are configured. |
// |
// This section must be last in or1200_defines.v file so |
// that all units are already configured and thus |
// configuration registers are properly set. |
// |
|
// Define if you want configuration registers implemented |
`define OR1200_CFGR_IMPLEMENTED |
|
// Define if you want full address decode inside SYS group |
`define OR1200_SYS_FULL_DECODE |
|
// Offsets of VR, UPR and CFGR registers |
`define OR1200_SPRGRP_SYS_VR 4'h0 |
`define OR1200_SPRGRP_SYS_UPR 4'h1 |
`define OR1200_SPRGRP_SYS_CPUCFGR 4'h2 |
`define OR1200_SPRGRP_SYS_DMMUCFGR 4'h3 |
`define OR1200_SPRGRP_SYS_IMMUCFGR 4'h4 |
`define OR1200_SPRGRP_SYS_DCCFGR 4'h5 |
`define OR1200_SPRGRP_SYS_ICCFGR 4'h6 |
`define OR1200_SPRGRP_SYS_DCFGR 4'h7 |
|
// VR fields |
`define OR1200_VR_REV_BITS 5:0 |
`define OR1200_VR_RES1_BITS 15:6 |
`define OR1200_VR_CFG_BITS 23:16 |
`define OR1200_VR_VER_BITS 31:24 |
|
// VR values |
`define OR1200_VR_REV 6'h01 |
`define OR1200_VR_RES1 10'h000 |
`define OR1200_VR_CFG 8'h00 |
`define OR1200_VR_VER 8'h12 |
|
// UPR fields |
`define OR1200_UPR_UP_BITS 0 |
`define OR1200_UPR_DCP_BITS 1 |
`define OR1200_UPR_ICP_BITS 2 |
`define OR1200_UPR_DMP_BITS 3 |
`define OR1200_UPR_IMP_BITS 4 |
`define OR1200_UPR_MP_BITS 5 |
`define OR1200_UPR_DUP_BITS 6 |
`define OR1200_UPR_PCUP_BITS 7 |
`define OR1200_UPR_PMP_BITS 8 |
`define OR1200_UPR_PICP_BITS 9 |
`define OR1200_UPR_TTP_BITS 10 |
`define OR1200_UPR_RES1_BITS 23:11 |
`define OR1200_UPR_CUP_BITS 31:24 |
|
// UPR values |
`define OR1200_UPR_UP 1'b1 |
`ifdef OR1200_NO_DC |
`define OR1200_UPR_DCP 1'b0 |
`else |
`define OR1200_UPR_DCP 1'b1 |
`endif |
`ifdef OR1200_NO_IC |
`define OR1200_UPR_ICP 1'b0 |
`else |
`define OR1200_UPR_ICP 1'b1 |
`endif |
`ifdef OR1200_NO_DMMU |
`define OR1200_UPR_DMP 1'b0 |
`else |
`define OR1200_UPR_DMP 1'b1 |
`endif |
`ifdef OR1200_NO_IMMU |
`define OR1200_UPR_IMP 1'b0 |
`else |
`define OR1200_UPR_IMP 1'b1 |
`endif |
`define OR1200_UPR_MP 1'b1 // MAC always present |
`ifdef OR1200_DU_IMPLEMENTED |
`define OR1200_UPR_DUP 1'b1 |
`else |
`define OR1200_UPR_DUP 1'b0 |
`endif |
`define OR1200_UPR_PCUP 1'b0 // Performance counters not present |
`ifdef OR1200_DU_IMPLEMENTED |
`define OR1200_UPR_PMP 1'b1 |
`else |
`define OR1200_UPR_PMP 1'b0 |
`endif |
`ifdef OR1200_DU_IMPLEMENTED |
`define OR1200_UPR_PICP 1'b1 |
`else |
`define OR1200_UPR_PICP 1'b0 |
`endif |
`ifdef OR1200_DU_IMPLEMENTED |
`define OR1200_UPR_TTP 1'b1 |
`else |
`define OR1200_UPR_TTP 1'b0 |
`endif |
`define OR1200_UPR_RES1 13'h0000 |
`define OR1200_UPR_CUP 8'h00 |
|
// CPUCFGR fields |
`define OR1200_CPUCFGR_NSGF_BITS 3:0 |
`define OR1200_CPUCFGR_HGF_BITS 4 |
`define OR1200_CPUCFGR_OB32S_BITS 5 |
`define OR1200_CPUCFGR_OB64S_BITS 6 |
`define OR1200_CPUCFGR_OF32S_BITS 7 |
`define OR1200_CPUCFGR_OF64S_BITS 8 |
`define OR1200_CPUCFGR_OV64S_BITS 9 |
`define OR1200_CPUCFGR_RES1_BITS 31:10 |
|
// CPUCFGR values |
`define OR1200_CPUCFGR_NSGF 4'h0 |
`ifdef OR1200_RFRAM_16REG |
`define OR1200_CPUCFGR_HGF 1'b1 |
`else |
`define OR1200_CPUCFGR_HGF 1'b0 |
`endif |
`define OR1200_CPUCFGR_OB32S 1'b1 |
`define OR1200_CPUCFGR_OB64S 1'b0 |
`define OR1200_CPUCFGR_OF32S 1'b0 |
`define OR1200_CPUCFGR_OF64S 1'b0 |
`define OR1200_CPUCFGR_OV64S 1'b0 |
`define OR1200_CPUCFGR_RES1 22'h000000 |
|
// DMMUCFGR fields |
`define OR1200_DMMUCFGR_NTW_BITS 1:0 |
`define OR1200_DMMUCFGR_NTS_BITS 4:2 |
`define OR1200_DMMUCFGR_NAE_BITS 7:5 |
`define OR1200_DMMUCFGR_CRI_BITS 8 |
`define OR1200_DMMUCFGR_PRI_BITS 9 |
`define OR1200_DMMUCFGR_TEIRI_BITS 10 |
`define OR1200_DMMUCFGR_HTR_BITS 11 |
`define OR1200_DMMUCFGR_RES1_BITS 31:12 |
|
// DMMUCFGR values |
`ifdef OR1200_NO_DMMU |
`define OR1200_DMMUCFGR_NTW 2'h0 // Irrelevant |
`define OR1200_DMMUCFGR_NTS 3'h0 // Irrelevant |
`define OR1200_DMMUCFGR_NAE 3'h0 // Irrelevant |
`define OR1200_DMMUCFGR_CRI 1'b0 // Irrelevant |
`define OR1200_DMMUCFGR_PRI 1'b0 // Irrelevant |
`define OR1200_DMMUCFGR_TEIRI 1'b0 // Irrelevant |
`define OR1200_DMMUCFGR_HTR 1'b0 // Irrelevant |
`define OR1200_DMMUCFGR_RES1 20'h00000 |
`else |
`define OR1200_DMMUCFGR_NTW 2'h0 // 1 TLB way |
`define OR1200_DMMUCFGR_NTS 3'h`OR1200_DTLB_INDXW // Num TLB sets |
`define OR1200_DMMUCFGR_NAE 3'h0 // No ATB entries |
`define OR1200_DMMUCFGR_CRI 1'b0 // No control register |
`define OR1200_DMMUCFGR_PRI 1'b0 // No protection reg |
`define OR1200_DMMUCFGR_TEIRI 1'b1 // TLB entry inv reg impl. |
`define OR1200_DMMUCFGR_HTR 1'b0 // No HW TLB reload |
`define OR1200_DMMUCFGR_RES1 20'h00000 |
`endif |
|
// IMMUCFGR fields |
`define OR1200_IMMUCFGR_NTW_BITS 1:0 |
`define OR1200_IMMUCFGR_NTS_BITS 4:2 |
`define OR1200_IMMUCFGR_NAE_BITS 7:5 |
`define OR1200_IMMUCFGR_CRI_BITS 8 |
`define OR1200_IMMUCFGR_PRI_BITS 9 |
`define OR1200_IMMUCFGR_TEIRI_BITS 10 |
`define OR1200_IMMUCFGR_HTR_BITS 11 |
`define OR1200_IMMUCFGR_RES1_BITS 31:12 |
|
// IMMUCFGR values |
`ifdef OR1200_NO_IMMU |
`define OR1200_IMMUCFGR_NTW 2'h0 // Irrelevant |
`define OR1200_IMMUCFGR_NTS 3'h0 // Irrelevant |
`define OR1200_IMMUCFGR_NAE 3'h0 // Irrelevant |
`define OR1200_IMMUCFGR_CRI 1'b0 // Irrelevant |
`define OR1200_IMMUCFGR_PRI 1'b0 // Irrelevant |
`define OR1200_IMMUCFGR_TEIRI 1'b0 // Irrelevant |
`define OR1200_IMMUCFGR_HTR 1'b0 // Irrelevant |
`define OR1200_IMMUCFGR_RES1 20'h00000 |
`else |
`define OR1200_IMMUCFGR_NTW 2'h0 // 1 TLB way |
`define OR1200_IMMUCFGR_NTS 3'h`OR1200_ITLB_INDXW // Num TLB sets |
`define OR1200_IMMUCFGR_NAE 3'h0 // No ATB entry |
`define OR1200_IMMUCFGR_CRI 1'b0 // No control reg |
`define OR1200_IMMUCFGR_PRI 1'b0 // No protection reg |
`define OR1200_IMMUCFGR_TEIRI 1'b1 // TLB entry inv reg impl |
`define OR1200_IMMUCFGR_HTR 1'b0 // No HW TLB reload |
`define OR1200_IMMUCFGR_RES1 20'h00000 |
`endif |
|
// DCCFGR fields |
`define OR1200_DCCFGR_NCW_BITS 2:0 |
`define OR1200_DCCFGR_NCS_BITS 6:3 |
`define OR1200_DCCFGR_CBS_BITS 7 |
`define OR1200_DCCFGR_CWS_BITS 8 |
`define OR1200_DCCFGR_CCRI_BITS 9 |
`define OR1200_DCCFGR_CBIRI_BITS 10 |
`define OR1200_DCCFGR_CBPRI_BITS 11 |
`define OR1200_DCCFGR_CBLRI_BITS 12 |
`define OR1200_DCCFGR_CBFRI_BITS 13 |
`define OR1200_DCCFGR_CBWBRI_BITS 14 |
`define OR1200_DCCFGR_RES1_BITS 31:15 |
|
// DCCFGR values |
`ifdef OR1200_NO_DC |
`define OR1200_DCCFGR_NCW 3'h0 // Irrelevant |
`define OR1200_DCCFGR_NCS 4'h0 // Irrelevant |
`define OR1200_DCCFGR_CBS 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CWS 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CCRI 1'b1 // Irrelevant |
`define OR1200_DCCFGR_CBIRI 1'b1 // Irrelevant |
`define OR1200_DCCFGR_CBPRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CBLRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CBFRI 1'b1 // Irrelevant |
`define OR1200_DCCFGR_CBWBRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_RES1 17'h00000 |
`else |
`define OR1200_DCCFGR_NCW 3'h0 // 1 cache way |
`define OR1200_DCCFGR_NCS (`OR1200_DCTAG) // Num cache sets |
`define OR1200_DCCFGR_CBS (`OR1200_DCLS-4) // 16 byte cache block |
`define OR1200_DCCFGR_CWS 1'b0 // Write-through strategy |
`define OR1200_DCCFGR_CCRI 1'b1 // Cache control reg impl. |
`define OR1200_DCCFGR_CBIRI 1'b1 // Cache block inv reg impl. |
`define OR1200_DCCFGR_CBPRI 1'b0 // Cache block prefetch reg not impl. |
`define OR1200_DCCFGR_CBLRI 1'b0 // Cache block lock reg not impl. |
`define OR1200_DCCFGR_CBFRI 1'b1 // Cache block flush reg impl. |
`define OR1200_DCCFGR_CBWBRI 1'b0 // Cache block WB reg not impl. |
`define OR1200_DCCFGR_RES1 17'h00000 |
`endif |
|
// ICCFGR fields |
`define OR1200_ICCFGR_NCW_BITS 2:0 |
`define OR1200_ICCFGR_NCS_BITS 6:3 |
`define OR1200_ICCFGR_CBS_BITS 7 |
`define OR1200_ICCFGR_CWS_BITS 8 |
`define OR1200_ICCFGR_CCRI_BITS 9 |
`define OR1200_ICCFGR_CBIRI_BITS 10 |
`define OR1200_ICCFGR_CBPRI_BITS 11 |
`define OR1200_ICCFGR_CBLRI_BITS 12 |
`define OR1200_ICCFGR_CBFRI_BITS 13 |
`define OR1200_ICCFGR_CBWBRI_BITS 14 |
`define OR1200_ICCFGR_RES1_BITS 31:15 |
|
// ICCFGR values |
`ifdef OR1200_NO_IC |
`define OR1200_ICCFGR_NCW 3'h0 // Irrelevant |
`define OR1200_ICCFGR_NCS 4'h0 // Irrelevant |
`define OR1200_ICCFGR_CBS 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CWS 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CCRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CBIRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CBPRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CBLRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CBFRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CBWBRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_RES1 17'h00000 |
`else |
`define OR1200_ICCFGR_NCW 3'h0 // 1 cache way |
`define OR1200_ICCFGR_NCS (`OR1200_ICTAG) // Num cache sets |
`define OR1200_ICCFGR_CBS (`OR1200_ICLS-4) // 16 byte cache block |
`define OR1200_ICCFGR_CWS 1'b0 // Irrelevant |
`define OR1200_ICCFGR_CCRI 1'b1 // Cache control reg impl. |
`define OR1200_ICCFGR_CBIRI 1'b1 // Cache block inv reg impl. |
`define OR1200_ICCFGR_CBPRI 1'b0 // Cache block prefetch reg not impl. |
`define OR1200_ICCFGR_CBLRI 1'b0 // Cache block lock reg not impl. |
`define OR1200_ICCFGR_CBFRI 1'b1 // Cache block flush reg impl. |
`define OR1200_ICCFGR_CBWBRI 1'b0 // Irrelevant |
`define OR1200_ICCFGR_RES1 17'h00000 |
`endif |
|
// DCFGR fields |
`define OR1200_DCFGR_NDP_BITS 2:0 |
`define OR1200_DCFGR_WPCI_BITS 3 |
`define OR1200_DCFGR_RES1_BITS 31:4 |
|
// DCFGR values |
`ifdef OR1200_DU_HWBKPTS |
`define OR1200_DCFGR_NDP 3'h`OR1200_DU_DVRDCR_PAIRS // # of DVR/DCR pairs |
`ifdef OR1200_DU_DWCR0 |
`define OR1200_DCFGR_WPCI 1'b1 |
`else |
`define OR1200_DCFGR_WPCI 1'b0 // WP counters not impl. |
`endif |
`else |
`define OR1200_DCFGR_NDP 3'h0 // Zero DVR/DCR pairs |
`define OR1200_DCFGR_WPCI 1'b0 // WP counters not impl. |
`endif |
`define OR1200_DCFGR_RES1 28'h0000000 |
|
/ddr2_mig/ddr2_phy_dqs_iob.v
0,0 → 1,263
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_dqs_iob.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module places the data strobes in the IOBs. |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.2 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added |
// on IODELAY primitives. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_dqs_iob # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter DDR_TYPE = 1, |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
parameter IODELAY_GRP = "IODELAY_MIG" |
) |
( |
input clk0, |
input clkdiv0, |
input rst0, |
input dlyinc_dqs, |
input dlyce_dqs, |
input dlyrst_dqs, |
input dlyinc_gate, |
input dlyce_gate, |
input dlyrst_gate, |
input dqs_oe_n, |
input dqs_rst_n, |
input en_dqs, |
inout ddr_dqs, |
inout ddr_dqs_n, |
output dq_ce, |
output delayed_dqs |
); |
|
wire clk180; |
wire dqs_bufio; |
|
wire dqs_ibuf; |
wire dqs_idelay; |
wire dqs_oe_n_delay; |
wire dqs_oe_n_r; |
wire dqs_rst_n_delay; |
reg dqs_rst_n_r /* synthesis syn_preserve = 1*/; |
wire dqs_out; |
wire en_dqs_sync /* synthesis syn_keep = 1 */; |
|
// for simulation only. Synthesis should ignore this delay |
localparam DQS_NET_DELAY = 0.8; |
|
assign clk180 = ~clk0; |
|
// add delta delay to inputs clocked by clk180 to avoid delta-delay |
// simulation issues |
assign dqs_rst_n_delay = dqs_rst_n; |
assign dqs_oe_n_delay = dqs_oe_n; |
|
//*************************************************************************** |
// DQS input-side resources: |
// - IODELAY (pad -> IDELAY) |
// - BUFIO (IDELAY -> BUFIO) |
//*************************************************************************** |
|
// Route DQS from PAD to IDELAY |
(* IODELAY_GROUP = IODELAY_GRP *) IODELAY # |
( |
.DELAY_SRC("I"), |
.IDELAY_TYPE("VARIABLE"), |
.HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE), |
.IDELAY_VALUE(0), |
.ODELAY_VALUE(0) |
) |
u_idelay_dqs |
( |
.DATAOUT (dqs_idelay), |
.C (clkdiv0), |
.CE (dlyce_dqs), |
.DATAIN (), |
.IDATAIN (dqs_ibuf), |
.INC (dlyinc_dqs), |
.ODATAIN (), |
.RST (dlyrst_dqs), |
.T () |
); |
|
// From IDELAY to BUFIO |
BUFIO u_bufio_dqs |
( |
.I (dqs_idelay), |
.O (dqs_bufio) |
); |
|
// To model additional delay of DQS BUFIO + gating network |
// for behavioral simulation. Make sure to select a delay number smaller |
// than half clock cycle (otherwise output will not track input changes |
// because of inertial delay). Duplicate to avoid delta delay issues. |
assign #(DQS_NET_DELAY) i_delayed_dqs = dqs_bufio; |
assign #(DQS_NET_DELAY) delayed_dqs = dqs_bufio; |
|
//*************************************************************************** |
// DQS gate circuit (not supported for all controllers) |
//*************************************************************************** |
|
// Gate routing: |
// en_dqs -> IDELAY -> en_dqs_sync -> IDDR.S -> dq_ce -> |
// capture IDDR.CE |
|
// Delay CE control so that it's in phase with delayed DQS |
(* IODELAY_GROUP = IODELAY_GRP *) IODELAY # |
( |
.DELAY_SRC ("DATAIN"), |
.IDELAY_TYPE ("VARIABLE"), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IDELAY_VALUE (0), |
.ODELAY_VALUE (0) |
) |
u_iodelay_dq_ce |
( |
.DATAOUT (en_dqs_sync), |
.C (clkdiv0), |
.CE (dlyce_gate), |
.DATAIN (en_dqs), |
.IDATAIN (), |
.INC (dlyinc_gate), |
.ODATAIN (), |
.RST (dlyrst_gate), |
.T () |
); |
|
// Generate sync'ed CE to DQ IDDR's using an IDDR clocked by DQS |
// We could also instantiate a negative-edge SDR flop here |
IDDR # |
( |
.DDR_CLK_EDGE ("OPPOSITE_EDGE"), |
.INIT_Q1 (1'b0), |
.INIT_Q2 (1'b0), |
.SRTYPE ("ASYNC") |
) |
u_iddr_dq_ce |
( |
.Q1 (), |
.Q2 (dq_ce), // output on falling edge |
.C (i_delayed_dqs), |
.CE (1'b1), |
.D (en_dqs_sync), |
.R (1'b0), |
.S (en_dqs_sync) |
); |
|
//*************************************************************************** |
// DQS output-side resources |
//*************************************************************************** |
|
// synthesis attribute keep of dqs_rst_n_r is "true" |
always @(posedge clk180) |
dqs_rst_n_r <= dqs_rst_n_delay; |
|
ODDR # |
( |
.SRTYPE("SYNC"), |
.DDR_CLK_EDGE("OPPOSITE_EDGE") |
) |
u_oddr_dqs |
( |
.Q (dqs_out), |
.C (clk180), |
.CE (1'b1), |
.D1 (dqs_rst_n_r), // keep output deasserted for write preamble |
.D2 (1'b0), |
.R (1'b0), |
.S (1'b0) |
); |
|
(* IOB = "FORCE" *) FDP u_tri_state_dqs |
( |
.D (dqs_oe_n_delay), |
.Q (dqs_oe_n_r), |
.C (clk180), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
|
//*************************************************************************** |
|
// use either single-ended (for DDR1) or differential (for DDR2) DQS input |
|
generate |
if (DDR_TYPE > 0) begin: gen_dqs_iob_ddr2 |
IOBUFDS u_iobuf_dqs |
( |
.O (dqs_ibuf), |
.IO (ddr_dqs), |
.IOB (ddr_dqs_n), |
.I (dqs_out), |
.T (dqs_oe_n_r) |
); |
end else begin: gen_dqs_iob_ddr1 |
IOBUF u_iobuf_dqs |
( |
.O (dqs_ibuf), |
.IO (ddr_dqs), |
.I (dqs_out), |
.T (dqs_oe_n_r) |
); |
end |
endgenerate |
|
endmodule |
/ddr2_mig/ddr2_top.v
0,0 → 1,278
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_top.v |
// /___/ /\ Date Last Modified: $Date: 2009/01/15 14:22:14 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// System level module. This level contains just the memory controller. |
// This level will be intiantated when the user wants to remove the |
// synthesizable test bench, IDELAY control block and the clock |
// generation modules. |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 |
// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_top # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, // # of memory bank addr bits |
parameter CKE_WIDTH = 1, // # of memory clock enable outputs |
parameter CLK_WIDTH = 1, // # of clock outputs |
parameter COL_WIDTH = 10, // # of memory column bits |
parameter CS_NUM = 1, // # of separate memory chip selects |
parameter CS_BITS = 0, // set to log2(CS_NUM) (rounded up) |
parameter CS_WIDTH = 1, // # of total memory chip selects |
parameter USE_DM_PORT = 1, // enable Data Mask (=1 enable) |
parameter DM_WIDTH = 9, // # of data mask bits |
parameter DQ_WIDTH = 72, // # of data width |
parameter DQ_BITS = 7, // set to log2(DQS_WIDTH*DQ_PER_DQS) |
parameter DQ_PER_DQS = 8, // # of DQ data bits per strobe |
parameter DQS_WIDTH = 9, // # of DQS strobes |
parameter DQS_BITS = 4, // set to log2(DQS_WIDTH) |
parameter HIGH_PERFORMANCE_MODE = "TRUE", // IODELAY Performance Mode |
parameter IODELAY_GRP = "IODELAY_MIG", // IODELAY Group Name |
parameter ODT_WIDTH = 1, // # of memory on-die term enables |
parameter ROW_WIDTH = 14, // # of memory row & # of addr bits |
parameter APPDATA_WIDTH = 144, // # of usr read/write data bus bits |
parameter ADDITIVE_LAT = 0, // additive write latency |
parameter BURST_LEN = 4, // burst length (in double words) |
parameter BURST_TYPE = 0, // burst type (=0 seq; =1 interlved) |
parameter CAS_LAT = 5, // CAS latency |
parameter ECC_ENABLE = 0, // enable ECC (=1 enable) |
parameter ODT_TYPE = 1, // ODT (=0(none),=1(75),=2(150),=3(50)) |
parameter MULTI_BANK_EN = 1, // enable bank management |
parameter TWO_T_TIME_EN = 0, // 2t timing for unbuffered dimms |
parameter REDUCE_DRV = 0, // reduced strength mem I/O (=1 yes) |
parameter REG_ENABLE = 1, // registered addr/ctrl (=1 yes) |
parameter TREFI_NS = 7800, // auto refresh interval (ns) |
parameter TRAS = 40000, // active->precharge delay |
parameter TRCD = 15000, // active->read/write delay |
parameter TRFC = 105000, // ref->ref, ref->active delay |
parameter TRP = 15000, // precharge->command delay |
parameter TRTP = 7500, // read->precharge delay |
parameter TWR = 15000, // used to determine wr->prech |
parameter TWTR = 10000, // write->read delay |
parameter CLK_PERIOD = 3000, // Core/Mem clk period (in ps) |
parameter SIM_ONLY = 0, // = 1 to skip power up delay |
parameter DEBUG_EN = 0, // Enable debug signals/controls |
parameter FPGA_SPEED_GRADE = 2 // FPGA Speed Grade |
) |
( |
input clk0, |
input usr_clk, // jb |
input clk90, |
input clkdiv0, |
input rst0, |
input rst90, |
input rstdiv0, |
input [2:0] app_af_cmd, |
input [30:0] app_af_addr, |
input app_af_wren, |
input app_wdf_wren, |
input [APPDATA_WIDTH-1:0] app_wdf_data, |
input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, |
output app_af_afull, |
output app_wdf_afull, |
output rd_data_valid, |
output [APPDATA_WIDTH-1:0] rd_data_fifo_out, |
output [1:0] rd_ecc_error, |
output phy_init_done, |
output [CLK_WIDTH-1:0] ddr2_ck, |
output [CLK_WIDTH-1:0] ddr2_ck_n, |
output [ROW_WIDTH-1:0] ddr2_a, |
output [BANK_WIDTH-1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output [CS_WIDTH-1:0] ddr2_cs_n, |
output [CKE_WIDTH-1:0] ddr2_cke, |
output [ODT_WIDTH-1:0] ddr2_odt, |
output [DM_WIDTH-1:0] ddr2_dm, |
inout [DQS_WIDTH-1:0] ddr2_dqs, |
inout [DQS_WIDTH-1:0] ddr2_dqs_n, |
inout [DQ_WIDTH-1:0] ddr2_dq, |
// Debug signals (optional use) |
input dbg_idel_up_all, |
input dbg_idel_down_all, |
input dbg_idel_up_dq, |
input dbg_idel_down_dq, |
input dbg_idel_up_dqs, |
input dbg_idel_down_dqs, |
input dbg_idel_up_gate, |
input dbg_idel_down_gate, |
input [DQ_BITS-1:0] dbg_sel_idel_dq, |
input dbg_sel_all_idel_dq, |
input [DQS_BITS:0] dbg_sel_idel_dqs, |
input dbg_sel_all_idel_dqs, |
input [DQS_BITS:0] dbg_sel_idel_gate, |
input dbg_sel_all_idel_gate, |
output [3:0] dbg_calib_done, |
output [3:0] dbg_calib_err, |
output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, |
output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly |
); |
|
// memory initialization/control logic |
ddr2_mem_if_top # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.CLK_WIDTH (CLK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.USE_DM_PORT (USE_DM_PORT), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_BITS (DQ_BITS), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_BITS (DQS_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.MULTI_BANK_EN (MULTI_BANK_EN), |
.TWO_T_TIME_EN (TWO_T_TIME_EN), |
.ODT_TYPE (ODT_TYPE), |
.DDR_TYPE (1), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TREFI_NS (TREFI_NS), |
.TRAS (TRAS), |
.TRCD (TRCD), |
.TRFC (TRFC), |
.TRP (TRP), |
.TRTP (TRTP), |
.TWR (TWR), |
.TWTR (TWTR), |
.CLK_PERIOD (CLK_PERIOD), |
.SIM_ONLY (SIM_ONLY), |
.DEBUG_EN (DEBUG_EN), |
.FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) |
) |
u_mem_if_top |
( |
.clk0 (clk0), |
.usr_clk (usr_clk), // jb |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.rst0 (rst0), |
.rst90 (rst90), |
.rstdiv0 (rstdiv0), |
.app_af_cmd (app_af_cmd), |
.app_af_addr (app_af_addr), |
.app_af_wren (app_af_wren), |
.app_wdf_wren (app_wdf_wren), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.app_af_afull (app_af_afull), |
.app_wdf_afull (app_wdf_afull), |
.rd_data_valid (rd_data_valid), |
.rd_data_fifo_out (rd_data_fifo_out), |
.rd_ecc_error (rd_ecc_error), |
.phy_init_done (phy_init_done), |
.ddr_ck (ddr2_ck), |
.ddr_ck_n (ddr2_ck_n), |
.ddr_addr (ddr2_a), |
.ddr_ba (ddr2_ba), |
.ddr_ras_n (ddr2_ras_n), |
.ddr_cas_n (ddr2_cas_n), |
.ddr_we_n (ddr2_we_n), |
.ddr_cs_n (ddr2_cs_n), |
.ddr_cke (ddr2_cke), |
.ddr_odt (ddr2_odt), |
.ddr_dm (ddr2_dm), |
.ddr_dqs (ddr2_dqs), |
.ddr_dqs_n (ddr2_dqs_n), |
.ddr_dq (ddr2_dq), |
.dbg_idel_up_all (dbg_idel_up_all), |
.dbg_idel_down_all (dbg_idel_down_all), |
.dbg_idel_up_dq (dbg_idel_up_dq), |
.dbg_idel_down_dq (dbg_idel_down_dq), |
.dbg_idel_up_dqs (dbg_idel_up_dqs), |
.dbg_idel_down_dqs (dbg_idel_down_dqs), |
.dbg_idel_up_gate (dbg_idel_up_gate), |
.dbg_idel_down_gate (dbg_idel_down_gate), |
.dbg_sel_idel_dq (dbg_sel_idel_dq), |
.dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), |
.dbg_sel_idel_dqs (dbg_sel_idel_dqs), |
.dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), |
.dbg_sel_idel_gate (dbg_sel_idel_gate), |
.dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), |
.dbg_calib_done (dbg_calib_done), |
.dbg_calib_err (dbg_calib_err), |
.dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), |
.dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), |
.dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), |
.dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), |
.dbg_calib_rden_dly (dbg_calib_rden_dly), |
.dbg_calib_gate_dly (dbg_calib_gate_dly) |
); |
|
endmodule |
/ddr2_mig/ddr2_ctrl.v
0,0 → 1,1225
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_ctrl.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Wed Aug 30 2006 |
// \___\/\___\ |
// |
// |
//Device: Virtex-5 |
//Design Name: DDR/DDR2 |
//Purpose: |
// This module is the main control logic of the memory interface. All |
// commands are issued from here according to the burst, CAS Latency and the |
// user commands. |
//Reference: |
//Revision History: |
// Rev 1.2 - Fixed auto refresh to activate bug. KP 11-19-2007 |
// Rev 1.3 - For Dual Rank parts support CS logic modified. KP. 05/08/08 |
// Rev 1.4 - AUTO_REFRESH_WAIT state modified for Auto Refresh flag asserted |
// immediately after calibration is completed. KP. 07/28/08 |
// Rev 1.5 - Assignment of bank_valid_r is modified to fix a bug in |
// Bank Management logic. PK. 10/29/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_ctrl # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter CS_NUM = 1, |
parameter ROW_WIDTH = 14, |
parameter ADDITIVE_LAT = 0, |
parameter BURST_LEN = 4, |
parameter CAS_LAT = 5, |
parameter ECC_ENABLE = 0, |
parameter REG_ENABLE = 1, |
parameter TREFI_NS = 7800, |
parameter TRAS = 40000, |
parameter TRCD = 15000, |
parameter TRRD = 10000, |
parameter TRFC = 105000, |
parameter TRP = 15000, |
parameter TRTP = 7500, |
parameter TWR = 15000, |
parameter TWTR = 10000, |
parameter CLK_PERIOD = 3000, |
parameter MULTI_BANK_EN = 1, |
parameter TWO_T_TIME_EN = 0, |
parameter DDR_TYPE = 1 |
) |
( |
input clk, |
input rst, |
input [2:0] af_cmd, |
input [30:0] af_addr, |
input af_empty, |
input phy_init_done, |
output ctrl_ref_flag, |
output ctrl_af_rden, |
output reg ctrl_wren, |
output reg ctrl_rden, |
output [ROW_WIDTH-1:0] ctrl_addr, |
output [BANK_WIDTH-1:0] ctrl_ba, |
output ctrl_ras_n, |
output ctrl_cas_n, |
output ctrl_we_n, |
output [CS_NUM-1:0] ctrl_cs_n |
); |
|
// input address split into various ranges |
localparam ROW_RANGE_START = COL_WIDTH; |
localparam ROW_RANGE_END = ROW_WIDTH + ROW_RANGE_START - 1; |
localparam BANK_RANGE_START = ROW_RANGE_END + 1; |
localparam BANK_RANGE_END = BANK_WIDTH + BANK_RANGE_START - 1; |
localparam CS_RANGE_START = BANK_RANGE_START + BANK_WIDTH; |
localparam CS_RANGE_END = CS_BITS + CS_RANGE_START - 1; |
// compare address (for determining bank/row hits) split into various ranges |
// (compare address doesn't include column bits) |
localparam CMP_WIDTH = CS_BITS + BANK_WIDTH + ROW_WIDTH; |
localparam CMP_ROW_RANGE_START = 0; |
localparam CMP_ROW_RANGE_END = ROW_WIDTH + CMP_ROW_RANGE_START - 1; |
localparam CMP_BANK_RANGE_START = CMP_ROW_RANGE_END + 1; |
localparam CMP_BANK_RANGE_END = BANK_WIDTH + CMP_BANK_RANGE_START - 1; |
localparam CMP_CS_RANGE_START = CMP_BANK_RANGE_END + 1; |
localparam CMP_CS_RANGE_END = CS_BITS + CMP_CS_RANGE_START-1; |
|
localparam BURST_LEN_DIV2 = BURST_LEN / 2; |
localparam OPEN_BANK_NUM = 4; |
localparam CS_BITS_FIX = (CS_BITS == 0) ? 1 : CS_BITS; |
|
// calculation counters based on clock cycle and memory parameters |
// TRAS: ACTIVE->PRECHARGE interval - 2 |
localparam integer TRAS_CYC = (TRAS + CLK_PERIOD)/CLK_PERIOD; |
// TRCD: ACTIVE->READ/WRITE interval - 3 (for DDR2 factor in ADD_LAT) |
localparam integer TRRD_CYC = (TRRD + CLK_PERIOD)/CLK_PERIOD; |
localparam integer TRCD_CYC = (((TRCD + CLK_PERIOD)/CLK_PERIOD) > |
ADDITIVE_LAT )? |
((TRCD+CLK_PERIOD)/ CLK_PERIOD) - ADDITIVE_LAT : 0; |
// TRFC: REFRESH->REFRESH, REFRESH->ACTIVE interval - 2 |
localparam integer TRFC_CYC = (TRFC + CLK_PERIOD)/CLK_PERIOD; |
// TRP: PRECHARGE->COMMAND interval - 2 |
// for precharge all add 1 extra clock cycle |
localparam integer TRP_CYC = ((TRP + CLK_PERIOD)/CLK_PERIOD) +1; |
// TRTP: READ->PRECHARGE interval - 2 (Al + BL/2 + (max (TRTP, 2tck))-2 |
localparam integer TRTP_TMP_MIN = (((TRTP + CLK_PERIOD)/CLK_PERIOD) >= 2)? |
((TRTP + CLK_PERIOD)/CLK_PERIOD) : 2; |
localparam integer TRTP_CYC = TRTP_TMP_MIN + ADDITIVE_LAT |
+ BURST_LEN_DIV2 - 2; |
// TWR: WRITE->PRECHARGE interval - 2 |
localparam integer WR_LAT = (DDR_TYPE > 0) ? CAS_LAT + ADDITIVE_LAT - 1 : 1; |
localparam integer TWR_CYC = ((TWR + CLK_PERIOD)/CLK_PERIOD) + |
WR_LAT + BURST_LEN_DIV2 ; |
// TWTR: WRITE->READ interval - 3 (for DDR1, TWTR = 2 clks) |
// DDR2 = CL-1 + BL/2 +TWTR |
localparam integer TWTR_TMP_MIN = (TWTR + CLK_PERIOD)/CLK_PERIOD; |
localparam integer TWTR_CYC = (DDR_TYPE > 0) ? (TWTR_TMP_MIN + (CAS_LAT -1) |
+ BURST_LEN_DIV2 ): 2; |
|
// TRTW: READ->WRITE interval - 3 |
// DDR1: CL + (BL/2) |
// DDR2: (BL/2) + 2. Two more clocks are added to |
// the DDR2 counter to account for the delay in |
// arrival of the DQS during reads (pcb trace + buffer |
// delays + memory parameters). |
localparam TRTW_CYC = (DDR_TYPE > 0) ? BURST_LEN_DIV2 + 4 : |
(CAS_LAT == 25) ? 2 + BURST_LEN_DIV2 : CAS_LAT + BURST_LEN_DIV2; |
|
localparam integer CAS_LAT_RD = (CAS_LAT == 25) ? 2 : CAS_LAT; |
|
// Make sure all values >= 0 (some may be = 0) |
localparam TRAS_COUNT = (TRAS_CYC > 0) ? TRAS_CYC : 0; |
localparam TRCD_COUNT = (TRCD_CYC > 0) ? TRCD_CYC : 0; |
localparam TRRD_COUNT = (TRRD_CYC > 0) ? TRRD_CYC : 0; |
localparam TRFC_COUNT = (TRFC_CYC > 0) ? TRFC_CYC : 0; |
localparam TRP_COUNT = (TRP_CYC > 0) ? TRP_CYC : 0; |
localparam TRTP_COUNT = (TRTP_CYC > 0) ? TRTP_CYC : 0; |
localparam TWR_COUNT = (TWR_CYC > 0) ? TWR_CYC : 0; |
localparam TWTR_COUNT = (TWTR_CYC > 0) ? TWTR_CYC : 0; |
localparam TRTW_COUNT = (TRTW_CYC > 0) ? TRTW_CYC : 0; |
|
// Auto refresh interval |
localparam TREFI_COUNT = ((TREFI_NS * 1000)/CLK_PERIOD) - 1; |
|
// memory controller states |
localparam CTRL_IDLE = 5'h00; |
localparam CTRL_PRECHARGE = 5'h01; |
localparam CTRL_PRECHARGE_WAIT = 5'h02; |
localparam CTRL_AUTO_REFRESH = 5'h03; |
localparam CTRL_AUTO_REFRESH_WAIT = 5'h04; |
localparam CTRL_ACTIVE = 5'h05; |
localparam CTRL_ACTIVE_WAIT = 5'h06; |
localparam CTRL_BURST_READ = 5'h07; |
localparam CTRL_READ_WAIT = 5'h08; |
localparam CTRL_BURST_WRITE = 5'h09; |
localparam CTRL_WRITE_WAIT = 5'h0A; |
localparam CTRL_PRECHARGE_WAIT1 = 5'h0B; |
|
|
reg [CMP_WIDTH-1:0] act_addr_r; |
wire [30:0] af_addr_r; |
reg [30:0] af_addr_r1; |
reg [30:0] af_addr_r2; |
reg [30:0] af_addr_r3; |
wire [2:0] af_cmd_r; |
reg [2:0] af_cmd_r1; |
reg [2:0] af_cmd_r2; |
reg af_valid_r; |
reg af_valid_r1; |
reg af_valid_r2; |
reg [CS_BITS_FIX :0] auto_cnt_r; |
reg auto_ref_r; |
reg [(OPEN_BANK_NUM*CMP_WIDTH)-1:0] bank_cmp_addr_r; |
reg [OPEN_BANK_NUM-1:0] bank_hit; |
reg [OPEN_BANK_NUM-1:0] bank_hit_r; |
reg [OPEN_BANK_NUM-1:0] bank_hit_r1; |
reg [OPEN_BANK_NUM-1:0] bank_valid_r; |
reg bank_conflict_r; |
reg conflict_resolved_r; |
reg ctrl_af_rden_r; |
reg conflict_detect_r; |
wire conflict_detect; |
reg cs_change_r; |
reg cs_change_sticky_r; |
reg [ROW_WIDTH-1:0] ddr_addr_r; |
wire [ROW_WIDTH-1:0] ddr_addr_col; |
wire [ROW_WIDTH-1:0] ddr_addr_row; |
reg [BANK_WIDTH-1:0] ddr_ba_r; |
reg ddr_cas_n_r; |
reg [CS_NUM-1:0] ddr_cs_n_r; |
reg ddr_ras_n_r; |
reg ddr_we_n_r; |
reg [4:0] next_state; |
reg no_precharge_wait_r; |
reg no_precharge_r; |
reg no_precharge_r1; |
reg phy_init_done_r; |
reg [4:0] precharge_ok_cnt_r; |
reg precharge_ok_r; |
reg [4:0] ras_cnt_r; |
reg [3:0] rcd_cnt_r; |
reg rcd_cnt_ok_r; |
reg [2:0] rdburst_cnt_r; |
reg rdburst_ok_r; |
reg rdburst_rden_ok_r; |
reg rd_af_flag_r; |
wire rd_flag; |
reg rd_flag_r; |
reg [4:0] rd_to_wr_cnt_r; |
reg rd_to_wr_ok_r; |
reg ref_flag_r; |
reg [11:0] refi_cnt_r; |
reg refi_cnt_ok_r; |
reg rst_r |
/* synthesis syn_preserve = 1 */; |
reg rst_r1 |
/* synthesis syn_maxfan = 10 */; |
reg [7:0] rfc_cnt_r; |
reg rfc_ok_r; |
reg [3:0] row_miss; |
reg [3:0] row_conflict_r; |
reg [3:0] rp_cnt_r; |
reg rp_cnt_ok_r; |
reg [CMP_WIDTH-1:0] sb_open_add_r; |
reg [4:0] state_r; |
reg [4:0] state_r1; |
wire sm_rden; |
reg sm_rden_r; |
reg [2:0] trrd_cnt_r; |
reg trrd_cnt_ok_r; |
reg [2:0] two_t_enable_r; |
reg [CS_NUM-1:0] two_t_enable_r1; |
reg [2:0] wrburst_cnt_r; |
reg wrburst_ok_r; |
reg wrburst_wren_ok_r; |
wire wr_flag; |
reg wr_flag_r; |
reg [4:0] wr_to_rd_cnt_r; |
reg wr_to_rd_ok_r; |
|
// XST attributes for local reset "tree" |
// synthesis attribute shreg_extract of rst_r is "no"; |
// synthesis attribute shreg_extract of rst_r1 is "no"; |
// synthesis attribute equivalent_register_removal of rst_r is "no" |
|
//*************************************************************************** |
|
// sm_rden is used to assert read enable to the address FIFO |
assign sm_rden = ((state_r == CTRL_BURST_WRITE) || |
(state_r == CTRL_BURST_READ)) ; |
|
// assert read flag to the adress FIFO |
assign ctrl_af_rden = sm_rden || rd_af_flag_r; |
|
// local reset "tree" for controller logic only. Create this to ease timing |
// on reset path. Prohibit equivalent register removal on RST_R to prevent |
// "sharing" with other local reset trees (caution: make sure global fanout |
// limit is set to large enough value, otherwise SLICES may be used for |
// fanout control on RST_R. |
always @(posedge clk) begin |
rst_r <= rst; |
rst_r1 <= rst_r; |
end |
|
//***************************************************************** |
// interpret commands from Command/Address FIFO |
//***************************************************************** |
|
assign wr_flag = (af_valid_r2) ? ((af_cmd_r2 == 3'b000) ? 1'b1 : 1'b0): 1'b0; |
assign rd_flag = (af_valid_r2) ? ((af_cmd_r2 == 3'b001) ? 1'b1 : 1'b0): 1'b0; |
|
always @(posedge clk) begin |
rd_flag_r <= rd_flag; |
wr_flag_r <= wr_flag; |
end |
|
////////////////////////////////////////////////// |
// The data from the address FIFO is fetched and |
// stored in two register stages. The data will be |
// pulled out of the second register stage whenever |
// the state machine can handle new data from the |
// address FIFO. |
|
// This flag is asserted when there is no |
// cmd & address in the pipe. When there is |
// valid cmd & addr from the address FIFO the |
// af_valid signals will be asserted. This flag will |
// be set the cycle af_valid_r is de-asserted. |
always @(posedge clk) begin |
// for simulation purposes - to force CTRL_AF_RDEN low during reset |
if (rst_r1) |
rd_af_flag_r <= 1'd0; |
else if((ctrl_af_rden_r) || |
(rd_af_flag_r && (af_valid_r || af_valid_r1))) |
rd_af_flag_r <= 1'd0; |
else if (~af_valid_r1 || ~af_valid_r) |
rd_af_flag_r <= 1'd1; |
|
end |
|
// First register stage for the cmd & add from the FIFO. |
// The af_valid_r signal gives the status of the data |
// in this stage. The af_valid_r will be asserted when there |
// is valid data. This register stage will be updated |
// 1. read to the FIFO and the FIFO not empty |
// 2. After write and read states |
// 3. The valid signal is not asserted in the last stage. |
always @(posedge clk) begin |
if (rst_r1)begin |
af_valid_r <= 1'd0; |
end else begin |
if (ctrl_af_rden_r || sm_rden_r || ~af_valid_r1 |
|| ~af_valid_r2)begin |
af_valid_r <= ctrl_af_rden_r; |
end |
end |
end |
|
// The output register in the FIFO is used. The addr |
// and command are already registered in the FIFO. |
assign af_addr_r = af_addr; |
assign af_cmd_r = af_cmd; |
|
// Second register stage for the cmd & add from the FIFO. |
// The af_valid_r1 signal gives the status of the data |
// in this stage. The af_valid_r will be asserted when there |
// is valid data. This register stage will be updated |
// 1. read to the FIFO and the FIFO not empty and there |
// is no valid data on this stage |
// 2. After write and read states |
// 3. The valid signal is not asserted in the last stage. |
always@(posedge clk) begin |
if (rst_r1)begin |
af_valid_r1 <= 1'd0; |
af_addr_r1 <= {31{1'bx}}; |
af_cmd_r1 <= {3{1'bx}}; |
end else if (~af_valid_r1 || sm_rden_r || |
~af_valid_r2) begin |
af_valid_r1 <= af_valid_r; |
af_addr_r1 <= af_addr_r; |
af_cmd_r1 <= af_cmd_r; |
end |
end |
|
// The state machine uses the address and command in this |
// register stage. The data is fetched from the second |
// register stage whenever the state machine can accept new |
// addr. The conflict flags are also generated based on the |
// second register stage and updated when the new address |
// is loaded for the state machine. |
always@(posedge clk) begin |
if (rst_r1)begin |
af_valid_r2 <= 1'd0; |
af_addr_r2 <= {31{1'bx}}; |
af_cmd_r2 <= {3{1'bx}}; |
bank_hit_r <= {OPEN_BANK_NUM{1'bx}}; |
bank_conflict_r <= 1'bx; |
row_conflict_r <= 4'bx; |
end else if(sm_rden || ~af_valid_r2)begin |
af_valid_r2 <= af_valid_r1; |
af_addr_r2 <= af_addr_r1; |
af_cmd_r2 <= af_cmd_r1; |
if(MULTI_BANK_EN)begin |
bank_hit_r <= bank_hit; |
row_conflict_r <= row_miss; |
bank_conflict_r <= (~(|bank_hit)); |
end else begin |
bank_hit_r <= {OPEN_BANK_NUM{1'b0}}; |
bank_conflict_r <= 1'd0; |
row_conflict_r[0] <= (af_addr_r1[CS_RANGE_END:ROW_RANGE_START] |
!= sb_open_add_r[CMP_WIDTH-1:0]); |
end |
end |
end // always@ (posedge clk) |
|
//detecting cs change for multi chip select case |
generate |
if(CS_NUM > 1) begin: gen_cs_change |
always @(posedge clk) begin |
if(sm_rden || ~af_valid_r2)begin |
cs_change_r <= af_addr_r1[CS_RANGE_END:CS_RANGE_START] != |
af_addr_r2[CS_RANGE_END:CS_RANGE_START] ; |
cs_change_sticky_r <= |
af_addr_r1[CS_RANGE_END:CS_RANGE_START] != |
af_addr_r2[CS_RANGE_END:CS_RANGE_START] ; |
end else |
cs_change_r <= 1'd0; |
end |
end // block: gen_cs_change |
else begin: gen_cs_0 |
always @(posedge clk) begin |
cs_change_r <= 1'd0; |
cs_change_sticky_r <= 1'd0; |
end |
end |
endgenerate |
|
assign conflict_detect = (MULTI_BANK_EN) ? |
((|(row_conflict_r[3:0] & bank_hit_r[3:0])) |
| bank_conflict_r) & af_valid_r2 : |
row_conflict_r[0] & af_valid_r2; |
|
always @(posedge clk) begin |
conflict_detect_r <= conflict_detect; |
sm_rden_r <= sm_rden; |
af_addr_r3 <= af_addr_r2; |
ctrl_af_rden_r <= ctrl_af_rden & ~af_empty; |
end |
|
// conflict resolved signal. When this signal is asserted |
// the conflict is resolved. The address to be compared |
// for the conflict_resolved_r will be stored in act_add_r |
// when the bank is opened. |
always @(posedge clk) begin |
conflict_resolved_r <= (act_addr_r == |
af_addr_r2[CS_RANGE_END:ROW_RANGE_START]); |
if((state_r == CTRL_ACTIVE)) |
act_addr_r <= af_addr_r2[CS_RANGE_END:ROW_RANGE_START]; |
end |
|
//*************************************************************************** |
// Bank management logic |
// Semi-hardcoded for now for 4 banks |
// will keep multiple banks open if MULTI_BANK_EN is true. |
//*************************************************************************** |
|
genvar bank_i; |
generate // if multiple bank option chosen |
if(MULTI_BANK_EN) begin: gen_multi_bank_open |
|
for (bank_i = 0; bank_i < OPEN_BANK_NUM; |
bank_i = bank_i + 1) begin: gen_bank_hit1 |
// asserted if bank address match + open bank entry is valid |
always @(*) begin |
bank_hit[bank_i] |
= ((bank_cmp_addr_r[(CMP_WIDTH*(bank_i+1))-1: |
(CMP_WIDTH*bank_i)+ROW_WIDTH] == |
af_addr_r1[CS_RANGE_END:BANK_RANGE_START]) && |
bank_valid_r[bank_i]); |
// asserted if row address match (no check for bank entry valid, rely |
// on this term to be used in conjunction with BANK_HIT[]) |
row_miss[bank_i] |
= (bank_cmp_addr_r[(CMP_WIDTH*bank_i)+ROW_WIDTH-1: |
(CMP_WIDTH*bank_i)] != |
af_addr_r1[ROW_RANGE_END:ROW_RANGE_START]); |
end |
end |
|
always @(posedge clk) begin |
no_precharge_wait_r <= bank_valid_r[3] & bank_conflict_r; |
bank_hit_r1 <= bank_hit_r; |
end |
|
always@(*) |
no_precharge_r = ~bank_valid_r[3] & bank_conflict_r; |
|
always@(posedge clk) |
no_precharge_r1 <= no_precharge_r; |
|
|
always @(posedge clk) begin |
// Clear all bank valid bits during AR (i.e. since all banks get |
// precharged during auto-refresh) |
if ((state_r1 == CTRL_AUTO_REFRESH)) begin |
bank_valid_r <= {OPEN_BANK_NUM{1'b0}}; |
bank_cmp_addr_r <= {(OPEN_BANK_NUM*CMP_WIDTH-1){1'b0}}; |
end else begin |
if (state_r1 == CTRL_ACTIVE) begin |
// 00 is always going to have the latest bank and row. |
bank_cmp_addr_r[CMP_WIDTH-1:0] |
<= af_addr_r3[CS_RANGE_END:ROW_RANGE_START]; |
// This indicates the bank was activated |
bank_valid_r[0] <= 1'b1; |
|
case ({bank_hit_r1[2:0]}) |
3'b001: begin |
bank_cmp_addr_r[CMP_WIDTH-1:0] |
<= af_addr_r3[CS_RANGE_END:ROW_RANGE_START]; |
// This indicates the bank was activated |
bank_valid_r[0] <= 1'b1; |
end |
3'b010: begin //(b0->b1) |
bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH] |
<= bank_cmp_addr_r[CMP_WIDTH-1:0]; |
bank_valid_r[1] <= bank_valid_r[0]; |
end |
3'b100:begin //(b0->b1, b1->b2) |
bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH] |
<= bank_cmp_addr_r[CMP_WIDTH-1:0]; |
bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH] |
<= bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH]; |
bank_valid_r[1] <= bank_valid_r[0]; |
bank_valid_r[2] <= bank_valid_r[1]; |
end |
default: begin //(b0->b1, b1->b2, b2->b3) |
bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH] |
<= bank_cmp_addr_r[CMP_WIDTH-1:0]; |
bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH] |
<= bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH]; |
bank_cmp_addr_r[(4*CMP_WIDTH)-1:3*CMP_WIDTH] |
<= bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH]; |
bank_valid_r[1] <= bank_valid_r[0]; |
bank_valid_r[2] <= bank_valid_r[1]; |
bank_valid_r[3] <= bank_valid_r[2]; |
end |
endcase |
end |
end |
end |
end else begin: gen_single_bank_open // single bank option |
always @(posedge clk) begin |
no_precharge_r <= 1'd0; |
no_precharge_r1 <= 1'd0; |
no_precharge_wait_r <= 1'd0; |
if (rst_r1) |
sb_open_add_r <= {CMP_WIDTH{1'b0}}; |
else if (state_r == CTRL_ACTIVE) |
sb_open_add_r <= af_addr_r2[CS_RANGE_END:ROW_RANGE_START]; |
end |
end |
endgenerate |
|
//*************************************************************************** |
// Timing counters |
//*************************************************************************** |
|
//***************************************************************** |
// Write and read enable generation for PHY |
//***************************************************************** |
|
// write burst count. Counts from (BL/2 to 1). |
// Also logic for controller write enable. |
always @(posedge clk) begin |
if (state_r == CTRL_BURST_WRITE) begin |
wrburst_cnt_r <= BURST_LEN_DIV2; |
end else if (wrburst_cnt_r >= 3'd1) |
wrburst_cnt_r <= wrburst_cnt_r - 1; |
end // always @ (posedge clk) |
|
|
always @(posedge clk) begin |
if (rst_r1) begin |
ctrl_wren <= 1'b0; |
end else if (state_r == CTRL_BURST_WRITE) begin |
ctrl_wren <= 1'b1; |
end else if (wrburst_wren_ok_r) |
ctrl_wren <= 1'b0; |
end |
|
|
always @(posedge clk) begin |
if ((state_r == CTRL_BURST_WRITE) |
&& (BURST_LEN_DIV2 > 2)) |
wrburst_ok_r <= 1'd0; |
else if ((wrburst_cnt_r <= 3'd3) || |
(BURST_LEN_DIV2 <= 2)) |
wrburst_ok_r <= 1'b1; |
end |
|
// flag to check when wrburst count has reached |
// a value of 1. This flag is used in the ctrl_wren |
// logic |
always @(posedge clk) begin |
if(wrburst_cnt_r == 3'd2) |
wrburst_wren_ok_r <=1'b1; |
else |
wrburst_wren_ok_r <= 1'b0; |
end |
|
|
// read burst count. Counts from (BL/2 to 1) |
always @(posedge clk) begin |
if (state_r == CTRL_BURST_READ) begin |
rdburst_cnt_r <= BURST_LEN_DIV2; |
end else if (rdburst_cnt_r >= 3'd1) |
rdburst_cnt_r <= rdburst_cnt_r - 1; |
end // always @ (posedge clk) |
|
|
always @(posedge clk) begin |
if (rst_r1) begin |
ctrl_rden <= 1'b0; |
end else if (state_r == CTRL_BURST_READ) begin |
ctrl_rden <= 1'b1; |
end else if (rdburst_rden_ok_r) |
ctrl_rden <= 1'b0; |
end |
|
// the rd_burst_ok_r signal will be asserted one cycle later |
// in multi chip select cases if the back to back read is to |
// different chip selects. The cs_changed_sticky_r signal will |
// be asserted only for multi chip select cases. |
always @(posedge clk) begin |
if ((state_r == CTRL_BURST_READ) |
&& (BURST_LEN_DIV2 > 2)) |
rdburst_ok_r <= 1'd0; |
else if ((rdburst_cnt_r <=( 3'd3 - cs_change_sticky_r)) || |
(BURST_LEN_DIV2 <= 2)) |
rdburst_ok_r <= 1'b1; |
end |
|
// flag to check when rdburst count has reached |
// a value of 1. This flag is used in the ctrl_rden |
// logic |
always @(posedge clk) begin |
if (rdburst_cnt_r == 3'd2) |
rdburst_rden_ok_r <= 1'b1; |
else |
rdburst_rden_ok_r <= 1'b0; |
end |
|
|
//***************************************************************** |
// Various delay counters |
// The counters are checked for value of <= 3 to determine the |
// if the count values are reached during different commands. |
// It is checked for 3 because |
// 1. The counters are loaded during the state when the command |
// state is reached (+1) |
// 2. After the <= 3 condition is reached the sm takes two cycles |
// to transition to the new command state (+2) |
//***************************************************************** |
|
// tRP count - precharge command period |
always @(posedge clk) begin |
if (state_r == CTRL_PRECHARGE) |
rp_cnt_r <= TRP_COUNT; |
else if (rp_cnt_r != 4'd0) |
rp_cnt_r <= rp_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if (state_r == CTRL_PRECHARGE) |
rp_cnt_ok_r <= 1'd0; |
else if (rp_cnt_r <= 4'd3) |
rp_cnt_ok_r <= 1'd1; |
end |
|
// tRFC count - refresh-refresh, refresh-active |
always @(posedge clk) begin |
if (state_r == CTRL_AUTO_REFRESH) |
rfc_cnt_r <= TRFC_COUNT; |
else if (rfc_cnt_r != 8'd0) |
rfc_cnt_r <= rfc_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if (state_r == CTRL_AUTO_REFRESH) |
rfc_ok_r <= 1'b0; |
else if(rfc_cnt_r <= 8'd3) |
rfc_ok_r <= 1'b1; |
end |
|
// tRCD count - active to read/write |
always @(posedge clk) begin |
if (state_r == CTRL_ACTIVE) |
rcd_cnt_r <= TRCD_COUNT; |
else if (rcd_cnt_r != 4'd0) |
rcd_cnt_r <= rcd_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if ((state_r == CTRL_ACTIVE) |
&& (TRCD_COUNT > 2)) |
rcd_cnt_ok_r <= 1'd0; |
else if (rcd_cnt_r <= 4'd3) |
rcd_cnt_ok_r <= 1; |
end |
|
// tRRD count - active to active |
always @(posedge clk) begin |
if (state_r == CTRL_ACTIVE) |
trrd_cnt_r <= TRRD_COUNT; |
else if (trrd_cnt_r != 3'd0) |
trrd_cnt_r <= trrd_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if (state_r == CTRL_ACTIVE) |
trrd_cnt_ok_r <= 1'd0; |
else if (trrd_cnt_r <= 3'd3) |
trrd_cnt_ok_r <= 1; |
end |
|
// tRAS count - active to precharge |
always @(posedge clk) begin |
if (state_r == CTRL_ACTIVE) |
ras_cnt_r <= TRAS_COUNT; |
else if (ras_cnt_r != 5'd0) |
ras_cnt_r <= ras_cnt_r - 1; |
end |
|
// counter for write to prcharge |
// read to precharge and |
// activate to precharge |
// precharge_ok_cnt_r is added with trtp count, |
// there can be cases where the sm can go from |
// activate to read and the act->pre count time |
// would not have been satisfied. The rd->pre |
// time is very less. wr->pre time is almost the |
// same as act-> pre |
always @(posedge clk) begin |
if (state_r == CTRL_BURST_READ) begin |
// assign only if the cnt is < TRTP_COUNT |
if (precharge_ok_cnt_r < TRTP_COUNT) |
precharge_ok_cnt_r <= TRTP_COUNT; |
end else if (state_r == CTRL_BURST_WRITE) |
precharge_ok_cnt_r <= TWR_COUNT; |
else if (state_r == CTRL_ACTIVE) |
precharge_ok_cnt_r <= TRAS_COUNT; |
else if (precharge_ok_cnt_r != 5'd0) |
precharge_ok_cnt_r <= precharge_ok_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if ((state_r == CTRL_BURST_READ) || |
(state_r == CTRL_BURST_WRITE)|| |
(state_r == CTRL_ACTIVE)) |
precharge_ok_r <= 1'd0; |
else if(precharge_ok_cnt_r <= 5'd3) |
precharge_ok_r <=1'd1; |
end |
|
// write to read counter |
// write to read includes : write latency + burst time + tWTR |
always @(posedge clk) begin |
if (rst_r1) |
wr_to_rd_cnt_r <= 5'd0; |
else if (state_r == CTRL_BURST_WRITE) |
wr_to_rd_cnt_r <= (TWTR_COUNT); |
else if (wr_to_rd_cnt_r != 5'd0) |
wr_to_rd_cnt_r <= wr_to_rd_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if (state_r == CTRL_BURST_WRITE) |
wr_to_rd_ok_r <= 1'd0; |
else if (wr_to_rd_cnt_r <= 5'd3) |
wr_to_rd_ok_r <= 1'd1; |
end |
|
// read to write counter |
always @(posedge clk) begin |
if (rst_r1) |
rd_to_wr_cnt_r <= 5'd0; |
else if (state_r == CTRL_BURST_READ) |
rd_to_wr_cnt_r <= (TRTW_COUNT); |
else if (rd_to_wr_cnt_r != 5'd0) |
rd_to_wr_cnt_r <= rd_to_wr_cnt_r - 1; |
end |
|
always @(posedge clk) begin |
if (state_r == CTRL_BURST_READ) |
rd_to_wr_ok_r <= 1'b0; |
else if (rd_to_wr_cnt_r <= 5'd3) |
rd_to_wr_ok_r <= 1'b1; |
end |
|
always @(posedge clk) begin |
if(refi_cnt_r == (TREFI_COUNT -1)) |
refi_cnt_ok_r <= 1'b1; |
else |
refi_cnt_ok_r <= 1'b0; |
end |
|
// auto refresh interval counter in refresh_clk domain |
always @(posedge clk) begin |
if ((rst_r1) || (refi_cnt_ok_r)) begin |
refi_cnt_r <= 12'd0; |
end else begin |
refi_cnt_r <= refi_cnt_r + 1; |
end |
end // always @ (posedge clk) |
|
// auto refresh flag |
always @(posedge clk) begin |
if (refi_cnt_ok_r) begin |
ref_flag_r <= 1'b1; |
end else begin |
ref_flag_r <= 1'b0; |
end |
end // always @ (posedge clk) |
|
assign ctrl_ref_flag = ref_flag_r; |
|
//refresh flag detect |
//auto_ref high indicates auto_refresh requirement |
//auto_ref is held high until auto refresh command is issued. |
always @(posedge clk)begin |
if (rst_r1) |
auto_ref_r <= 1'b0; |
else if (ref_flag_r) |
auto_ref_r <= 1'b1; |
else if (state_r == CTRL_AUTO_REFRESH) |
auto_ref_r <= 1'b0; |
end |
|
|
// keep track of which chip selects got auto-refreshed (avoid auto-refreshing |
// all CS's at once to avoid current spike) |
always @(posedge clk)begin |
if (rst_r1 || (state_r1 == CTRL_PRECHARGE)) |
auto_cnt_r <= 'd0; |
else if (state_r1 == CTRL_AUTO_REFRESH) |
auto_cnt_r <= auto_cnt_r + 1; |
end |
|
// register for timing purposes. Extra delay doesn't really matter |
always @(posedge clk) |
phy_init_done_r <= phy_init_done; |
|
always @(posedge clk)begin |
if (rst_r1) begin |
state_r <= CTRL_IDLE; |
state_r1 <= CTRL_IDLE; |
end else begin |
state_r <= next_state; |
state_r1 <= state_r; |
end |
end |
|
//*************************************************************************** |
// main control state machine |
//*************************************************************************** |
|
always @(*) begin |
next_state = state_r; |
(* full_case, parallel_case *) case (state_r) |
CTRL_IDLE: begin |
// perform auto refresh as soon as we are done with calibration. |
// The calibration logic does not do any refreshes. |
if (phy_init_done_r) |
next_state = CTRL_AUTO_REFRESH; |
end |
|
CTRL_PRECHARGE: begin |
if (auto_ref_r) |
next_state = CTRL_PRECHARGE_WAIT1; |
// when precharging an LRU bank, do not have to go to wait state |
// since we can't possibly be activating row in same bank next |
// disabled for 2t timing. There needs to be a gap between cmds |
// in 2t timing |
else if (no_precharge_wait_r && !TWO_T_TIME_EN) |
next_state = CTRL_ACTIVE; |
else |
next_state = CTRL_PRECHARGE_WAIT; |
end |
|
CTRL_PRECHARGE_WAIT:begin |
if (rp_cnt_ok_r)begin |
if (auto_ref_r) |
// precharge again to make sure we close all the banks |
next_state = CTRL_PRECHARGE; |
else |
next_state = CTRL_ACTIVE; |
end |
end |
|
CTRL_PRECHARGE_WAIT1: |
if (rp_cnt_ok_r) |
next_state = CTRL_AUTO_REFRESH; |
|
CTRL_AUTO_REFRESH: |
next_state = CTRL_AUTO_REFRESH_WAIT; |
|
CTRL_AUTO_REFRESH_WAIT: |
//staggering Auto refresh for multi |
// chip select designs. The SM waits |
// for the rfc time before issuing the |
// next auto refresh. |
if (auto_cnt_r < (CS_NUM))begin |
if (rfc_ok_r ) |
next_state = CTRL_AUTO_REFRESH; |
end else if (rfc_ok_r)begin |
if(auto_ref_r) |
// MIG 2.3: For deep designs if Auto Refresh |
// flag asserted immediately after calibration is completed |
next_state = CTRL_PRECHARGE; |
else if ( wr_flag || rd_flag) |
next_state = CTRL_ACTIVE; |
end |
|
CTRL_ACTIVE: |
next_state = CTRL_ACTIVE_WAIT; |
|
CTRL_ACTIVE_WAIT: begin |
if (rcd_cnt_ok_r) begin |
if ((conflict_detect_r && ~conflict_resolved_r) || |
auto_ref_r) begin |
if (no_precharge_r1 && ~auto_ref_r && trrd_cnt_ok_r) |
next_state = CTRL_ACTIVE; |
else if(precharge_ok_r) |
next_state = CTRL_PRECHARGE; |
end else if ((wr_flag_r) && (rd_to_wr_ok_r)) |
next_state = CTRL_BURST_WRITE; |
else if ((rd_flag_r)&& (wr_to_rd_ok_r)) |
next_state = CTRL_BURST_READ; |
end |
end |
|
// beginning of write burst |
CTRL_BURST_WRITE: begin |
if (BURST_LEN_DIV2 == 1) begin |
// special case if BL = 2 (i.e. burst lasts only one clk cycle) |
if (wr_flag) |
// if we have another non-conflict write command right after the |
// current write, then stay in this state |
next_state = CTRL_BURST_WRITE; |
else |
// otherwise, if we're done with this burst, and have no write |
// immediately scheduled after this one, wait until write-read |
// delay has passed |
next_state = CTRL_WRITE_WAIT; |
end else |
// otherwise BL > 2, and we have at least one more write cycle for |
// current burst |
next_state = CTRL_WRITE_WAIT; |
// continuation of write burst (also covers waiting after write burst |
// has completed for write-read delay to pass) |
end |
|
CTRL_WRITE_WAIT: begin |
if ((conflict_detect) || auto_ref_r) begin |
if (no_precharge_r && ~auto_ref_r && wrburst_ok_r) |
next_state = CTRL_ACTIVE; |
else if (precharge_ok_r) |
next_state = CTRL_PRECHARGE; |
end else if (wrburst_ok_r && wr_flag) |
next_state = CTRL_BURST_WRITE; |
else if ((rd_flag) && (wr_to_rd_ok_r)) |
next_state = CTRL_BURST_READ; |
end |
|
CTRL_BURST_READ: begin |
if (BURST_LEN_DIV2 == 1) begin |
// special case if BL = 2 (i.e. burst lasts only one clk cycle) |
if (rd_flag) |
next_state = CTRL_BURST_READ; |
else |
next_state = CTRL_READ_WAIT; |
end else |
next_state = CTRL_READ_WAIT; |
end |
|
CTRL_READ_WAIT: begin |
if ((conflict_detect) || auto_ref_r)begin |
if (no_precharge_r && ~auto_ref_r && rdburst_ok_r) |
next_state = CTRL_ACTIVE; |
else if (precharge_ok_r) |
next_state = CTRL_PRECHARGE; |
// for burst of 4 in multi chip select |
// if there is a change in cs wait one cycle before the |
// next read command. cs_change_r will be asserted. |
end else if (rdburst_ok_r && rd_flag && ~cs_change_r) |
next_state = CTRL_BURST_READ; |
else if (wr_flag && (rd_to_wr_ok_r)) |
next_state = CTRL_BURST_WRITE; |
end |
endcase |
end |
|
//*************************************************************************** |
// control signals to memory |
//*************************************************************************** |
|
always @(posedge clk) begin |
if ((state_r == CTRL_AUTO_REFRESH) || |
(state_r == CTRL_ACTIVE) || |
(state_r == CTRL_PRECHARGE)) begin |
ddr_ras_n_r <= 1'b0; |
two_t_enable_r[0] <= 1'b0; |
end else begin |
if (TWO_T_TIME_EN) |
ddr_ras_n_r <= two_t_enable_r[0] ; |
else |
ddr_ras_n_r <= 1'd1; |
two_t_enable_r[0] <= 1'b1; |
end |
end |
|
always @(posedge clk)begin |
if ((state_r == CTRL_BURST_WRITE) || |
(state_r == CTRL_BURST_READ) || |
(state_r == CTRL_AUTO_REFRESH)) begin |
ddr_cas_n_r <= 1'b0; |
two_t_enable_r[1] <= 1'b0; |
end else begin |
if (TWO_T_TIME_EN) |
ddr_cas_n_r <= two_t_enable_r[1]; |
else |
ddr_cas_n_r <= 1'b1; |
two_t_enable_r[1] <= 1'b1; |
end |
end |
|
always @(posedge clk) begin |
if ((state_r == CTRL_BURST_WRITE) || |
(state_r == CTRL_PRECHARGE)) begin |
ddr_we_n_r <= 1'b0; |
two_t_enable_r[2] <= 1'b0; |
end else begin |
if(TWO_T_TIME_EN) |
ddr_we_n_r <= two_t_enable_r[2]; |
else |
ddr_we_n_r <= 1'b1; |
two_t_enable_r[2] <= 1'b1; |
end |
end |
|
// turn off auto-precharge when issuing commands (A10 = 0) |
// mapping the col add for linear addressing. |
generate |
if (TWO_T_TIME_EN) begin: gen_addr_col_two_t |
if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0 |
assign ddr_addr_col = {af_addr_r3[COL_WIDTH-1:10], 1'b0, |
af_addr_r3[9:0]}; |
end else begin |
if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1 |
assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, |
af_addr_r3[COL_WIDTH-1:10], 1'b0, |
af_addr_r3[9:0]}; |
end else begin: gen_ddr_addr_col_2 |
assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0, |
af_addr_r3[COL_WIDTH-1:0]}; |
end |
end |
end else begin: gen_addr_col_one_t |
if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0_1 |
assign ddr_addr_col = {af_addr_r2[COL_WIDTH-1:10], 1'b0, |
af_addr_r2[9:0]}; |
end else begin |
if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1_1 |
assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, |
af_addr_r2[COL_WIDTH-1:10], 1'b0, |
af_addr_r2[9:0]}; |
end else begin: gen_ddr_addr_col_2_1 |
assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0, |
af_addr_r2[COL_WIDTH-1:0]}; |
end |
end |
end |
endgenerate |
|
// Assign address during row activate |
generate |
if (TWO_T_TIME_EN) |
assign ddr_addr_row = af_addr_r3[ROW_RANGE_END:ROW_RANGE_START]; |
else |
assign ddr_addr_row = af_addr_r2[ROW_RANGE_END:ROW_RANGE_START]; |
endgenerate |
|
|
always @(posedge clk)begin |
if ((state_r == CTRL_ACTIVE) || |
((state_r1 == CTRL_ACTIVE) && TWO_T_TIME_EN)) |
ddr_addr_r <= ddr_addr_row; |
else if ((state_r == CTRL_BURST_WRITE) || |
(state_r == CTRL_BURST_READ) || |
(((state_r1 == CTRL_BURST_WRITE) || |
(state_r1 == CTRL_BURST_READ)) && |
TWO_T_TIME_EN)) |
ddr_addr_r <= ddr_addr_col; |
else if (((state_r == CTRL_PRECHARGE) || |
((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) |
&& auto_ref_r) begin |
// if we're precharging as a result of AUTO-REFRESH, precharge all banks |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
ddr_addr_r[10] <= 1'b1; |
end else if ((state_r == CTRL_PRECHARGE) || |
((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) |
// if we're precharging to close a specific bank/row, set A10=0 |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
else |
ddr_addr_r <= {ROW_WIDTH{1'bx}}; |
end |
|
always @(posedge clk)begin |
// whenever we're precharging, we're either: (1) precharging all banks (in |
// which case banks bits are don't care, (2) precharging the LRU bank, |
// b/c we've exceeded the limit of # of banks open (need to close the LRU |
// bank to make room for a new one), (3) we haven't exceed the maximum # |
// of banks open, but we trying to open a different row in a bank that's |
// already open |
if (((state_r == CTRL_PRECHARGE) || |
((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) && |
bank_conflict_r && MULTI_BANK_EN) |
// When LRU bank needs to be closed |
ddr_ba_r <= bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_BANK_RANGE_END: |
(3*CMP_WIDTH)+CMP_BANK_RANGE_START]; |
else begin |
// Either precharge due to refresh or bank hit case |
if (TWO_T_TIME_EN) |
ddr_ba_r <= af_addr_r3[BANK_RANGE_END:BANK_RANGE_START]; |
else |
ddr_ba_r <= af_addr_r2[BANK_RANGE_END:BANK_RANGE_START]; |
end |
end |
|
// chip enable generation logic |
generate |
// if only one chip select, always assert it after reset |
if (CS_BITS == 0) begin: gen_ddr_cs_0 |
always @(posedge clk) |
if (rst_r1) |
ddr_cs_n_r[0] <= 1'b1; |
else |
ddr_cs_n_r[0] <= 1'b0; |
// otherwise if we have multiple chip selects |
end else begin: gen_ddr_cs_1 |
if(TWO_T_TIME_EN) begin: gen_2t_cs |
always @(posedge clk) |
if (rst_r1) |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
else if ((state_r1 == CTRL_AUTO_REFRESH)) begin |
// if auto-refreshing, only auto-refresh one CS at any time (avoid |
// beating on the ground plane by refreshing all CS's at same time) |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[auto_cnt_r] <= 1'b0; |
end else if (auto_ref_r && (state_r1 == CTRL_PRECHARGE)) begin |
ddr_cs_n_r <= {CS_NUM{1'b0}}; |
end else if ((state_r1 == CTRL_PRECHARGE) && ( bank_conflict_r |
&& MULTI_BANK_EN))begin |
// precharging the LRU bank |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_CS_RANGE_END: |
(3*CMP_WIDTH)+CMP_CS_RANGE_START]] <= 1'b0; |
end else begin |
// otherwise, check the upper address bits to see which CS to assert |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[af_addr_r3[CS_RANGE_END:CS_RANGE_START]] <= 1'b0; |
end // else: !if(((state_r == CTRL_PRECHARGE) ||... |
end else begin: gen_1t_cs // block: gen_2t_cs |
always @(posedge clk) |
if (rst_r1) |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
else if ((state_r == CTRL_AUTO_REFRESH) ) begin |
// if auto-refreshing, only auto-refresh one CS at any time (avoid |
// beating on the ground plane by refreshing all CS's at same time) |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[auto_cnt_r] <= 1'b0; |
end else if (auto_ref_r && (state_r == CTRL_PRECHARGE) ) begin |
ddr_cs_n_r <= {CS_NUM{1'b0}}; |
end else if ((state_r == CTRL_PRECHARGE) && |
(bank_conflict_r && MULTI_BANK_EN))begin |
// precharging the LRU bank |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_CS_RANGE_END: |
(3*CMP_WIDTH)+CMP_CS_RANGE_START]] <= 1'b0; |
end else begin |
// otherwise, check the upper address bits to see which CS to assert |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
ddr_cs_n_r[af_addr_r2[CS_RANGE_END:CS_RANGE_START]] <= 1'b0; |
end // else: !if(((state_r == CTRL_PRECHARGE) ||... |
end // block: gen_1t_cs |
end |
endgenerate |
|
// registring the two_t timing enable signal. |
// This signal will be asserted (low) when the |
// chip select has to be asserted. |
always @(posedge clk)begin |
if(&two_t_enable_r) |
two_t_enable_r1 <= {CS_NUM{1'b1}}; |
else |
two_t_enable_r1 <= {CS_NUM{1'b0}}; |
end |
|
assign ctrl_addr = ddr_addr_r; |
assign ctrl_ba = ddr_ba_r; |
assign ctrl_ras_n = ddr_ras_n_r; |
assign ctrl_cas_n = ddr_cas_n_r; |
assign ctrl_we_n = ddr_we_n_r; |
assign ctrl_cs_n = (TWO_T_TIME_EN) ? |
(ddr_cs_n_r | two_t_enable_r1) : |
ddr_cs_n_r; |
|
endmodule |
|
/ddr2_mig/ddr2_usr_addr_fifo.v
0,0 → 1,133
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_usr_addr_fifo.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:01 $ |
// \ \ / \ Date Created: Mon Aug 28 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module instantiates the block RAM based FIFO to store the user |
// address and the command information. Also calculates potential bank/row |
// conflicts by comparing the new address with last address issued. |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_usr_addr_fifo # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter ROW_WIDTH = 14 |
) |
( |
input clk0, |
input rst0, |
input usr_clk, |
input [2:0] app_af_cmd, |
input [30:0] app_af_addr, |
input app_af_wren, |
input ctrl_af_rden, |
output [2:0] af_cmd, |
output [30:0] af_addr, |
output af_empty, |
output app_af_afull |
); |
|
wire [35:0] fifo_data_out; |
reg rst_r; |
|
|
always @(posedge clk0) |
rst_r <= rst0; |
|
|
//*************************************************************************** |
|
assign af_cmd = fifo_data_out[33:31]; |
assign af_addr = fifo_data_out[30:0]; |
|
//*************************************************************************** |
|
FIFO36 # |
( |
.ALMOST_EMPTY_OFFSET (13'h0007), |
.ALMOST_FULL_OFFSET (13'h000F), |
.DATA_WIDTH (36), |
.DO_REG (1), |
.EN_SYN ("FALSE"), // changed to FLASE - jb |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_af |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (app_af_afull), |
.DO (fifo_data_out[31:0]), |
.DOP (fifo_data_out[35:32]), |
.EMPTY (af_empty), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.WRCOUNT (), |
.WRERR (), |
.DI ({app_af_cmd[0],app_af_addr}), |
.DIP ({2'b00,app_af_cmd[2:1]}), |
.RDCLK (clk0), |
.RDEN (ctrl_af_rden), |
.RST (rst_r), |
//.WRCLK (clk0), |
.WRCLK (usr_clk), |
.WREN (app_af_wren) |
); |
|
endmodule |
/ddr2_mig/ddr2_phy_dm_iob.v
0,0 → 1,106
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_dm_iob.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module places the data mask signals into the IOBs. |
//Reference: |
//Revision History: |
// Rev 1.1 - To fix timing issues with Synplicity 9.6.1, syn_preserve |
// attribute added for the instance u_dm_ce. PK. 11/11/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_dm_iob |
( |
input clk90, |
input dm_ce, |
input mask_data_rise, |
input mask_data_fall, |
output ddr_dm |
); |
|
wire dm_out; |
wire dm_ce_r; |
|
FDRSE_1 u_dm_ce |
( |
.Q (dm_ce_r), |
.C (clk90), |
.CE (1'b1), |
.D (dm_ce), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve=1 */; |
|
ODDR # |
( |
.SRTYPE("SYNC"), |
.DDR_CLK_EDGE("SAME_EDGE") |
) |
u_oddr_dm |
( |
.Q (dm_out), |
.C (clk90), |
.CE (dm_ce_r), |
.D1 (mask_data_rise), |
.D2 (mask_data_fall), |
.R (1'b0), |
.S (1'b0) |
); |
|
OBUF u_obuf_dm |
( |
.I (dm_out), |
.O (ddr_dm) |
); |
|
endmodule |
/ddr2_mig/ddr2_phy_write.v
0,0 → 1,442
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_write.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Thu Aug 24 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
//Reference: |
// Handles delaying various write control signals appropriately depending |
// on CAS latency, additive latency, etc. Also splits the data and mask in |
// rise and fall buses. |
//Revision History: |
// Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_write # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter DQ_WIDTH = 72, |
parameter CS_NUM = 1, |
parameter ADDITIVE_LAT = 0, |
parameter CAS_LAT = 5, |
parameter ECC_ENABLE = 0, |
parameter ODT_TYPE = 1, |
parameter REG_ENABLE = 1, |
parameter DDR_TYPE = 1 |
) |
( |
input clk0, |
input clk90, |
input rst90, |
input [(2*DQ_WIDTH)-1:0] wdf_data, |
input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, |
input ctrl_wren, |
input phy_init_wren, |
input phy_init_data_sel, |
output reg dm_ce, |
output reg [1:0] dq_oe_n, |
output reg dqs_oe_n , |
output reg dqs_rst_n , |
output wdf_rden, |
output reg [CS_NUM-1:0] odt , |
output [DQ_WIDTH-1:0] wr_data_rise, |
output [DQ_WIDTH-1:0] wr_data_fall, |
output [(DQ_WIDTH/8)-1:0] mask_data_rise, |
output [(DQ_WIDTH/8)-1:0] mask_data_fall |
); |
|
localparam MASK_WIDTH = DQ_WIDTH/8; |
localparam DDR1 = 0; |
localparam DDR2 = 1; |
localparam DDR3 = 2; |
|
// (MIN,MAX) value of WR_LATENCY for DDR1: |
// REG_ENABLE = (0,1) |
// ECC_ENABLE = (0,1) |
// Write latency = 1 |
// Total: (1,3) |
// (MIN,MAX) value of WR_LATENCY for DDR2: |
// REG_ENABLE = (0,1) |
// ECC_ENABLE = (0,1) |
// Write latency = ADDITIVE_CAS + CAS_LAT - 1 = (0,4) + (3,5) - 1 = (2,8) |
// ADDITIVE_LAT = (0,4) (JEDEC79-2B) |
// CAS_LAT = (3,5) (JEDEC79-2B) |
// Total: (2,10) |
localparam WR_LATENCY = (DDR_TYPE == DDR3) ? |
(ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) : |
(DDR_TYPE == DDR2) ? |
(ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) : |
(1 + REG_ENABLE ); |
|
// NOTE that ODT timing does not need to be delayed for registered |
// DIMM case, since like other control/address signals, it gets |
// delayed by one clock cycle at the DIMM |
localparam ODT_WR_LATENCY = WR_LATENCY - REG_ENABLE; |
|
wire dm_ce_0; |
reg dm_ce_r; |
wire [1:0] dq_oe_0; |
reg [1:0] dq_oe_n_90_r1; |
reg [1:0] dq_oe_270; |
wire dqs_oe_0; |
reg dqs_oe_270; |
reg dqs_oe_n_180_r1; |
wire dqs_rst_0; |
reg dqs_rst_n_180_r1; |
reg dqs_rst_270; |
reg ecc_dm_error_r; |
reg ecc_dm_error_r1; |
reg [(DQ_WIDTH-1):0] init_data_f; |
reg [(DQ_WIDTH-1):0] init_data_r; |
reg [3:0] init_wdf_cnt_r; |
wire odt_0; |
reg rst90_r /* synthesis syn_maxfan = 10 */; |
reg [10:0] wr_stages ; |
reg [(2*DQ_WIDTH)-1:0] wdf_data_r; |
reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r; |
wire [(2*DQ_WIDTH/8)-1:0] wdf_ecc_mask; |
|
reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1; |
wire wdf_rden_0; |
reg calib_rden_90_r; |
reg wdf_rden_90_r; |
reg wdf_rden_90_r1; |
reg wdf_rden_270; |
|
always @(posedge clk90) |
rst90_r <= rst90; |
|
//*************************************************************************** |
// Analysis of additional pipeline delays: |
// 1. dq_oe (DQ 3-state): 1 CLK90 cyc in IOB 3-state FF |
// 2. dqs_oe (DQS 3-state): 1 CLK180 cyc in IOB 3-state FF |
// 3. dqs_rst (DQS output value reset): 1 CLK180 cyc in FF + 1 CLK180 cyc |
// in IOB DDR |
// 4. odt (ODT control): 1 CLK0 cyc in IOB FF |
// 5. write data (output two cyc after wdf_rden - output of RAMB_FIFO w/ |
// output register enabled): 2 CLK90 cyc in OSERDES |
//*************************************************************************** |
|
// DQS 3-state must be asserted one extra clock cycle due b/c of write |
// pre- and post-amble (extra half clock cycle for each) |
assign dqs_oe_0 = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; |
|
// same goes for ODT, need to handle both pre- and post-amble (generate |
// ODT only for DDR2) |
// ODT generation for DDR2 based on write latency. The MIN write |
// latency is 2. Based on the write latency ODT is asserted. |
generate |
if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2 |
if(ODT_WR_LATENCY > 2) |
assign odt_0 = |
wr_stages[ODT_WR_LATENCY-1] | |
wr_stages[ODT_WR_LATENCY-2] | |
wr_stages[ODT_WR_LATENCY-3] ; |
else |
assign odt_0 = |
wr_stages[ODT_WR_LATENCY] | |
wr_stages[ODT_WR_LATENCY-1] | |
wr_stages[ODT_WR_LATENCY-2] ; |
end else |
assign odt_0 = 1'b0; |
endgenerate |
|
assign dq_oe_0[0] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY]; |
assign dq_oe_0[1] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; |
assign dqs_rst_0 = ~wr_stages[WR_LATENCY-2]; |
assign dm_ce_0 = wr_stages[WR_LATENCY] | wr_stages[WR_LATENCY-1] |
| wr_stages[WR_LATENCY-2]; |
|
// write data fifo, read flag assertion |
generate |
if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2 |
if (WR_LATENCY > 2) |
assign wdf_rden_0 = wr_stages[WR_LATENCY-3]; |
else |
assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; |
end else begin: gen_wdf_ddr1 |
assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; |
end |
endgenerate |
|
// first stage isn't registered |
always @(*) |
wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren; |
|
always @(posedge clk0) begin |
wr_stages[1] <= wr_stages[0]; |
wr_stages[2] <= wr_stages[1]; |
wr_stages[3] <= wr_stages[2]; |
wr_stages[4] <= wr_stages[3]; |
wr_stages[5] <= wr_stages[4]; |
wr_stages[6] <= wr_stages[5]; |
wr_stages[7] <= wr_stages[6]; |
wr_stages[8] <= wr_stages[7]; |
wr_stages[9] <= wr_stages[8]; |
wr_stages[10] <= wr_stages[9]; |
end |
|
// intermediate synchronization to CLK270 |
always @(negedge clk90) begin |
dq_oe_270 <= dq_oe_0; |
dqs_oe_270 <= dqs_oe_0; |
dqs_rst_270 <= dqs_rst_0; |
wdf_rden_270 <= wdf_rden_0; |
end |
|
// synchronize DQS signals to CLK180 |
always @(negedge clk0) begin |
dqs_oe_n_180_r1 <= ~dqs_oe_270; |
dqs_rst_n_180_r1 <= ~dqs_rst_270; |
end |
|
// All write data-related signals synced to CLK90 |
always @(posedge clk90) begin |
dq_oe_n_90_r1 <= ~dq_oe_270; |
wdf_rden_90_r <= wdf_rden_270; |
end |
|
// generate for wdf_rden and calib rden. These signals |
// are asserted based on write latency. For write |
// latency of 2, the extra register stage is taken out. |
generate |
if (WR_LATENCY > 2) begin |
always @(posedge clk90) begin |
// assert wdf rden only for non calibration opertations |
wdf_rden_90_r1 <= wdf_rden_90_r & |
phy_init_data_sel; |
// rden for calibration |
calib_rden_90_r <= wdf_rden_90_r; |
end |
end else begin |
always @(*) begin |
wdf_rden_90_r1 = wdf_rden_90_r |
& phy_init_data_sel; |
calib_rden_90_r = wdf_rden_90_r; |
end |
end // else: !if(WR_LATENCY > 2) |
endgenerate |
|
// dm CE signal to stop dm oscilation |
always @(negedge clk90)begin |
dm_ce_r <= dm_ce_0; |
dm_ce <= dm_ce_r; |
end |
|
// When in ECC mode the upper byte [71:64] will have the |
// ECC parity. Mapping the bytes which have valid data |
// to the upper byte in ecc mode. Also in ecc mode there |
// is an extra register stage to account for timing. |
|
genvar mask_i; |
generate |
if(ECC_ENABLE) begin |
for (mask_i = 0; mask_i < (2*DQ_WIDTH)/72; |
mask_i = mask_i+1) begin: gen_mask |
assign wdf_ecc_mask[((mask_i*9)+9)-1:(mask_i*9)] = |
{&wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9], |
wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9]}; |
end |
end |
endgenerate |
|
generate |
if (ECC_ENABLE) begin:gen_ecc_reg |
always @(posedge clk90)begin |
if(phy_init_data_sel) |
wdf_mask_r <= wdf_ecc_mask; |
else |
wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; |
end |
end else begin |
always@(posedge clk90) begin |
if (phy_init_data_sel) |
wdf_mask_r <= wdf_mask_data; |
else |
wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; |
end |
end |
endgenerate |
|
always @(posedge clk90) begin |
if(phy_init_data_sel) |
wdf_data_r <= wdf_data; |
else |
wdf_data_r <={init_data_f,init_data_r}; |
end |
|
// Error generation block during simulation. |
// Error will be displayed when all the DM |
// bits are not zero. The error will be |
// displayed only during the start of the sequence |
// for errors that are continous over many cycles. |
generate |
if (ECC_ENABLE) begin: gen_ecc_error |
always @(posedge clk90) begin |
//synthesis translate_off |
wdf_mask_r1 <= wdf_mask_r; |
if(DQ_WIDTH > 72) |
ecc_dm_error_r |
<= ( |
(~wdf_mask_r1[35] && (|wdf_mask_r1[34:27])) || |
(~wdf_mask_r1[26] && (|wdf_mask_r1[25:18])) || |
(~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || |
(~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; |
else |
ecc_dm_error_r |
<= ((~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || |
(~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; |
ecc_dm_error_r1 <= ecc_dm_error_r ; |
if (ecc_dm_error_r && ~ecc_dm_error_r1) // assert the error only once. |
$display ("ECC DM ERROR. "); |
//synthesis translate_on |
end |
end |
endgenerate |
|
//*************************************************************************** |
// State logic to write calibration training patterns |
//*************************************************************************** |
|
always @(posedge clk90) begin |
if (rst90_r) begin |
init_wdf_cnt_r <= 4'd0; |
init_data_r <= {64{1'bx}}; |
init_data_f <= {64{1'bx}}; |
end else begin |
init_wdf_cnt_r <= init_wdf_cnt_r + calib_rden_90_r; |
casex (init_wdf_cnt_r) |
// First stage calibration. Pattern (rise/fall) = 1(r)->0(f) |
// The rise data and fall data are already interleaved in the manner |
// required for data into the WDF write FIFO |
4'b00xx: begin |
init_data_r <= {DQ_WIDTH{1'b1}}; |
init_data_f <= {DQ_WIDTH{1'b0}}; |
end |
// Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f) |
4'b01x0: begin |
init_data_r <= {DQ_WIDTH{1'b1}}; |
init_data_f <= {DQ_WIDTH{1'b1}}; |
end |
4'b01x1: begin |
init_data_r <= {DQ_WIDTH{1'b0}}; |
init_data_f <= {DQ_WIDTH{1'b0}}; |
end |
// MIG 2.1: Changed Stage 3/4 training pattern |
// Third and fourth stage calibration patern = |
// 11(r)->ee(f)->ee(r)->11(f)-11(r)->ee(f)->ee(r)->11(f) |
4'b1000: begin |
init_data_r <= {DQ_WIDTH/4{4'h1}}; |
init_data_f <= {DQ_WIDTH/4{4'hE}}; |
end |
4'b1001: begin |
init_data_r <= {DQ_WIDTH/4{4'hE}}; |
init_data_f <= {DQ_WIDTH/4{4'h1}}; |
end |
4'b1010: begin |
init_data_r <= {(DQ_WIDTH/4){4'h1}}; |
init_data_f <= {(DQ_WIDTH/4){4'hE}}; |
end |
4'b1011: begin |
init_data_r <= {(DQ_WIDTH/4){4'hE}}; |
init_data_f <= {(DQ_WIDTH/4){4'h1}}; |
end |
default: begin |
init_data_f <= {(2*DQ_WIDTH){1'bx}}; |
init_data_r <= {(2*DQ_WIDTH){1'bx}}; |
end |
endcase |
end |
end |
|
//*************************************************************************** |
|
always @(posedge clk90) |
dq_oe_n <= dq_oe_n_90_r1; |
|
always @(negedge clk0) |
dqs_oe_n <= dqs_oe_n_180_r1; |
|
always @(negedge clk0) |
dqs_rst_n <= dqs_rst_n_180_r1; |
|
// generate for odt. odt is asserted based on |
// write latency. For write latency of 2 |
// the extra register stage is taken out. |
generate |
if (ODT_WR_LATENCY > 2) begin |
always @(posedge clk0) begin |
odt <= 'b0; |
odt[0] <= odt_0; |
end |
end else begin |
always @ (*) begin |
odt = 'b0; |
odt[0] = odt_0; |
end |
end |
endgenerate |
|
assign wdf_rden = wdf_rden_90_r1; |
|
//*************************************************************************** |
// Format write data/mask: Data is in format: {fall, rise} |
//*************************************************************************** |
|
assign wr_data_rise = wdf_data_r[DQ_WIDTH-1:0]; |
assign wr_data_fall = wdf_data_r[(2*DQ_WIDTH)-1:DQ_WIDTH]; |
assign mask_data_rise = wdf_mask_r[MASK_WIDTH-1:0]; |
assign mask_data_fall = wdf_mask_r[(2*MASK_WIDTH)-1:MASK_WIDTH]; |
|
endmodule |
/ddr2_mig/ddr2_mig.v
0,0 → 1,618
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_mig.v |
// /___/ /\ Date Last Modified: $Date: 2009/02/03 18:46:29 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// Top-level module. Simple model for what the user might use |
// Typically, the user will only instantiate MEM_INTERFACE_TOP in their |
// code, and generate all backend logic (test bench) separately. |
// In addition to the memory controller, the module instantiates: |
// 1. Clock generation/distribution, reset logic |
// 2. IDELAY control block |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 |
// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
(* X_CORE_INFO = "mig_v3_0_ddr2_v5, Coregen 11.1" , CORE_GENERATION_INFO = "ddr2_v5,mig_v3_0,{component_name=ddr2_mig, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=4, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, DDR2_CLK_PERIOD=3750, RST_ACT_LOW=1}" *) |
module ddr2_mig # |
( |
parameter BANK_WIDTH = 2, |
// # of memory bank addr bits. |
parameter CKE_WIDTH = 1, |
// # of memory clock enable outputs. |
parameter CLK_WIDTH = 2, |
// # of clock outputs. |
parameter COL_WIDTH = 10, |
// # of memory column bits. |
parameter CS_NUM = 1, |
// # of separate memory chip selects. |
parameter CS_WIDTH = 1, |
// # of total memory chip selects. |
parameter CS_BITS = 0, |
// set to log2(CS_NUM) (rounded up). |
parameter DM_WIDTH = 8, |
// # of data mask bits. |
parameter DQ_WIDTH = 64, |
// # of data width. |
parameter DQ_PER_DQS = 8, |
// # of DQ data bits per strobe. |
parameter DQS_WIDTH = 8, |
// # of DQS strobes. |
parameter DQ_BITS = 6, |
// set to log2(DQS_WIDTH*DQ_PER_DQS). |
parameter DQS_BITS = 3, |
// set to log2(DQS_WIDTH). |
parameter ODT_WIDTH = 1, |
// # of memory on-die term enables. |
parameter ROW_WIDTH = 13, |
// # of memory row and # of addr bits. |
parameter ADDITIVE_LAT = 0, |
// additive write latency. |
parameter BURST_LEN = 4, |
// burst length (in double words). |
parameter BURST_TYPE = 0, |
// burst type (=0 seq; =1 interleaved). |
parameter CAS_LAT = 4, |
// CAS latency. |
parameter ECC_ENABLE = 0, |
// enable ECC (=1 enable). |
parameter APPDATA_WIDTH = 128, |
// # of usr read/write data bus bits. |
parameter MULTI_BANK_EN = 1, |
// Keeps multiple banks open. (= 1 enable). |
parameter TWO_T_TIME_EN = 1, |
// 2t timing for unbuffered dimms. |
parameter ODT_TYPE = 1, |
// ODT (=0(none),=1(75),=2(150),=3(50)). |
parameter REDUCE_DRV = 0, |
// reduced strength mem I/O (=1 yes). |
parameter REG_ENABLE = 0, |
// registered addr/ctrl (=1 yes). |
parameter TREFI_NS = 7800, |
// auto refresh interval (ns). |
parameter TRAS = 40000, |
// active->precharge delay. |
parameter TRCD = 15000, |
// active->read/write delay. |
parameter TRFC = 105000, |
// refresh->refresh, refresh->active delay. |
parameter TRP = 15000, |
// precharge->command delay. |
parameter TRTP = 7500, |
// read->precharge delay. |
parameter TWR = 15000, |
// used to determine write->precharge. |
parameter TWTR = 7500, |
// write->read delay. |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
// # = TRUE, the IODELAY performance mode is set |
// to high. |
// # = FALSE, the IODELAY performance mode is set |
// to low. |
parameter SIM_ONLY = 0, |
// = 1 to skip SDRAM power up delay. |
parameter DEBUG_EN = 0, |
// Enable debug signals/controls. |
// When this parameter is changed from 0 to 1, |
// make sure to uncomment the coregen commands |
// in ise_flow.bat or create_ise.bat files in |
// par folder. |
parameter CLK_PERIOD = 3750, |
// Core/Memory clock period (in ps). |
parameter CLK_TYPE = "SINGLE_ENDED", |
// # = "DIFFERENTIAL " ->; Differential input clocks , |
// # = "SINGLE_ENDED" -> Single ended input clocks. |
parameter DLL_FREQ_MODE = "HIGH", |
// DCM Frequency range. |
parameter RST_ACT_LOW = 1 |
// =1 for active low reset, =0 for active high. |
) |
( |
inout [DQ_WIDTH-1:0] ddr2_dq, |
output [ROW_WIDTH-1:0] ddr2_a, |
output [BANK_WIDTH-1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output [CS_WIDTH-1:0] ddr2_cs_n, |
output [ODT_WIDTH-1:0] ddr2_odt, |
output [CKE_WIDTH-1:0] ddr2_cke, |
output [DM_WIDTH-1:0] ddr2_dm, |
input sys_clk, |
input idly_clk_200, |
input sys_rst_n, |
output phy_init_done, |
output rst0_tb, |
output clk0_tb, |
input usr_clk, // jb |
output app_wdf_afull, |
output app_af_afull, |
output rd_data_valid, |
input app_wdf_wren, |
input app_af_wren, |
input [30:0] app_af_addr, |
input [2:0] app_af_cmd, |
output [(APPDATA_WIDTH)-1:0] rd_data_fifo_out, |
input [(APPDATA_WIDTH)-1:0] app_wdf_data, |
input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, |
inout [DQS_WIDTH-1:0] ddr2_dqs, |
inout [DQS_WIDTH-1:0] ddr2_dqs_n, |
output [CLK_WIDTH-1:0] ddr2_ck, |
output [CLK_WIDTH-1:0] ddr2_ck_n |
); |
|
//*************************************************************************** |
// IODELAY Group Name: Replication and placement of IDELAYCTRLs will be |
// handled automatically by software tools if IDELAYCTRLs have same refclk, |
// reset and rdy nets. Designs with a unique RESET will commonly create a |
// unique RDY. Constraint IODELAY_GROUP is associated to a set of IODELAYs |
// with an IDELAYCTRL. The parameter IODELAY_GRP value can be any string. |
//*************************************************************************** |
|
localparam IODELAY_GRP = "IODELAY_MIG"; |
|
initial |
$display("Xilinx DDR2 MIGed controller at %m\n"); |
|
|
|
|
wire sys_clk_p; |
wire sys_clk_n; |
wire clk200_p; |
wire clk200_n; |
wire rst0; |
wire rst90; |
wire rstdiv0; |
wire rst200; |
wire clk0; |
wire clk90; |
wire clkdiv0; |
wire clk200; |
wire idelay_ctrl_rdy; |
|
|
//Debug signals |
|
|
wire [3:0] dbg_calib_done; |
wire [3:0] dbg_calib_err; |
wire [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt; |
wire [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt; |
wire [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt; |
wire [DQS_WIDTH-1:0] dbg_calib_rd_data_sel; |
wire [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly; |
wire [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly; |
wire dbg_idel_up_all; |
wire dbg_idel_down_all; |
wire dbg_idel_up_dq; |
wire dbg_idel_down_dq; |
wire dbg_idel_up_dqs; |
wire dbg_idel_down_dqs; |
wire dbg_idel_up_gate; |
wire dbg_idel_down_gate; |
wire [DQ_BITS-1:0] dbg_sel_idel_dq; |
wire dbg_sel_all_idel_dq; |
wire [DQS_BITS:0] dbg_sel_idel_dqs; |
wire dbg_sel_all_idel_dqs; |
wire [DQS_BITS:0] dbg_sel_idel_gate; |
wire dbg_sel_all_idel_gate; |
|
|
// Debug signals (optional use) |
|
//*********************************** |
// PHY Debug Port demo |
//*********************************** |
wire [35:0] cs_control0; |
wire [35:0] cs_control1; |
wire [35:0] cs_control2; |
wire [35:0] cs_control3; |
wire [191:0] vio0_in; |
wire [95:0] vio1_in; |
wire [99:0] vio2_in; |
wire [31:0] vio3_out; |
|
|
|
|
//*************************************************************************** |
|
assign rst0_tb = rst0; |
assign clk0_tb = clk0; |
assign sys_clk_p = 1'b1; |
assign sys_clk_n = 1'b0; |
assign clk200_p = 1'b1; |
assign clk200_n = 1'b0; |
|
ddr2_idelay_ctrl # |
( |
.IODELAY_GRP (IODELAY_GRP) |
) |
u_ddr2_idelay_ctrl |
( |
.rst200 (rst200), |
.clk200 (clk200), |
.idelay_ctrl_rdy (idelay_ctrl_rdy) |
); |
|
ddr2_infrastructure # |
( |
.CLK_PERIOD (CLK_PERIOD), |
.CLK_TYPE (CLK_TYPE), |
.DLL_FREQ_MODE (DLL_FREQ_MODE), |
.RST_ACT_LOW (RST_ACT_LOW) |
) |
u_ddr2_infrastructure |
( |
.sys_clk_p (sys_clk_p), |
.sys_clk_n (sys_clk_n), |
.sys_clk (sys_clk), |
.clk200_p (clk200_p), |
.clk200_n (clk200_n), |
.idly_clk_200 (idly_clk_200), |
.sys_rst_n (sys_rst_n), |
.rst0 (rst0), |
.rst90 (rst90), |
.rstdiv0 (rstdiv0), |
.rst200 (rst200), |
.clk0 (clk0), |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.clk200 (clk200), |
.idelay_ctrl_rdy (idelay_ctrl_rdy) |
); |
|
ddr2_top # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.CLK_WIDTH (CLK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.CS_BITS (CS_BITS), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_WIDTH (DQS_WIDTH), |
.DQ_BITS (DQ_BITS), |
.DQS_BITS (DQS_BITS), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.MULTI_BANK_EN (MULTI_BANK_EN), |
.TWO_T_TIME_EN (TWO_T_TIME_EN), |
.ODT_TYPE (ODT_TYPE), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TREFI_NS (TREFI_NS), |
.TRAS (TRAS), |
.TRCD (TRCD), |
.TRFC (TRFC), |
.TRP (TRP), |
.TRTP (TRTP), |
.TWR (TWR), |
.TWTR (TWTR), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP), |
.SIM_ONLY (SIM_ONLY), |
.DEBUG_EN (DEBUG_EN), |
.CLK_PERIOD (CLK_PERIOD), |
.FPGA_SPEED_GRADE (1), |
.USE_DM_PORT (1) |
) |
u_ddr2_top_0 |
( |
.ddr2_dq (ddr2_dq), |
.ddr2_a (ddr2_a), |
.ddr2_ba (ddr2_ba), |
.ddr2_ras_n (ddr2_ras_n), |
.ddr2_cas_n (ddr2_cas_n), |
.ddr2_we_n (ddr2_we_n), |
.ddr2_cs_n (ddr2_cs_n), |
.ddr2_odt (ddr2_odt), |
.ddr2_cke (ddr2_cke), |
.ddr2_dm (ddr2_dm), |
.phy_init_done (phy_init_done), |
.rst0 (rst0), |
.rst90 (rst90), |
.rstdiv0 (rstdiv0), |
.clk0 (clk0), |
.usr_clk (usr_clk), // jb |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.app_wdf_afull (app_wdf_afull), |
.app_af_afull (app_af_afull), |
.rd_data_valid (rd_data_valid), |
.app_wdf_wren (app_wdf_wren), |
.app_af_wren (app_af_wren), |
.app_af_addr (app_af_addr), |
.app_af_cmd (app_af_cmd), |
.rd_data_fifo_out (rd_data_fifo_out), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.ddr2_dqs (ddr2_dqs), |
.ddr2_dqs_n (ddr2_dqs_n), |
.ddr2_ck (ddr2_ck), |
.rd_ecc_error (), |
.ddr2_ck_n (ddr2_ck_n), |
|
.dbg_calib_done (dbg_calib_done), |
.dbg_calib_err (dbg_calib_err), |
.dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), |
.dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), |
.dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), |
.dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), |
.dbg_calib_rden_dly (dbg_calib_rden_dly), |
.dbg_calib_gate_dly (dbg_calib_gate_dly), |
.dbg_idel_up_all (dbg_idel_up_all), |
.dbg_idel_down_all (dbg_idel_down_all), |
.dbg_idel_up_dq (dbg_idel_up_dq), |
.dbg_idel_down_dq (dbg_idel_down_dq), |
.dbg_idel_up_dqs (dbg_idel_up_dqs), |
.dbg_idel_down_dqs (dbg_idel_down_dqs), |
.dbg_idel_up_gate (dbg_idel_up_gate), |
.dbg_idel_down_gate (dbg_idel_down_gate), |
.dbg_sel_idel_dq (dbg_sel_idel_dq), |
.dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), |
.dbg_sel_idel_dqs (dbg_sel_idel_dqs), |
.dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), |
.dbg_sel_idel_gate (dbg_sel_idel_gate), |
.dbg_sel_all_idel_gate (dbg_sel_all_idel_gate) |
); |
|
|
//***************************************************************** |
// Hooks to prevent sim/syn compilation errors (mainly for VHDL - but |
// keep it also in Verilog version of code) w/ floating inputs if |
// DEBUG_EN = 0. |
//***************************************************************** |
|
generate |
if (DEBUG_EN == 0) begin: gen_dbg_tie_off |
assign dbg_idel_up_all = 'b0; |
assign dbg_idel_down_all = 'b0; |
assign dbg_idel_up_dq = 'b0; |
assign dbg_idel_down_dq = 'b0; |
assign dbg_idel_up_dqs = 'b0; |
assign dbg_idel_down_dqs = 'b0; |
assign dbg_idel_up_gate = 'b0; |
assign dbg_idel_down_gate = 'b0; |
assign dbg_sel_idel_dq = 'b0; |
assign dbg_sel_all_idel_dq = 'b0; |
assign dbg_sel_idel_dqs = 'b0; |
assign dbg_sel_all_idel_dqs = 'b0; |
assign dbg_sel_idel_gate = 'b0; |
assign dbg_sel_all_idel_gate = 'b0; |
end else begin: gen_dbg_enable |
|
//***************************************************************** |
// PHY Debug Port example - see MIG User's Guide, XAPP858 or |
// Answer Record 29443 |
// This logic supports up to 32 DQ and 8 DQS I/O |
// NOTES: |
// 1. PHY Debug Port demo connects to 4 VIO modules: |
// - 3 VIO modules with only asynchronous inputs |
// * Monitor IDELAY taps for DQ, DQS, DQS Gate |
// * Calibration status |
// - 1 VIO module with synchronous outputs |
// * Allow dynamic adjustment o f IDELAY taps |
// 2. User may need to modify this code to incorporate other |
// chipscope-related modules in their larger design (e.g. |
// if they have other ILA/VIO modules, they will need to |
// for example instantiate a larger ICON module). In addition |
// user may want to instantiate more VIO modules to control |
// IDELAY for more DQ, DQS than is shown here |
//***************************************************************** |
|
icon4 u_icon |
( |
.control0 (cs_control0), |
.control1 (cs_control1), |
.control2 (cs_control2), |
.control3 (cs_control3) |
); |
|
//***************************************************************** |
// VIO ASYNC input: Display current IDELAY setting for up to 32 |
// DQ taps (32x6) = 192 |
//***************************************************************** |
|
vio_async_in192 u_vio0 |
( |
.control (cs_control0), |
.async_in (vio0_in) |
); |
|
//***************************************************************** |
// VIO ASYNC input: Display current IDELAY setting for up to 8 DQS |
// and DQS Gate taps (8x6x2) = 96 |
//***************************************************************** |
|
vio_async_in96 u_vio1 |
( |
.control (cs_control1), |
.async_in (vio1_in) |
); |
|
//***************************************************************** |
// VIO ASYNC input: Display other calibration results |
//***************************************************************** |
|
vio_async_in100 u_vio2 |
( |
.control (cs_control2), |
.async_in (vio2_in) |
); |
|
//***************************************************************** |
// VIO SYNC output: Dynamically change IDELAY taps |
//***************************************************************** |
|
vio_sync_out32 u_vio3 |
( |
.control (cs_control3), |
.clk (clkdiv0), |
.sync_out (vio3_out) |
); |
|
//***************************************************************** |
// Bit assignments: |
// NOTE: Not all VIO, ILA inputs/outputs may be used - these will |
// be dependent on the user's particular bit width |
//***************************************************************** |
|
if (DQ_WIDTH <= 32) begin: gen_dq_le_32 |
assign vio0_in[(6*DQ_WIDTH)-1:0] |
= dbg_calib_dq_tap_cnt[(6*DQ_WIDTH)-1:0]; |
end else begin: gen_dq_gt_32 |
assign vio0_in = dbg_calib_dq_tap_cnt[191:0]; |
end |
|
if (DQS_WIDTH <= 8) begin: gen_dqs_le_8 |
assign vio1_in[(6*DQS_WIDTH)-1:0] |
= dbg_calib_dqs_tap_cnt[(6*DQS_WIDTH)-1:0]; |
assign vio1_in[(12*DQS_WIDTH)-1:(6*DQS_WIDTH)] |
= dbg_calib_gate_tap_cnt[(6*DQS_WIDTH)-1:0]; |
end else begin: gen_dqs_gt_32 |
assign vio1_in[47:0] = dbg_calib_dqs_tap_cnt[47:0]; |
assign vio1_in[95:48] = dbg_calib_gate_tap_cnt[47:0]; |
end |
|
//dbg_calib_rd_data_sel |
|
if (DQS_WIDTH <= 8) begin: gen_rdsel_le_8 |
assign vio2_in[(DQS_WIDTH)+7:8] |
= dbg_calib_rd_data_sel[(DQS_WIDTH)-1:0]; |
end else begin: gen_rdsel_gt_32 |
assign vio2_in[15:8] |
= dbg_calib_rd_data_sel[7:0]; |
end |
|
//dbg_calib_rden_dly |
|
if (DQS_WIDTH <= 8) begin: gen_calrd_le_8 |
assign vio2_in[(5*DQS_WIDTH)+19:20] |
= dbg_calib_rden_dly[(5*DQS_WIDTH)-1:0]; |
end else begin: gen_calrd_gt_32 |
assign vio2_in[59:20] |
= dbg_calib_rden_dly[39:0]; |
end |
|
//dbg_calib_gate_dly |
|
if (DQS_WIDTH <= 8) begin: gen_calgt_le_8 |
assign vio2_in[(5*DQS_WIDTH)+59:60] |
= dbg_calib_gate_dly[(5*DQS_WIDTH)-1:0]; |
end else begin: gen_calgt_gt_32 |
assign vio2_in[99:60] |
= dbg_calib_gate_dly[39:0]; |
end |
|
//dbg_sel_idel_dq |
|
if (DQ_BITS <= 5) begin: gen_selid_le_5 |
assign dbg_sel_idel_dq[DQ_BITS-1:0] |
= vio3_out[DQ_BITS+7:8]; |
end else begin: gen_selid_gt_32 |
assign dbg_sel_idel_dq[4:0] |
= vio3_out[12:8]; |
end |
|
//dbg_sel_idel_dqs |
|
if (DQS_BITS <= 3) begin: gen_seldqs_le_3 |
assign dbg_sel_idel_dqs[DQS_BITS:0] |
= vio3_out[(DQS_BITS+16):16]; |
end else begin: gen_seldqs_gt_32 |
assign dbg_sel_idel_dqs[3:0] |
= vio3_out[19:16]; |
end |
|
//dbg_sel_idel_gate |
|
if (DQS_BITS <= 3) begin: gen_gtdqs_le_3 |
assign dbg_sel_idel_gate[DQS_BITS:0] |
= vio3_out[(DQS_BITS+21):21]; |
end else begin: gen_gtdqs_gt_32 |
assign dbg_sel_idel_gate[3:0] |
= vio3_out[24:21]; |
end |
|
|
assign vio2_in[3:0] = dbg_calib_done; |
assign vio2_in[7:4] = dbg_calib_err; |
|
assign dbg_idel_up_all = vio3_out[0]; |
assign dbg_idel_down_all = vio3_out[1]; |
assign dbg_idel_up_dq = vio3_out[2]; |
assign dbg_idel_down_dq = vio3_out[3]; |
assign dbg_idel_up_dqs = vio3_out[4]; |
assign dbg_idel_down_dqs = vio3_out[5]; |
assign dbg_idel_up_gate = vio3_out[6]; |
assign dbg_idel_down_gate = vio3_out[7]; |
assign dbg_sel_all_idel_dq = vio3_out[15]; |
assign dbg_sel_all_idel_dqs = vio3_out[20]; |
assign dbg_sel_all_idel_gate = vio3_out[25]; |
end |
endgenerate |
|
endmodule |
/ddr2_mig/ddr2_chipscope.v
0,0 → 1,114
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_chipscope.v |
// /___/ /\ Date Last Modified: $Data$ |
// \ \ / \ Date Created: 9/14/06 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Purpose: |
// Skeleton Chipscope module declarations - for simulation only |
//Reference: |
//Revision History: |
// |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module icon4 |
( |
control0, |
control1, |
control2, |
control3 |
) |
/* synthesis syn_black_box syn_noprune = 1 */; |
output [35:0] control0; |
output [35:0] control1; |
output [35:0] control2; |
output [35:0] control3; |
endmodule |
|
module vio_async_in192 |
( |
control, |
async_in |
) |
/* synthesis syn_black_box syn_noprune = 1 */; |
input [35:0] control; |
input [191:0] async_in; |
endmodule |
|
module vio_async_in96 |
( |
control, |
async_in |
) |
/* synthesis syn_black_box syn_noprune = 1 */; |
input [35:0] control; |
input [95:0] async_in; |
endmodule |
|
module vio_async_in100 |
( |
control, |
async_in |
) |
/* synthesis syn_black_box syn_noprune = 1 */; |
input [35:0] control; |
input [99:0] async_in; |
endmodule |
|
module vio_sync_out32 |
( |
control, |
clk, |
sync_out |
) |
/* synthesis syn_black_box syn_noprune = 1 */; |
input [35:0] control; |
input clk; |
output [31:0] sync_out; |
endmodule |
/ddr2_mig/ddr2_phy_dq_iob.v
0,0 → 1,592
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_dq_iob.v |
// /___/ /\ Date Last Modified: $Date: 2009/01/15 14:22:14 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module places the data in the IOBs. |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.2 - DIRT strings removed and modified the code. PK. 11/13/08 |
// Rev 1.3 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added |
// on IODELAY primitive. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_dq_iob # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
parameter IODELAY_GRP = "IODELAY_MIG", |
parameter FPGA_SPEED_GRADE = 2 |
) |
( |
input clk0, |
input clk90, |
input clkdiv0, |
input rst90, |
input dlyinc, |
input dlyce, |
input dlyrst, |
input [1:0] dq_oe_n, |
input dqs, |
input ce, |
input rd_data_sel, |
input wr_data_rise, |
input wr_data_fall, |
output rd_data_rise, |
output rd_data_fall, |
inout ddr_dq |
); |
|
wire dq_iddr_clk; |
wire dq_idelay; |
wire dq_in; |
wire dq_oe_n_r; |
wire dq_out; |
wire stg2a_out_fall; |
wire stg2a_out_rise; |
(* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg2b_out_fall; |
(* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg2b_out_rise; |
wire stg3a_out_fall; |
wire stg3a_out_rise; |
wire stg3b_out_fall; |
wire stg3b_out_rise; |
|
//*************************************************************************** |
// Directed routing constraints for route between IDDR and stage 2 capture |
// in fabric. |
// Only 2 out of the 12 wire declarations will be used for any given |
// instantiation of this module. |
// Varies according: |
// (1) I/O column (left, center, right) used |
// (2) Which I/O in I/O pair (master, slave) used |
// Nomenclature: _Xy, X = column (0 = left, 1 = center, 2 = right), |
// y = master or slave |
//*************************************************************************** |
|
// MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave |
|
(* XIL_PAR_DELAY = "500 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_rise_sg3; |
(* XIL_PAR_DELAY = "500 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_fall_sg3; |
(* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_rise_sg2; |
(* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_fall_sg2; |
(* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_rise_sg1; |
(* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) |
wire stg1_out_fall_sg1; |
|
//*************************************************************************** |
// Bidirectional I/O |
//*************************************************************************** |
|
IOBUF u_iobuf_dq |
( |
.I (dq_out), |
.T (dq_oe_n_r), |
.IO (ddr_dq), |
.O (dq_in) |
); |
|
//*************************************************************************** |
// Write (output) path |
//*************************************************************************** |
|
// on a write, rising edge of DQS corresponds to rising edge of CLK180 |
// (aka falling edge of CLK0 -> rising edge DQS). We also know: |
// 1. data must be driven 1/4 clk cycle before corresponding DQS edge |
// 2. first rising DQS edge driven on falling edge of CLK0 |
// 3. rising data must be driven 1/4 cycle before falling edge of CLK0 |
// 4. therefore, rising data driven on rising edge of CLK |
ODDR # |
( |
.SRTYPE("SYNC"), |
.DDR_CLK_EDGE("SAME_EDGE") |
) |
u_oddr_dq |
( |
.Q (dq_out), |
.C (clk90), |
.CE (1'b1), |
.D1 (wr_data_rise), |
.D2 (wr_data_fall), |
.R (1'b0), |
.S (1'b0) |
); |
|
// make sure output is tri-state during reset (DQ_OE_N_R = 1) |
ODDR # |
( |
.SRTYPE("ASYNC"), |
.DDR_CLK_EDGE("SAME_EDGE") |
) |
u_tri_state_dq |
( |
.Q (dq_oe_n_r), |
.C (clk90), |
.CE (1'b1), |
.D1 (dq_oe_n[0]), |
.D2 (dq_oe_n[1]), |
.R (1'b0), |
.S (rst90) |
); |
|
//*************************************************************************** |
// Read data capture scheme description: |
// Data capture consists of 3 ranks of flops, and a MUX |
// 1. Rank 1 ("Stage 1"): IDDR captures delayed DDR DQ from memory using |
// delayed DQS. |
// - Data is split into 2 SDR streams, one each for rise and fall data. |
// - BUFIO (DQS) input inverted to IDDR. IDDR configured in SAME_EDGE |
// mode. This means that: (1) Q1 = fall data, Q2 = rise data, |
// (2) Both rise and fall data are output on falling edge of DQS - |
// rather than rise output being output on one edge of DQS, and fall |
// data on the other edge if the IDDR were configured in OPPOSITE_EDGE |
// mode. This simplifies Stage 2 capture (only one core clock edge |
// used, removing effects of duty-cycle-distortion), and saves one |
// fabric flop in Rank 3. |
// 2. Rank 2 ("Stage 2"): Fabric flops are used to capture output of first |
// rank into FPGA clock (CLK) domain. Each rising/falling SDR stream |
// from IDDR is feed into two flops, one clocked off rising and one off |
// falling edge of CLK. One of these flops is chosen, with the choice |
// being the one that reduces # of DQ/DQS taps necessary to align Stage |
// 1 and Stage 2. Same edge is used to capture both rise and fall SDR |
// streams. |
// 3. Rank 3 ("Stage 3"): Removes half-cycle paths in CLK domain from |
// output of Rank 2. This stage, like Stage 2, is clocked by CLK. Note |
// that Stage 3 can be expanded to also support SERDES functionality |
// 4. Output MUX: Selects whether Stage 1 output is aligned to rising or |
// falling edge of CLK (i.e. specifically this selects whether IDDR |
// rise/fall output is transfered to rising or falling edge of CLK). |
// Implementation: |
// 1. Rank 1 is implemented using an IDDR primitive |
// 2. Rank 2 is implemented using: |
// - An RPM to fix the location of the capture flops near the DQ I/O. |
// The exact RPM used depends on which I/O column (left, center, |
// right) the DQ I/O is placed at - this affects the optimal location |
// of the slice flops (or does it - can we always choose the two |
// columns to slices to the immediate right of the I/O to use, no |
// matter what the column?). The origin of the RPM must be set in the |
// UCF file using the RLOC_ORIGIN constraint (where the original is |
// based on the DQ I/O location). |
// - Directed Routing Constraints ("DIRT strings") to fix the routing |
// to the rank 2 fabric flops. This is done to minimize: (1) total |
// route delay (and therefore minimize voltage/temperature-related |
// variations), and (2) minimize skew both within each rising and |
// falling data net, as well as between the rising and falling nets. |
// The exact DIRT string used depends on: (1) which I/O column the |
// DQ I/O is placed, and (2) whether the DQ I/O is placed on the |
// "Master" or "Slave" I/O of a diff pair (DQ is not differential, but |
// the routing will be affected by which of each I/O pair is used) |
// 3. Rank 3 is implemented using fabric flops. No LOC or DIRT contraints |
// are used, tools are expected to place these and meet PERIOD timing |
// without constraints (constraints may be necessary for "full" designs, |
// in this case, user may need to add LOC constraints - if this is the |
// case, there are no constraints - other than meeting PERIOD timing - |
// for rank 3 flops. |
//*************************************************************************** |
|
//*************************************************************************** |
// MIG 2.2: Define AREA_GROUP = "DDR_CAPTURE_FFS" contain all RPM flops in |
// design. In UCF file, add constraint: |
// AREA_GROUP "DDR_CAPTURE_FFS" GROUP = CLOSED; |
// This is done to prevent MAP from packing unrelated logic into |
// the slices used by the RPMs. Doing so may cause the DIRT strings |
// that define the IDDR -> fabric flop routing to later become |
// unroutable during PAR because the unrelated logic placed by MAP |
// may use routing resources required by the DIRT strings. MAP |
// does not currently take into account DIRT strings when placing |
// logic |
//*************************************************************************** |
|
// IDELAY to delay incoming data for synchronization purposes |
(* IODELAY_GROUP = IODELAY_GRP *) IODELAY # |
( |
.DELAY_SRC ("I"), |
.IDELAY_TYPE ("VARIABLE"), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IDELAY_VALUE (0), |
.ODELAY_VALUE (0) |
) |
u_idelay_dq |
( |
.DATAOUT (dq_idelay), |
.C (clkdiv0), |
.CE (dlyce), |
.DATAIN (), |
.IDATAIN (dq_in), |
.INC (dlyinc), |
.ODATAIN (), |
.RST (dlyrst), |
.T () |
); |
|
//*************************************************************************** |
// Rank 1 capture: Use IDDR to generate two SDR outputs |
//*************************************************************************** |
|
// invert clock to IDDR in order to use SAME_EDGE mode (otherwise, we "run |
// out of clocks" because DQS is not continuous |
assign dq_iddr_clk = ~dqs; |
|
//*************************************************************************** |
// Rank 2 capture: Use fabric flops to capture Rank 1 output. Use RPM and |
// DIRT strings here. |
// BEL ("Basic Element of Logic") and relative location constraints for |
// second stage capture. C |
// Varies according: |
// (1) I/O column (left, center, right) used |
// (2) Which I/O in I/O pair (master, slave) used |
//*************************************************************************** |
|
// MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave |
// Take out generate statements - collapses to a single case |
|
generate |
if (FPGA_SPEED_GRADE == 3) begin: gen_stg2_sg3 |
IDDR # |
( |
.DDR_CLK_EDGE ("SAME_EDGE") |
) |
u_iddr_dq |
( |
.Q1 (stg1_out_fall_sg3), |
.Q2 (stg1_out_rise_sg3), |
.C (dq_iddr_clk), |
.CE (ce), |
.D (dq_idelay), |
.R (1'b0), |
.S (1'b0) |
); |
|
//********************************************************* |
// Slice #1 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 rising edge domain ("stg2a") |
// 2. stg2 falling edge -> stg3 rising edge transfer |
//********************************************************* |
|
// Stage 2 capture |
FDRSE u_ff_stg2a_fall |
( |
.Q (stg2a_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg3), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg2a_rise |
( |
.Q (stg2a_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg3), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
// Stage 3 falling -> rising edge translation |
FDRSE u_ff_stg3b_fall |
( |
.Q (stg3b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_fall), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg3b_rise |
( |
.Q (stg3b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_rise), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
//********************************************************* |
// Slice #2 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 falling edge domain ("stg2b") |
//********************************************************* |
|
FDRSE_1 u_ff_stg2b_fall |
( |
.Q (stg2b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg3), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
FDRSE_1 u_ff_stg2b_rise |
( |
.Q (stg2b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg3), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end else if (FPGA_SPEED_GRADE == 2) begin: gen_stg2_sg2 |
IDDR # |
( |
.DDR_CLK_EDGE ("SAME_EDGE") |
) |
u_iddr_dq |
( |
.Q1 (stg1_out_fall_sg2), |
.Q2 (stg1_out_rise_sg2), |
.C (dq_iddr_clk), |
.CE (ce), |
.D (dq_idelay), |
.R (1'b0), |
.S (1'b0) |
); |
|
//********************************************************* |
// Slice #1 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 rising edge domain ("stg2a") |
// 2. stg2 falling edge -> stg3 rising edge transfer |
//********************************************************* |
|
// Stage 2 capture |
FDRSE u_ff_stg2a_fall |
( |
.Q (stg2a_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg2), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg2a_rise |
( |
.Q (stg2a_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg2), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
// Stage 3 falling -> rising edge translation |
FDRSE u_ff_stg3b_fall |
( |
.Q (stg3b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_fall), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg3b_rise |
( |
.Q (stg3b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_rise), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
//********************************************************* |
// Slice #2 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 falling edge domain ("stg2b") |
//********************************************************* |
|
FDRSE_1 u_ff_stg2b_fall |
( |
.Q (stg2b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg2), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
FDRSE_1 u_ff_stg2b_rise |
( |
.Q (stg2b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg2), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end else if (FPGA_SPEED_GRADE == 1) begin: gen_stg2_sg1 |
IDDR # |
( |
.DDR_CLK_EDGE ("SAME_EDGE") |
) |
u_iddr_dq |
( |
.Q1 (stg1_out_fall_sg1), |
.Q2 (stg1_out_rise_sg1), |
.C (dq_iddr_clk), |
.CE (ce), |
.D (dq_idelay), |
.R (1'b0), |
.S (1'b0) |
); |
|
//********************************************************* |
// Slice #1 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 rising edge domain ("stg2a") |
// 2. stg2 falling edge -> stg3 rising edge transfer |
//********************************************************* |
|
// Stage 2 capture |
FDRSE u_ff_stg2a_fall |
( |
.Q (stg2a_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg1), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg2a_rise |
( |
.Q (stg2a_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg1), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
// Stage 3 falling -> rising edge translation |
FDRSE u_ff_stg3b_fall |
( |
.Q (stg3b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_fall), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
FDRSE u_ff_stg3b_rise |
( |
.Q (stg3b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg2b_out_rise), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
//********************************************************* |
// Slice #2 (posedge CLK): Used for: |
// 1. IDDR transfer to CLK0 falling edge domain ("stg2b") |
//********************************************************* |
|
FDRSE_1 u_ff_stg2b_fall |
( |
.Q (stg2b_out_fall), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_fall_sg1), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
|
FDRSE_1 u_ff_stg2b_rise |
( |
.Q (stg2b_out_rise), |
.C (clk0), |
.CE (1'b1), |
.D (stg1_out_rise_sg1), |
.R (1'b0), |
.S (1'b0) |
)/* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
//*************************************************************************** |
// Second stage flops clocked by posedge CLK0 don't need another layer of |
// registering |
//*************************************************************************** |
|
assign stg3a_out_rise = stg2a_out_rise; |
assign stg3a_out_fall = stg2a_out_fall; |
|
//******************************************************************* |
|
assign rd_data_rise = (rd_data_sel) ? stg3a_out_rise : stg3b_out_rise; |
assign rd_data_fall = (rd_data_sel) ? stg3a_out_fall : stg3b_out_fall; |
|
endmodule |
/ddr2_mig/ddr2_mem_if_top.v
0,0 → 1,382
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_mem_if_top.v |
// /___/ /\ Date Last Modified: $Date: 2009/01/15 14:22:14 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR/DDR2 |
//Purpose: |
// Top-level for parameterizable (DDR or DDR2) memory interface |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 |
// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 |
// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_mem_if_top # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter CKE_WIDTH = 1, |
parameter CLK_WIDTH = 1, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter CS_NUM = 1, |
parameter CS_WIDTH = 1, |
parameter USE_DM_PORT = 1, |
parameter DM_WIDTH = 9, |
parameter DQ_WIDTH = 72, |
parameter DQ_BITS = 7, |
parameter DQ_PER_DQS = 8, |
parameter DQS_BITS = 4, |
parameter DQS_WIDTH = 9, |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
parameter IODELAY_GRP = "IODELAY_MIG", |
parameter ODT_WIDTH = 1, |
parameter ROW_WIDTH = 14, |
parameter APPDATA_WIDTH = 144, |
parameter ADDITIVE_LAT = 0, |
parameter BURST_LEN = 4, |
parameter BURST_TYPE = 0, |
parameter CAS_LAT = 5, |
parameter ECC_ENABLE = 0, |
parameter MULTI_BANK_EN = 1, |
parameter TWO_T_TIME_EN = 0, |
parameter ODT_TYPE = 1, |
parameter DDR_TYPE = 1, |
parameter REDUCE_DRV = 0, |
parameter REG_ENABLE = 1, |
parameter TREFI_NS = 7800, |
parameter TRAS = 40000, |
parameter TRCD = 15000, |
parameter TRFC = 105000, |
parameter TRP = 15000, |
parameter TRTP = 7500, |
parameter TWR = 15000, |
parameter TWTR = 10000, |
parameter CLK_PERIOD = 3000, |
parameter SIM_ONLY = 0, |
parameter DEBUG_EN = 0, |
parameter FPGA_SPEED_GRADE = 2 |
) |
( |
input clk0, |
input usr_clk, // jb |
input clk90, |
input clkdiv0, |
input rst0, |
input rst90, |
input rstdiv0, |
input [2:0] app_af_cmd, |
input [30:0] app_af_addr, |
input app_af_wren, |
input app_wdf_wren, |
input [APPDATA_WIDTH-1:0] app_wdf_data, |
input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, |
output [1:0] rd_ecc_error, |
output app_af_afull, |
output app_wdf_afull, |
output rd_data_valid, |
output [APPDATA_WIDTH-1:0] rd_data_fifo_out, |
output phy_init_done, |
output [CLK_WIDTH-1:0] ddr_ck, |
output [CLK_WIDTH-1:0] ddr_ck_n, |
output [ROW_WIDTH-1:0] ddr_addr, |
output [BANK_WIDTH-1:0] ddr_ba, |
output ddr_ras_n, |
output ddr_cas_n, |
output ddr_we_n, |
output [CS_WIDTH-1:0] ddr_cs_n, |
output [CKE_WIDTH-1:0] ddr_cke, |
output [ODT_WIDTH-1:0] ddr_odt, |
output [DM_WIDTH-1:0] ddr_dm, |
inout [DQS_WIDTH-1:0] ddr_dqs, |
inout [DQS_WIDTH-1:0] ddr_dqs_n, |
inout [DQ_WIDTH-1:0] ddr_dq, |
// Debug signals (optional use) |
input dbg_idel_up_all, |
input dbg_idel_down_all, |
input dbg_idel_up_dq, |
input dbg_idel_down_dq, |
input dbg_idel_up_dqs, |
input dbg_idel_down_dqs, |
input dbg_idel_up_gate, |
input dbg_idel_down_gate, |
input [DQ_BITS-1:0] dbg_sel_idel_dq, |
input dbg_sel_all_idel_dq, |
input [DQS_BITS:0] dbg_sel_idel_dqs, |
input dbg_sel_all_idel_dqs, |
input [DQS_BITS:0] dbg_sel_idel_gate, |
input dbg_sel_all_idel_gate, |
output [3:0] dbg_calib_done, |
output [3:0] dbg_calib_err, |
output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, |
output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly |
); |
|
wire [30:0] af_addr; |
wire [2:0] af_cmd; |
wire af_empty; |
wire [ROW_WIDTH-1:0] ctrl_addr; |
wire ctrl_af_rden; |
wire [BANK_WIDTH-1:0] ctrl_ba; |
wire ctrl_cas_n; |
wire [CS_NUM-1:0] ctrl_cs_n; |
wire ctrl_ras_n; |
wire ctrl_rden; |
wire ctrl_ref_flag; |
wire ctrl_we_n; |
wire ctrl_wren; |
wire [DQS_WIDTH-1:0] phy_calib_rden; |
wire [DQS_WIDTH-1:0] phy_calib_rden_sel; |
wire [DQ_WIDTH-1:0] rd_data_fall; |
wire [DQ_WIDTH-1:0] rd_data_rise; |
wire [(2*DQ_WIDTH)-1:0] wdf_data; |
wire [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data; |
wire wdf_rden; |
|
//*************************************************************************** |
|
ddr2_phy_top # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.CLK_WIDTH (CLK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.USE_DM_PORT (USE_DM_PORT), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_BITS (DQ_BITS), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_BITS (DQS_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.TWO_T_TIME_EN (TWO_T_TIME_EN), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.ODT_TYPE (ODT_TYPE), |
.DDR_TYPE (DDR_TYPE), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TWR (TWR), |
.CLK_PERIOD (CLK_PERIOD), |
.SIM_ONLY (SIM_ONLY), |
.DEBUG_EN (DEBUG_EN), |
.FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) |
) |
u_phy_top |
( |
.clk0 (clk0), |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.rst0 (rst0), |
.rst90 (rst90), |
.rstdiv0 (rstdiv0), |
.ctrl_wren (ctrl_wren), |
.ctrl_addr (ctrl_addr), |
.ctrl_ba (ctrl_ba), |
.ctrl_ras_n (ctrl_ras_n), |
.ctrl_cas_n (ctrl_cas_n), |
.ctrl_we_n (ctrl_we_n), |
.ctrl_cs_n (ctrl_cs_n), |
.ctrl_rden (ctrl_rden), |
.ctrl_ref_flag (ctrl_ref_flag), |
.wdf_data (wdf_data), |
.wdf_mask_data (wdf_mask_data), |
.wdf_rden (wdf_rden), |
.phy_init_done (phy_init_done), |
.phy_calib_rden (phy_calib_rden), |
.phy_calib_rden_sel (phy_calib_rden_sel), |
.rd_data_rise (rd_data_rise), |
.rd_data_fall (rd_data_fall), |
.ddr_ck (ddr_ck), |
.ddr_ck_n (ddr_ck_n), |
.ddr_addr (ddr_addr), |
.ddr_ba (ddr_ba), |
.ddr_ras_n (ddr_ras_n), |
.ddr_cas_n (ddr_cas_n), |
.ddr_we_n (ddr_we_n), |
.ddr_cs_n (ddr_cs_n), |
.ddr_cke (ddr_cke), |
.ddr_odt (ddr_odt), |
.ddr_dm (ddr_dm), |
.ddr_dqs (ddr_dqs), |
.ddr_dqs_n (ddr_dqs_n), |
.ddr_dq (ddr_dq), |
.dbg_idel_up_all (dbg_idel_up_all), |
.dbg_idel_down_all (dbg_idel_down_all), |
.dbg_idel_up_dq (dbg_idel_up_dq), |
.dbg_idel_down_dq (dbg_idel_down_dq), |
.dbg_idel_up_dqs (dbg_idel_up_dqs), |
.dbg_idel_down_dqs (dbg_idel_down_dqs), |
.dbg_idel_up_gate (dbg_idel_up_gate), |
.dbg_idel_down_gate (dbg_idel_down_gate), |
.dbg_sel_idel_dq (dbg_sel_idel_dq), |
.dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), |
.dbg_sel_idel_dqs (dbg_sel_idel_dqs), |
.dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), |
.dbg_sel_idel_gate (dbg_sel_idel_gate), |
.dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), |
.dbg_calib_done (dbg_calib_done), |
.dbg_calib_err (dbg_calib_err), |
.dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), |
.dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), |
.dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), |
.dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), |
.dbg_calib_rden_dly (dbg_calib_rden_dly), |
.dbg_calib_gate_dly (dbg_calib_gate_dly) |
); |
|
ddr2_usr_top # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_WIDTH (DQS_WIDTH), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.ECC_ENABLE (ECC_ENABLE), |
.ROW_WIDTH (ROW_WIDTH) |
) |
u_usr_top |
( |
.clk0 (clk0), |
.usr_clk (usr_clk), //jb |
.clk90 (clk90), |
.rst0 (rst0), |
.rd_data_in_rise (rd_data_rise), |
.rd_data_in_fall (rd_data_fall), |
.phy_calib_rden (phy_calib_rden), |
.phy_calib_rden_sel(phy_calib_rden_sel), |
.rd_data_valid (rd_data_valid), |
.rd_ecc_error (rd_ecc_error), |
.rd_data_fifo_out (rd_data_fifo_out), |
.app_af_cmd (app_af_cmd), |
.app_af_addr (app_af_addr), |
.app_af_wren (app_af_wren), |
.ctrl_af_rden (ctrl_af_rden), |
.af_cmd (af_cmd), |
.af_addr (af_addr), |
.af_empty (af_empty), |
.app_af_afull (app_af_afull), |
.app_wdf_wren (app_wdf_wren), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.wdf_rden (wdf_rden), |
.app_wdf_afull (app_wdf_afull), |
.wdf_data (wdf_data), |
.wdf_mask_data (wdf_mask_data) |
); |
|
|
ddr2_ctrl # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.CS_NUM (CS_NUM), |
.ROW_WIDTH (ROW_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.REG_ENABLE (REG_ENABLE), |
.MULTI_BANK_EN (MULTI_BANK_EN), |
.TWO_T_TIME_EN (TWO_T_TIME_EN), |
.TREFI_NS (TREFI_NS), |
.TRAS (TRAS), |
.TRCD (TRCD), |
.TRFC (TRFC), |
.TRP (TRP), |
.TRTP (TRTP), |
.TWR (TWR), |
.TWTR (TWTR), |
.CLK_PERIOD (CLK_PERIOD), |
.DDR_TYPE (DDR_TYPE) |
) |
u_ctrl |
( |
.clk (clk0), |
.rst (rst0), |
.af_cmd (af_cmd), |
.af_addr (af_addr), |
.af_empty (af_empty), |
.phy_init_done (phy_init_done), |
.ctrl_ref_flag (ctrl_ref_flag), |
.ctrl_af_rden (ctrl_af_rden), |
.ctrl_wren (ctrl_wren), |
.ctrl_rden (ctrl_rden), |
.ctrl_addr (ctrl_addr), |
.ctrl_ba (ctrl_ba), |
.ctrl_ras_n (ctrl_ras_n), |
.ctrl_cas_n (ctrl_cas_n), |
.ctrl_we_n (ctrl_we_n), |
.ctrl_cs_n (ctrl_cs_n) |
); |
|
endmodule |
/ddr2_mig/ddr2_infrastructure.v
0,0 → 1,352
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_infrastructure.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// Clock generation/distribution and reset synchronization |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter CLK_TYPE added and logic for DIFFERENTIAL and |
// SINGLE_ENDED added. PK. 6/20/08 |
// Rev 1.2 - Loacalparam CLK_GENERATOR added and logic for clocks generation |
// using PLL or DCM added as generic code. PK. 10/14/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_infrastructure # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter CLK_PERIOD = 3000, |
parameter CLK_TYPE = "DIFFERENTIAL", |
parameter DLL_FREQ_MODE = "HIGH", |
parameter RST_ACT_LOW = 1 |
) |
( |
input sys_clk_p, |
input sys_clk_n, |
input sys_clk, |
input clk200_p, |
input clk200_n, |
input idly_clk_200, |
output clk0, |
output clk90, |
output clk200, |
output clkdiv0, |
input sys_rst_n, |
input idelay_ctrl_rdy, |
output rst0, |
output rst90, |
output rst200, |
output rstdiv0 |
); |
|
// # of clock cycles to delay deassertion of reset. Needs to be a fairly |
// high number not so much for metastability protection, but to give time |
// for reset (i.e. stable clock cycles) to propagate through all state |
// machines and to all control signals (i.e. not all control signals have |
// resets, instead they rely on base state logic being reset, and the effect |
// of that reset propagating through the logic). Need this because we may not |
// be getting stable clock cycles while reset asserted (i.e. since reset |
// depends on PLL/DCM lock status) |
localparam RST_SYNC_NUM = 25; |
localparam CLK_PERIOD_NS = CLK_PERIOD / 1000.0; |
localparam CLK_PERIOD_INT = CLK_PERIOD/1000; |
|
// By default this Parameter (CLK_GENERATOR) value is "PLL". If this |
// Parameter is set to "PLL", PLL is used to generate the design clocks. |
// If this Parameter is set to "DCM", |
// DCM is used to generate the design clocks. |
localparam CLK_GENERATOR = "PLL"; |
|
wire clk0_bufg; |
wire clk0_bufg_in; |
wire clk90_bufg; |
wire clk90_bufg_in; |
wire clk200_bufg; |
wire clk200_ibufg; |
wire clkdiv0_bufg; |
wire clkdiv0_bufg_in; |
wire clkfbout_clkfbin; |
wire locked; |
reg [RST_SYNC_NUM-1:0] rst0_sync_r /* synthesis syn_maxfan = 10 */; |
reg [RST_SYNC_NUM-1:0] rst200_sync_r /* synthesis syn_maxfan = 10 */; |
reg [RST_SYNC_NUM-1:0] rst90_sync_r /* synthesis syn_maxfan = 10 */; |
reg [(RST_SYNC_NUM/2)-1:0] rstdiv0_sync_r /* synthesis syn_maxfan = 10 */; |
wire rst_tmp; |
wire sys_clk_ibufg; |
wire sys_rst; |
|
assign sys_rst = RST_ACT_LOW ? ~sys_rst_n: sys_rst_n; |
|
assign clk0 = clk0_bufg; |
assign clk90 = clk90_bufg; |
assign clk200 = clk200_bufg; |
assign clkdiv0 = clkdiv0_bufg; |
|
generate |
if(CLK_TYPE == "DIFFERENTIAL") begin : DIFF_ENDED_CLKS_INST |
//*************************************************************************** |
// Differential input clock input buffers |
//*************************************************************************** |
|
IBUFGDS_LVPECL_25 SYS_CLK_INST |
( |
.I (sys_clk_p), |
.IB (sys_clk_n), |
.O (sys_clk_ibufg) |
); |
|
IBUFGDS_LVPECL_25 IDLY_CLK_INST |
( |
.I (clk200_p), |
.IB (clk200_n), |
.O (clk200_ibufg) |
); |
|
end/* else if(CLK_TYPE == "SINGLE_ENDED") begin : SINGLE_ENDED_CLKS_INST |
//************************************************************************** |
// Single ended input clock input buffers |
//************************************************************************** |
|
IBUFG SYS_CLK_INST |
( |
.I (sys_clk), |
.O (sys_clk_ibufg) |
); |
|
IBUFG IDLY_CLK_INST |
( |
.I (idly_clk_200), |
.O (clk200_ibufg) |
); |
// This is being instantiated inside another design. these signals are properly generated elsewhere -- jb |
end*/ |
endgenerate |
assign sys_clk_ibufg = sys_clk; |
//assign idly_clk_200 = clk200_ibufg; |
assign clk200_bufg = idly_clk_200; |
|
/* |
BUFG CLK_200_BUFG |
( |
.O (clk200_bufg), |
.I (clk200_ibufg) |
); |
*/ |
//*************************************************************************** |
// Global clock generation and distribution |
//*************************************************************************** |
|
generate |
if (CLK_GENERATOR == "PLL") begin : gen_pll_adv |
PLL_ADV # |
( |
.BANDWIDTH ("OPTIMIZED"), |
.CLKIN1_PERIOD (CLK_PERIOD_NS), |
.CLKIN2_PERIOD (10.000), |
.CLKOUT0_DIVIDE (CLK_PERIOD_INT), |
.CLKOUT1_DIVIDE (CLK_PERIOD_INT), |
.CLKOUT2_DIVIDE (CLK_PERIOD_INT*2), |
.CLKOUT3_DIVIDE (1), |
.CLKOUT4_DIVIDE (1), |
.CLKOUT5_DIVIDE (1), |
.CLKOUT0_PHASE (0.000), |
.CLKOUT1_PHASE (90.000), |
.CLKOUT2_PHASE (0.000), |
.CLKOUT3_PHASE (0.000), |
.CLKOUT4_PHASE (0.000), |
.CLKOUT5_PHASE (0.000), |
.CLKOUT0_DUTY_CYCLE (0.500), |
.CLKOUT1_DUTY_CYCLE (0.500), |
.CLKOUT2_DUTY_CYCLE (0.500), |
.CLKOUT3_DUTY_CYCLE (0.500), |
.CLKOUT4_DUTY_CYCLE (0.500), |
.CLKOUT5_DUTY_CYCLE (0.500), |
.COMPENSATION ("SYSTEM_SYNCHRONOUS"), |
.DIVCLK_DIVIDE (1), |
.CLKFBOUT_MULT (CLK_PERIOD_INT), |
.CLKFBOUT_PHASE (0.0), |
.REF_JITTER (0.005000) |
) |
u_pll_adv |
( |
.CLKFBIN (clkfbout_clkfbin), |
.CLKINSEL (1'b1), |
.CLKIN1 (sys_clk_ibufg), |
.CLKIN2 (1'b0), |
.DADDR (5'b0), |
.DCLK (1'b0), |
.DEN (1'b0), |
.DI (16'b0), |
.DWE (1'b0), |
.REL (1'b0), |
.RST (sys_rst), |
.CLKFBDCM (), |
.CLKFBOUT (clkfbout_clkfbin), |
.CLKOUTDCM0 (), |
.CLKOUTDCM1 (), |
.CLKOUTDCM2 (), |
.CLKOUTDCM3 (), |
.CLKOUTDCM4 (), |
.CLKOUTDCM5 (), |
.CLKOUT0 (clk0_bufg_in), |
.CLKOUT1 (clk90_bufg_in), |
.CLKOUT2 (clkdiv0_bufg_in), |
.CLKOUT3 (), |
.CLKOUT4 (), |
.CLKOUT5 (), |
.DO (), |
.DRDY (), |
.LOCKED (locked) |
); |
end else if (CLK_GENERATOR == "DCM") begin: gen_dcm_base |
DCM_BASE # |
( |
.CLKIN_PERIOD (CLK_PERIOD_NS), |
.CLKDV_DIVIDE (2.0), |
.DLL_FREQUENCY_MODE (DLL_FREQ_MODE), |
.DUTY_CYCLE_CORRECTION ("TRUE"), |
.FACTORY_JF (16'hF0F0) |
) |
u_dcm_base |
( |
.CLK0 (clk0_bufg_in), |
.CLK180 (), |
.CLK270 (), |
.CLK2X (), |
.CLK2X180 (), |
.CLK90 (clk90_bufg_in), |
.CLKDV (clkdiv0_bufg_in), |
.CLKFX (), |
.CLKFX180 (), |
.LOCKED (locked), |
.CLKFB (clk0_bufg), |
.CLKIN (sys_clk_ibufg), |
.RST (sys_rst) |
); |
end |
endgenerate |
|
BUFG U_BUFG_CLK0 |
( |
.O (clk0_bufg), |
.I (clk0_bufg_in) |
); |
|
BUFG U_BUFG_CLK90 |
( |
.O (clk90_bufg), |
.I (clk90_bufg_in) |
); |
|
BUFG U_BUFG_CLKDIV0 |
( |
.O (clkdiv0_bufg), |
.I (clkdiv0_bufg_in) |
); |
|
|
//*************************************************************************** |
// Reset synchronization |
// NOTES: |
// 1. shut down the whole operation if the PLL/ DCM hasn't yet locked (and |
// by inference, this means that external SYS_RST_IN has been asserted - |
// PLL/DCM deasserts LOCKED as soon as SYS_RST_IN asserted) |
// 2. In the case of all resets except rst200, also assert reset if the |
// IDELAY master controller is not yet ready |
// 3. asynchronously assert reset. This was we can assert reset even if |
// there is no clock (needed for things like 3-stating output buffers). |
// reset deassertion is synchronous. |
//*************************************************************************** |
|
assign rst_tmp = sys_rst | ~locked | ~idelay_ctrl_rdy; |
|
// synthesis attribute max_fanout of rst0_sync_r is 10 |
always @(posedge clk0_bufg or posedge rst_tmp) |
if (rst_tmp) |
rst0_sync_r <= {RST_SYNC_NUM{1'b1}}; |
else |
// logical left shift by one (pads with 0) |
rst0_sync_r <= rst0_sync_r << 1; |
|
// synthesis attribute max_fanout of rstdiv0_sync_r is 10 |
always @(posedge clkdiv0_bufg or posedge rst_tmp) |
if (rst_tmp) |
rstdiv0_sync_r <= {(RST_SYNC_NUM/2){1'b1}}; |
else |
// logical left shift by one (pads with 0) |
rstdiv0_sync_r <= rstdiv0_sync_r << 1; |
|
// synthesis attribute max_fanout of rst90_sync_r is 10 |
always @(posedge clk90_bufg or posedge rst_tmp) |
if (rst_tmp) |
rst90_sync_r <= {RST_SYNC_NUM{1'b1}}; |
else |
rst90_sync_r <= rst90_sync_r << 1; |
|
// make sure CLK200 doesn't depend on IDELAY_CTRL_RDY, else chicken n' egg |
// synthesis attribute max_fanout of rst200_sync_r is 10 |
always @(posedge clk200_bufg or negedge locked) |
if (!locked) |
rst200_sync_r <= {RST_SYNC_NUM{1'b1}}; |
else |
rst200_sync_r <= rst200_sync_r << 1; |
|
|
assign rst0 = rst0_sync_r[RST_SYNC_NUM-1]; |
assign rst90 = rst90_sync_r[RST_SYNC_NUM-1]; |
assign rst200 = rst200_sync_r[RST_SYNC_NUM-1]; |
assign rstdiv0 = rstdiv0_sync_r[(RST_SYNC_NUM/2)-1]; |
|
endmodule |
/ddr2_mig/ddr2_usr_wr.v
0,0 → 1,338
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_usr_wr.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:01 $ |
// \ \ / \ Date Created: Mon Aug 28 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR/DDR2 |
//Purpose: |
// This module instantiates the modules containing internal FIFOs |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_usr_wr # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter DQ_WIDTH = 72, |
parameter APPDATA_WIDTH = 144, |
parameter ECC_ENABLE = 0, |
parameter ROW_WIDTH = 14 |
) |
( |
input clk0, |
input usr_clk, // jb |
input clk90, |
input rst0, |
// Write data FIFO interface |
input app_wdf_wren, |
input [APPDATA_WIDTH-1:0] app_wdf_data, |
input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, |
input wdf_rden, |
output app_wdf_afull, |
output [(2*DQ_WIDTH)-1:0] wdf_data, |
output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data |
); |
|
// determine number of FIFO72's to use based on data width |
// round up to next integer value when determining WDF_FIFO_NUM |
localparam WDF_FIFO_NUM = (ECC_ENABLE) ? (APPDATA_WIDTH+63)/64 : |
((2*DQ_WIDTH)+63)/64; |
// MASK_WIDTH = number of bytes in data bus |
localparam MASK_WIDTH = DQ_WIDTH/8; |
|
wire [WDF_FIFO_NUM-1:0] i_wdf_afull; |
wire [DQ_WIDTH-1:0] i_wdf_data_fall_in; |
wire [DQ_WIDTH-1:0] i_wdf_data_fall_out; |
wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_in; |
wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_out; |
wire [DQ_WIDTH-1:0] i_wdf_data_rise_in; |
wire [DQ_WIDTH-1:0] i_wdf_data_rise_out; |
wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_in; |
wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_out; |
wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_in; |
wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_out; |
wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_in; |
wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_out; |
reg rst_r; |
|
// ECC signals |
wire [(2*DQ_WIDTH)-1:0] i_wdf_data_out_ecc; |
wire [((2*DQ_WIDTH)/8)-1:0] i_wdf_mask_data_out_ecc; |
wire [63:0] i_wdf_mask_data_out_ecc_wire; |
wire [((2*DQ_WIDTH)/8)-1:0] mask_data_in_ecc; |
wire [63:0] mask_data_in_ecc_wire; |
|
//*************************************************************************** |
|
assign app_wdf_afull = i_wdf_afull[0]; |
|
always @(posedge clk0 ) |
rst_r <= rst0; |
|
genvar wdf_di_i; |
genvar wdf_do_i; |
genvar mask_i; |
genvar wdf_i; |
generate |
if(ECC_ENABLE) begin // ECC code |
|
assign wdf_data = i_wdf_data_out_ecc; |
|
// the byte 9 dm is always held to 0 |
assign wdf_mask_data = i_wdf_mask_data_out_ecc; |
|
|
|
// generate for write data fifo . |
for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf |
|
FIFO36_72 # |
( |
.ALMOST_EMPTY_OFFSET (9'h007), |
.ALMOST_FULL_OFFSET (9'h00F), |
.DO_REG (1), // extra CC output delay |
.EN_ECC_WRITE ("TRUE"), |
.EN_ECC_READ ("FALSE"), |
.EN_SYN ("FALSE"), |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_wdf_ecc |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (i_wdf_afull[wdf_i]), |
.DBITERR (), |
.DO (i_wdf_data_out_ecc[((64*(wdf_i+1))+(wdf_i *8))-1: |
(64*wdf_i)+(wdf_i *8)]), |
.DOP (i_wdf_data_out_ecc[(72*(wdf_i+1))-1: |
(64*(wdf_i+1))+ (8*wdf_i) ]), |
.ECCPARITY (), |
.EMPTY (), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.SBITERR (), |
.WRCOUNT (), |
.WRERR (), |
.DI (app_wdf_data[(64*(wdf_i+1))-1: |
(64*wdf_i)]), |
.DIP (), |
.RDCLK (clk90), |
.RDEN (wdf_rden), |
.RST (rst_r), // or can use rst0 |
.WRCLK (clk0), |
// .WRCLK (usr_clk), //jb |
.WREN (app_wdf_wren) |
); |
end |
|
// remapping the mask data. The mask data from user i/f does not have |
// the mask for the ECC byte. Assigning 0 to the ECC mask byte. |
for (mask_i = 0; mask_i < (DQ_WIDTH)/36; |
mask_i = mask_i +1) begin: gen_mask |
assign mask_data_in_ecc[((8*(mask_i+1))+ mask_i)-1:((8*mask_i)+mask_i)] |
= app_wdf_mask_data[(8*(mask_i+1))-1:8*(mask_i)] ; |
assign mask_data_in_ecc[((8*(mask_i+1))+mask_i)] = 1'd0; |
end |
|
// assign ecc bits to temp variables to avoid |
// sim warnings. Not all the 64 bits of the fifo |
// are used in ECC mode. |
assign mask_data_in_ecc_wire[((2*DQ_WIDTH)/8)-1:0] = mask_data_in_ecc; |
assign mask_data_in_ecc_wire[63:((2*DQ_WIDTH)/8)] = |
{(64-((2*DQ_WIDTH)/8)){1'b0}}; |
assign i_wdf_mask_data_out_ecc = |
i_wdf_mask_data_out_ecc_wire[((2*DQ_WIDTH)/8)-1:0]; |
|
|
FIFO36_72 # |
( |
.ALMOST_EMPTY_OFFSET (9'h007), |
.ALMOST_FULL_OFFSET (9'h00F), |
.DO_REG (1), // extra CC output delay |
.EN_ECC_WRITE ("TRUE"), |
.EN_ECC_READ ("FALSE"), |
.EN_SYN ("FALSE"), |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_wdf_ecc_mask |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (), |
.DBITERR (), |
.DO (i_wdf_mask_data_out_ecc_wire), |
.DOP (), |
.ECCPARITY (), |
.EMPTY (), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.SBITERR (), |
.WRCOUNT (), |
.WRERR (), |
.DI (mask_data_in_ecc_wire), |
.DIP (), |
.RDCLK (clk90), |
.RDEN (wdf_rden), |
.RST (rst_r), // or can use rst0 |
.WRCLK (clk0), |
// .WRCLK (usr_clk), // jb |
.WREN (app_wdf_wren) |
); |
end else begin |
|
//*********************************************************************** |
|
// Define intermediate buses: |
assign i_wdf_data_rise_in |
= app_wdf_data[DQ_WIDTH-1:0]; |
assign i_wdf_data_fall_in |
= app_wdf_data[(2*DQ_WIDTH)-1:DQ_WIDTH]; |
assign i_wdf_mask_data_rise_in |
= app_wdf_mask_data[MASK_WIDTH-1:0]; |
assign i_wdf_mask_data_fall_in |
= app_wdf_mask_data[(2*MASK_WIDTH)-1:MASK_WIDTH]; |
|
//*********************************************************************** |
// Write data FIFO Input: |
// Arrange DQ's so that the rise data and fall data are interleaved. |
// the data arrives at the input of the wdf fifo as {fall,rise}. |
// It is remapped as: |
// {...fall[15:8],rise[15:8],fall[7:0],rise[7:0]} |
// This is done to avoid having separate fifo's for rise and fall data |
// and to keep rise/fall data for the same DQ's on same FIFO |
// Data masks are interleaved in a similar manner |
// NOTE: Initialization data from PHY_INIT module does not need to be |
// interleaved - it's already in the correct format - and the same |
// initialization pattern from PHY_INIT is sent to all write FIFOs |
//*********************************************************************** |
|
for (wdf_di_i = 0; wdf_di_i < MASK_WIDTH; |
wdf_di_i = wdf_di_i + 1) begin: gen_wdf_data_in |
assign i_wdf_data_in[(16*wdf_di_i)+15:(16*wdf_di_i)] |
= {i_wdf_data_fall_in[(8*wdf_di_i)+7:(8*wdf_di_i)], |
i_wdf_data_rise_in[(8*wdf_di_i)+7:(8*wdf_di_i)]}; |
assign i_wdf_mask_data_in[(2*wdf_di_i)+1:(2*wdf_di_i)] |
= {i_wdf_mask_data_fall_in[wdf_di_i], |
i_wdf_mask_data_rise_in[wdf_di_i]}; |
end |
|
//*********************************************************************** |
// Write data FIFO Output: |
// FIFO DQ and mask outputs must be untangled and put in the standard |
// format of {fall,rise}. Same goes for mask output |
//*********************************************************************** |
|
for (wdf_do_i = 0; wdf_do_i < MASK_WIDTH; |
wdf_do_i = wdf_do_i + 1) begin: gen_wdf_data_out |
assign i_wdf_data_rise_out[(8*wdf_do_i)+7:(8*wdf_do_i)] |
= i_wdf_data_out[(16*wdf_do_i)+7:(16*wdf_do_i)]; |
assign i_wdf_data_fall_out[(8*wdf_do_i)+7:(8*wdf_do_i)] |
= i_wdf_data_out[(16*wdf_do_i)+15:(16*wdf_do_i)+8]; |
assign i_wdf_mask_data_rise_out[wdf_do_i] |
= i_wdf_mask_data_out[2*wdf_do_i]; |
assign i_wdf_mask_data_fall_out[wdf_do_i] |
= i_wdf_mask_data_out[(2*wdf_do_i)+1]; |
end |
|
assign wdf_data = {i_wdf_data_fall_out, |
i_wdf_data_rise_out}; |
|
assign wdf_mask_data = {i_wdf_mask_data_fall_out, |
i_wdf_mask_data_rise_out}; |
|
//*********************************************************************** |
|
for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf |
|
FIFO36_72 # |
( |
.ALMOST_EMPTY_OFFSET (9'h007), |
.ALMOST_FULL_OFFSET (9'h00F), |
.DO_REG (1), // extra CC output delay |
.EN_ECC_WRITE ("FALSE"), |
.EN_ECC_READ ("FALSE"), |
.EN_SYN ("FALSE"), |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_wdf |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (i_wdf_afull[wdf_i]), |
.DBITERR (), |
.DO (i_wdf_data_out[(64*(wdf_i+1))-1:64*wdf_i]), |
.DOP (i_wdf_mask_data_out[(8*(wdf_i+1))-1:8*wdf_i]), |
.ECCPARITY (), |
.EMPTY (), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.SBITERR (), |
.WRCOUNT (), |
.WRERR (), |
.DI (i_wdf_data_in[(64*(wdf_i+1))-1:64*wdf_i]), |
.DIP (i_wdf_mask_data_in[(8*(wdf_i+1))-1:8*wdf_i]), |
.RDCLK (clk90), |
.RDEN (wdf_rden), |
.RST (rst_r), // or can use rst0 |
.WRCLK (clk0), |
// .WRCLK (usr_clk), //jb |
.WREN (app_wdf_wren) |
); |
end |
end |
endgenerate |
|
endmodule |
/ddr2_mig/ddr2_phy_top.v
0,0 → 1,395
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_top.v |
// /___/ /\ Date Last Modified: $Date: 2009/02/03 18:50:12 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// Top-level for memory physical layer (PHY) interface |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 |
// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 |
// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
(* X_CORE_INFO = "mig_v3_0_ddr2_sdram_v5, Coregen 11.1" , CORE_GENERATION_INFO = "ddr2_sdram_v5,mig_v3_0,{component_name=ddr2_phy_top, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=4, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, DDR2_CLK_PERIOD=3750, RST_ACT_LOW=1}" *) |
module ddr2_phy_top # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter CLK_WIDTH = 1, |
parameter CKE_WIDTH = 1, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter CS_NUM = 1, |
parameter CS_WIDTH = 1, |
parameter USE_DM_PORT = 1, |
parameter DM_WIDTH = 9, |
parameter DQ_WIDTH = 72, |
parameter DQ_BITS = 7, |
parameter DQ_PER_DQS = 8, |
parameter DQS_WIDTH = 9, |
parameter DQS_BITS = 4, |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
parameter IODELAY_GRP = "IODELAY_MIG", |
parameter ODT_WIDTH = 1, |
parameter ROW_WIDTH = 14, |
parameter ADDITIVE_LAT = 0, |
parameter TWO_T_TIME_EN = 0, |
parameter BURST_LEN = 4, |
parameter BURST_TYPE = 0, |
parameter CAS_LAT = 5, |
parameter TWR = 15000, |
parameter ECC_ENABLE = 0, |
parameter ODT_TYPE = 1, |
parameter DDR_TYPE = 1, |
parameter REDUCE_DRV = 0, |
parameter REG_ENABLE = 1, |
parameter CLK_PERIOD = 3000, |
parameter SIM_ONLY = 0, |
parameter DEBUG_EN = 0, |
parameter FPGA_SPEED_GRADE = 2 |
) |
( |
input clk0, |
input clk90, |
input clkdiv0, |
input rst0, |
input rst90, |
input rstdiv0, |
input ctrl_wren, |
input [ROW_WIDTH-1:0] ctrl_addr, |
input [BANK_WIDTH-1:0] ctrl_ba, |
input ctrl_ras_n, |
input ctrl_cas_n, |
input ctrl_we_n, |
input [CS_NUM-1:0] ctrl_cs_n, |
input ctrl_rden, |
input ctrl_ref_flag, |
input [(2*DQ_WIDTH)-1:0] wdf_data, |
input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, |
output wdf_rden, |
output phy_init_done, |
output [DQS_WIDTH-1:0] phy_calib_rden, |
output [DQS_WIDTH-1:0] phy_calib_rden_sel, |
output [DQ_WIDTH-1:0] rd_data_rise, |
output [DQ_WIDTH-1:0] rd_data_fall, |
output [CLK_WIDTH-1:0] ddr_ck, |
output [CLK_WIDTH-1:0] ddr_ck_n, |
output [ROW_WIDTH-1:0] ddr_addr, |
output [BANK_WIDTH-1:0] ddr_ba, |
output ddr_ras_n, |
output ddr_cas_n, |
output ddr_we_n, |
output [CS_WIDTH-1:0] ddr_cs_n, |
output [CKE_WIDTH-1:0] ddr_cke, |
output [ODT_WIDTH-1:0] ddr_odt, |
output [DM_WIDTH-1:0] ddr_dm, |
inout [DQS_WIDTH-1:0] ddr_dqs, |
inout [DQS_WIDTH-1:0] ddr_dqs_n, |
inout [DQ_WIDTH-1:0] ddr_dq, |
// Debug signals (optional use) |
input dbg_idel_up_all, |
input dbg_idel_down_all, |
input dbg_idel_up_dq, |
input dbg_idel_down_dq, |
input dbg_idel_up_dqs, |
input dbg_idel_down_dqs, |
input dbg_idel_up_gate, |
input dbg_idel_down_gate, |
input [DQ_BITS-1:0] dbg_sel_idel_dq, |
input dbg_sel_all_idel_dq, |
input [DQS_BITS:0] dbg_sel_idel_dqs, |
input dbg_sel_all_idel_dqs, |
input [DQS_BITS:0] dbg_sel_idel_gate, |
input dbg_sel_all_idel_gate, |
output [3:0] dbg_calib_done, |
output [3:0] dbg_calib_err, |
output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, |
output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly |
); |
|
wire [3:0] calib_done; |
wire calib_ref_done; |
wire calib_ref_req; |
wire [3:0] calib_start; |
wire dm_ce; |
wire [1:0] dq_oe_n; |
wire dqs_oe_n; |
wire dqs_rst_n; |
wire [(DQ_WIDTH/8)-1:0] mask_data_fall; |
wire [(DQ_WIDTH/8)-1:0] mask_data_rise; |
wire [CS_NUM-1:0] odt; |
wire [ROW_WIDTH-1:0] phy_init_addr; |
wire [BANK_WIDTH-1:0] phy_init_ba; |
wire phy_init_cas_n; |
wire [CKE_WIDTH-1:0] phy_init_cke; |
wire [CS_NUM-1:0] phy_init_cs_n; |
wire phy_init_data_sel; |
wire phy_init_ras_n; |
wire phy_init_rden; |
wire phy_init_we_n; |
wire phy_init_wren; |
wire [DQ_WIDTH-1:0] wr_data_fall; |
wire [DQ_WIDTH-1:0] wr_data_rise; |
|
//*************************************************************************** |
|
ddr2_phy_write # |
( |
.DQ_WIDTH (DQ_WIDTH), |
.CS_NUM (CS_NUM), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.ODT_TYPE (ODT_TYPE), |
.REG_ENABLE (REG_ENABLE), |
.DDR_TYPE (DDR_TYPE) |
) |
u_phy_write |
( |
.clk0 (clk0), |
.clk90 (clk90), |
.rst90 (rst90), |
.wdf_data (wdf_data), |
.wdf_mask_data (wdf_mask_data), |
.ctrl_wren (ctrl_wren), |
.phy_init_wren (phy_init_wren), |
.phy_init_data_sel (phy_init_data_sel), |
.dm_ce (dm_ce), |
.dq_oe_n (dq_oe_n), |
.dqs_oe_n (dqs_oe_n), |
.dqs_rst_n (dqs_rst_n), |
.wdf_rden (wdf_rden), |
.odt (odt), |
.wr_data_rise (wr_data_rise), |
.wr_data_fall (wr_data_fall), |
.mask_data_rise (mask_data_rise), |
.mask_data_fall (mask_data_fall) |
); |
|
ddr2_phy_io # |
( |
.CLK_WIDTH (CLK_WIDTH), |
.USE_DM_PORT (USE_DM_PORT), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_BITS (DQ_BITS), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_BITS (DQS_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP), |
.ODT_WIDTH (ODT_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.CAS_LAT (CAS_LAT), |
.REG_ENABLE (REG_ENABLE), |
.CLK_PERIOD (CLK_PERIOD), |
.DDR_TYPE (DDR_TYPE), |
.SIM_ONLY (SIM_ONLY), |
.DEBUG_EN (DEBUG_EN), |
.FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) |
) |
u_phy_io |
( |
.clk0 (clk0), |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.rst0 (rst0), |
.rst90 (rst90), |
.rstdiv0 (rstdiv0), |
.dm_ce (dm_ce), |
.dq_oe_n (dq_oe_n), |
.dqs_oe_n (dqs_oe_n), |
.dqs_rst_n (dqs_rst_n), |
.calib_start (calib_start), |
.ctrl_rden (ctrl_rden), |
.phy_init_rden (phy_init_rden), |
.calib_ref_done (calib_ref_done), |
.calib_done (calib_done), |
.calib_ref_req (calib_ref_req), |
.calib_rden (phy_calib_rden), |
.calib_rden_sel (phy_calib_rden_sel), |
.wr_data_rise (wr_data_rise), |
.wr_data_fall (wr_data_fall), |
.mask_data_rise (mask_data_rise), |
.mask_data_fall (mask_data_fall), |
.rd_data_rise (rd_data_rise), |
.rd_data_fall (rd_data_fall), |
.ddr_ck (ddr_ck), |
.ddr_ck_n (ddr_ck_n), |
.ddr_dm (ddr_dm), |
.ddr_dqs (ddr_dqs), |
.ddr_dqs_n (ddr_dqs_n), |
.ddr_dq (ddr_dq), |
.dbg_idel_up_all (dbg_idel_up_all), |
.dbg_idel_down_all (dbg_idel_down_all), |
.dbg_idel_up_dq (dbg_idel_up_dq), |
.dbg_idel_down_dq (dbg_idel_down_dq), |
.dbg_idel_up_dqs (dbg_idel_up_dqs), |
.dbg_idel_down_dqs (dbg_idel_down_dqs), |
.dbg_idel_up_gate (dbg_idel_up_gate), |
.dbg_idel_down_gate (dbg_idel_down_gate), |
.dbg_sel_idel_dq (dbg_sel_idel_dq), |
.dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), |
.dbg_sel_idel_dqs (dbg_sel_idel_dqs), |
.dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), |
.dbg_sel_idel_gate (dbg_sel_idel_gate), |
.dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), |
.dbg_calib_done (dbg_calib_done), |
.dbg_calib_err (dbg_calib_err), |
.dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), |
.dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), |
.dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), |
.dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), |
.dbg_calib_rden_dly (dbg_calib_rden_dly), |
.dbg_calib_gate_dly (dbg_calib_gate_dly) |
); |
|
ddr2_phy_ctl_io # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.TWO_T_TIME_EN (TWO_T_TIME_EN), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.DDR_TYPE (DDR_TYPE) |
) |
u_phy_ctl_io |
( |
.clk0 (clk0), |
.clk90 (clk90), |
.rst0 (rst0), |
.rst90 (rst90), |
.ctrl_addr (ctrl_addr), |
.ctrl_ba (ctrl_ba), |
.ctrl_ras_n (ctrl_ras_n), |
.ctrl_cas_n (ctrl_cas_n), |
.ctrl_we_n (ctrl_we_n), |
.ctrl_cs_n (ctrl_cs_n), |
.phy_init_addr (phy_init_addr), |
.phy_init_ba (phy_init_ba), |
.phy_init_ras_n (phy_init_ras_n), |
.phy_init_cas_n (phy_init_cas_n), |
.phy_init_we_n (phy_init_we_n), |
.phy_init_cs_n (phy_init_cs_n), |
.phy_init_cke (phy_init_cke), |
.phy_init_data_sel (phy_init_data_sel), |
.odt (odt), |
.ddr_addr (ddr_addr), |
.ddr_ba (ddr_ba), |
.ddr_ras_n (ddr_ras_n), |
.ddr_cas_n (ddr_cas_n), |
.ddr_we_n (ddr_we_n), |
.ddr_cke (ddr_cke), |
.ddr_cs_n (ddr_cs_n), |
.ddr_odt (ddr_odt) |
); |
|
ddr2_phy_init # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.CS_NUM (CS_NUM), |
.DQ_WIDTH (DQ_WIDTH), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.TWO_T_TIME_EN(TWO_T_TIME_EN), |
.CAS_LAT (CAS_LAT), |
.ODT_TYPE (ODT_TYPE), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TWR (TWR), |
.CLK_PERIOD (CLK_PERIOD), |
.DDR_TYPE (DDR_TYPE), |
.SIM_ONLY (SIM_ONLY) |
) |
u_phy_init |
( |
.clk0 (clk0), |
.clkdiv0 (clkdiv0), |
.rst0 (rst0), |
.rstdiv0 (rstdiv0), |
.calib_done (calib_done), |
.ctrl_ref_flag (ctrl_ref_flag), |
.calib_ref_req (calib_ref_req), |
.calib_start (calib_start), |
.calib_ref_done (calib_ref_done), |
.phy_init_wren (phy_init_wren), |
.phy_init_rden (phy_init_rden), |
.phy_init_addr (phy_init_addr), |
.phy_init_ba (phy_init_ba), |
.phy_init_ras_n (phy_init_ras_n), |
.phy_init_cas_n (phy_init_cas_n), |
.phy_init_we_n (phy_init_we_n), |
.phy_init_cs_n (phy_init_cs_n), |
.phy_init_cke (phy_init_cke), |
.phy_init_done (phy_init_done), |
.phy_init_data_sel (phy_init_data_sel) |
); |
|
endmodule |
/ddr2_mig/ddr2_phy_init.v
0,0 → 1,1189
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_init.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Thu Aug 24 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
//Reference: |
// This module is the intialization control logic of the memory interface. |
// All commands are issued from here acoording to the burst, CAS Latency and |
// the user commands. |
//Revision History: |
// Rev 1.1 - Localparam WR_RECOVERY added and mapped to |
// load mode register. PK. 14/7/08 |
// Rev 1.2 - To issue an Auto Refresh command to each chip during various |
// calibration stages logic modified. PK. 08/10/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_init # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter CKE_WIDTH = 1, |
parameter COL_WIDTH = 10, |
parameter CS_BITS = 0, |
parameter CS_NUM = 1, |
parameter DQ_WIDTH = 72, |
parameter ODT_WIDTH = 1, |
parameter ROW_WIDTH = 14, |
parameter ADDITIVE_LAT = 0, |
parameter BURST_LEN = 4, |
parameter TWO_T_TIME_EN = 0, |
parameter BURST_TYPE = 0, |
parameter CAS_LAT = 5, |
parameter ODT_TYPE = 1, |
parameter REDUCE_DRV = 0, |
parameter REG_ENABLE = 1, |
parameter TWR = 15000, |
parameter CLK_PERIOD = 3000, |
parameter DDR_TYPE = 1, |
parameter SIM_ONLY = 0 |
) |
( |
input clk0, |
input clkdiv0, |
input rst0, |
input rstdiv0, |
input [3:0] calib_done, |
input ctrl_ref_flag, |
input calib_ref_req, |
output reg [3:0] calib_start, |
output reg calib_ref_done, |
output reg phy_init_wren, |
output reg phy_init_rden, |
output [ROW_WIDTH-1:0] phy_init_addr, |
output [BANK_WIDTH-1:0] phy_init_ba, |
output phy_init_ras_n, |
output phy_init_cas_n, |
output phy_init_we_n, |
output [CS_NUM-1:0] phy_init_cs_n, |
output [CKE_WIDTH-1:0] phy_init_cke, |
output reg phy_init_done, |
output phy_init_data_sel |
); |
|
// time to wait between consecutive commands in PHY_INIT - this is a |
// generic number, and must be large enough to account for worst case |
// timing parameter (tRFC - refresh-to-active) across all memory speed |
// grades and operating frequencies. Expressed in CLKDIV clock cycles. |
localparam CNTNEXT_CMD = 7'b1111111; |
// time to wait between read and read or precharge for stage 3 & 4 |
// the larger CNTNEXT_CMD can also be used, use smaller number to |
// speed up calibration - avoid tRAS violation, and speeds up simulation |
localparam CNTNEXT_RD = 4'b1111; |
|
// Write recovery (WR) time - is defined by |
// tWR (in nanoseconds) by tCK (in nanoseconds) and rounding up a |
// noninteger value to the next integer |
localparam integer WR_RECOVERY = ((TWR + CLK_PERIOD) - 1)/CLK_PERIOD; |
localparam CS_BITS_FIX = (CS_BITS == 0) ? 1 : CS_BITS; |
|
localparam INIT_CAL1_READ = 5'h00; |
localparam INIT_CAL2_READ = 5'h01; |
localparam INIT_CAL3_READ = 5'h02; |
localparam INIT_CAL4_READ = 5'h03; |
localparam INIT_CAL1_WRITE = 5'h04; |
localparam INIT_CAL2_WRITE = 5'h05; |
localparam INIT_CAL3_WRITE = 5'h06; |
localparam INIT_DUMMY_ACTIVE_WAIT = 5'h07; |
localparam INIT_PRECHARGE = 5'h08; |
localparam INIT_LOAD_MODE = 5'h09; |
localparam INIT_AUTO_REFRESH = 5'h0A; |
localparam INIT_IDLE = 5'h0B; |
localparam INIT_CNT_200 = 5'h0C; |
localparam INIT_CNT_200_WAIT = 5'h0D; |
localparam INIT_PRECHARGE_WAIT = 5'h0E; |
localparam INIT_MODE_REGISTER_WAIT = 5'h0F; |
localparam INIT_AUTO_REFRESH_WAIT = 5'h10; |
localparam INIT_DEEP_MEMORY_ST = 5'h11; |
localparam INIT_DUMMY_ACTIVE = 5'h12; |
localparam INIT_CAL1_WRITE_READ = 5'h13; |
localparam INIT_CAL1_READ_WAIT = 5'h14; |
localparam INIT_CAL2_WRITE_READ = 5'h15; |
localparam INIT_CAL2_READ_WAIT = 5'h16; |
localparam INIT_CAL3_WRITE_READ = 5'h17; |
localparam INIT_CAL3_READ_WAIT = 5'h18; |
localparam INIT_CAL4_READ_WAIT = 5'h19; |
localparam INIT_CALIB_REF = 5'h1A; |
localparam INIT_ZQCL = 5'h1B; |
localparam INIT_WAIT_DLLK_ZQINIT = 5'h1C; |
|
localparam INIT_CNTR_INIT = 4'h0; |
localparam INIT_CNTR_PRECH_1 = 4'h1; |
localparam INIT_CNTR_EMR2_INIT = 4'h2; |
localparam INIT_CNTR_EMR3_INIT = 4'h3; |
localparam INIT_CNTR_EMR_EN_DLL = 4'h4; |
localparam INIT_CNTR_MR_RST_DLL = 4'h5; |
localparam INIT_CNTR_CNT_200_WAIT = 4'h6; |
localparam INIT_CNTR_PRECH_2 = 4'h7; |
localparam INIT_CNTR_AR_1 = 4'h8; |
localparam INIT_CNTR_AR_2 = 4'h9; |
localparam INIT_CNTR_MR_ACT_DLL = 4'hA; |
localparam INIT_CNTR_EMR_DEF_OCD = 4'hB; |
localparam INIT_CNTR_EMR_EXIT_OCD = 4'hC; |
localparam INIT_CNTR_DEEP_MEM = 4'hD; |
localparam INIT_CNTR_PRECH_3 = 4'hE; |
localparam INIT_CNTR_DONE = 4'hF; |
|
localparam DDR1 = 0; |
localparam DDR2 = 1; |
localparam DDR3 = 2; |
|
reg [CS_BITS_FIX :0] auto_cnt_r; |
reg [1:0] burst_addr_r; |
reg [1:0] burst_cnt_r; |
wire [1:0] burst_val; |
wire cal_read; |
wire cal_write; |
wire cal_write_read; |
reg cal1_started_r; |
reg cal2_started_r; |
reg cal4_started_r; |
reg [3:0] calib_done_r; |
reg calib_ref_req_posedge; |
reg calib_ref_req_r; |
reg [15:0] calib_start_shift0_r; |
reg [15:0] calib_start_shift1_r; |
reg [15:0] calib_start_shift2_r; |
reg [15:0] calib_start_shift3_r; |
reg [1:0] chip_cnt_r; |
reg [4:0] cke_200us_cnt_r; |
reg cke_200us_cnt_en_r; |
reg [7:0] cnt_200_cycle_r; |
reg cnt_200_cycle_done_r; |
reg [6:0] cnt_cmd_r; |
reg cnt_cmd_ok_r; |
reg [3:0] cnt_rd_r; |
reg cnt_rd_ok_r; |
reg ctrl_ref_flag_r; |
reg done_200us_r; |
reg [ROW_WIDTH-1:0] ddr_addr_r; |
reg [ROW_WIDTH-1:0] ddr_addr_r1; |
reg [BANK_WIDTH-1:0] ddr_ba_r; |
reg [BANK_WIDTH-1:0] ddr_ba_r1; |
reg ddr_cas_n_r; |
reg ddr_cas_n_r1; |
reg [CKE_WIDTH-1:0] ddr_cke_r; |
reg [CS_NUM-1:0] ddr_cs_n_r; |
reg [CS_NUM-1:0] ddr_cs_n_r1; |
reg [CS_NUM-1:0] ddr_cs_disable_r; |
reg ddr_ras_n_r; |
reg ddr_ras_n_r1; |
reg ddr_we_n_r; |
reg ddr_we_n_r1; |
wire [15:0] ext_mode_reg; |
reg [3:0] init_cnt_r; |
reg init_done_r; |
reg [4:0] init_next_state; |
reg [4:0] init_state_r; |
reg [4:0] init_state_r1; |
reg [4:0] init_state_r1_2t; |
reg [4:0] init_state_r2; |
wire [15:0] load_mode_reg; |
wire [15:0] load_mode_reg0; |
wire [15:0] load_mode_reg1; |
wire [15:0] load_mode_reg2; |
wire [15:0] load_mode_reg3; |
reg phy_init_done_r; |
reg phy_init_done_r1; |
reg phy_init_done_r2; |
reg phy_init_done_r3; |
reg refresh_req; |
wire [3:0] start_cal; |
|
//*************************************************************************** |
|
//***************************************************************** |
// DDR1 and DDR2 Load mode register |
// Mode Register (MR): |
// [15:14] - unused - 00 |
// [13] - reserved - 0 |
// [12] - Power-down mode - 0 (normal) |
// [11:9] - write recovery - for Auto Precharge (tWR/tCK) |
// [8] - DLL reset - 0 or 1 |
// [7] - Test Mode - 0 (normal) |
// [6:4] - CAS latency - CAS_LAT |
// [3] - Burst Type - BURST_TYPE |
// [2:0] - Burst Length - BURST_LEN |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR2) begin: gen_load_mode_reg_ddr2 |
assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : |
((BURST_LEN == 4) ? 3'b010 : 3'b111); |
assign load_mode_reg[3] = BURST_TYPE; |
assign load_mode_reg[6:4] = (CAS_LAT == 3) ? 3'b011 : |
((CAS_LAT == 4) ? 3'b100 : |
((CAS_LAT == 5) ? 3'b101 : 3'b111)); |
assign load_mode_reg[7] = 1'b0; |
assign load_mode_reg[8] = 1'b0; // init value only (DLL not reset) |
assign load_mode_reg[11:9] = (WR_RECOVERY == 6) ? 3'b101 : |
((WR_RECOVERY == 5) ? 3'b100 : |
((WR_RECOVERY == 4) ? 3'b011 : |
((WR_RECOVERY == 3) ? 3'b010 : |
3'b001))); |
assign load_mode_reg[15:12] = 4'b000; |
end else if (DDR_TYPE == DDR1)begin: gen_load_mode_reg_ddr1 |
assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : |
((BURST_LEN == 4) ? 3'b010 : |
((BURST_LEN == 2) ? 3'b001 : 3'b111)); |
assign load_mode_reg[3] = BURST_TYPE; |
assign load_mode_reg[6:4] = (CAS_LAT == 2) ? 3'b010 : |
((CAS_LAT == 3) ? 3'b011 : |
((CAS_LAT == 25) ? 3'b110 : 3'b111)); |
assign load_mode_reg[12:7] = 6'b000000; // init value only |
assign load_mode_reg[15:13] = 3'b000; |
end |
endgenerate |
|
//***************************************************************** |
// DDR1 and DDR2 ext mode register |
// Extended Mode Register (MR): |
// [15:14] - unused - 00 |
// [13] - reserved - 0 |
// [12] - output enable - 0 (enabled) |
// [11] - RDQS enable - 0 (disabled) |
// [10] - DQS# enable - 0 (enabled) |
// [9:7] - OCD Program - 111 or 000 (first 111, then 000 during init) |
// [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) |
// [5:3] - Additive CAS - ADDITIVE_CAS |
// [2] - RTT[0] |
// [1] - Output drive - REDUCE_DRV (= 0(full), = 1 (reduced) |
// [0] - DLL enable - 0 (normal) |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR2) begin: gen_ext_mode_reg_ddr2 |
assign ext_mode_reg[0] = 1'b0; |
assign ext_mode_reg[1] = REDUCE_DRV; |
assign ext_mode_reg[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? |
1'b1 : 1'b0; |
assign ext_mode_reg[5:3] = (ADDITIVE_LAT == 0) ? 3'b000 : |
((ADDITIVE_LAT == 1) ? 3'b001 : |
((ADDITIVE_LAT == 2) ? 3'b010 : |
((ADDITIVE_LAT == 3) ? 3'b011 : |
((ADDITIVE_LAT == 4) ? 3'b100 : |
3'b111)))); |
assign ext_mode_reg[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? |
1'b1 : 1'b0; |
assign ext_mode_reg[9:7] = 3'b000; |
assign ext_mode_reg[10] = 1'b0; |
assign ext_mode_reg[15:10] = 6'b000000; |
end else if (DDR_TYPE == DDR1)begin: gen_ext_mode_reg_ddr1 |
assign ext_mode_reg[0] = 1'b0; |
assign ext_mode_reg[1] = REDUCE_DRV; |
assign ext_mode_reg[12:2] = 11'b00000000000; |
assign ext_mode_reg[15:13] = 3'b000; |
end |
endgenerate |
|
//***************************************************************** |
// DDR3 Load mode reg0 |
// Mode Register (MR0): |
// [15:13] - unused - 000 |
// [12] - Precharge Power-down DLL usage - 0 (DLL frozen, slow-exit), |
// 1 (DLL maintained) |
// [11:9] - write recovery for Auto Precharge (tWR/tCK = 6) |
// [8] - DLL reset - 0 or 1 |
// [7] - Test Mode - 0 (normal) |
// [6:4],[2] - CAS latency - CAS_LAT |
// [3] - Burst Type - BURST_TYPE |
// [1:0] - Burst Length - BURST_LEN |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR3) begin: gen_load_mode_reg0_ddr3 |
assign load_mode_reg0[1:0] = (BURST_LEN == 8) ? 2'b00 : |
((BURST_LEN == 4) ? 2'b10 : 2'b11); |
// Part of CAS latency. This bit is '0' for all CAS latencies |
assign load_mode_reg0[2] = 1'b0; |
assign load_mode_reg0[3] = BURST_TYPE; |
assign load_mode_reg0[6:4] = (CAS_LAT == 5) ? 3'b001 : |
(CAS_LAT == 6) ? 3'b010 : 3'b111; |
assign load_mode_reg0[7] = 1'b0; |
// init value only (DLL reset) |
assign load_mode_reg0[8] = 1'b1; |
assign load_mode_reg0[11:9] = 3'b010; |
// Precharge Power-Down DLL 'slow-exit' |
assign load_mode_reg0[12] = 1'b0; |
assign load_mode_reg0[15:13] = 3'b000; |
end |
endgenerate |
|
//***************************************************************** |
// DDR3 Load mode reg1 |
// Mode Register (MR1): |
// [15:13] - unused - 00 |
// [12] - output enable - 0 (enabled for DQ, DQS, DQS#) |
// [11] - TDQS enable - 0 (TDQS disabled and DM enabled) |
// [10] - reserved - 0 (must be '0') |
// [9] - RTT[2] - 0 |
// [8] - reserved - 0 (must be '0') |
// [7] - write leveling - 0 (disabled), 1 (enabled) |
// [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) |
// [5] - Output driver impedance[1] - 0 (RZQ/6 and RZQ/7) |
// [4:3] - Additive CAS - ADDITIVE_CAS |
// [2] - RTT[0] |
// [1] - Output driver impedance[0] - 0(RZQ/6), or 1 (RZQ/7) |
// [0] - DLL enable - 0 (normal) |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg1_ddr3 |
// DLL enabled during Imitialization |
assign load_mode_reg1[0] = 1'b0; |
// RZQ/6 |
assign load_mode_reg1[1] = REDUCE_DRV; |
assign load_mode_reg1[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? |
1'b1 : 1'b0; |
assign load_mode_reg1[4:3] = (ADDITIVE_LAT == 0) ? 2'b00 : |
((ADDITIVE_LAT == 1) ? 2'b01 : |
((ADDITIVE_LAT == 2) ? 2'b10 : |
3'b111)); |
// RZQ/6 |
assign load_mode_reg1[5] = 1'b0; |
assign load_mode_reg1[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? |
1'b1 : 1'b0; |
// Make zero WRITE_LEVEL |
assign load_mode_reg1[7] = 0; |
assign load_mode_reg1[8] = 1'b0; |
assign load_mode_reg1[9] = 1'b0; |
assign load_mode_reg1[10] = 1'b0; |
assign load_mode_reg1[15:11] = 5'b00000; |
end |
endgenerate |
|
//***************************************************************** |
// DDR3 Load mode reg2 |
// Mode Register (MR2): |
// [15:11] - unused - 00 |
// [10:9] - RTT_WR - 00 (Dynamic ODT off) |
// [8] - reserved - 0 (must be '0') |
// [7] - self-refresh temperature range - |
// 0 (normal), 1 (extended) |
// [6] - Auto Self-Refresh - 0 (manual), 1(auto) |
// [5:3] - CAS Write Latency (CWL) - |
// 000 (5 for 400 MHz device), |
// 001 (6 for 400 MHz to 533 MHz devices), |
// 010 (7 for 533 MHz to 667 MHz devices), |
// 011 (8 for 667 MHz to 800 MHz) |
// [2:0] - Partial Array Self-Refresh (Optional) - |
// 000 (full array) |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg2_ddr3 |
assign load_mode_reg2[2:0] = 3'b000; |
assign load_mode_reg2[5:3] = (CAS_LAT == 5) ? 3'b000 : |
(CAS_LAT == 6) ? 3'b001 : 3'b111; |
assign load_mode_reg2[6] = 1'b0; // Manual Self-Refresh |
assign load_mode_reg2[7] = 1'b0; |
assign load_mode_reg2[8] = 1'b0; |
assign load_mode_reg2[10:9] = 2'b00; |
assign load_mode_reg2[15:11] = 5'b00000; |
end |
endgenerate |
|
//***************************************************************** |
// DDR3 Load mode reg3 |
// Mode Register (MR3): |
// [15:3] - unused - All zeros |
// [2] - MPR Operation - 0(normal operation), 1(data flow from MPR) |
// [1:0] - MPR location - 00 (Predefined pattern) |
//***************************************************************** |
|
generate |
if (DDR_TYPE == DDR3)begin: gen_ext_mode_reg3_ddr3 |
assign load_mode_reg3[1:0] = 2'b00; |
assign load_mode_reg3[2] = 1'b0; |
assign load_mode_reg3[15:3] = 13'b0000000000000; |
end |
endgenerate |
|
//*************************************************************************** |
// Logic for calibration start, and for auto-refresh during cal request |
// CALIB_REF_REQ is used by calibration logic to request auto-refresh |
// durign calibration (used to avoid tRAS violation is certain calibration |
// stages take a long time). Once the auto-refresh is complete and cal can |
// be resumed, CALIB_REF_DONE is asserted by PHY_INIT. |
//*************************************************************************** |
|
// generate pulse for each of calibration start controls |
assign start_cal[0] = ((init_state_r1 == INIT_CAL1_READ) && |
(init_state_r2 != INIT_CAL1_READ)); |
assign start_cal[1] = ((init_state_r1 == INIT_CAL2_READ) && |
(init_state_r2 != INIT_CAL2_READ)); |
assign start_cal[2] = ((init_state_r1 == INIT_CAL3_READ) && |
(init_state_r2 == INIT_CAL3_WRITE_READ)); |
assign start_cal[3] = ((init_state_r1 == INIT_CAL4_READ) && |
(init_state_r2 == INIT_DUMMY_ACTIVE_WAIT)); |
|
// Generate positive-edge triggered, latched signal to force initialization |
// to pause calibration, and to issue auto-refresh. Clear flag as soon as |
// refresh initiated |
always @(posedge clkdiv0) |
if (rstdiv0) begin |
calib_ref_req_r <= 1'b0; |
calib_ref_req_posedge <= 1'b0; |
refresh_req <= 1'b0; |
end else begin |
calib_ref_req_r <= calib_ref_req; |
calib_ref_req_posedge <= calib_ref_req & ~calib_ref_req_r; |
if (init_state_r1 == INIT_AUTO_REFRESH) |
refresh_req <= 1'b0; |
else if (calib_ref_req_posedge) |
refresh_req <= 1'b1; |
end |
|
// flag to tell cal1 calibration was started. |
// This flag is used for cal1 auto refreshes |
// some of these bits may not be needed - only needed for those stages that |
// need refreshes within the stage (i.e. very long stages) |
always @(posedge clkdiv0) |
if (rstdiv0) begin |
cal1_started_r <= 1'b0; |
cal2_started_r <= 1'b0; |
cal4_started_r <= 1'b0; |
end else begin |
if (calib_start[0]) |
cal1_started_r <= 1'b1; |
if (calib_start[1]) |
cal2_started_r <= 1'b1; |
if (calib_start[3]) |
cal4_started_r <= 1'b1; |
end |
|
// Delay start of each calibration by 16 clock cycles to |
// ensure that when calibration logic begins, that read data is already |
// appearing on the bus. Don't really need it, it's more for simulation |
// purposes. Each circuit should synthesize using an SRL16. |
// In first stage of calibration periodic auto refreshes |
// will be issued to meet memory timing. calib_start_shift0_r[15] will be |
// asserted more than once.calib_start[0] is anded with cal1_started_r so |
// that it is asserted only once. cal1_refresh_done is anded with |
// cal1_started_r so that it is asserted after the auto refreshes. |
always @(posedge clkdiv0) begin |
calib_start_shift0_r <= {calib_start_shift0_r[14:0], start_cal[0]}; |
calib_start_shift1_r <= {calib_start_shift1_r[14:0], start_cal[1]}; |
calib_start_shift2_r <= {calib_start_shift2_r[14:0], start_cal[2]}; |
calib_start_shift3_r <= {calib_start_shift3_r[14:0], start_cal[3]}; |
calib_start[0] <= calib_start_shift0_r[15] & ~cal1_started_r; |
calib_start[1] <= calib_start_shift1_r[15] & ~cal2_started_r; |
calib_start[2] <= calib_start_shift2_r[15]; |
calib_start[3] <= calib_start_shift3_r[15] & ~cal4_started_r; |
calib_ref_done <= calib_start_shift0_r[15] | |
calib_start_shift1_r[15] | |
calib_start_shift3_r[15]; |
end |
|
// generate delay for various states that require it (no maximum delay |
// requirement, make sure that terminal count is large enough to cover |
// all cases) |
always @(posedge clkdiv0) begin |
case (init_state_r) |
INIT_PRECHARGE_WAIT, |
INIT_MODE_REGISTER_WAIT, |
INIT_AUTO_REFRESH_WAIT, |
INIT_DUMMY_ACTIVE_WAIT, |
INIT_CAL1_WRITE_READ, |
INIT_CAL1_READ_WAIT, |
INIT_CAL2_WRITE_READ, |
INIT_CAL2_READ_WAIT, |
INIT_CAL3_WRITE_READ: |
cnt_cmd_r <= cnt_cmd_r + 1; |
default: |
cnt_cmd_r <= 7'b0000000; |
endcase |
end |
|
// assert when count reaches the value |
always @(posedge clkdiv0) begin |
if(cnt_cmd_r == CNTNEXT_CMD) |
cnt_cmd_ok_r <= 1'b1; |
else |
cnt_cmd_ok_r <= 1'b0; |
end |
|
always @(posedge clkdiv0) begin |
case (init_state_r) |
INIT_CAL3_READ_WAIT, |
INIT_CAL4_READ_WAIT: |
cnt_rd_r <= cnt_rd_r + 1; |
default: |
cnt_rd_r <= 4'b0000; |
endcase |
end |
|
always @(posedge clkdiv0) begin |
if(cnt_rd_r == CNTNEXT_RD) |
cnt_rd_ok_r <= 1'b1; |
else |
cnt_rd_ok_r <= 1'b0; |
end |
|
//*************************************************************************** |
// Initial delay after power-on |
//*************************************************************************** |
|
// register the refresh flag from the controller. |
// The refresh flag is in full frequency domain - so a pulsed version must |
// be generated for half freq domain using 2 consecutive full clk cycles |
// The registered version is used for the 200us counter |
always @(posedge clk0) |
ctrl_ref_flag_r <= ctrl_ref_flag; |
always @(posedge clkdiv0) |
cke_200us_cnt_en_r <= ctrl_ref_flag || ctrl_ref_flag_r; |
|
// 200us counter for cke |
always @(posedge clkdiv0) |
if (rstdiv0) begin |
// skip power-up count if only simulating |
if (SIM_ONLY) |
cke_200us_cnt_r <= 5'b00001; |
else |
cke_200us_cnt_r <= 5'd27; |
end else if (cke_200us_cnt_en_r) |
cke_200us_cnt_r <= cke_200us_cnt_r - 1; |
|
always @(posedge clkdiv0) |
if (rstdiv0) |
done_200us_r <= 1'b0; |
else if (!done_200us_r) |
done_200us_r <= (cke_200us_cnt_r == 5'b00000); |
|
// 200 clocks counter - count value : h'64 required for initialization |
// Counts 100 divided by two clocks |
always @(posedge clkdiv0) |
if (rstdiv0 || (init_state_r == INIT_CNT_200)) |
cnt_200_cycle_r <= 8'h64; |
else if (init_state_r == INIT_ZQCL) // ddr3 |
cnt_200_cycle_r <= 8'hC8; |
else if (cnt_200_cycle_r != 8'h00) |
cnt_200_cycle_r <= cnt_200_cycle_r - 1; |
|
always @(posedge clkdiv0) |
if (rstdiv0 || (init_state_r == INIT_CNT_200) |
|| (init_state_r == INIT_ZQCL)) |
cnt_200_cycle_done_r <= 1'b0; |
else if (cnt_200_cycle_r == 8'h00) |
cnt_200_cycle_done_r <= 1'b1; |
|
//***************************************************************** |
// handle deep memory configuration: |
// During initialization: Repeat initialization sequence once for each |
// chip select. Note that we could perform initalization for all chip |
// selects simulataneously. Probably fine - any potential SI issues with |
// auto refreshing all chip selects at once? |
// Once initialization complete, assert only CS[1] for calibration. |
//***************************************************************** |
|
always @(posedge clkdiv0) |
if (rstdiv0) begin |
chip_cnt_r <= 2'b00; |
end else if (init_state_r == INIT_DEEP_MEMORY_ST) begin |
if (chip_cnt_r != CS_NUM) |
chip_cnt_r <= chip_cnt_r + 1; |
else |
chip_cnt_r <= 2'b00; |
// MIG 2.4: Modified to issue an Auto Refresh commmand |
// to each chip select during various calibration stages |
end else if (init_state_r == INIT_PRECHARGE && init_done_r) begin |
chip_cnt_r <= 2'b00; |
end else if (init_state_r1 == INIT_AUTO_REFRESH && init_done_r) begin |
if (chip_cnt_r < (CS_NUM-1)) |
chip_cnt_r <= chip_cnt_r + 1; |
end |
|
// keep track of which chip selects got auto-refreshed (avoid auto-refreshing |
// all CS's at once to avoid current spike) |
always @(posedge clkdiv0)begin |
if (rstdiv0 || init_state_r == INIT_PRECHARGE) |
auto_cnt_r <= 'd0; |
else if (init_state_r == INIT_AUTO_REFRESH && init_done_r) begin |
if (auto_cnt_r < CS_NUM) |
auto_cnt_r <= auto_cnt_r + 1; |
end |
end |
|
always @(posedge clkdiv0) |
if (rstdiv0) begin |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
end else begin |
ddr_cs_n_r <= {CS_NUM{1'b1}}; |
if ((init_state_r == INIT_DUMMY_ACTIVE) || |
((init_state_r == INIT_PRECHARGE) && (~init_done_r))|| |
(init_state_r == INIT_LOAD_MODE) || |
(init_state_r == INIT_AUTO_REFRESH) || |
(init_state_r == INIT_ZQCL ) || |
(((init_state_r == INIT_CAL1_READ) || |
(init_state_r == INIT_CAL2_READ) || |
(init_state_r == INIT_CAL3_READ) || |
(init_state_r == INIT_CAL4_READ) || |
(init_state_r == INIT_CAL1_WRITE) || |
(init_state_r == INIT_CAL2_WRITE) || |
(init_state_r == INIT_CAL3_WRITE)) && (burst_cnt_r == 2'b00))) |
ddr_cs_n_r[chip_cnt_r] <= 1'b0; |
else if (init_state_r == INIT_PRECHARGE) |
ddr_cs_n_r <= {CS_NUM{1'b0}}; |
else |
ddr_cs_n_r[chip_cnt_r] <= 1'b1; |
end |
|
//*************************************************************************** |
// Write/read burst logic |
//*************************************************************************** |
|
assign cal_write = ((init_state_r == INIT_CAL1_WRITE) || |
(init_state_r == INIT_CAL2_WRITE) || |
(init_state_r == INIT_CAL3_WRITE)); |
assign cal_read = ((init_state_r == INIT_CAL1_READ) || |
(init_state_r == INIT_CAL2_READ) || |
(init_state_r == INIT_CAL3_READ) || |
(init_state_r == INIT_CAL4_READ)); |
assign cal_write_read = ((init_state_r == INIT_CAL1_READ) || |
(init_state_r == INIT_CAL2_READ) || |
(init_state_r == INIT_CAL3_READ) || |
(init_state_r == INIT_CAL4_READ) || |
(init_state_r == INIT_CAL1_WRITE) || |
(init_state_r == INIT_CAL2_WRITE) || |
(init_state_r == INIT_CAL3_WRITE)); |
|
assign burst_val = (BURST_LEN == 4) ? 2'b00 : |
(BURST_LEN == 8) ? 2'b01 : 2'b00; |
|
// keep track of current address - need this if burst length < 8 for |
// stage 2-4 calibration writes and reads. Make sure value always gets |
// initialized to 0 before we enter write/read state. This is used to |
// keep track of when another burst must be issued |
always @(posedge clkdiv0) |
if (cal_write_read) |
burst_addr_r <= burst_addr_r + 2; |
else |
burst_addr_r <= 2'b00; |
|
// write/read burst count |
always @(posedge clkdiv0) |
if (cal_write_read) |
if (burst_cnt_r == 2'b00) |
burst_cnt_r <= burst_val; |
else // SHOULD THIS BE -2 CHECK THIS LOGIC |
burst_cnt_r <= burst_cnt_r - 1; |
else |
burst_cnt_r <= 2'b00; |
|
// indicate when a write is occurring |
always @(posedge clkdiv0) |
// MIG 2.1: Remove (burst_addr_r<4) term - not used |
// phy_init_wren <= cal_write && (burst_addr_r < 3'd4); |
phy_init_wren <= cal_write; |
|
// used for read enable calibration, pulse to indicate when read issued |
always @(posedge clkdiv0) |
// MIG 2.1: Remove (burst_addr_r<4) term - not used |
// phy_init_rden <= cal_read && (burst_addr_r < 3'd4); |
phy_init_rden <= cal_read; |
|
//*************************************************************************** |
// Initialization state machine |
//*************************************************************************** |
|
always @(posedge clkdiv0) |
// every time we need to initialize another rank of memory, need to |
// reset init count, and repeat the entire initialization (but not |
// calibration) sequence |
if (rstdiv0 || (init_state_r == INIT_DEEP_MEMORY_ST)) |
init_cnt_r <= INIT_CNTR_INIT; |
else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_PRECHARGE) && |
(init_cnt_r == INIT_CNTR_PRECH_1)) |
// skip EMR(2) and EMR(3) register loads |
init_cnt_r <= INIT_CNTR_EMR_EN_DLL; |
else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_LOAD_MODE) && |
(init_cnt_r == INIT_CNTR_MR_ACT_DLL)) |
// skip OCD calibration for DDR1 |
init_cnt_r <= INIT_CNTR_DEEP_MEM; |
else if ((DDR_TYPE == DDR3) && (init_state_r == INIT_ZQCL)) |
// skip states for DDR3 |
init_cnt_r <= INIT_CNTR_DEEP_MEM; |
else if ((init_state_r == INIT_LOAD_MODE) || |
((init_state_r == INIT_PRECHARGE) |
&& (init_state_r1 != INIT_CALIB_REF))|| |
((init_state_r == INIT_AUTO_REFRESH) |
&& (~init_done_r))|| |
(init_state_r == INIT_CNT_200)) |
init_cnt_r <= init_cnt_r + 1; |
|
always @(posedge clkdiv0) begin |
if ((init_state_r == INIT_IDLE) && (init_cnt_r == INIT_CNTR_DONE)) begin |
phy_init_done_r <= 1'b1; |
end else |
phy_init_done_r <= 1'b0; |
end |
|
// phy_init_done to the controller and the user interface. |
// It is delayed by four clocks to account for the |
// multi cycle path constraint to the (phy_init_data_sel) |
// to the phy layer. |
always @(posedge clkdiv0)begin |
phy_init_done_r1 <= phy_init_done_r; |
phy_init_done_r2 <= phy_init_done_r1; |
phy_init_done_r3 <= phy_init_done_r2; |
phy_init_done <= phy_init_done_r3; |
end |
|
// Instantiate primitive to allow this flop to be attached to multicycle |
// path constraint in UCF. This signal goes to PHY_WRITE and PHY_CTL_IO |
// datapath logic only. Because it is a multi-cycle path, it can be |
// clocked by either CLKDIV0 or CLK0. |
FDRSE u_ff_phy_init_data_sel |
( |
.Q (phy_init_data_sel), |
.C (clkdiv0), |
.CE (1'b1), |
.D (phy_init_done_r1), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve=1 */ |
/* synthesis syn_replicate = 0 */; |
|
//synthesis translate_off |
always @(posedge calib_done[0]) |
$display ("First Stage Calibration completed at time %t", $time); |
|
always @(posedge calib_done[1]) |
$display ("Second Stage Calibration completed at time %t", $time); |
|
always @(posedge calib_done[2]) begin |
$display ("Third Stage Calibration completed at time %t", $time); |
end |
|
always @(posedge calib_done[3]) begin |
$display ("Fourth Stage Calibration completed at time %t", $time); |
$display ("Calibration completed at time %t", $time); |
end |
//synthesis translate_on |
|
always @(posedge clkdiv0) begin |
if ((init_cnt_r >= INIT_CNTR_DEEP_MEM))begin |
init_done_r <= 1'b1; |
end else |
init_done_r <= 1'b0; |
end |
|
//***************************************************************** |
|
always @(posedge clkdiv0) |
if (rstdiv0) begin |
init_state_r <= INIT_IDLE; |
init_state_r1 <= INIT_IDLE; |
init_state_r2 <= INIT_IDLE; |
calib_done_r <= 4'b0000; |
end else begin |
init_state_r <= init_next_state; |
init_state_r1 <= init_state_r; |
init_state_r2 <= init_state_r1; |
calib_done_r <= calib_done; // register for timing |
end |
|
always @(*) begin |
init_next_state = init_state_r; |
(* full_case, parallel_case *) case (init_state_r) |
INIT_IDLE: begin |
if (done_200us_r) begin |
(* parallel_case *) case (init_cnt_r) |
INIT_CNTR_INIT: |
init_next_state = INIT_CNT_200; |
INIT_CNTR_PRECH_1: |
init_next_state = INIT_PRECHARGE; |
INIT_CNTR_EMR2_INIT: |
init_next_state = INIT_LOAD_MODE; // EMR(2) |
INIT_CNTR_EMR3_INIT: |
init_next_state = INIT_LOAD_MODE; // EMR(3); |
INIT_CNTR_EMR_EN_DLL: |
init_next_state = INIT_LOAD_MODE; // EMR, enable DLL |
INIT_CNTR_MR_RST_DLL: |
init_next_state = INIT_LOAD_MODE; // MR, reset DLL |
INIT_CNTR_CNT_200_WAIT:begin |
if(DDR_TYPE == DDR3) |
init_next_state = INIT_ZQCL; // DDR3 |
else |
// Wait 200cc after reset DLL |
init_next_state = INIT_CNT_200; |
end |
INIT_CNTR_PRECH_2: |
init_next_state = INIT_PRECHARGE; |
INIT_CNTR_AR_1: |
init_next_state = INIT_AUTO_REFRESH; |
INIT_CNTR_AR_2: |
init_next_state = INIT_AUTO_REFRESH; |
INIT_CNTR_MR_ACT_DLL: |
init_next_state = INIT_LOAD_MODE; // MR, unreset DLL |
INIT_CNTR_EMR_DEF_OCD: |
init_next_state = INIT_LOAD_MODE; // EMR, OCD default |
INIT_CNTR_EMR_EXIT_OCD: |
init_next_state = INIT_LOAD_MODE; // EMR, enable OCD exit |
INIT_CNTR_DEEP_MEM: begin |
if ((chip_cnt_r < CS_NUM-1)) |
init_next_state = INIT_DEEP_MEMORY_ST; |
else if (cnt_200_cycle_done_r) |
init_next_state = INIT_DUMMY_ACTIVE; |
else |
init_next_state = INIT_IDLE; |
end |
INIT_CNTR_PRECH_3: |
init_next_state = INIT_PRECHARGE; |
INIT_CNTR_DONE: |
init_next_state = INIT_IDLE; |
default : |
init_next_state = INIT_IDLE; |
endcase |
end |
end |
INIT_CNT_200: |
init_next_state = INIT_CNT_200_WAIT; |
INIT_CNT_200_WAIT: |
if (cnt_200_cycle_done_r) |
init_next_state = INIT_IDLE; |
INIT_PRECHARGE: |
init_next_state = INIT_PRECHARGE_WAIT; |
INIT_PRECHARGE_WAIT: |
if (cnt_cmd_ok_r)begin |
if (init_done_r && (!(&calib_done_r))) |
init_next_state = INIT_AUTO_REFRESH; |
else |
init_next_state = INIT_IDLE; |
end |
INIT_ZQCL: |
init_next_state = INIT_WAIT_DLLK_ZQINIT; |
INIT_WAIT_DLLK_ZQINIT: |
if (cnt_200_cycle_done_r) |
init_next_state = INIT_IDLE; |
INIT_LOAD_MODE: |
init_next_state = INIT_MODE_REGISTER_WAIT; |
INIT_MODE_REGISTER_WAIT: |
if (cnt_cmd_ok_r) |
init_next_state = INIT_IDLE; |
INIT_AUTO_REFRESH: |
init_next_state = INIT_AUTO_REFRESH_WAIT; |
INIT_AUTO_REFRESH_WAIT: |
// MIG 2.4: Modified to issue an Auto Refresh commmand |
// to each chip select during various calibration stages |
if (auto_cnt_r < CS_NUM && init_done_r) begin |
if (cnt_cmd_ok_r) |
init_next_state = INIT_AUTO_REFRESH; |
end else if (cnt_cmd_ok_r)begin |
if(init_done_r) |
init_next_state = INIT_DUMMY_ACTIVE; |
else |
init_next_state = INIT_IDLE; |
end |
INIT_DEEP_MEMORY_ST: |
init_next_state = INIT_IDLE; |
// single row activate. All subsequent calibration writes and |
// read will take place in this row |
INIT_DUMMY_ACTIVE: |
init_next_state = INIT_DUMMY_ACTIVE_WAIT; |
INIT_DUMMY_ACTIVE_WAIT: |
if (cnt_cmd_ok_r)begin |
if (~calib_done_r[0]) begin |
// if returning to stg1 after refresh, don't need to write |
if (cal1_started_r) |
init_next_state = INIT_CAL1_READ; |
// if first entering stg1, need to write training pattern |
else |
init_next_state = INIT_CAL1_WRITE; |
end else if (~calib_done[1]) begin |
if (cal2_started_r) |
init_next_state = INIT_CAL2_READ; |
else |
init_next_state = INIT_CAL2_WRITE; |
end else if (~calib_done_r[2]) |
init_next_state = INIT_CAL3_WRITE; |
else |
init_next_state = INIT_CAL4_READ; |
end |
// Stage 1 calibration (write and continuous read) |
INIT_CAL1_WRITE: |
if (burst_addr_r == 2'b10) |
init_next_state = INIT_CAL1_WRITE_READ; |
INIT_CAL1_WRITE_READ: |
if (cnt_cmd_ok_r) |
init_next_state = INIT_CAL1_READ; |
INIT_CAL1_READ: |
// Stage 1 requires inter-stage auto-refresh |
if (calib_done_r[0] || refresh_req) |
init_next_state = INIT_CAL1_READ_WAIT; |
INIT_CAL1_READ_WAIT: |
if (cnt_cmd_ok_r) |
init_next_state = INIT_CALIB_REF; |
// Stage 2 calibration (write and continuous read) |
INIT_CAL2_WRITE: |
if (burst_addr_r == 2'b10) |
init_next_state = INIT_CAL2_WRITE_READ; |
INIT_CAL2_WRITE_READ: |
if (cnt_cmd_ok_r) |
init_next_state = INIT_CAL2_READ; |
INIT_CAL2_READ: |
// Stage 2 requires inter-stage auto-refresh |
if (calib_done_r[1] || refresh_req) |
init_next_state = INIT_CAL2_READ_WAIT; |
INIT_CAL2_READ_WAIT: |
if(cnt_cmd_ok_r) |
init_next_state = INIT_CALIB_REF; |
// Stage 3 calibration (write and continuous read) |
INIT_CAL3_WRITE: |
if (burst_addr_r == 2'b10) |
init_next_state = INIT_CAL3_WRITE_READ; |
INIT_CAL3_WRITE_READ: |
if (cnt_cmd_ok_r) |
init_next_state = INIT_CAL3_READ; |
INIT_CAL3_READ: |
if (burst_addr_r == 2'b10) |
init_next_state = INIT_CAL3_READ_WAIT; |
INIT_CAL3_READ_WAIT: begin |
if (cnt_rd_ok_r) |
if (calib_done_r[2]) begin |
init_next_state = INIT_CALIB_REF; |
end else |
init_next_state = INIT_CAL3_READ; |
end |
// Stage 4 calibration (continuous read only, same pattern as stage 3) |
// only used if DQS_GATE supported |
INIT_CAL4_READ: |
if (burst_addr_r == 2'b10) |
init_next_state = INIT_CAL4_READ_WAIT; |
INIT_CAL4_READ_WAIT: begin |
if (cnt_rd_ok_r) |
// Stage 4 requires inter-stage auto-refresh |
if (calib_done_r[3] || refresh_req) |
init_next_state = INIT_PRECHARGE; |
else |
init_next_state = INIT_CAL4_READ; |
end |
INIT_CALIB_REF: |
init_next_state = INIT_PRECHARGE; |
endcase |
end |
|
//*************************************************************************** |
// Memory control/address |
//*************************************************************************** |
|
always @(posedge clkdiv0) |
if ((init_state_r == INIT_DUMMY_ACTIVE) || |
(init_state_r == INIT_PRECHARGE) || |
(init_state_r == INIT_LOAD_MODE) || |
(init_state_r == INIT_AUTO_REFRESH)) begin |
ddr_ras_n_r <= 1'b0; |
end else begin |
ddr_ras_n_r <= 1'b1; |
end |
|
always @(posedge clkdiv0) |
if ((init_state_r == INIT_LOAD_MODE) || |
(init_state_r == INIT_AUTO_REFRESH) || |
(cal_write_read && (burst_cnt_r == 2'b00))) begin |
ddr_cas_n_r <= 1'b0; |
end else begin |
ddr_cas_n_r <= 1'b1; |
end |
|
always @(posedge clkdiv0) |
if ((init_state_r == INIT_LOAD_MODE) || |
(init_state_r == INIT_PRECHARGE) || |
(init_state_r == INIT_ZQCL) || |
(cal_write && (burst_cnt_r == 2'b00)))begin |
ddr_we_n_r <= 1'b0; |
end else begin |
ddr_we_n_r <= 1'b1; |
end |
|
//***************************************************************** |
// memory address during init |
//***************************************************************** |
|
always @(posedge clkdiv0) begin |
if ((init_state_r == INIT_PRECHARGE) |
|| (init_state_r == INIT_ZQCL))begin |
// Precharge all - set A10 = 1 |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
ddr_addr_r[10] <= 1'b1; |
ddr_ba_r <= {BANK_WIDTH{1'b0}}; |
end else if (init_state_r == INIT_LOAD_MODE) begin |
ddr_ba_r <= {BANK_WIDTH{1'b0}}; |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
case (init_cnt_r) |
// EMR (2) |
INIT_CNTR_EMR2_INIT: begin |
ddr_ba_r[1:0] <= 2'b10; |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
end |
// EMR (3) |
INIT_CNTR_EMR3_INIT: begin |
ddr_ba_r[1:0] <= 2'b11; |
if(DDR_TYPE == DDR3) |
ddr_addr_r <= load_mode_reg3[ROW_WIDTH-1:0]; |
else |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
end |
// EMR write - A0 = 0 for DLL enable |
INIT_CNTR_EMR_EN_DLL: begin |
ddr_ba_r[1:0] <= 2'b01; |
if(DDR_TYPE == DDR3) |
ddr_addr_r <= load_mode_reg1[ROW_WIDTH-1:0]; |
else |
ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; |
end |
// MR write, reset DLL (A8=1) |
INIT_CNTR_MR_RST_DLL: begin |
if(DDR_TYPE == DDR3) |
ddr_addr_r <= load_mode_reg0[ROW_WIDTH-1:0]; |
else |
ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; |
ddr_ba_r[1:0] <= 2'b00; |
ddr_addr_r[8] <= 1'b1; |
end |
// MR write, unreset DLL (A8=0) |
INIT_CNTR_MR_ACT_DLL: begin |
ddr_ba_r[1:0] <= 2'b00; |
ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; |
end |
// EMR write, OCD default state |
INIT_CNTR_EMR_DEF_OCD: begin |
ddr_ba_r[1:0] <= 2'b01; |
ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; |
ddr_addr_r[9:7] <= 3'b111; |
end |
// EMR write - OCD exit |
INIT_CNTR_EMR_EXIT_OCD: begin |
ddr_ba_r[1:0] <= 2'b01; |
ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; |
end |
default: begin |
ddr_ba_r <= {BANK_WIDTH{1'bx}}; |
ddr_addr_r <= {ROW_WIDTH{1'bx}}; |
end |
endcase |
end else if (cal_write_read) begin |
// when writing or reading for Stages 2-4, since training pattern is |
// either 4 (stage 2) or 8 (stage 3-4) long, if BURST LEN < 8, then |
// need to issue multiple bursts to read entire training pattern |
ddr_addr_r[ROW_WIDTH-1:3] <= {ROW_WIDTH-4{1'b0}}; |
ddr_addr_r[2:0] <= {burst_addr_r, 1'b0}; |
ddr_ba_r <= {BANK_WIDTH-1{1'b0}}; |
end else if (init_state_r == INIT_DUMMY_ACTIVE) begin |
// all calibration writing read takes place in row 0x0 only |
ddr_ba_r <= {BANK_WIDTH{1'b0}}; |
ddr_addr_r <= {ROW_WIDTH{1'b0}}; |
end else begin |
// otherwise, cry me a river |
ddr_ba_r <= {BANK_WIDTH{1'bx}}; |
ddr_addr_r <= {ROW_WIDTH{1'bx}}; |
end |
end |
|
// Keep CKE asserted after initial power-on delay |
always @(posedge clkdiv0) |
ddr_cke_r <= {CKE_WIDTH{done_200us_r}}; |
|
// register commands to memory. Two clock cycle delay from state -> output |
always @(posedge clk0) begin |
ddr_addr_r1 <= ddr_addr_r; |
ddr_ba_r1 <= ddr_ba_r; |
ddr_cas_n_r1 <= ddr_cas_n_r; |
ddr_ras_n_r1 <= ddr_ras_n_r; |
ddr_we_n_r1 <= ddr_we_n_r; |
ddr_cs_n_r1 <= ddr_cs_n_r; |
end // always @ (posedge clk0) |
|
always @(posedge clk0) |
init_state_r1_2t <= init_state_r1; |
|
// logic to toggle chip select. The chip_select is |
// clocked of clkdiv0 and will be asserted for |
// two clock cycles. |
always @(posedge clk0) begin |
if(rst0) |
ddr_cs_disable_r <= {CS_NUM{1'b0}}; |
else begin |
if(| ddr_cs_disable_r) |
ddr_cs_disable_r <= {CS_NUM{1'b0}}; |
else begin |
if (TWO_T_TIME_EN) begin |
if (init_state_r1_2t == INIT_PRECHARGE && init_done_r) |
ddr_cs_disable_r <= 'd3; |
else |
ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r1[chip_cnt_r]; |
end |
else begin |
if (init_state_r1 == INIT_PRECHARGE && init_done_r) |
ddr_cs_disable_r <= 'd3; |
else |
ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r[chip_cnt_r]; |
end |
end |
end |
end |
|
|
assign phy_init_addr = ddr_addr_r; |
assign phy_init_ba = ddr_ba_r; |
assign phy_init_cas_n = ddr_cas_n_r; |
assign phy_init_cke = ddr_cke_r; |
assign phy_init_ras_n = ddr_ras_n_r; |
assign phy_init_we_n = ddr_we_n_r; |
assign phy_init_cs_n = (TWO_T_TIME_EN) ? |
ddr_cs_n_r1 | ddr_cs_disable_r |
: ddr_cs_n_r| ddr_cs_disable_r; |
|
endmodule |
/ddr2_mig/ddr2_phy_io.v
0,0 → 1,353
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_io.v |
// /___/ /\ Date Last Modified: $Date: 2009/01/15 14:22:14 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module instantiates calibration logic, data, data strobe and the |
// data mask iobs. |
//Reference: |
//Revision History: |
// Rev 1.1 - DM_IOB instance made based on USE_DM_PORT value . PK. 25/6/08 |
// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 |
// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_io # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter CLK_WIDTH = 1, |
parameter USE_DM_PORT = 1, |
parameter DM_WIDTH = 9, |
parameter DQ_WIDTH = 72, |
parameter DQ_BITS = 7, |
parameter DQ_PER_DQS = 8, |
parameter DQS_BITS = 4, |
parameter DQS_WIDTH = 9, |
parameter HIGH_PERFORMANCE_MODE = "TRUE", |
parameter IODELAY_GRP = "IODELAY_MIG", |
parameter ODT_WIDTH = 1, |
parameter ADDITIVE_LAT = 0, |
parameter CAS_LAT = 5, |
parameter REG_ENABLE = 1, |
parameter CLK_PERIOD = 3000, |
parameter DDR_TYPE = 1, |
parameter SIM_ONLY = 0, |
parameter DEBUG_EN = 0, |
parameter FPGA_SPEED_GRADE = 2 |
) |
( |
input clk0, |
input clk90, |
input clkdiv0, |
input rst0, |
input rst90, |
input rstdiv0, |
input dm_ce, |
input [1:0] dq_oe_n, |
input dqs_oe_n, |
input dqs_rst_n, |
input [3:0] calib_start, |
input ctrl_rden, |
input phy_init_rden, |
input calib_ref_done, |
output [3:0] calib_done, |
output calib_ref_req, |
output [DQS_WIDTH-1:0] calib_rden, |
output [DQS_WIDTH-1:0] calib_rden_sel, |
input [DQ_WIDTH-1:0] wr_data_rise, |
input [DQ_WIDTH-1:0] wr_data_fall, |
input [(DQ_WIDTH/8)-1:0] mask_data_rise, |
input [(DQ_WIDTH/8)-1:0] mask_data_fall, |
output [(DQ_WIDTH)-1:0] rd_data_rise, |
output [(DQ_WIDTH)-1:0] rd_data_fall, |
output [CLK_WIDTH-1:0] ddr_ck, |
output [CLK_WIDTH-1:0] ddr_ck_n, |
output [DM_WIDTH-1:0] ddr_dm, |
inout [DQS_WIDTH-1:0] ddr_dqs, |
inout [DQS_WIDTH-1:0] ddr_dqs_n, |
inout [DQ_WIDTH-1:0] ddr_dq, |
// Debug signals (optional use) |
input dbg_idel_up_all, |
input dbg_idel_down_all, |
input dbg_idel_up_dq, |
input dbg_idel_down_dq, |
input dbg_idel_up_dqs, |
input dbg_idel_down_dqs, |
input dbg_idel_up_gate, |
input dbg_idel_down_gate, |
input [DQ_BITS-1:0] dbg_sel_idel_dq, |
input dbg_sel_all_idel_dq, |
input [DQS_BITS:0] dbg_sel_idel_dqs, |
input dbg_sel_all_idel_dqs, |
input [DQS_BITS:0] dbg_sel_idel_gate, |
input dbg_sel_all_idel_gate, |
output [3:0] dbg_calib_done, |
output [3:0] dbg_calib_err, |
output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, |
output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly |
); |
|
// ratio of # of physical DM outputs to bytes in data bus |
// may be different - e.g. if using x4 components |
localparam DM_TO_BYTE_RATIO = DM_WIDTH / (DQ_WIDTH/8); |
|
wire [CLK_WIDTH-1:0] ddr_ck_q; |
wire [DQS_WIDTH-1:0] delayed_dqs; |
wire [DQ_WIDTH-1:0] dlyce_dq; |
wire [DQS_WIDTH-1:0] dlyce_dqs; |
wire [DQS_WIDTH-1:0] dlyce_gate; |
wire [DQ_WIDTH-1:0] dlyinc_dq; |
wire [DQS_WIDTH-1:0] dlyinc_dqs; |
wire [DQS_WIDTH-1:0] dlyinc_gate; |
wire dlyrst_dq; |
wire dlyrst_dqs; |
wire [DQS_WIDTH-1:0] dlyrst_gate; |
wire [DQS_WIDTH-1:0] dq_ce; |
(* KEEP = "TRUE" *) wire [DQS_WIDTH-1:0] en_dqs /* synthesis syn_keep = 1 */; |
wire [DQS_WIDTH-1:0] rd_data_sel; |
|
//*************************************************************************** |
|
ddr2_phy_calib # |
( |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_BITS (DQ_BITS), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQS_BITS (DQS_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.CAS_LAT (CAS_LAT), |
.REG_ENABLE (REG_ENABLE), |
.CLK_PERIOD (CLK_PERIOD), |
.SIM_ONLY (SIM_ONLY), |
.DEBUG_EN (DEBUG_EN) |
) |
u_phy_calib |
( |
.clk (clk0), |
.clkdiv (clkdiv0), |
.rstdiv (rstdiv0), |
.calib_start (calib_start), |
.ctrl_rden (ctrl_rden), |
.phy_init_rden (phy_init_rden), |
.rd_data_rise (rd_data_rise), |
.rd_data_fall (rd_data_fall), |
.calib_ref_done (calib_ref_done), |
.calib_done (calib_done), |
.calib_ref_req (calib_ref_req), |
.calib_rden (calib_rden), |
.calib_rden_sel (calib_rden_sel), |
.dlyrst_dq (dlyrst_dq), |
.dlyce_dq (dlyce_dq), |
.dlyinc_dq (dlyinc_dq), |
.dlyrst_dqs (dlyrst_dqs), |
.dlyce_dqs (dlyce_dqs), |
.dlyinc_dqs (dlyinc_dqs), |
.dlyrst_gate (dlyrst_gate), |
.dlyce_gate (dlyce_gate), |
.dlyinc_gate (dlyinc_gate), |
.en_dqs (en_dqs), |
.rd_data_sel (rd_data_sel), |
.dbg_idel_up_all (dbg_idel_up_all), |
.dbg_idel_down_all (dbg_idel_down_all), |
.dbg_idel_up_dq (dbg_idel_up_dq), |
.dbg_idel_down_dq (dbg_idel_down_dq), |
.dbg_idel_up_dqs (dbg_idel_up_dqs), |
.dbg_idel_down_dqs (dbg_idel_down_dqs), |
.dbg_idel_up_gate (dbg_idel_up_gate), |
.dbg_idel_down_gate (dbg_idel_down_gate), |
.dbg_sel_idel_dq (dbg_sel_idel_dq), |
.dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), |
.dbg_sel_idel_dqs (dbg_sel_idel_dqs), |
.dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), |
.dbg_sel_idel_gate (dbg_sel_idel_gate), |
.dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), |
.dbg_calib_done (dbg_calib_done), |
.dbg_calib_err (dbg_calib_err), |
.dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), |
.dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), |
.dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), |
.dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), |
.dbg_calib_rden_dly (dbg_calib_rden_dly), |
.dbg_calib_gate_dly (dbg_calib_gate_dly) |
); |
|
//*************************************************************************** |
// Memory clock generation |
//*************************************************************************** |
|
genvar ck_i; |
generate |
for(ck_i = 0; ck_i < CLK_WIDTH; ck_i = ck_i+1) begin: gen_ck |
ODDR # |
( |
.SRTYPE ("SYNC"), |
.DDR_CLK_EDGE ("OPPOSITE_EDGE") |
) |
u_oddr_ck_i |
( |
.Q (ddr_ck_q[ck_i]), |
.C (clk0), |
.CE (1'b1), |
.D1 (1'b0), |
.D2 (1'b1), |
.R (1'b0), |
.S (1'b0) |
); |
// Can insert ODELAY here if required |
OBUFDS u_obuf_ck_i |
( |
.I (ddr_ck_q[ck_i]), |
.O (ddr_ck[ck_i]), |
.OB (ddr_ck_n[ck_i]) |
); |
end |
endgenerate |
|
//*************************************************************************** |
// DQS instances |
//*************************************************************************** |
|
genvar dqs_i; |
generate |
for(dqs_i = 0; dqs_i < DQS_WIDTH; dqs_i = dqs_i+1) begin: gen_dqs |
ddr2_phy_dqs_iob # |
( |
.DDR_TYPE (DDR_TYPE), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP) |
) |
u_iob_dqs |
( |
.clk0 (clk0), |
.clkdiv0 (clkdiv0), |
.rst0 (rst0), |
.dlyinc_dqs (dlyinc_dqs[dqs_i]), |
.dlyce_dqs (dlyce_dqs[dqs_i]), |
.dlyrst_dqs (dlyrst_dqs), |
.dlyinc_gate (dlyinc_gate[dqs_i]), |
.dlyce_gate (dlyce_gate[dqs_i]), |
.dlyrst_gate (dlyrst_gate[dqs_i]), |
.dqs_oe_n (dqs_oe_n), |
.dqs_rst_n (dqs_rst_n), |
.en_dqs (en_dqs[dqs_i]), |
.ddr_dqs (ddr_dqs[dqs_i]), |
.ddr_dqs_n (ddr_dqs_n[dqs_i]), |
.dq_ce (dq_ce[dqs_i]), |
.delayed_dqs (delayed_dqs[dqs_i]) |
); |
end |
endgenerate |
|
//*************************************************************************** |
// DM instances |
//*************************************************************************** |
|
genvar dm_i; |
generate |
if (USE_DM_PORT) begin: gen_dm_inst |
for(dm_i = 0; dm_i < DM_WIDTH; dm_i = dm_i+1) begin: gen_dm |
ddr2_phy_dm_iob u_iob_dm |
( |
.clk90 (clk90), |
.dm_ce (dm_ce), |
.mask_data_rise (mask_data_rise[dm_i/DM_TO_BYTE_RATIO]), |
.mask_data_fall (mask_data_fall[dm_i/DM_TO_BYTE_RATIO]), |
.ddr_dm (ddr_dm[dm_i]) |
); |
end |
end |
endgenerate |
|
//*************************************************************************** |
// DQ IOB instances |
//*************************************************************************** |
|
genvar dq_i; |
generate |
for(dq_i = 0; dq_i < DQ_WIDTH; dq_i = dq_i+1) begin: gen_dq |
ddr2_phy_dq_iob # |
( |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.IODELAY_GRP (IODELAY_GRP), |
.FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) |
) |
u_iob_dq |
( |
.clk0 (clk0), |
.clk90 (clk90), |
.clkdiv0 (clkdiv0), |
.rst90 (rst90), |
.dlyinc (dlyinc_dq[dq_i]), |
.dlyce (dlyce_dq[dq_i]), |
.dlyrst (dlyrst_dq), |
.dq_oe_n (dq_oe_n), |
.dqs (delayed_dqs[dq_i/DQ_PER_DQS]), |
.ce (dq_ce[dq_i/DQ_PER_DQS]), |
.rd_data_sel (rd_data_sel[dq_i/DQ_PER_DQS]), |
.wr_data_rise (wr_data_rise[dq_i]), |
.wr_data_fall (wr_data_fall[dq_i]), |
.rd_data_rise (rd_data_rise[dq_i]), |
.rd_data_fall (rd_data_fall[dq_i]), |
.ddr_dq (ddr_dq[dq_i]) |
); |
end |
endgenerate |
|
endmodule |
/ddr2_mig/ddr2_phy_ctl_io.v
0,0 → 1,302
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_ctl_io.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Thu Aug 24 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module puts the memory control signals like address, bank address, |
// row address strobe, column address strobe, write enable and clock enable |
// in the IOBs. |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_ctl_io # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter CKE_WIDTH = 1, |
parameter COL_WIDTH = 10, |
parameter CS_NUM = 1, |
parameter TWO_T_TIME_EN = 0, |
parameter CS_WIDTH = 1, |
parameter ODT_WIDTH = 1, |
parameter ROW_WIDTH = 14, |
parameter DDR_TYPE = 1 |
) |
( |
input clk0, |
input clk90, |
input rst0, |
input rst90, |
input [ROW_WIDTH-1:0] ctrl_addr, |
input [BANK_WIDTH-1:0] ctrl_ba, |
input ctrl_ras_n, |
input ctrl_cas_n, |
input ctrl_we_n, |
input [CS_NUM-1:0] ctrl_cs_n, |
input [ROW_WIDTH-1:0] phy_init_addr, |
input [BANK_WIDTH-1:0] phy_init_ba, |
input phy_init_ras_n, |
input phy_init_cas_n, |
input phy_init_we_n, |
input [CS_NUM-1:0] phy_init_cs_n, |
input [CKE_WIDTH-1:0] phy_init_cke, |
input phy_init_data_sel, |
input [CS_NUM-1:0] odt, |
output [ROW_WIDTH-1:0] ddr_addr, |
output [BANK_WIDTH-1:0] ddr_ba, |
output ddr_ras_n, |
output ddr_cas_n, |
output ddr_we_n, |
output [CKE_WIDTH-1:0] ddr_cke, |
output [CS_WIDTH-1:0] ddr_cs_n, |
output [ODT_WIDTH-1:0] ddr_odt |
); |
|
reg [ROW_WIDTH-1:0] addr_mux; |
reg [BANK_WIDTH-1:0] ba_mux; |
reg cas_n_mux; |
reg [CS_NUM-1:0] cs_n_mux; |
reg ras_n_mux; |
reg we_n_mux; |
|
|
|
//*************************************************************************** |
|
|
|
|
// MUX to choose from either PHY or controller for SDRAM control |
|
generate // in 2t timing mode the extra register stage cannot be used. |
if(TWO_T_TIME_EN) begin // the control signals are asserted for two cycles |
always @(*)begin |
if (phy_init_data_sel) begin |
addr_mux = ctrl_addr; |
ba_mux = ctrl_ba; |
cas_n_mux = ctrl_cas_n; |
cs_n_mux = ctrl_cs_n; |
ras_n_mux = ctrl_ras_n; |
we_n_mux = ctrl_we_n; |
end else begin |
addr_mux = phy_init_addr; |
ba_mux = phy_init_ba; |
cas_n_mux = phy_init_cas_n; |
cs_n_mux = phy_init_cs_n; |
ras_n_mux = phy_init_ras_n; |
we_n_mux = phy_init_we_n; |
end |
end |
end else begin |
always @(posedge clk0)begin // register the signals in non 2t mode |
if (phy_init_data_sel) begin |
addr_mux <= ctrl_addr; |
ba_mux <= ctrl_ba; |
cas_n_mux <= ctrl_cas_n; |
cs_n_mux <= ctrl_cs_n; |
ras_n_mux <= ctrl_ras_n; |
we_n_mux <= ctrl_we_n; |
end else begin |
addr_mux <= phy_init_addr; |
ba_mux <= phy_init_ba; |
cas_n_mux <= phy_init_cas_n; |
cs_n_mux <= phy_init_cs_n; |
ras_n_mux <= phy_init_ras_n; |
we_n_mux <= phy_init_we_n; |
end |
end |
end |
endgenerate |
|
//*************************************************************************** |
// Output flop instantiation |
// NOTE: Make sure all control/address flops are placed in IOBs |
//*************************************************************************** |
|
// RAS: = 1 at reset |
(* IOB = "FORCE" *) FDCPE u_ff_ras_n |
( |
.Q (ddr_ras_n), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (ras_n_mux), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
|
// CAS: = 1 at reset |
(* IOB = "FORCE" *) FDCPE u_ff_cas_n |
( |
.Q (ddr_cas_n), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (cas_n_mux), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
|
// WE: = 1 at reset |
(* IOB = "FORCE" *) FDCPE u_ff_we_n |
( |
.Q (ddr_we_n), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (we_n_mux), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
|
// CKE: = 0 at reset |
genvar cke_i; |
generate |
for (cke_i = 0; cke_i < CKE_WIDTH; cke_i = cke_i + 1) begin: gen_cke |
(* IOB = "FORCE" *) FDCPE u_ff_cke |
( |
.Q (ddr_cke[cke_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (rst0), |
.D (phy_init_cke[cke_i]), |
.PRE (1'b0) |
) /* synthesis syn_useioff = 1 */; |
end |
endgenerate |
|
// chip select: = 1 at reset |
// For unbuffered dimms the loading will be high. The chip select |
// can be asserted early if the loading is very high. The |
// code as is uses clock 0. If needed clock 270 can be used to |
// toggle chip select 1/4 clock cycle early. The code has |
// the clock 90 input for the early assertion of chip select. |
|
genvar cs_i; |
generate |
for(cs_i = 0; cs_i < CS_WIDTH; cs_i = cs_i + 1) begin: gen_cs_n |
if(TWO_T_TIME_EN) begin |
(* IOB = "FORCE" *) FDCPE u_ff_cs_n |
( |
.Q (ddr_cs_n[cs_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
end else begin // if (TWO_T_TIME_EN) |
(* IOB = "FORCE" *) FDCPE u_ff_cs_n |
( |
.Q (ddr_cs_n[cs_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), |
.PRE (rst0) |
) /* synthesis syn_useioff = 1 */; |
end // else: !if(TWO_T_TIME_EN) |
end |
endgenerate |
|
// address: = X at reset |
genvar addr_i; |
generate |
for (addr_i = 0; addr_i < ROW_WIDTH; addr_i = addr_i + 1) begin: gen_addr |
(* IOB = "FORCE" *) FDCPE u_ff_addr |
( |
.Q (ddr_addr[addr_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (addr_mux[addr_i]), |
.PRE (1'b0) |
) /* synthesis syn_useioff = 1 */; |
end |
endgenerate |
|
// bank address = X at reset |
genvar ba_i; |
generate |
for (ba_i = 0; ba_i < BANK_WIDTH; ba_i = ba_i + 1) begin: gen_ba |
(* IOB = "FORCE" *) FDCPE u_ff_ba |
( |
.Q (ddr_ba[ba_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (1'b0), |
.D (ba_mux[ba_i]), |
.PRE (1'b0) |
) /* synthesis syn_useioff = 1 */; |
end |
endgenerate |
|
// ODT control = 0 at reset |
genvar odt_i; |
generate |
if (DDR_TYPE > 0) begin: gen_odt_ddr2 |
for (odt_i = 0; odt_i < ODT_WIDTH; odt_i = odt_i + 1) begin: gen_odt |
(* IOB = "FORCE" *) FDCPE u_ff_odt |
( |
.Q (ddr_odt[odt_i]), |
.C (clk0), |
.CE (1'b1), |
.CLR (rst0), |
.D (odt[(odt_i*CS_NUM)/ODT_WIDTH]), |
.PRE (1'b0) |
) /* synthesis syn_useioff = 1 */; |
end |
end |
endgenerate |
|
endmodule |
/ddr2_mig/ddr2_phy_calib.v
0,0 → 1,2349
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_phy_calib.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Thu Aug 10 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module handles calibration after memory initialization. |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_phy_calib # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter DQ_WIDTH = 72, |
parameter DQ_BITS = 7, |
parameter DQ_PER_DQS = 8, |
parameter DQS_BITS = 4, |
parameter DQS_WIDTH = 9, |
parameter ADDITIVE_LAT = 0, |
parameter CAS_LAT = 5, |
parameter REG_ENABLE = 1, |
parameter CLK_PERIOD = 3000, |
parameter SIM_ONLY = 0, |
parameter DEBUG_EN = 0 |
) |
( |
input clk, |
input clkdiv, |
input rstdiv, |
input [3:0] calib_start, |
input ctrl_rden, |
input phy_init_rden, |
input [DQ_WIDTH-1:0] rd_data_rise, |
input [DQ_WIDTH-1:0] rd_data_fall, |
input calib_ref_done, |
output reg [3:0] calib_done, |
output reg calib_ref_req, |
output [DQS_WIDTH-1:0] calib_rden, |
output reg [DQS_WIDTH-1:0] calib_rden_sel, |
output reg dlyrst_dq, |
output reg [DQ_WIDTH-1:0] dlyce_dq, |
output reg [DQ_WIDTH-1:0] dlyinc_dq, |
output reg dlyrst_dqs, |
output reg [DQS_WIDTH-1:0] dlyce_dqs, |
output reg [DQS_WIDTH-1:0] dlyinc_dqs, |
output reg [DQS_WIDTH-1:0] dlyrst_gate, |
output reg [DQS_WIDTH-1:0] dlyce_gate, |
output reg [DQS_WIDTH-1:0] dlyinc_gate, |
output [DQS_WIDTH-1:0] en_dqs, |
output [DQS_WIDTH-1:0] rd_data_sel, |
// Debug signals (optional use) |
input dbg_idel_up_all, |
input dbg_idel_down_all, |
input dbg_idel_up_dq, |
input dbg_idel_down_dq, |
input dbg_idel_up_dqs, |
input dbg_idel_down_dqs, |
input dbg_idel_up_gate, |
input dbg_idel_down_gate, |
input [DQ_BITS-1:0] dbg_sel_idel_dq, |
input dbg_sel_all_idel_dq, |
input [DQS_BITS:0] dbg_sel_idel_dqs, |
input dbg_sel_all_idel_dqs, |
input [DQS_BITS:0] dbg_sel_idel_gate, |
input dbg_sel_all_idel_gate, |
output [3:0] dbg_calib_done, |
output [3:0] dbg_calib_err, |
output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, |
output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, |
output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, |
output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly |
); |
|
// minimum time (in IDELAY taps) for which capture data must be stable for |
// algorithm to consider |
localparam MIN_WIN_SIZE = 5; |
// IDEL_SET_VAL = (# of cycles - 1) to wait after changing IDELAY value |
// we only have to wait enough for input with new IDELAY value to |
// propagate through pipeline stages. |
localparam IDEL_SET_VAL = 3'b111; |
// # of clock cycles to delay read enable to determine if read data pattern |
// is correct for stage 3/4 (RDEN, DQS gate) calibration |
localparam CALIB_RDEN_PIPE_LEN = 31; |
// translate CAS latency into number of clock cycles for read valid delay |
// determination. Really only needed for CL = 2.5 (set to 2) |
localparam CAS_LAT_RDEN = (CAS_LAT == 25) ? 2 : CAS_LAT; |
// an SRL32 is used to delay CTRL_RDEN to generate read valid signal. This |
// is min possible value delay through SRL32 can be |
localparam RDEN_BASE_DELAY = CAS_LAT_RDEN + ADDITIVE_LAT + REG_ENABLE; |
// an SRL32 is used to delay the CTRL_RDEN from the read postamble DQS |
// gate. This is min possible value the SRL32 delay can be: |
// - Delay from end of deassertion of CTRL_RDEN to last falling edge of |
// read burst = 3.5 (CTRL_RDEN -> CAS delay) + 3 (min CAS latency) = 6.5 |
// - Minimum time for DQS gate circuit to be generated: |
// * 1 cyc to register CTRL_RDEN from controller |
// * 1 cyc after RDEN_CTRL falling edge |
// * 1 cyc min through SRL32 |
// * 1 cyc through SRL32 output flop |
// * 0 (<1) cyc of synchronization to DQS domain via IDELAY |
// * 1 cyc of delay through IDDR to generate CE to DQ IDDR's |
// Total = 5 cyc < 6.5 cycles |
// The total should be less than 5.5 cycles to account prop delays |
// adding one cycle to the synchronization time via the IDELAY. |
// NOTE: Value differs because of optional pipeline register added |
// for case of RDEN_BASE_DELAY > 3 to improve timing |
localparam GATE_BASE_DELAY = RDEN_BASE_DELAY - 3; |
localparam GATE_BASE_INIT = (GATE_BASE_DELAY <= 1) ? 0 : GATE_BASE_DELAY; |
// used for RDEN calibration: difference between shift value used during |
// calibration, and shift value for actual RDEN SRL. Only applies when |
// RDEN edge is immediately captured by CLKDIV0. If not (depends on phase |
// of CLK0 and CLKDIV0 when RDEN is asserted), then add 1 to this value. |
localparam CAL3_RDEN_SRL_DLY_DELTA = 6; |
// fix minimum value of DQS to be 1 to handle the case where's there's only |
// one DQS group. We could also enforce that user always inputs minimum |
// value of 1 for DQS_BITS (even when DQS_WIDTH=1). Leave this as safeguard |
// Assume we don't have to do this for DQ, DQ_WIDTH always > 1 |
localparam DQS_BITS_FIX = (DQS_BITS == 0) ? 1 : DQS_BITS; |
// how many taps to "pre-delay" DQ before stg 1 calibration - not needed for |
// current calibration, but leave for debug |
localparam DQ_IDEL_INIT = 6'b000000; |
// # IDELAY taps per bit time (i.e. half cycle). Limit to 63. |
localparam integer BIT_TIME_TAPS = (CLK_PERIOD/150 < 64) ? |
CLK_PERIOD/150 : 63; |
|
// used in various places during stage 4 cal: (1) determines maximum taps |
// to increment when finding right edge, (2) amount to decrement after |
// finding left edge, (3) amount to increment after finding right edge |
localparam CAL4_IDEL_BIT_VAL = (BIT_TIME_TAPS >= 6'b100000) ? |
6'b100000 : BIT_TIME_TAPS; |
|
localparam CAL1_IDLE = 4'h0; |
localparam CAL1_INIT = 4'h1; |
localparam CAL1_INC_IDEL = 4'h2; |
localparam CAL1_FIND_FIRST_EDGE = 4'h3; |
localparam CAL1_FIRST_EDGE_IDEL_WAIT = 4'h4; |
localparam CAL1_FOUND_FIRST_EDGE_WAIT = 4'h5; |
localparam CAL1_FIND_SECOND_EDGE = 4'h6; |
localparam CAL1_SECOND_EDGE_IDEL_WAIT = 4'h7; |
localparam CAL1_CALC_IDEL = 4'h8; |
localparam CAL1_DEC_IDEL = 4'h9; |
localparam CAL1_DONE = 4'hA; |
|
localparam CAL2_IDLE = 4'h0; |
localparam CAL2_INIT = 4'h1; |
localparam CAL2_INIT_IDEL_WAIT = 4'h2; |
localparam CAL2_FIND_EDGE_POS = 4'h3; |
localparam CAL2_FIND_EDGE_IDEL_WAIT_POS = 4'h4; |
localparam CAL2_FIND_EDGE_NEG = 4'h5; |
localparam CAL2_FIND_EDGE_IDEL_WAIT_NEG = 4'h6; |
localparam CAL2_DEC_IDEL = 4'h7; |
localparam CAL2_DONE = 4'h8; |
|
localparam CAL3_IDLE = 3'h0; |
localparam CAL3_INIT = 3'h1; |
localparam CAL3_DETECT = 3'h2; |
localparam CAL3_RDEN_PIPE_CLR_WAIT = 3'h3; |
localparam CAL3_DONE = 3'h4; |
|
localparam CAL4_IDLE = 3'h0; |
localparam CAL4_INIT = 3'h1; |
localparam CAL4_FIND_WINDOW = 3'h2; |
localparam CAL4_FIND_EDGE = 3'h3; |
localparam CAL4_IDEL_WAIT = 3'h4; |
localparam CAL4_RDEN_PIPE_CLR_WAIT = 3'h5; |
localparam CAL4_ADJ_IDEL = 3'h6; |
localparam CAL4_DONE = 3'h7; |
|
integer i, j; |
|
reg [5:0] cal1_bit_time_tap_cnt; |
reg [1:0] cal1_data_chk_last; |
reg cal1_data_chk_last_valid; |
reg [1:0] cal1_data_chk_r; |
reg cal1_dlyce_dq; |
reg cal1_dlyinc_dq; |
reg cal1_dqs_dq_init_phase; |
reg cal1_detect_edge; |
reg cal1_detect_stable; |
reg cal1_found_second_edge; |
reg cal1_found_rising; |
reg cal1_found_window; |
reg cal1_first_edge_done; |
reg [5:0] cal1_first_edge_tap_cnt; |
reg [6:0] cal1_idel_dec_cnt; |
reg [5:0] cal1_idel_inc_cnt; |
reg [5:0] cal1_idel_max_tap; |
reg cal1_idel_max_tap_we; |
reg [5:0] cal1_idel_tap_cnt; |
reg cal1_idel_tap_limit_hit; |
reg [6:0] cal1_low_freq_idel_dec; |
reg cal1_ref_req; |
wire cal1_refresh; |
reg [3:0] cal1_state; |
reg [3:0] cal1_window_cnt; |
reg cal2_curr_sel; |
wire cal2_detect_edge; |
reg cal2_dlyce_dqs; |
reg cal2_dlyinc_dqs; |
reg [5:0] cal2_idel_dec_cnt; |
reg [5:0] cal2_idel_tap_cnt; |
reg [5:0] cal2_idel_tap_limit; |
reg cal2_idel_tap_limit_hit; |
reg cal2_rd_data_fall_last_neg; |
reg cal2_rd_data_fall_last_pos; |
reg cal2_rd_data_last_valid_neg; |
reg cal2_rd_data_last_valid_pos; |
reg cal2_rd_data_rise_last_neg; |
reg cal2_rd_data_rise_last_pos; |
reg [DQS_WIDTH-1:0] cal2_rd_data_sel; |
wire cal2_rd_data_sel_edge; |
reg [DQS_WIDTH-1:0] cal2_rd_data_sel_r; |
reg cal2_ref_req; |
reg [3:0] cal2_state; |
reg cal3_data_match; |
reg cal3_data_match_stgd; |
wire cal3_data_valid; |
wire cal3_match_found; |
wire [4:0] cal3_rden_dly; |
reg [4:0] cal3_rden_srl_a; |
reg [2:0] cal3_state; |
wire cal4_data_good; |
reg cal4_data_match; |
reg cal4_data_match_stgd; |
wire cal4_data_valid; |
reg cal4_dlyce_gate; |
reg cal4_dlyinc_gate; |
reg cal4_dlyrst_gate; |
reg [4:0] cal4_gate_srl_a; |
reg [5:0] cal4_idel_adj_cnt; |
reg cal4_idel_adj_inc; |
reg cal4_idel_bit_tap; |
reg [5:0] cal4_idel_tap_cnt; |
reg cal4_idel_max_tap; |
reg [4:0] cal4_rden_srl_a; |
reg cal4_ref_req; |
reg cal4_seek_left; |
reg cal4_stable_window; |
reg [2:0] cal4_state; |
reg [3:0] cal4_window_cnt; |
reg [3:0] calib_done_tmp; // only for stg1/2/4 |
reg calib_ctrl_gate_pulse_r; |
reg calib_ctrl_rden; |
reg calib_ctrl_rden_r; |
wire calib_ctrl_rden_negedge; |
reg calib_ctrl_rden_negedge_r; |
reg [3:0] calib_done_r; |
reg [3:0] calib_err; |
reg [1:0] calib_err_2; |
wire calib_init_gate_pulse; |
reg calib_init_gate_pulse_r; |
reg calib_init_gate_pulse_r1; |
reg calib_init_rden; |
reg calib_init_rden_r; |
reg [4:0] calib_rden_srl_a; |
wire [4:0] calib_rden_srl_a_r; |
reg [(5*DQS_WIDTH)-1:0] calib_rden_dly; |
reg calib_rden_edge_r; |
reg [4:0] calib_rden_pipe_cnt; |
wire calib_rden_srl_out; |
wire calib_rden_srl_out_r; |
reg calib_rden_srl_out_r1; |
reg calib_rden_valid; |
reg calib_rden_valid_stgd; |
reg [DQ_BITS-1:0] count_dq; |
reg [DQS_BITS_FIX-1:0] count_dqs; |
reg [DQS_BITS_FIX-1:0] count_gate; |
reg [DQS_BITS_FIX-1:0] count_rden; |
reg ctrl_rden_r; |
wire dlyce_or; |
reg [(5*DQS_WIDTH)-1:0] gate_dly; |
wire [(5*DQS_WIDTH)-1:0] gate_dly_r; |
wire gate_srl_in; |
wire [DQS_WIDTH-1:0] gate_srl_out; |
wire [DQS_WIDTH-1:0] gate_srl_out_r; |
reg [2:0] idel_set_cnt; |
wire idel_set_wait; |
reg [DQ_BITS-1:0] next_count_dq; |
reg [DQS_BITS_FIX-1:0] next_count_dqs; |
reg [DQS_BITS_FIX-1:0] next_count_gate; |
reg phy_init_rden_r; |
reg phy_init_rden_r1; |
reg [DQ_WIDTH-1:0] rd_data_fall_1x_r; |
reg [DQS_WIDTH-1:0] rd_data_fall_1x_r1; |
reg [DQS_WIDTH-1:0] rd_data_fall_2x_r; |
wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1; |
wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2; |
reg [DQ_WIDTH-1:0] rd_data_rise_1x_r; |
reg [DQS_WIDTH-1:0] rd_data_rise_1x_r1; |
reg [DQS_WIDTH-1:0] rd_data_rise_2x_r; |
wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1; |
wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2; |
reg rdd_fall_q1; |
reg rdd_fall_q1_r; |
reg rdd_fall_q1_r1; |
reg rdd_fall_q2; |
reg rdd_fall_q2_r; |
reg rdd_rise_q1; |
reg rdd_rise_q1_r; |
reg rdd_rise_q1_r1; |
reg rdd_rise_q2; |
reg rdd_rise_q2_r; |
reg [DQS_BITS_FIX-1:0] rdd_mux_sel; |
reg rden_dec; |
reg [(5*DQS_WIDTH)-1:0] rden_dly; |
wire [(5*DQS_WIDTH)-1:0] rden_dly_r; |
reg [4:0] rden_dly_0; |
reg rden_inc; |
reg [DQS_WIDTH-1:0] rden_mux; |
wire [DQS_WIDTH-1:0] rden_srl_out; |
|
// Debug |
integer x; |
reg [5:0] dbg_dq_tap_cnt [DQ_WIDTH-1:0]; |
reg [5:0] dbg_dqs_tap_cnt [DQS_WIDTH-1:0]; |
reg [5:0] dbg_gate_tap_cnt [DQS_WIDTH-1:0]; |
|
//*************************************************************************** |
// Debug output ("dbg_phy_calib_*") |
// NOTES: |
// 1. All debug outputs coming out of PHY_CALIB are clocked off CLKDIV0, |
// although they are also static after calibration is complete. This |
// means the user can either connect them to a Chipscope ILA, or to |
// either a sync/async VIO input block. Using an async VIO has the |
// advantage of not requiring these paths to meet cycle-to-cycle timing. |
// 2. The widths of most of these debug buses are dependent on the # of |
// DQS/DQ bits (e.g. dq_tap_cnt width = 6 * (# of DQ bits) |
// SIGNAL DESCRIPTION: |
// 1. calib_done: 4 bits - each one asserted as each phase of calibration |
// is completed. |
// 2. calib_err: 4 bits - each one asserted when a calibration error |
// encountered for that stage. Some of these bits may not |
// be used (not all cal stages report an error). |
// 3. dq_tap_cnt: final IDELAY tap counts for all DQ IDELAYs |
// 4. dqs_tap_cnt: final IDELAY tap counts for all DQS IDELAYs |
// 5. gate_tap_cnt: final IDELAY tap counts for all DQS gate |
// synchronization IDELAYs |
// 6. rd_data_sel: final read capture MUX (either "positive" or "negative" |
// edge capture) settings for all DQS groups |
// 7. rden_dly: related to # of cycles after issuing a read until when |
// read data is valid - for all DQS groups |
// 8. gate_dly: related to # of cycles after issuing a read until when |
// clock enable for all DQ's is deasserted to prevent |
// effect of DQS postamble glitch - for all DQS groups |
//*************************************************************************** |
|
//***************************************************************** |
// Record IDELAY tap values by "snooping" IDELAY control signals |
//***************************************************************** |
|
// record DQ IDELAY tap values |
genvar dbg_dq_tc_i; |
generate |
for (dbg_dq_tc_i = 0; dbg_dq_tc_i < DQ_WIDTH; |
dbg_dq_tc_i = dbg_dq_tc_i + 1) begin: gen_dbg_dq_tap_cnt |
assign dbg_calib_dq_tap_cnt[(6*dbg_dq_tc_i)+5:(6*dbg_dq_tc_i)] |
= dbg_dq_tap_cnt[dbg_dq_tc_i]; |
always @(posedge clkdiv) |
if (rstdiv | dlyrst_dq) |
dbg_dq_tap_cnt[dbg_dq_tc_i] <= 6'b000000; |
else |
if (dlyce_dq[dbg_dq_tc_i]) |
if (dlyinc_dq[dbg_dq_tc_i]) |
dbg_dq_tap_cnt[dbg_dq_tc_i] |
<= dbg_dq_tap_cnt[dbg_dq_tc_i] + 1; |
else |
dbg_dq_tap_cnt[dbg_dq_tc_i] |
<= dbg_dq_tap_cnt[dbg_dq_tc_i] - 1; |
end |
endgenerate |
|
// record DQS IDELAY tap values |
genvar dbg_dqs_tc_i; |
generate |
for (dbg_dqs_tc_i = 0; dbg_dqs_tc_i < DQS_WIDTH; |
dbg_dqs_tc_i = dbg_dqs_tc_i + 1) begin: gen_dbg_dqs_tap_cnt |
assign dbg_calib_dqs_tap_cnt[(6*dbg_dqs_tc_i)+5:(6*dbg_dqs_tc_i)] |
= dbg_dqs_tap_cnt[dbg_dqs_tc_i]; |
always @(posedge clkdiv) |
if (rstdiv | dlyrst_dqs) |
dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= 6'b000000; |
else |
if (dlyce_dqs[dbg_dqs_tc_i]) |
if (dlyinc_dqs[dbg_dqs_tc_i]) |
dbg_dqs_tap_cnt[dbg_dqs_tc_i] |
<= dbg_dqs_tap_cnt[dbg_dqs_tc_i] + 1; |
else |
dbg_dqs_tap_cnt[dbg_dqs_tc_i] |
<= dbg_dqs_tap_cnt[dbg_dqs_tc_i] - 1; |
end |
endgenerate |
|
// record DQS gate IDELAY tap values |
genvar dbg_gate_tc_i; |
generate |
for (dbg_gate_tc_i = 0; dbg_gate_tc_i < DQS_WIDTH; |
dbg_gate_tc_i = dbg_gate_tc_i + 1) begin: gen_dbg_gate_tap_cnt |
assign dbg_calib_gate_tap_cnt[(6*dbg_gate_tc_i)+5:(6*dbg_gate_tc_i)] |
= dbg_gate_tap_cnt[dbg_gate_tc_i]; |
always @(posedge clkdiv) |
if (rstdiv | dlyrst_gate[dbg_gate_tc_i]) |
dbg_gate_tap_cnt[dbg_gate_tc_i] <= 6'b000000; |
else |
if (dlyce_gate[dbg_gate_tc_i]) |
if (dlyinc_gate[dbg_gate_tc_i]) |
dbg_gate_tap_cnt[dbg_gate_tc_i] |
<= dbg_gate_tap_cnt[dbg_gate_tc_i] + 1; |
else |
dbg_gate_tap_cnt[dbg_gate_tc_i] |
<= dbg_gate_tap_cnt[dbg_gate_tc_i] - 1; |
end |
endgenerate |
|
assign dbg_calib_done = calib_done; |
assign dbg_calib_err = calib_err; |
assign dbg_calib_rd_data_sel = cal2_rd_data_sel; |
assign dbg_calib_rden_dly = rden_dly; |
assign dbg_calib_gate_dly = gate_dly; |
|
//*************************************************************************** |
// Read data pipelining, and read data "ISERDES" data width expansion |
//*************************************************************************** |
|
// For all data bits, register incoming capture data to slow clock to improve |
// timing. Adding single pipeline stage does not affect functionality (as |
// long as we make sure to wait extra clock cycle after changing DQ IDELAY) |
// Also note in this case that we're "missing" every other clock cycle's |
// worth of data capture since we're sync'ing to the slow clock. This is |
// fine for stage 1 and stage 2 cal, but not for stage 3 and 4 (see below |
// for different circuit to handle those stages) |
always @(posedge clkdiv) begin |
rd_data_rise_1x_r <= rd_data_rise; |
rd_data_fall_1x_r <= rd_data_fall; |
end |
|
// For every DQ_PER_DQS bit, generate what is essentially a ISERDES-type |
// data width expander. Will need this for stage 3 and 4 cal, where we need |
// to compare data over consecutive clock cycles. We can also use this for |
// stage 2 as well (stage 2 doesn't require every bit to be looked at, only |
// one bit per DQS group) |
genvar rdd_i; |
generate |
for (rdd_i = 0; rdd_i < DQS_WIDTH; rdd_i = rdd_i + 1) begin: gen_rdd |
// first stage: keep data in fast clk domain. Store data over two |
// consecutive clock cycles for rise/fall data for proper transfer |
// to slow clock domain |
always @(posedge clk) begin |
rd_data_rise_2x_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)]; |
rd_data_fall_2x_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)]; |
end |
// second stage, register first stage to slow clock domain, 2nd stage |
// consists of both these flops, and the rd_data_rise_1x_r flops |
always @(posedge clkdiv) begin |
rd_data_rise_1x_r1[rdd_i] <= rd_data_rise_2x_r[rdd_i]; |
rd_data_fall_1x_r1[rdd_i] <= rd_data_fall_2x_r[rdd_i]; |
end |
// now we have four outputs - representing rise/fall outputs over last |
// 2 fast clock cycles. However, the ordering these represent can either |
// be: (1) Q2 = data @ time = n, Q1 = data @ time = n+1, or (2) |
// Q2 = data @ time = n - 1, Q1 = data @ time = n (and data at [Q1,Q2] |
// is "staggered") - leave it up to the stage of calibration using this |
// to figure out which is which, if they care at all (e.g. stage 2 cal |
// doesn't care about the ordering) |
assign rd_data_rise_chk_q1[rdd_i] |
= rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)]; |
assign rd_data_rise_chk_q2[rdd_i] |
= rd_data_rise_1x_r1[rdd_i]; |
assign rd_data_fall_chk_q1[rdd_i] |
= rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)]; |
assign rd_data_fall_chk_q2[rdd_i] |
= rd_data_fall_1x_r1[rdd_i]; |
end |
endgenerate |
|
//***************************************************************** |
// Outputs of these simplified ISERDES circuits then feed MUXes based on |
// which DQ the current calibration algorithm needs to look at |
//***************************************************************** |
|
// generate MUX control; assume that adding an extra pipeline stage isn't |
// an issue - whatever stage cal logic is using output of MUX will wait |
// enough time after changing it |
always @(posedge clkdiv) begin |
(* full_case, parallel_case *) case (calib_done[2:0]) |
3'b001: rdd_mux_sel <= next_count_dqs; |
3'b011: rdd_mux_sel <= count_rden; |
3'b111: rdd_mux_sel <= next_count_gate; |
endcase |
end |
|
always @(posedge clkdiv) begin |
rdd_rise_q1 <= rd_data_rise_chk_q1[rdd_mux_sel]; |
rdd_rise_q2 <= rd_data_rise_chk_q2[rdd_mux_sel]; |
rdd_fall_q1 <= rd_data_fall_chk_q1[rdd_mux_sel]; |
rdd_fall_q2 <= rd_data_fall_chk_q2[rdd_mux_sel]; |
end |
|
//*************************************************************************** |
// Demultiplexor to control (reset, increment, decrement) IDELAY tap values |
// For DQ: |
// STG1: for per-bit-deskew, only inc/dec the current DQ. For non-per |
// deskew, increment all bits in the current DQS set |
// STG2: inc/dec all DQ's in the current DQS set. |
// NOTE: Nice to add some error checking logic here (or elsewhere in the |
// code) to check if logic attempts to overflow tap value |
//*************************************************************************** |
|
// don't use DLYRST to reset value of IDELAY after reset. Need to change this |
// if we want to allow user to recalibrate after initial reset |
always @(posedge clkdiv) |
if (rstdiv) begin |
dlyrst_dq <= 1'b1; |
dlyrst_dqs <= 1'b1; |
end else begin |
dlyrst_dq <= 1'b0; |
dlyrst_dqs <= 1'b0; |
end |
|
always @(posedge clkdiv) begin |
if (rstdiv) begin |
dlyce_dq <= 'b0; |
dlyinc_dq <= 'b0; |
dlyce_dqs <= 'b0; |
dlyinc_dqs <= 'b0; |
end else begin |
dlyce_dq <= 'b0; |
dlyinc_dq <= 'b0; |
dlyce_dqs <= 'b0; |
dlyinc_dqs <= 'b0; |
|
// stage 1 cal: change only specified DQ |
if (cal1_dlyce_dq) begin |
if (SIM_ONLY == 0) begin |
dlyce_dq[count_dq] <= 1'b1; |
dlyinc_dq[count_dq] <= cal1_dlyinc_dq; |
end else begin |
// if simulation, then calibrate only first DQ, apply results |
// to all DQs (i.e. assume delay on all DQs is the same) |
for (i = 0; i < DQ_WIDTH; i = i + 1) begin: loop_sim_dq_dly |
dlyce_dq[i] <= 1'b1; |
dlyinc_dq[i] <= cal1_dlyinc_dq; |
end |
end |
end else if (cal2_dlyce_dqs) begin |
// stage 2 cal: change DQS and all corresponding DQ's |
if (SIM_ONLY == 0) begin |
dlyce_dqs[count_dqs] <= 1'b1; |
dlyinc_dqs[count_dqs] <= cal2_dlyinc_dqs; |
for (i = 0; i < DQ_PER_DQS; i = i + 1) begin: loop_dqs_dly |
dlyce_dq[(DQ_PER_DQS*count_dqs)+i] <= 1'b1; |
dlyinc_dq[(DQ_PER_DQS*count_dqs)+i] <= cal2_dlyinc_dqs; |
end |
end else begin |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_dqs_dly |
// if simulation, then calibrate only first DQS |
dlyce_dqs[i] <= 1'b1; |
dlyinc_dqs[i] <= cal2_dlyinc_dqs; |
for (j = 0; j < DQ_PER_DQS; j = j + 1) begin: loop_sim_dq_dqs_dly |
dlyce_dq[(DQ_PER_DQS*i)+j] <= 1'b1; |
dlyinc_dq[(DQ_PER_DQS*i)+j] <= cal2_dlyinc_dqs; |
end |
end |
end |
end else if (DEBUG_EN != 0) begin |
// DEBUG: allow user to vary IDELAY tap settings |
// For DQ IDELAY taps |
if (dbg_idel_up_all || dbg_idel_down_all || |
dbg_sel_all_idel_dq) begin |
for (x = 0; x < DQ_WIDTH; x = x + 1) begin: loop_dly_inc_dq |
dlyce_dq[x] <= dbg_idel_up_all | dbg_idel_down_all | |
dbg_idel_up_dq | dbg_idel_down_dq; |
dlyinc_dq[x] <= dbg_idel_up_all | dbg_idel_up_dq; |
end |
end else begin |
dlyce_dq <= 'b0; |
dlyce_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq | |
dbg_idel_down_dq; |
dlyinc_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq; |
end |
// For DQS IDELAY taps |
if (dbg_idel_up_all || dbg_idel_down_all || |
dbg_sel_all_idel_dqs) begin |
for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_dqs |
dlyce_dqs[x] <= dbg_idel_up_all | dbg_idel_down_all | |
dbg_idel_up_dqs | dbg_idel_down_dqs; |
dlyinc_dqs[x] <= dbg_idel_up_all | dbg_idel_up_dqs; |
end |
end else begin |
dlyce_dqs <= 'b0; |
dlyce_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs | |
dbg_idel_down_dqs; |
dlyinc_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs; |
end |
end |
end |
end |
|
// GATE synchronization is handled directly by Stage 4 calibration FSM |
always @(posedge clkdiv) |
if (rstdiv) begin |
dlyrst_gate <= {DQS_WIDTH{1'b1}}; |
dlyce_gate <= {DQS_WIDTH{1'b0}}; |
dlyinc_gate <= {DQS_WIDTH{1'b0}}; |
end else begin |
dlyrst_gate <= {DQS_WIDTH{1'b0}}; |
dlyce_gate <= {DQS_WIDTH{1'b0}}; |
dlyinc_gate <= {DQS_WIDTH{1'b0}}; |
|
if (cal4_dlyrst_gate) begin |
if (SIM_ONLY == 0) |
dlyrst_gate[count_gate] <= 1'b1; |
else |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly_rst |
dlyrst_gate[i] <= 1'b1; |
end |
end |
|
if (cal4_dlyce_gate) begin |
if (SIM_ONLY == 0) begin |
dlyce_gate[count_gate] <= 1'b1; |
dlyinc_gate[count_gate] <= cal4_dlyinc_gate; |
end else begin |
// if simulation, then calibrate only first gate |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly |
dlyce_gate[i] <= 1'b1; |
dlyinc_gate[i] <= cal4_dlyinc_gate; |
end |
end |
end else if (DEBUG_EN != 0) begin |
// DEBUG: allow user to vary IDELAY tap settings |
if (dbg_idel_up_all || dbg_idel_down_all || |
dbg_sel_all_idel_gate) begin |
for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_gate |
dlyce_gate[x] <= dbg_idel_up_all | dbg_idel_down_all | |
dbg_idel_up_gate | dbg_idel_down_gate; |
dlyinc_gate[x] <= dbg_idel_up_all | dbg_idel_up_gate; |
end |
end else begin |
dlyce_gate <= {DQS_WIDTH{1'b0}}; |
dlyce_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate | |
dbg_idel_down_gate; |
dlyinc_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate; |
end |
end |
end |
|
//*************************************************************************** |
// signal to tell calibration state machines to wait and give IDELAY time to |
// settle after it's value is changed (both time for IDELAY chain to settle, |
// and for settled output to propagate through ISERDES). For general use: use |
// for any calibration state machines that modify any IDELAY. |
// Should give at least enough time for IDELAY output to settle (technically |
// for V5, this should be "glitchless" when IDELAY taps are changed, so don't |
// need any time here), and also time for new data to propagate through both |
// ISERDES and the "RDD" MUX + associated pipelining |
// For now, give very "generous" delay - doesn't really matter since only |
// needed during calibration |
//*************************************************************************** |
|
// determine if calibration polarity has changed |
always @(posedge clkdiv) |
cal2_rd_data_sel_r <= cal2_rd_data_sel; |
|
assign cal2_rd_data_sel_edge = |(cal2_rd_data_sel ^ cal2_rd_data_sel_r); |
|
// combine requests to modify any of the IDELAYs into one. Also when second |
// stage capture "edge" polarity is changed (IDELAY isn't changed in this |
// case, but use the same counter to stall cal logic) |
assign dlyce_or = cal1_dlyce_dq | |
cal2_dlyce_dqs | |
cal2_rd_data_sel_edge | |
cal4_dlyce_gate | |
cal4_dlyrst_gate; |
|
// SYN_NOTE: Can later recode to avoid combinational path |
assign idel_set_wait = dlyce_or || (idel_set_cnt != IDEL_SET_VAL); |
|
always @(posedge clkdiv) |
if (rstdiv) |
idel_set_cnt <= 4'b0000; |
else if (dlyce_or) |
idel_set_cnt <= 4'b0000; |
else if (idel_set_cnt != IDEL_SET_VAL) |
idel_set_cnt <= idel_set_cnt + 1; |
|
// generate request to PHY_INIT logic to issue auto-refresh |
// used by certain states to force prech/auto-refresh part way through |
// calibration to avoid a tRAS violation (which will happen if that |
// stage of calibration lasts long enough). This signal must meet the |
// following requirements: (1) only transition from 0->1 when the refresh |
// request is needed, (2) stay at 1 and only transition 1->0 when |
// CALIB_REF_DONE is asserted |
always @(posedge clkdiv) |
if (rstdiv) |
calib_ref_req <= 1'b0; |
else |
calib_ref_req <= cal1_ref_req | cal2_ref_req | cal4_ref_req; |
|
// stage 1 calibration requests auto-refresh every 4 bits |
generate |
if (DQ_BITS < 2) begin: gen_cal1_refresh_dq_lte4 |
assign cal1_refresh = 1'b0; |
end else begin: gen_cal1_refresh_dq_gt4 |
assign cal1_refresh = (next_count_dq[1:0] == 2'b00); |
end |
endgenerate |
|
//*************************************************************************** |
// First stage calibration: DQ-DQS |
// Definitions: |
// edge: detected when varying IDELAY, and current capture data != prev |
// capture data |
// valid bit window: detected when current capture data == prev capture |
// data for more than half the bit time |
// starting conditions for DQS-DQ phase: |
// case 1: when DQS starts somewhere in rising edge bit window, or |
// on the right edge of the rising bit window. |
// case 2: when DQS starts somewhere in falling edge bit window, or |
// on the right edge of the falling bit window. |
// Algorithm Description: |
// 1. Increment DQ IDELAY until we find an edge. |
// 2. While we're finding the first edge, note whether a valid bit window |
// has been detected before we found an edge. If so, then figure out if |
// this is the rising or falling bit window. If rising, then our starting |
// DQS-DQ phase is case 1. If falling, then it's case 2. If don't detect |
// a valid bit window, then we must have started on the edge of a window. |
// Need to wait until later on to decide which case we are. |
// - Store FIRST_EDGE IDELAY value |
// 3. Now look for second edge. |
// 4. While we're finding the second edge, note whether valid bit window |
// is detected. If so, then use to, along with results from (2) to figure |
// out what the starting case is. If in rising bit window, then we're in |
// case 2. If falling, then case 1. |
// - Store SECOND_EDGE IDELAY value |
// NOTES: |
// a. Finding two edges allows us to calculate the bit time (although |
// not the "same" bit time polarity - need to investigate this |
// more). |
// b. If we run out of taps looking for the second edge, then the bit |
// time must be too long (>= 2.5ns, and DQS-DQ starting phase must be |
// case 1). |
// 5. Calculate absolute amount to delay DQ as: |
// If second edge found, and case 1: |
// - DQ_IDELAY = FIRST_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) |
// If second edge found, and case 2: |
// - DQ_IDELAY = SECOND_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) |
// If second edge not found, then need to make an approximation on |
// how much to shift by (should be okay, because we have more timing |
// margin): |
// - DQ_IDELAY = FIRST_EDGE - 0.5 * (bit_time) |
// NOTE: Does this account for either case 1 or case 2????? |
// NOTE: It's also possible even when we find the second edge, that |
// to instead just use half the bit time to subtract from either |
// FIRST or SECOND_EDGE. Finding the actual bit time (which is |
// what (SECOND_EDGE - FIRST_EDGE) is, is slightly more accurate, |
// since it takes into account duty cycle distortion. |
// 6. Repeat for each DQ in current DQS set. |
//*************************************************************************** |
|
//***************************************************************** |
// for first stage calibration - used for checking if DQS is aligned to the |
// particular DQ, such that we're in the data valid window. Basically, this |
// is one giant MUX. |
// = [falling data, rising data] |
// = [0, 1] = rising DQS aligned in proper (rising edge) bit window |
// = [1, 0] = rising DQS aligned in wrong (falling edge) bit window |
// = [0, 0], or [1,1] = in uncertain region between windows |
//***************************************************************** |
|
// SYN_NOTE: May have to split this up into multiple levels - MUX can get |
// very wide - as wide as the data bus width |
always @(posedge clkdiv) |
cal1_data_chk_r <= {rd_data_fall_1x_r[next_count_dq], |
rd_data_rise_1x_r[next_count_dq]}; |
|
//***************************************************************** |
// determine when an edge has occurred - when either the current value |
// is different from the previous latched value or when the DATA_CHK |
// outputs are the same (rare, but indicates that we're at an edge) |
// This is only valid when the IDELAY output and propagation of the |
// data through the capture flops has had a chance to settle out. |
//***************************************************************** |
|
// write CAL1_DETECT_EDGE and CAL1_DETECT_STABLE in such a way that |
// if X's are captured on the bus during functional simulation, that |
// the logic will register this as an edge detected. Do this to allow |
// use of this HDL with Denali memory models (Denali models drive DQ |
// to X's on both edges of the data valid window to simulate jitter) |
// This is only done for functional simulation purposes. **Should not** |
// make the final synthesized logic more complicated, but it does make |
// the HDL harder to understand b/c we have to "phrase" the logic |
// slightly differently than when not worrying about X's |
always @(*) begin |
// no edge found if: (1) we have recorded prev edge, and rise |
// data == fall data, (2) we haven't yet recorded prev edge, but |
// rise/fall data is equal to either [0,1] or [1,0] (i.e. rise/fall |
// data isn't either X's, or [0,0] or [1,1], which indicates we're |
// in the middle of an edge, since normally rise != fall data for stg1) |
if ((cal1_data_chk_last_valid && |
(cal1_data_chk_r == cal1_data_chk_last)) || |
(!cal1_data_chk_last_valid && |
((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10)))) |
cal1_detect_edge = 1'b0; |
else |
cal1_detect_edge = 1'b1; |
end |
|
always @(*) begin |
// assert if we've found a region where data valid window is stable |
// over consecutive IDELAY taps, and either rise/fall = [1,0], or [0,1] |
if ((cal1_data_chk_last_valid && |
(cal1_data_chk_r == cal1_data_chk_last)) && |
((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10))) |
cal1_detect_stable <= 1'b1; |
else |
cal1_detect_stable <= 1'b0; |
end |
|
//***************************************************************** |
// Find valid window: keep track of how long we've been in the same data |
// window. If it's been long enough, then declare that we've found a valid |
// window. Also returns whether we found a rising or falling window (only |
// valid when found_window is asserted) |
//***************************************************************** |
|
always @(posedge clkdiv) begin |
if (cal1_state == CAL1_INIT) begin |
cal1_window_cnt <= 4'b0000; |
cal1_found_window <= 1'b0; |
cal1_found_rising <= 1'bx; |
end else if (!cal1_data_chk_last_valid) begin |
// if we haven't stored a previous value of CAL1_DATA_CHK (or it got |
// invalidated because we detected an edge, and are now looking for the |
// second edge), then make sure FOUND_WINDOW deasserted on following |
// clock edge (to avoid finding a false window immediately after finding |
// an edge). Note that because of jitter, it's possible to not find an |
// edge at the end of the IDELAY increment settling time, but to find an |
// edge on the next clock cycle (e.g. during CAL1_FIND_FIRST_EDGE) |
cal1_window_cnt <= 4'b0000; |
cal1_found_window <= 1'b0; |
cal1_found_rising <= 1'bx; |
end else if (((cal1_state == CAL1_FIRST_EDGE_IDEL_WAIT) || |
(cal1_state == CAL1_SECOND_EDGE_IDEL_WAIT)) && |
!idel_set_wait) begin |
// while finding the first and second edges, see if we can detect a |
// stable bit window (occurs over MIN_WIN_SIZE number of taps). If |
// so, then we're away from an edge, and can conclusively determine the |
// starting DQS-DQ phase. |
if (cal1_detect_stable) begin |
cal1_window_cnt <= cal1_window_cnt + 1; |
if (cal1_window_cnt == MIN_WIN_SIZE-1) begin |
cal1_found_window <= 1'b1; |
if (cal1_data_chk_r == 2'b01) |
cal1_found_rising <= 1'b1; |
else |
cal1_found_rising <= 1'b0; |
end |
end else begin |
// otherwise, we're not in a data valid window, reset the window |
// counter, and indicate we're not currently in window. This should |
// happen by design at least once after finding the first edge. |
cal1_window_cnt <= 4'b0000; |
cal1_found_window <= 1'b0; |
cal1_found_rising <= 1'bx; |
end |
end |
end |
|
//***************************************************************** |
// keep track of edge tap counts found, and whether we've |
// incremented to the maximum number of taps allowed |
//***************************************************************** |
|
always @(posedge clkdiv) |
if (cal1_state == CAL1_INIT) begin |
cal1_idel_tap_limit_hit <= 1'b0; |
cal1_idel_tap_cnt <= 6'b000000; |
end else if (cal1_dlyce_dq) begin |
if (cal1_dlyinc_dq) begin |
cal1_idel_tap_cnt <= cal1_idel_tap_cnt + 1; |
cal1_idel_tap_limit_hit <= (cal1_idel_tap_cnt == 6'b111110); |
end else begin |
cal1_idel_tap_cnt <= cal1_idel_tap_cnt - 1; |
cal1_idel_tap_limit_hit <= 1'b0; |
end |
end |
|
//***************************************************************** |
// Pipeline for better timing - amount to decrement by if second |
// edge not found |
//***************************************************************** |
// if only one edge found (possible for low frequencies), then: |
// 1. Assume starting DQS-DQ phase has DQS in DQ window (aka "case 1") |
// 2. We have to decrement by (63 - first_edge_tap_cnt) + (BIT_TIME_TAPS/2) |
// (i.e. decrement by 63-first_edge_tap_cnt to get to right edge of |
// DQ window. Then decrement again by (BIT_TIME_TAPS/2) to get to center |
// of DQ window. |
// 3. Clamp the above value at 63 to ensure we don't underflow IDELAY |
// (note: clamping happens in the CAL1 state machine) |
always @(posedge clkdiv) |
cal1_low_freq_idel_dec |
<= (7'b0111111 - {1'b0, cal1_first_edge_tap_cnt}) + |
(BIT_TIME_TAPS/2); |
|
//***************************************************************** |
// Keep track of max taps used during stage 1, use this to limit |
// the number of taps that can be used in stage 2 |
//***************************************************************** |
|
always @(posedge clkdiv) |
if (rstdiv) begin |
cal1_idel_max_tap <= 6'b000000; |
cal1_idel_max_tap_we <= 1'b0; |
end else begin |
// pipeline latch enable for CAL1_IDEL_MAX_TAP - we have plenty |
// of time, tap count gets updated, then dead cycles waiting for |
// IDELAY output to settle |
cal1_idel_max_tap_we <= (cal1_idel_max_tap < cal1_idel_tap_cnt); |
// record maximum # of taps used for stg 1 cal |
if ((cal1_state == CAL1_DONE) && cal1_idel_max_tap_we) |
cal1_idel_max_tap <= cal1_idel_tap_cnt; |
end |
|
//***************************************************************** |
|
always @(posedge clkdiv) |
if (rstdiv) begin |
calib_done[0] <= 1'b0; |
calib_done_tmp[0] <= 1'bx; |
calib_err[0] <= 1'b0; |
count_dq <= {DQ_BITS{1'b0}}; |
next_count_dq <= {DQ_BITS{1'b0}}; |
cal1_bit_time_tap_cnt <= 6'bxxxxxx; |
cal1_data_chk_last <= 2'bxx; |
cal1_data_chk_last_valid <= 1'bx; |
cal1_dlyce_dq <= 1'b0; |
cal1_dlyinc_dq <= 1'b0; |
cal1_dqs_dq_init_phase <= 1'bx; |
cal1_first_edge_done <= 1'bx; |
cal1_found_second_edge <= 1'bx; |
cal1_first_edge_tap_cnt <= 6'bxxxxxx; |
cal1_idel_dec_cnt <= 7'bxxxxxxx; |
cal1_idel_inc_cnt <= 6'bxxxxxx; |
cal1_ref_req <= 1'b0; |
cal1_state <= CAL1_IDLE; |
end else begin |
// default values for all "pulse" outputs |
cal1_ref_req <= 1'b0; |
cal1_dlyce_dq <= 1'b0; |
cal1_dlyinc_dq <= 1'b0; |
|
case (cal1_state) |
CAL1_IDLE: begin |
count_dq <= {DQ_BITS{1'b0}}; |
next_count_dq <= {DQ_BITS{1'b0}}; |
if (calib_start[0]) begin |
calib_done[0] <= 1'b0; |
calib_done_tmp[0] <= 1'b0; |
cal1_state <= CAL1_INIT; |
end |
end |
|
CAL1_INIT: begin |
cal1_data_chk_last_valid <= 1'b0; |
cal1_found_second_edge <= 1'b0; |
cal1_dqs_dq_init_phase <= 1'b0; |
cal1_idel_inc_cnt <= 6'b000000; |
cal1_state <= CAL1_INC_IDEL; |
end |
|
// increment DQ IDELAY so that either: (1) DQS starts somewhere in |
// first rising DQ window, or (2) DQS starts in first falling DQ |
// window. The amount to shift is frequency dependent (and is either |
// precalculated by MIG or possibly adjusted by the user) |
CAL1_INC_IDEL: |
if ((cal1_idel_inc_cnt == DQ_IDEL_INIT) && !idel_set_wait) begin |
cal1_state <= CAL1_FIND_FIRST_EDGE; |
end else if (cal1_idel_inc_cnt != DQ_IDEL_INIT) begin |
cal1_idel_inc_cnt <= cal1_idel_inc_cnt + 1; |
cal1_dlyce_dq <= 1'b1; |
cal1_dlyinc_dq <= 1'b1; |
end |
|
// look for first edge |
CAL1_FIND_FIRST_EDGE: begin |
// Determine DQS-DQ phase if we can detect enough of a valid window |
if (cal1_found_window) |
cal1_dqs_dq_init_phase <= ~cal1_found_rising; |
// find first edge - if found then record position |
if (cal1_detect_edge) begin |
cal1_state <= CAL1_FOUND_FIRST_EDGE_WAIT; |
cal1_first_edge_done <= 1'b0; |
cal1_first_edge_tap_cnt <= cal1_idel_tap_cnt; |
cal1_data_chk_last_valid <= 1'b0; |
end else begin |
// otherwise, store the current value of DATA_CHK, increment |
// DQ IDELAY, and compare again |
cal1_state <= CAL1_FIRST_EDGE_IDEL_WAIT; |
cal1_data_chk_last <= cal1_data_chk_r; |
// avoid comparing against DATA_CHK_LAST for previous iteration |
cal1_data_chk_last_valid <= 1'b1; |
cal1_dlyce_dq <= 1'b1; |
cal1_dlyinc_dq <= 1'b1; |
end |
end |
|
// wait for DQ IDELAY to settle |
CAL1_FIRST_EDGE_IDEL_WAIT: |
if (!idel_set_wait) |
cal1_state <= CAL1_FIND_FIRST_EDGE; |
|
// delay state between finding first edge and looking for second |
// edge. Necessary in order to invalidate CAL1_FOUND_WINDOW before |
// starting to look for second edge |
CAL1_FOUND_FIRST_EDGE_WAIT: |
cal1_state <= CAL1_FIND_SECOND_EDGE; |
|
// Try and find second edge |
CAL1_FIND_SECOND_EDGE: begin |
// When looking for 2nd edge, first make sure data stabilized (by |
// detecting valid data window) - needed to avoid false edges |
if (cal1_found_window) begin |
cal1_first_edge_done <= 1'b1; |
cal1_dqs_dq_init_phase <= cal1_found_rising; |
end |
// exit if run out of taps to increment |
if (cal1_idel_tap_limit_hit) |
cal1_state <= CAL1_CALC_IDEL; |
else begin |
// found second edge, record the current edge count |
if (cal1_first_edge_done && cal1_detect_edge) begin |
cal1_state <= CAL1_CALC_IDEL; |
cal1_found_second_edge <= 1'b1; |
cal1_bit_time_tap_cnt <= cal1_idel_tap_cnt - |
cal1_first_edge_tap_cnt + 1; |
end else begin |
cal1_state <= CAL1_SECOND_EDGE_IDEL_WAIT; |
cal1_data_chk_last <= cal1_data_chk_r; |
cal1_data_chk_last_valid <= 1'b1; |
cal1_dlyce_dq <= 1'b1; |
cal1_dlyinc_dq <= 1'b1; |
end |
end |
end |
|
// wait for DQ IDELAY to settle, then store ISERDES output |
CAL1_SECOND_EDGE_IDEL_WAIT: |
if (!idel_set_wait) |
cal1_state <= CAL1_FIND_SECOND_EDGE; |
|
// pipeline delay state to calculate amount to decrement DQ IDELAY |
// NOTE: We're calculating the amount to decrement by, not the |
// absolute setting for DQ IDELAY |
CAL1_CALC_IDEL: begin |
// if two edges found |
if (cal1_found_second_edge) |
// case 1: DQS was in DQ window to start with. First edge found |
// corresponds to left edge of DQ rising window. Backup by 1.5*BT |
// NOTE: In this particular case, it is possible to decrement |
// "below 0" in the case where DQS delay is less than 0.5*BT, |
// need to limit decrement to prevent IDELAY tap underflow |
if (!cal1_dqs_dq_init_phase) |
cal1_idel_dec_cnt <= {1'b0, cal1_bit_time_tap_cnt} + |
{1'b0, (cal1_bit_time_tap_cnt >> 1)}; |
// case 2: DQS was in wrong DQ window (in DQ falling window). |
// First edge found is right edge of DQ rising window. Second |
// edge is left edge of DQ rising window. Backup by 0.5*BT |
else |
cal1_idel_dec_cnt <= {1'b0, (cal1_bit_time_tap_cnt >> 1)}; |
// if only one edge found - assume will always be case 1 - DQS in |
// DQS window. Case 2 only possible if path delay on DQS > 5ns |
else |
cal1_idel_dec_cnt <= cal1_low_freq_idel_dec; |
cal1_state <= CAL1_DEC_IDEL; |
end |
|
// decrement DQ IDELAY for final adjustment |
CAL1_DEC_IDEL: |
// once adjustment is complete, we're done with calibration for |
// this DQ, now return to IDLE state and repeat for next DQ |
// Add underflow protection for case of 2 edges found and DQS |
// starting in DQ window (see comments for above state) - note we |
// have to take into account delayed value of CAL1_IDEL_TAP_CNT - |
// gets updated one clock cycle after CAL1_DLYCE/INC_DQ |
if ((cal1_idel_dec_cnt == 7'b0000000) || |
(cal1_dlyce_dq && (cal1_idel_tap_cnt == 6'b000001))) begin |
cal1_state <= CAL1_DONE; |
// stop when all DQ's calibrated, or DQ[0] cal'ed (for sim) |
if ((count_dq == DQ_WIDTH-1) || (SIM_ONLY != 0)) |
calib_done_tmp[0] <= 1'b1; |
else |
// need for VHDL simulation to prevent out-of-index error |
next_count_dq <= count_dq + 1; |
end else begin |
// keep decrementing until final tap count reached |
cal1_idel_dec_cnt <= cal1_idel_dec_cnt - 1; |
cal1_dlyce_dq <= 1'b1; |
cal1_dlyinc_dq <= 1'b0; |
end |
|
// delay state to allow count_dq and DATA_CHK to point to the next |
// DQ bit (allows us to potentially begin checking for an edge on |
// next DQ right away). |
CAL1_DONE: |
if (!idel_set_wait) begin |
count_dq <= next_count_dq; |
if (calib_done_tmp[0]) begin |
calib_done[0] <= 1'b1; |
cal1_state <= CAL1_IDLE; |
end else begin |
// request auto-refresh after every 8-bits calibrated to |
// avoid tRAS violation |
if (cal1_refresh) begin |
cal1_ref_req <= 1'b1; |
if (calib_ref_done) |
cal1_state <= CAL1_INIT; |
end else |
// if no need this time for refresh, proceed to next bit |
cal1_state <= CAL1_INIT; |
end |
end |
endcase |
end |
|
//*************************************************************************** |
// Second stage calibration: DQS-FPGA Clock |
// Algorithm Description: |
// 1. Assumes a training pattern that will produce a pattern oscillating at |
// half the core clock frequency each on rise and fall outputs, and such |
// that rise and fall outputs are 180 degrees out of phase from each |
// other. Note that since the calibration logic runs at half the speed |
// of the interface, expect that data sampled with the slow clock always |
// to be constant (either always = 1, or = 0, and rise data != fall data) |
// unless we cross the edge of the data valid window |
// 2. Start by setting RD_DATA_SEL = 0. This selects the rising capture data |
// sync'ed to rising edge of core clock, and falling edge data sync'ed |
// to falling edge of core clock |
// 3. Start looking for an edge. An edge is defined as either: (1) a |
// change in capture value or (2) an invalid capture value (e.g. rising |
// data != falling data for that same clock cycle). |
// 4. If an edge is found, go to step (6). If edge hasn't been found, then |
// set RD_DATA_SEL = 1, and try again. |
// 5. If no edge is found, then increment IDELAY and return to step (3) |
// 6. If an edge if found, then invert RD_DATA_SEL - this shifts the |
// capture point 180 degrees from the edge of the window (minus duty |
// cycle distortion, delay skew between rising/falling edge capture |
// paths, etc.) |
// 7. If no edge is found by CAL2_IDEL_TAP_LIMIT (= 63 - # taps used for |
// stage 1 calibration), then decrement IDELAY (without reinverting |
// RD_DATA_SEL) by CAL2_IDEL_TAP_LIMIT/2. This guarantees we at least |
// have CAL2_IDEL_TAP_LIMIT/2 of slack both before and after the |
// capture point (not optimal, but best we can do not having found an |
// of the window). This happens only for very low frequencies. |
// 8. Repeat for each DQS group. |
// NOTE: Step 6 is not optimal. A better (and perhaps more complicated) |
// algorithm might be to find both edges of the data valid window (using |
// the same polarity of RD_DATA_SEL), and then decrement to the midpoint. |
//*************************************************************************** |
|
// RD_DATA_SEL should be tagged with FROM-TO (multi-cycle) constraint in |
// UCF file to relax timing. This net is "pseudo-static" (after value is |
// changed, FSM waits number of cycles before using the output). |
// Note that we are adding one clock cycle of delay (to isolate it from |
// the other logic CAL2_RD_DATA_SEL feeds), make sure FSM waits long |
// enough to compensate (by default it does, it waits a few cycles more |
// than minimum # of clock cycles) |
genvar rd_i; |
generate |
for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rd_data_sel |
FDRSE u_ff_rd_data_sel |
( |
.Q (rd_data_sel[rd_i]), |
.C (clkdiv), |
.CE (1'b1), |
.D (cal2_rd_data_sel[rd_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
//***************************************************************** |
// Max number of taps used for stg2 cal dependent on number of taps |
// used for stg1 (give priority to stg1 cal - let it use as many |
// taps as it needs - the remainder of the IDELAY taps can be used |
// by stg2) |
//***************************************************************** |
|
always @(posedge clkdiv) |
cal2_idel_tap_limit <= 6'b111111 - cal1_idel_max_tap; |
|
//***************************************************************** |
// second stage calibration uses readback pattern of "1100" (i.e. |
// 1st rising = 1, 1st falling = 1, 2nd rising = 0, 2nd falling = 0) |
// only look at the first bit of each DQS group |
//***************************************************************** |
|
// deasserted when captured data has changed since IDELAY was |
// incremented, or when we're right on the edge (i.e. rise data = |
// fall data). |
assign cal2_detect_edge = |
((((rdd_rise_q1 != cal2_rd_data_rise_last_pos) || |
(rdd_fall_q1 != cal2_rd_data_fall_last_pos)) && |
cal2_rd_data_last_valid_pos && (!cal2_curr_sel)) || |
(((rdd_rise_q1 != cal2_rd_data_rise_last_neg) || |
(rdd_fall_q1 != cal2_rd_data_fall_last_neg)) && |
cal2_rd_data_last_valid_neg && (cal2_curr_sel)) || |
(rdd_rise_q1 != rdd_fall_q1)); |
|
//***************************************************************** |
// keep track of edge tap counts found, and whether we've |
// incremented to the maximum number of taps allowed |
// NOTE: Assume stage 2 cal always increments the tap count (never |
// decrements) when searching for edge of the data valid window |
//***************************************************************** |
|
always @(posedge clkdiv) |
if (cal2_state == CAL2_INIT) begin |
cal2_idel_tap_limit_hit <= 1'b0; |
cal2_idel_tap_cnt <= 6'b000000; |
end else if (cal2_dlyce_dqs) begin |
cal2_idel_tap_cnt <= cal2_idel_tap_cnt + 1; |
cal2_idel_tap_limit_hit <= (cal2_idel_tap_cnt == |
cal2_idel_tap_limit - 1); |
end |
|
//***************************************************************** |
|
always @(posedge clkdiv) |
if (rstdiv) begin |
calib_done[1] <= 1'b0; |
calib_done_tmp[1] <= 1'bx; |
calib_err[1] <= 1'b0; |
count_dqs <= 'b0; |
next_count_dqs <= 'b0; |
cal2_dlyce_dqs <= 1'b0; |
cal2_dlyinc_dqs <= 1'b0; |
cal2_idel_dec_cnt <= 6'bxxxxxx; |
cal2_rd_data_last_valid_neg <= 1'bx; |
cal2_rd_data_last_valid_pos <= 1'bx; |
cal2_rd_data_sel <= 'b0; |
cal2_ref_req <= 1'b0; |
cal2_state <= CAL2_IDLE; |
end else begin |
cal2_ref_req <= 1'b0; |
cal2_dlyce_dqs <= 1'b0; |
cal2_dlyinc_dqs <= 1'b0; |
|
case (cal2_state) |
CAL2_IDLE: begin |
count_dqs <= 'b0; |
next_count_dqs <= 'b0; |
if (calib_start[1]) begin |
cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; |
calib_done[1] <= 1'b0; |
calib_done_tmp[1] <= 1'b0; |
cal2_state <= CAL2_INIT; |
end |
end |
|
// Pass through this state every time we calibrate a new DQS group |
CAL2_INIT: begin |
cal2_curr_sel <= 1'b0; |
cal2_rd_data_last_valid_neg <= 1'b0; |
cal2_rd_data_last_valid_pos <= 1'b0; |
cal2_state <= CAL2_INIT_IDEL_WAIT; |
end |
|
// Stall state only used if calibration run more than once. Can take |
// this state out if design never runs calibration more than once. |
// We need this state to give time for MUX'ed data to settle after |
// resetting RD_DATA_SEL |
CAL2_INIT_IDEL_WAIT: |
if (!idel_set_wait) |
cal2_state <= CAL2_FIND_EDGE_POS; |
|
// Look for an edge - first check "positive-edge" stage 2 capture |
CAL2_FIND_EDGE_POS: begin |
// if found an edge, then switch to the opposite edge stage 2 |
// capture and we're done - no need to decrement the tap count, |
// since switching to the opposite edge will shift the capture |
// point by 180 degrees |
if (cal2_detect_edge) begin |
cal2_curr_sel <= 1'b1; |
cal2_state <= CAL2_DONE; |
// set all DQS groups to be the same for simulation |
if (SIM_ONLY != 0) |
cal2_rd_data_sel <= {DQS_WIDTH{1'b1}}; |
else |
cal2_rd_data_sel[count_dqs] <= 1'b1; |
if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) |
calib_done_tmp[1] <= 1'b1; |
else |
// MIG 2.1: Fix for simulation out-of-bounds error when |
// SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) |
next_count_dqs <= count_dqs + 1; |
end else begin |
// otherwise, invert polarity of stage 2 capture and look for |
// an edge with opposite capture clock polarity |
cal2_curr_sel <= 1'b1; |
cal2_rd_data_sel[count_dqs] <= 1'b1; |
cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_POS; |
cal2_rd_data_rise_last_pos <= rdd_rise_q1; |
cal2_rd_data_fall_last_pos <= rdd_fall_q1; |
cal2_rd_data_last_valid_pos <= 1'b1; |
end |
end |
|
// Give time to switch from positive-edge to negative-edge second |
// stage capture (need time for data to filter though pipe stages) |
CAL2_FIND_EDGE_IDEL_WAIT_POS: |
if (!idel_set_wait) |
cal2_state <= CAL2_FIND_EDGE_NEG; |
|
// Look for an edge - check "negative-edge" stage 2 capture |
CAL2_FIND_EDGE_NEG: |
if (cal2_detect_edge) begin |
cal2_curr_sel <= 1'b0; |
cal2_state <= CAL2_DONE; |
// set all DQS groups to be the same for simulation |
if (SIM_ONLY != 0) |
cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; |
else |
cal2_rd_data_sel[count_dqs] <= 1'b0; |
if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) |
calib_done_tmp[1] <= 1'b1; |
else |
// MIG 2.1: Fix for simulation out-of-bounds error when |
// SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) |
next_count_dqs <= count_dqs + 1; |
end else if (cal2_idel_tap_limit_hit) begin |
// otherwise, if we've run out of taps, then immediately |
// backoff by half # of taps used - that's our best estimate |
// for optimal calibration point. Doesn't matter whether which |
// polarity we're using for capture (we don't know which one is |
// best to use) |
cal2_idel_dec_cnt <= {1'b0, cal2_idel_tap_limit[5:1]}; |
cal2_state <= CAL2_DEC_IDEL; |
if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) |
calib_done_tmp[1] <= 1'b1; |
else |
// MIG 2.1: Fix for simulation out-of-bounds error when |
// SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) |
next_count_dqs <= count_dqs + 1; |
end else begin |
// otherwise, increment IDELAY, and start looking for edge again |
cal2_curr_sel <= 1'b0; |
cal2_rd_data_sel[count_dqs] <= 1'b0; |
cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_NEG; |
cal2_rd_data_rise_last_neg <= rdd_rise_q1; |
cal2_rd_data_fall_last_neg <= rdd_fall_q1; |
cal2_rd_data_last_valid_neg <= 1'b1; |
cal2_dlyce_dqs <= 1'b1; |
cal2_dlyinc_dqs <= 1'b1; |
end |
|
CAL2_FIND_EDGE_IDEL_WAIT_NEG: |
if (!idel_set_wait) |
cal2_state <= CAL2_FIND_EDGE_POS; |
|
// if no edge found, then decrement by half # of taps used |
CAL2_DEC_IDEL: begin |
if (cal2_idel_dec_cnt == 6'b000000) |
cal2_state <= CAL2_DONE; |
else begin |
cal2_idel_dec_cnt <= cal2_idel_dec_cnt - 1; |
cal2_dlyce_dqs <= 1'b1; |
cal2_dlyinc_dqs <= 1'b0; |
end |
end |
|
// delay state to allow count_dqs and ISERDES data to point to next |
// DQ bit (DQS group) before going to INIT |
CAL2_DONE: |
if (!idel_set_wait) begin |
count_dqs <= next_count_dqs; |
if (calib_done_tmp[1]) begin |
calib_done[1] <= 1'b1; |
cal2_state <= CAL2_IDLE; |
end else begin |
// request auto-refresh after every DQS group calibrated to |
// avoid tRAS violation |
cal2_ref_req <= 1'b1; |
if (calib_ref_done) |
cal2_state <= CAL2_INIT; |
end |
end |
endcase |
end |
|
//*************************************************************************** |
// Stage 3 calibration: Read Enable |
// Description: |
// read enable calibration determines the "round-trip" time (in # of CLK0 |
// cycles) between when a read command is issued by the controller, and |
// when the corresponding read data is synchronized by into the CLK0 domain |
// this is a long delay chain to delay read enable signal from controller/ |
// initialization logic (i.e. this is used for both initialization and |
// during normal controller operation). Stage 3 calibration logic decides |
// which delayed version is appropriate to use (which is affected by the |
// round trip delay of DQ/DQS) as a "valid" signal to tell rest of logic |
// when the captured data output from ISERDES is valid. |
//*************************************************************************** |
|
//***************************************************************** |
// Delay chains: Use shift registers |
// Two sets of delay chains are used: |
// 1. One to delay RDEN from PHY_INIT module for calibration |
// purposes (delay required for RDEN for calibration is different |
// than during normal operation) |
// 2. One per DQS group to delay RDEN from controller for normal |
// operation - the value to delay for each DQS group can be different |
// as is determined during calibration |
//***************************************************************** |
|
//***************************************************************** |
// First delay chain, use only for calibration |
// input = asserted on rising edge of RDEN from PHY_INIT module |
//***************************************************************** |
|
always @(posedge clk) begin |
ctrl_rden_r <= ctrl_rden; |
phy_init_rden_r <= phy_init_rden; |
phy_init_rden_r1 <= phy_init_rden_r; |
calib_rden_edge_r <= phy_init_rden_r & ~phy_init_rden_r1; |
end |
|
// Calibration shift register used for both Stage 3 and Stage 4 cal |
// (not strictly necessary for stage 4, but use as an additional check |
// to make sure we're checking for correct data on the right clock cycle) |
always @(posedge clkdiv) |
if (!calib_done[2]) |
calib_rden_srl_a <= cal3_rden_srl_a; |
else |
calib_rden_srl_a <= cal4_rden_srl_a; |
|
// Flops for targetting of multi-cycle path in UCF |
genvar cal_rden_ff_i; |
generate |
for (cal_rden_ff_i = 0; cal_rden_ff_i < 5; |
cal_rden_ff_i = cal_rden_ff_i+1) begin: gen_cal_rden_dly |
FDRSE u_ff_cal_rden_dly |
( |
.Q (calib_rden_srl_a_r[cal_rden_ff_i]), |
.C (clkdiv), |
.CE (1'b1), |
.D (calib_rden_srl_a[cal_rden_ff_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
SRLC32E u_calib_rden_srl |
( |
.Q (calib_rden_srl_out), |
.Q31 (), |
.A (calib_rden_srl_a_r), |
.CE (1'b1), |
.CLK (clk), |
.D (calib_rden_edge_r) |
); |
|
FDRSE u_calib_rden_srl_out_r |
( |
.Q (calib_rden_srl_out_r), |
.C (clk), |
.CE (1'b1), |
.D (calib_rden_srl_out), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */; |
|
// convert to CLKDIV domain. Two version are generated because we need |
// to be able to tell exactly which fast (clk) clock cycle the read |
// enable was asserted in. Only one of CALIB_DATA_VALID or |
// CALIB_DATA_VALID_STGD will be asserted for any given shift value |
always @(posedge clk) |
calib_rden_srl_out_r1 <= calib_rden_srl_out_r; |
|
always @(posedge clkdiv) begin |
calib_rden_valid <= calib_rden_srl_out_r; |
calib_rden_valid_stgd <= calib_rden_srl_out_r1; |
end |
|
//***************************************************************** |
// Second set of delays chain, use for normal reads |
// input = RDEN from controller |
//***************************************************************** |
|
// Flops for targetting of multi-cycle path in UCF |
genvar rden_ff_i; |
generate |
for (rden_ff_i = 0; rden_ff_i < 5*DQS_WIDTH; |
rden_ff_i = rden_ff_i+1) begin: gen_rden_dly |
FDRSE u_ff_rden_dly |
( |
.Q (rden_dly_r[rden_ff_i]), |
.C (clkdiv), |
.CE (1'b1), |
.D (rden_dly[rden_ff_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
// NOTE: Comment this section explaining purpose of SRL's |
genvar rden_i; |
generate |
for (rden_i = 0; rden_i < DQS_WIDTH; rden_i = rden_i + 1) begin: gen_rden |
SRLC32E u_rden_srl |
( |
.Q (rden_srl_out[rden_i]), |
.Q31 (), |
.A ({rden_dly_r[(rden_i*5)+4], |
rden_dly_r[(rden_i*5)+3], |
rden_dly_r[(rden_i*5)+2], |
rden_dly_r[(rden_i*5)+1], |
rden_dly_r[(rden_i*5)]}), |
.CE (1'b1), |
.CLK (clk), |
.D (ctrl_rden_r) |
); |
FDRSE u_calib_rden_r |
( |
.Q (calib_rden[rden_i]), |
.C (clk), |
.CE (1'b1), |
.D (rden_srl_out[rden_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */; |
end |
endgenerate |
|
//***************************************************************** |
// indicates that current received data is the correct pattern. Check both |
// rising and falling data for first DQ in each DQS group. Note that |
// we're checking using a pipelined version of read data, so need to take |
// this inherent delay into account in determining final read valid delay |
// Data is written to the memory in the following order (first -> last): |
// 0x1, 0xE, 0xE, 0x1, 0x1, 0xE, 0xE, 0x1 |
// Looking just at LSb, expect data in sequence (in binary): |
// 1, 0, 0, 1, 1, 0, 0, 1 |
// Check for the presence of the first 7 words, and compensate read valid |
// delay accordingly. Don't check last falling edge data, it may be |
// corrupted by the DQS tri-state glitch at end of read postamble |
// (glitch protection not yet active until stage 4 cal) |
//***************************************************************** |
|
always @(posedge clkdiv) begin |
rdd_rise_q1_r <= rdd_rise_q1; |
rdd_fall_q1_r <= rdd_fall_q1; |
rdd_rise_q2_r <= rdd_rise_q2; |
rdd_fall_q2_r <= rdd_fall_q2; |
rdd_rise_q1_r1 <= rdd_rise_q1_r; |
rdd_fall_q1_r1 <= rdd_fall_q1_r; |
end |
|
always @(posedge clkdiv) begin |
// For the following sequence from memory: |
// rise[0], fall[0], rise[1], fall[1] |
// if data is aligned out of fabric ISERDES: |
// RDD_RISE_Q2 = rise[0] |
// RDD_FALL_Q2 = fall[0] |
// RDD_RISE_Q1 = rise[1] |
// RDD_FALL_Q1 = fall[1] |
cal3_data_match <= ((rdd_rise_q2_r == 1) && |
(rdd_fall_q2_r == 0) && |
(rdd_rise_q1_r == 0) && |
(rdd_fall_q1_r == 1) && |
(rdd_rise_q2 == 1) && |
(rdd_fall_q2 == 0) && |
(rdd_rise_q1 == 0)); |
|
// if data is staggered out of fabric ISERDES: |
// RDD_RISE_Q1_R = rise[0] |
// RDD_FALL_Q1_R = fall[0] |
// RDD_RISE_Q2 = rise[1] |
// RDD_FALL_Q2 = fall[1] |
cal3_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && |
(rdd_fall_q1_r1 == 0) && |
(rdd_rise_q2_r == 0) && |
(rdd_fall_q2_r == 1) && |
(rdd_rise_q1_r == 1) && |
(rdd_fall_q1_r == 0) && |
(rdd_rise_q2 == 0)); |
end |
|
assign cal3_rden_dly = cal3_rden_srl_a - CAL3_RDEN_SRL_DLY_DELTA; |
assign cal3_data_valid = (calib_rden_valid | calib_rden_valid_stgd); |
assign cal3_match_found |
= ((calib_rden_valid && cal3_data_match) || |
(calib_rden_valid_stgd && cal3_data_match_stgd)); |
|
// when calibrating, check to see which clock cycle (after the read is |
// issued) does the expected data pattern arrive. Record this result |
// NOTE: Can add error checking here in case valid data not found on any |
// of the available pipeline stages |
always @(posedge clkdiv) begin |
if (rstdiv) begin |
cal3_rden_srl_a <= 5'bxxxxx; |
cal3_state <= CAL3_IDLE; |
calib_done[2] <= 1'b0; |
calib_err_2[0] <= 1'b0; |
count_rden <= {DQS_WIDTH{1'b0}}; |
rden_dly <= {5*DQS_WIDTH{1'b0}}; |
end else begin |
|
case (cal3_state) |
CAL3_IDLE: begin |
count_rden <= {DQS_WIDTH{1'b0}}; |
if (calib_start[2]) begin |
calib_done[2] <= 1'b0; |
cal3_state <= CAL3_INIT; |
end |
end |
|
CAL3_INIT: begin |
cal3_rden_srl_a <= RDEN_BASE_DELAY; |
// let SRL pipe clear after loading initial shift value |
cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; |
end |
|
CAL3_DETECT: |
if (cal3_data_valid) |
// if match found at the correct clock cycle |
if (cal3_match_found) begin |
|
// For simulation, load SRL addresses for all DQS with same value |
if (SIM_ONLY != 0) begin |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_rden_dly |
rden_dly[(i*5)] <= cal3_rden_dly[0]; |
rden_dly[(i*5)+1] <= cal3_rden_dly[1]; |
rden_dly[(i*5)+2] <= cal3_rden_dly[2]; |
rden_dly[(i*5)+3] <= cal3_rden_dly[3]; |
rden_dly[(i*5)+4] <= cal3_rden_dly[4]; |
end |
end else begin |
rden_dly[(count_rden*5)] <= cal3_rden_dly[0]; |
rden_dly[(count_rden*5)+1] <= cal3_rden_dly[1]; |
rden_dly[(count_rden*5)+2] <= cal3_rden_dly[2]; |
rden_dly[(count_rden*5)+3] <= cal3_rden_dly[3]; |
rden_dly[(count_rden*5)+4] <= cal3_rden_dly[4]; |
end |
|
// Use for stage 4 calibration |
calib_rden_dly[(count_rden*5)] <= cal3_rden_srl_a[0]; |
calib_rden_dly[(count_rden*5)+1] <= cal3_rden_srl_a[1]; |
calib_rden_dly[(count_rden*5)+2] <= cal3_rden_srl_a[2]; |
calib_rden_dly[(count_rden*5)+3] <= cal3_rden_srl_a[3]; |
calib_rden_dly[(count_rden*5)+4] <= cal3_rden_srl_a[4]; |
cal3_state <= CAL3_DONE; |
end else begin |
// If we run out of stages to shift, without finding correct |
// result, the stop and assert error |
if (cal3_rden_srl_a == 5'b11111) begin |
calib_err_2[0] <= 1'b1; |
cal3_state <= CAL3_IDLE; |
end else begin |
// otherwise, increase the shift value and try again |
cal3_rden_srl_a <= cal3_rden_srl_a + 1; |
cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; |
end |
end |
|
// give additional time for RDEN_R pipe to clear from effects of |
// previous pipeline or IDELAY tap change |
CAL3_RDEN_PIPE_CLR_WAIT: |
if (calib_rden_pipe_cnt == 5'b00000) |
cal3_state <= CAL3_DETECT; |
|
CAL3_DONE: begin |
if ((count_rden == DQS_WIDTH-1) || (SIM_ONLY != 0)) begin |
calib_done[2] <= 1'b1; |
cal3_state <= CAL3_IDLE; |
end else begin |
count_rden <= count_rden + 1; |
cal3_state <= CAL3_INIT; |
end |
end |
endcase |
end |
end |
|
//***************************************************************** |
// Last part of stage 3 calibration - compensate for differences |
// in delay between different DQS groups. Assume that in the worst |
// case, DQS groups can only differ by one clock cycle. Data for |
// certain DQS groups must be delayed by one clock cycle. |
// NOTE: May need to increase allowable variation to greater than |
// one clock cycle in certain customer designs. |
// Algorithm is: |
// 1. Record shift delay value for DQS[0] |
// 2. Compare each DQS[x] delay value to that of DQS[0]: |
// - If different, than record this fact (RDEN_MUX) |
// - If greater than DQS[0], set RDEN_INC. Assume greater by |
// one clock cycle only - this is a key assumption, assume no |
// more than a one clock cycle variation. |
// - If less than DQS[0], set RDEN_DEC |
// 3. After calibration is complete, set control for DQS group |
// delay (CALIB_RDEN_SEL): |
// - If RDEN_DEC = 1, then assume that DQS[0] is the lowest |
// delay (and at least one other DQS group has a higher |
// delay). |
// - If RDEN_INC = 1, then assume that DQS[0] is the highest |
// delay (and that all other DQS groups have the same or |
// lower delay). |
// - If both RDEN_INC and RDEN_DEC = 1, then flag error |
// (variation is too high for this algorithm to handle) |
//***************************************************************** |
|
always @(posedge clkdiv) begin |
if (rstdiv) begin |
calib_err_2[1] <= 1'b0; |
calib_rden_sel <= {DQS_WIDTH{1'bx}}; |
rden_dec <= 1'b0; |
rden_dly_0 <= 5'bxxxxx; |
rden_inc <= 1'b0; |
rden_mux <= {DQS_WIDTH{1'b0}}; |
end else begin |
// if a match if found, then store the value of rden_dly |
if (!calib_done[2]) begin |
if ((cal3_state == CAL3_DETECT) && cal3_match_found) begin |
// store the value for DQS[0] as a reference |
if (count_rden == 0) begin |
// for simulation, RDEN calibration only happens for DQS[0] |
// set RDEN_MUX for all DQS groups to be the same as DQS[0] |
if (SIM_ONLY != 0) |
rden_mux <= {DQS_WIDTH{1'b0}}; |
else begin |
// otherwise, load values for DQS[0] |
rden_dly_0 <= cal3_rden_srl_a; |
rden_mux[0] <= 1'b0; |
end |
end else if (SIM_ONLY == 0) begin |
// for all other DQS groups, compare RDEN_DLY delay value with |
// that of DQS[0] |
if (rden_dly_0 != cal3_rden_srl_a) begin |
// record that current DQS group has a different delay |
// than DQS[0] (the "reference" DQS group) |
rden_mux[count_rden] <= 1'b1; |
if (rden_dly_0 > cal3_rden_srl_a) |
rden_inc <= 1'b1; |
else if (rden_dly_0 < cal3_rden_srl_a) |
rden_dec <= 1'b1; |
// otherwise, if current DQS group has same delay as DQS[0], |
// then rden_mux[count_rden] remains at 0 (since rden_mux |
// array contents initialized to 0) |
end |
end |
end |
end else begin |
// Otherwise - if we're done w/ stage 2 calibration: |
// set final value for RDEN data delay |
// flag error if there's more than one cycle variation from DQS[0] |
calib_err_2[1] <= (rden_inc && rden_dec); |
if (rden_inc) |
// if DQS[0] delay represents max delay |
calib_rden_sel <= ~rden_mux; |
else |
// if DQS[0] delay represents min delay (or all the delays are |
// the same between DQS groups) |
calib_rden_sel <= rden_mux; |
end |
end |
end |
|
// flag error for stage 3 if appropriate |
always @(posedge clkdiv) |
calib_err[2] <= calib_err_2[0] | calib_err_2[1]; |
|
//*************************************************************************** |
// Stage 4 calibration: DQS gate |
//*************************************************************************** |
|
//***************************************************************** |
// indicates that current received data is the correct pattern. Same as |
// for READ VALID calibration, except that the expected data sequence is |
// different since DQS gate is asserted after the 6th word. |
// Data sequence: |
// Arrives from memory (at FPGA input) (R, F): 1 0 0 1 1 0 0 1 |
// After gating the sequence looks like: 1 0 0 1 1 0 1 0 (7th word = |
// 5th word, 8th word = 6th word) |
// What is the gate timing is off? Need to make sure we can distinquish |
// between the results of correct vs. incorrect gate timing. We also use |
// the "read_valid" signal from stage 3 calibration to help us determine |
// when to check for a valid sequence for stage 4 calibration (i.e. use |
// CAL4_DATA_VALID in addition to CAL4_DATA_MATCH/CAL4_DATA_MATCH_STGD) |
// Note that since the gate signal from the CLK0 domain is synchronized |
// to the falling edge of DQS, that the effect of the gate will only be |
// seen starting with a rising edge data (although it is possible |
// the GATE IDDR output could go metastable and cause a unexpected result |
// on the first rising and falling edges after the gate is enabled). |
// Also note that the actual DQS glitch can come more than 0.5*tCK after |
// the last falling edge of DQS and the constraint for this path is can |
// be > 0.5*tCK; however, this means when calibrating, the output of the |
// GATE IDDR may miss the setup time requirement of the rising edge flop |
// and only meet it for the falling edge flop. Therefore the rising |
// edge data immediately following the assertion of the gate can either |
// be a 1 or 0 (can rely on either) |
// As the timing on the gate is varied, we expect to see (sequence of |
// captured read data shown below): |
// - 1 0 0 1 1 0 0 1 (gate is really early, starts and ends before |
// read burst even starts) |
// - x 0 0 1 1 0 0 1 (gate pulse starts before the burst, and ends |
// - x y 0 1 1 0 0 1 sometime during the burst; x,y = 0, or 1, but |
// - x y x 1 1 0 0 1 all bits that show an x are the same value, |
// - x y x y 1 0 0 1 and y are the same value) |
// - x y x y x 0 0 1 |
// - x y x y x y 0 1 (gate starts just before start of burst) |
// - 1 0 x 0 x 0 x 0 (gate starts after 1st falling word. The "x" |
// represents possiblity that gate may not disable |
// clock for 2nd rising word in time) |
// - 1 0 0 1 x 1 x 1 (gate starts after 2nd falling word) |
// - 1 0 0 1 1 0 x 0 (gate starts after 3rd falling word - GOOD!!) |
// - 1 0 0 1 1 0 0 1 (gate starts after burst is already done) |
//***************************************************************** |
|
assign cal4_data_valid = calib_rden_valid | calib_rden_valid_stgd; |
assign cal4_data_good = (calib_rden_valid & |
cal4_data_match) | |
(calib_rden_valid_stgd & |
cal4_data_match_stgd); |
|
always @(posedge clkdiv) begin |
// if data is aligned out of fabric ISERDES: |
cal4_data_match <= ((rdd_rise_q2_r == 1) && |
(rdd_fall_q2_r == 0) && |
(rdd_rise_q1_r == 0) && |
(rdd_fall_q1_r == 1) && |
(rdd_rise_q2 == 1) && |
(rdd_fall_q2 == 0) && |
// MIG 2.1: Last rising edge data value not |
// guaranteed to be certain value at higher |
// frequencies |
// (rdd_rise_q1 == 0) && |
(rdd_fall_q1 == 0)); |
// if data is staggered out of fabric ISERDES: |
cal4_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && |
(rdd_fall_q1_r1 == 0) && |
(rdd_rise_q2_r == 0) && |
(rdd_fall_q2_r == 1) && |
(rdd_rise_q1_r == 1) && |
(rdd_fall_q1_r == 0) && |
// MIG 2.1: Last rising edge data value not |
// guaranteed to be certain value at higher |
// frequencies |
// (rdd_rise_q2 == 0) && |
(rdd_fall_q2 == 0)); |
end |
|
//***************************************************************** |
// DQS gate enable generation: |
// This signal gets synchronized to DQS domain, and drives IDDR |
// register that in turn asserts/deasserts CE to all 4 or 8 DQ |
// IDDR's in that DQS group. |
// 1. During normal (post-cal) operation, this is only for 2 clock |
// cycles following the end of a burst. Check for falling edge |
// of RDEN. But must also make sure NOT assert for a read-idle- |
// read (two non-consecutive reads, separated by exactly one |
// idle cycle) - in this case, don't assert the gate because: |
// (1) we don't have enough time to deassert the gate before the |
// first rising edge of DQS for second burst (b/c of fact |
// that DQS gate is generated in the fabric only off rising |
// edge of CLK0 - if we somehow had an ODDR in fabric, we |
// could pull this off, (2) assumption is that the DQS glitch |
// will not rise enough to cause a glitch because the |
// post-amble of the first burst is followed immediately by |
// the pre-amble of the next burst |
// 2. During stage 4 calibration, assert for 3 clock cycles |
// (assert gate enable one clock cycle early), since we gate out |
// the last two words (in addition to the crap on the DQ bus after |
// the DQS read postamble). |
// NOTE: PHY_INIT_RDEN and CTRL_RDEN have slightly different timing w/r |
// to when they are asserted w/r to the start of the read burst |
// (PHY_INIT_RDEN is one cycle earlier than CTRL_RDEN). |
//***************************************************************** |
|
// register for timing purposes for fast clock path - currently only |
// calib_done_r[2] used |
always @(posedge clk) |
calib_done_r <= calib_done; |
|
always @(*) begin |
calib_ctrl_rden = ctrl_rden; |
calib_init_rden = calib_done_r[2] & phy_init_rden; |
end |
|
assign calib_ctrl_rden_negedge = ~calib_ctrl_rden & calib_ctrl_rden_r; |
// check for read-idle-read before asserting DQS pulse at end of read |
assign calib_ctrl_gate_pulse = calib_ctrl_rden_negedge_r & |
~calib_ctrl_rden; |
always @(posedge clk) begin |
calib_ctrl_rden_r <= calib_ctrl_rden; |
calib_ctrl_rden_negedge_r <= calib_ctrl_rden_negedge; |
calib_ctrl_gate_pulse_r <= calib_ctrl_gate_pulse; |
end |
|
assign calib_init_gate_pulse = ~calib_init_rden & calib_init_rden_r; |
always @(posedge clk) begin |
calib_init_rden_r <= calib_init_rden; |
calib_init_gate_pulse_r <= calib_init_gate_pulse; |
calib_init_gate_pulse_r1 <= calib_init_gate_pulse_r; |
end |
|
// Gate is asserted: (1) during cal, for 3 cycles, starting 1 cycle |
// after falling edge of CTRL_RDEN, (2) during normal ops, for 2 |
// cycles, starting 2 cycles after falling edge of CTRL_RDEN |
assign gate_srl_in = ~((calib_ctrl_gate_pulse | |
calib_ctrl_gate_pulse_r) | |
(calib_init_gate_pulse | |
calib_init_gate_pulse_r | |
calib_init_gate_pulse_r1)); |
|
//***************************************************************** |
// generate DQS enable signal for each DQS group |
// There are differences between DQS gate signal for calibration vs. during |
// normal operation: |
// * calibration gates the second to last clock cycle of the burst, |
// rather than after the last word (e.g. for a 8-word, 4-cycle burst, |
// cycle 4 is gated for calibration; during normal operation, cycle |
// 5 (i.e. cycle after the last word) is gated) |
// enable for DQS is deasserted for two clock cycles, except when |
// we have the preamble for the next read immediately following |
// the postamble of the current read - assume DQS does not glitch |
// during this time, that it stays low. Also if we did have to gate |
// the DQS for this case, then we don't have enough time to deassert |
// the gate in time for the first rising edge of DQS for the second |
// read |
//***************************************************************** |
|
// Flops for targetting of multi-cycle path in UCF |
genvar gate_ff_i; |
generate |
for (gate_ff_i = 0; gate_ff_i < 5*DQS_WIDTH; |
gate_ff_i = gate_ff_i+1) begin: gen_gate_dly |
FDRSE u_ff_gate_dly |
( |
.Q (gate_dly_r[gate_ff_i]), |
.C (clkdiv), |
.CE (1'b1), |
.D (gate_dly[gate_ff_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
genvar gate_i; |
generate |
for (gate_i = 0; gate_i < DQS_WIDTH; gate_i = gate_i + 1) begin: gen_gate |
SRLC32E u_gate_srl |
( |
.Q (gate_srl_out[gate_i]), |
.Q31 (), |
.A ({gate_dly_r[(gate_i*5)+4], |
gate_dly_r[(gate_i*5)+3], |
gate_dly_r[(gate_i*5)+2], |
gate_dly_r[(gate_i*5)+1], |
gate_dly_r[(gate_i*5)]}), |
.CE (1'b1), |
.CLK (clk), |
.D (gate_srl_in) |
); |
|
// For GATE_BASE_DELAY > 0, have one extra cycle to register outputs |
// from controller before generating DQS gate pulse. In PAR, the |
// location of the controller logic can be far from the DQS gate |
// logic (DQS gate logic located near the DQS I/O's), contributing |
// to large net delays. Registering the controller outputs for |
// CL >= 4 (above 200MHz) adds a stage of pipelining to reduce net |
// delays |
if (GATE_BASE_DELAY > 0) begin: gen_gate_base_dly_gt3 |
// add flop between SRL32 and EN_DQS flop (which is located near the |
// DDR2 IOB's) |
FDRSE u_gate_srl_ff |
( |
.Q (gate_srl_out_r[gate_i]), |
.C (clk), |
.CE (1'b1), |
.D (gate_srl_out[gate_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */; |
end else begin: gen_gate_base_dly_le3 |
assign gate_srl_out_r[gate_i] = gate_srl_out[gate_i]; |
end |
|
FDRSE u_en_dqs_ff |
( |
.Q (en_dqs[gate_i]), |
.C (clk), |
.CE (1'b1), |
.D (gate_srl_out_r[gate_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve = 1 */ |
/* synthesis syn_replicate = 0 */; |
end |
endgenerate |
|
//***************************************************************** |
// Find valid window: keep track of how long we've been in the same data |
// window. If it's been long enough, then declare that we've found a stable |
// valid window - in particular, that we're past any region of instability |
// associated with the edge of the window. Use only when finding left edge |
//***************************************************************** |
|
always @(posedge clkdiv) |
// reset before we start to look for window |
if (cal4_state == CAL4_INIT) begin |
cal4_window_cnt <= 4'b0000; |
cal4_stable_window <= 1'b0; |
end else if ((cal4_state == CAL4_FIND_EDGE) && cal4_seek_left) begin |
// if we're looking for left edge, and incrementing IDELAY, count |
// consecutive taps over which we're in the window |
if (cal4_data_valid) begin |
if (cal4_data_good) |
cal4_window_cnt <= cal4_window_cnt + 1; |
else |
cal4_window_cnt <= 4'b0000; |
end |
|
if (cal4_window_cnt == MIN_WIN_SIZE-1) |
cal4_stable_window <= 1'b1; |
end |
|
//***************************************************************** |
// keep track of edge tap counts found, and whether we've |
// incremented to the maximum number of taps allowed |
//***************************************************************** |
|
always @(posedge clkdiv) |
if ((cal4_state == CAL4_INIT) || cal4_dlyrst_gate) begin |
cal4_idel_max_tap <= 1'b0; |
cal4_idel_bit_tap <= 1'b0; |
cal4_idel_tap_cnt <= 6'b000000; |
end else if (cal4_dlyce_gate) begin |
if (cal4_dlyinc_gate) begin |
cal4_idel_tap_cnt <= cal4_idel_tap_cnt + 1; |
cal4_idel_bit_tap <= (cal4_idel_tap_cnt == CAL4_IDEL_BIT_VAL-2); |
cal4_idel_max_tap <= (cal4_idel_tap_cnt == 6'b111110); |
end else begin |
cal4_idel_tap_cnt <= cal4_idel_tap_cnt - 1; |
cal4_idel_bit_tap <= 1'b0; |
cal4_idel_max_tap <= 1'b0; |
end |
end |
|
always @(posedge clkdiv) |
if ((cal4_state != CAL4_RDEN_PIPE_CLR_WAIT) && |
(cal3_state != CAL3_RDEN_PIPE_CLR_WAIT)) |
calib_rden_pipe_cnt <= CALIB_RDEN_PIPE_LEN-1; |
else |
calib_rden_pipe_cnt <= calib_rden_pipe_cnt - 1; |
|
//***************************************************************** |
// Stage 4 cal state machine |
//***************************************************************** |
|
always @(posedge clkdiv) |
if (rstdiv) begin |
calib_done[3] <= 1'b0; |
calib_done_tmp[3] <= 1'b0; |
calib_err[3] <= 1'b0; |
count_gate <= 'b0; |
gate_dly <= 'b0; |
next_count_gate <= 'b0; |
cal4_idel_adj_cnt <= 6'bxxxxxx; |
cal4_dlyce_gate <= 1'b0; |
cal4_dlyinc_gate <= 1'b0; |
cal4_dlyrst_gate <= 1'b0; // reset handled elsewhere in code |
cal4_gate_srl_a <= 5'bxxxxx; |
cal4_rden_srl_a <= 5'bxxxxx; |
cal4_ref_req <= 1'b0; |
cal4_seek_left <= 1'bx; |
cal4_state <= CAL4_IDLE; |
end else begin |
cal4_ref_req <= 1'b0; |
cal4_dlyce_gate <= 1'b0; |
cal4_dlyinc_gate <= 1'b0; |
cal4_dlyrst_gate <= 1'b0; |
|
case (cal4_state) |
CAL4_IDLE: begin |
count_gate <= 'b0; |
next_count_gate <= 'b0; |
if (calib_start[3]) begin |
gate_dly <= 'b0; |
calib_done[3] <= 1'b0; |
cal4_state <= CAL4_INIT; |
end |
end |
|
CAL4_INIT: begin |
// load: (1) initial value of gate delay SRL, (2) appropriate |
// value of RDEN SRL (so that we get correct "data valid" timing) |
cal4_gate_srl_a <= GATE_BASE_INIT; |
cal4_rden_srl_a <= {calib_rden_dly[(count_gate*5)+4], |
calib_rden_dly[(count_gate*5)+3], |
calib_rden_dly[(count_gate*5)+2], |
calib_rden_dly[(count_gate*5)+1], |
calib_rden_dly[(count_gate*5)]}; |
// let SRL pipe clear after loading initial shift value |
cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; |
end |
|
// sort of an initial state - start checking to see whether we're |
// already in the window or not |
CAL4_FIND_WINDOW: |
// decide right away if we start in the proper window - this |
// determines if we are then looking for the left (trailing) or |
// right (leading) edge of the data valid window |
if (cal4_data_valid) begin |
// if we find a match - then we're already in window, now look |
// for left edge. Otherwise, look for right edge of window |
cal4_seek_left <= cal4_data_good; |
cal4_state <= CAL4_FIND_EDGE; |
end |
|
CAL4_FIND_EDGE: |
// don't do anything until the exact clock cycle when to check that |
// readback data is valid or not |
if (cal4_data_valid) begin |
// we're currently in the window, look for left edge of window |
if (cal4_seek_left) begin |
// make sure we've passed the right edge before trying to detect |
// the left edge (i.e. avoid any edge "instability") - else, we |
// may detect an "false" edge too soon. By design, if we start in |
// the data valid window, always expect at least |
// MIN(BIT_TIME_TAPS,32) (-/+ jitter, see below) taps of valid |
// window before we hit the left edge (this is because when stage |
// 4 calibration first begins (i.e., gate_dly = 00, and IDELAY = |
// 00), we're guaranteed to NOT be in the window, and we always |
// start searching for MIN(BIT_TIME_TAPS,32) for the right edge |
// of window. If we don't find it, increment gate_dly, and if we |
// now start in the window, we have at least approximately |
// CLK_PERIOD-MIN(BIT_TIME_TAPS,32) = MIN(BIT_TIME_TAPS,32) taps. |
// It's approximately because jitter, noise, etc. can bring this |
// value down slightly. Because of this (although VERY UNLIKELY), |
// we have to protect against not decrementing IDELAY below 0 |
// during adjustment phase). |
if (cal4_stable_window && !cal4_data_good) begin |
// found left edge of window, dec by MIN(BIT_TIME_TAPS,32) |
cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; |
cal4_idel_adj_inc <= 1'b0; |
cal4_state <= CAL4_ADJ_IDEL; |
end else begin |
// Otherwise, keep looking for left edge: |
if (cal4_idel_max_tap) begin |
// ran out of taps looking for left edge (max=63) - happens |
// for low frequency case, decrement by 32 |
cal4_idel_adj_cnt <= 6'b100000; |
cal4_idel_adj_inc <= 1'b0; |
cal4_state <= CAL4_ADJ_IDEL; |
end else begin |
cal4_dlyce_gate <= 1'b1; |
cal4_dlyinc_gate <= 1'b1; |
cal4_state <= CAL4_IDEL_WAIT; |
end |
end |
end else begin |
// looking for right edge of window: |
// look for the first match - this means we've found the right |
// (leading) edge of the data valid window, increment by |
// MIN(BIT_TIME_TAPS,32) |
if (cal4_data_good) begin |
cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; |
cal4_idel_adj_inc <= 1'b1; |
cal4_state <= CAL4_ADJ_IDEL; |
end else begin |
// Otherwise, keep looking: |
// only look for MIN(BIT_TIME_TAPS,32) taps for right edge, |
// if we haven't found it, then inc gate delay, try again |
if (cal4_idel_bit_tap) begin |
// if we're already maxed out on gate delay, then error out |
// (simulation only - calib_err isn't currently connected) |
if (cal4_gate_srl_a == 5'b11111) begin |
calib_err[3] <= 1'b1; |
cal4_state <= CAL4_IDLE; |
end else begin |
// otherwise, increment gate delay count, and start |
// over again |
cal4_gate_srl_a <= cal4_gate_srl_a + 1; |
cal4_dlyrst_gate <= 1'b1; |
cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; |
end |
end else begin |
// keep looking for right edge |
cal4_dlyce_gate <= 1'b1; |
cal4_dlyinc_gate <= 1'b1; |
cal4_state <= CAL4_IDEL_WAIT; |
end |
end |
end |
end |
|
// wait for GATE IDELAY to settle, after reset or increment |
CAL4_IDEL_WAIT: begin |
// For simulation, load SRL addresses for all DQS with same value |
if (SIM_ONLY != 0) begin |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly |
gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; |
gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; |
gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; |
gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; |
gate_dly[(i*5)] <= cal4_gate_srl_a[0]; |
end |
end else begin |
gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; |
gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; |
gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; |
gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; |
gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; |
end |
// check to see if we've found edge of window |
if (!idel_set_wait) |
cal4_state <= CAL4_FIND_EDGE; |
end |
|
// give additional time for RDEN_R pipe to clear from effects of |
// previous pipeline (and IDELAY reset) |
CAL4_RDEN_PIPE_CLR_WAIT: begin |
// MIG 2.2: Bug fix - make sure to update GATE_DLY count, since |
// possible for FIND_EDGE->RDEN_PIPE_CLR_WAIT->FIND_WINDOW |
// transition (i.e. need to make sure the gate count updated in |
// FIND_EDGE gets reflected in GATE_DLY by the time we reach |
// state FIND_WINDOW) - previously GATE_DLY only being updated |
// during state CAL4_IDEL_WAIT |
if (SIM_ONLY != 0) begin |
for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly_pipe |
gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; |
gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; |
gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; |
gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; |
gate_dly[(i*5)] <= cal4_gate_srl_a[0]; |
end |
end else begin |
gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; |
gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; |
gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; |
gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; |
gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; |
end |
// look for new window |
if (calib_rden_pipe_cnt == 5'b00000) |
cal4_state <= CAL4_FIND_WINDOW; |
end |
|
// increment/decrement DQS/DQ IDELAY for final adjustment |
CAL4_ADJ_IDEL: |
// add underflow protection for corner case when left edge found |
// using fewer than MIN(BIT_TIME_TAPS,32) taps |
if ((cal4_idel_adj_cnt == 6'b000000) || |
(cal4_dlyce_gate && !cal4_dlyinc_gate && |
(cal4_idel_tap_cnt == 6'b000001))) begin |
cal4_state <= CAL4_DONE; |
// stop when all gates calibrated, or gate[0] cal'ed (for sim) |
if ((count_gate == DQS_WIDTH-1) || (SIM_ONLY != 0)) |
calib_done_tmp[3] <= 1'b1; |
else |
// need for VHDL simulation to prevent out-of-index error |
next_count_gate <= count_gate + 1; |
end else begin |
cal4_idel_adj_cnt <= cal4_idel_adj_cnt - 1; |
cal4_dlyce_gate <= 1'b1; |
// whether inc or dec depends on whether left or right edge found |
cal4_dlyinc_gate <= cal4_idel_adj_inc; |
end |
|
// wait for IDELAY output to settle after decrement. Check current |
// COUNT_GATE value and decide if we're done |
CAL4_DONE: |
if (!idel_set_wait) begin |
count_gate <= next_count_gate; |
if (calib_done_tmp[3]) begin |
calib_done[3] <= 1'b1; |
cal4_state <= CAL4_IDLE; |
end else begin |
// request auto-refresh after every DQS group calibrated to |
// avoid tRAS violation |
cal4_ref_req <= 1'b1; |
if (calib_ref_done) |
cal4_state <= CAL4_INIT; |
end |
end |
endcase |
end |
|
endmodule |
/ddr2_mig/ddr2_idelay_ctrl.v
0,0 → 1,87
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_idelay_ctrl.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:00 $ |
// \ \ / \ Date Created: Wed Aug 16 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module instantiates the IDELAYCTRL primitive of the Virtex-5 device |
// which continuously calibrates the IDELAY elements in the region in case of |
// varying operating conditions. It takes a 200MHz clock as an input |
//Reference: |
//Revision History: |
// Rev 1.1 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added |
// on IOELAYCTRL primitive. Generate logic on IDELAYCTRL removed |
// since tools will replicate idelactrl primitives.PK. 11/27/08 |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_idelay_ctrl # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter IODELAY_GRP = "IODELAY_MIG" |
) |
|
( |
input clk200, |
input rst200, |
output idelay_ctrl_rdy |
); |
|
(* IODELAY_GROUP = IODELAY_GRP *) IDELAYCTRL u_idelayctrl |
( |
.RDY(idelay_ctrl_rdy), |
.REFCLK(clk200), |
.RST(rst200) |
); |
|
endmodule |
/ddr2_mig/ddr2_usr_top.v
0,0 → 1,184
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_usr_top.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:01 $ |
// \ \ / \ Date Created: Mon Aug 28 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// This module interfaces with the user. The user should provide the data |
// and various commands. |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_usr_top # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter BANK_WIDTH = 2, |
parameter CS_BITS = 0, |
parameter COL_WIDTH = 10, |
parameter DQ_WIDTH = 72, |
parameter DQ_PER_DQS = 8, |
parameter APPDATA_WIDTH = 144, |
parameter ECC_ENABLE = 0, |
parameter DQS_WIDTH = 9, |
parameter ROW_WIDTH = 14 |
) |
( |
input clk0, |
input usr_clk, //jb |
input clk90, |
input rst0, |
input [DQ_WIDTH-1:0] rd_data_in_rise, |
input [DQ_WIDTH-1:0] rd_data_in_fall, |
input [DQS_WIDTH-1:0] phy_calib_rden, |
input [DQS_WIDTH-1:0] phy_calib_rden_sel, |
output rd_data_valid, |
output [APPDATA_WIDTH-1:0] rd_data_fifo_out, |
input [2:0] app_af_cmd, |
input [30:0] app_af_addr, |
input app_af_wren, |
input ctrl_af_rden, |
output [2:0] af_cmd, |
output [30:0] af_addr, |
output af_empty, |
output app_af_afull, |
output [1:0] rd_ecc_error, |
input app_wdf_wren, |
input [APPDATA_WIDTH-1:0] app_wdf_data, |
input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, |
input wdf_rden, |
output app_wdf_afull, |
output [(2*DQ_WIDTH)-1:0] wdf_data, |
output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data |
); |
|
wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_fall; |
wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_rise; |
|
//*************************************************************************** |
|
assign rd_data_fifo_out = {i_rd_data_fifo_out_fall, |
i_rd_data_fifo_out_rise}; |
|
// read data de-skew and ECC calculation |
ddr2_usr_rd # |
( |
.DQ_PER_DQS (DQ_PER_DQS), |
.ECC_ENABLE (ECC_ENABLE), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.DQS_WIDTH (DQS_WIDTH) |
) |
u_usr_rd |
( |
.clk0 (clk0), |
.rst0 (rst0), |
.rd_data_in_rise (rd_data_in_rise), |
.rd_data_in_fall (rd_data_in_fall), |
.rd_ecc_error (rd_ecc_error), |
.ctrl_rden (phy_calib_rden), |
.ctrl_rden_sel (phy_calib_rden_sel), |
.rd_data_valid (rd_data_valid), |
.rd_data_out_rise (i_rd_data_fifo_out_rise), |
.rd_data_out_fall (i_rd_data_fifo_out_fall) |
); |
|
// Command/Addres FIFO |
ddr2_usr_addr_fifo # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.ROW_WIDTH (ROW_WIDTH) |
) |
u_usr_addr_fifo |
( |
.clk0 (clk0), |
.usr_clk (usr_clk), //jb |
.rst0 (rst0), |
.app_af_cmd (app_af_cmd), |
.app_af_addr (app_af_addr), |
.app_af_wren (app_af_wren), |
.ctrl_af_rden (ctrl_af_rden), |
.af_cmd (af_cmd), |
.af_addr (af_addr), |
.af_empty (af_empty), |
.app_af_afull (app_af_afull) |
); |
|
ddr2_usr_wr # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_BITS (CS_BITS), |
.DQ_WIDTH (DQ_WIDTH), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.ECC_ENABLE (ECC_ENABLE), |
.ROW_WIDTH (ROW_WIDTH) |
) |
u_usr_wr |
( |
.clk0 (clk0), |
.usr_clk (usr_clk), // jb |
.clk90 (clk90), |
.rst0 (rst0), |
.app_wdf_wren (app_wdf_wren), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.wdf_rden (wdf_rden), |
.app_wdf_afull (app_wdf_afull), |
.wdf_data (wdf_data), |
.wdf_mask_data (wdf_mask_data) |
); |
|
endmodule |
/ddr2_mig/ddr2_usr_rd.v
0,0 → 1,299
//***************************************************************************** |
// DISCLAIMER OF LIABILITY |
// |
// This file contains proprietary and confidential information of |
// Xilinx, Inc. ("Xilinx"), that is distributed under a license |
// from Xilinx, and may be used, copied and/or disclosed only |
// pursuant to the terms of a valid license agreement with Xilinx. |
// |
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION |
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT |
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT, |
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx |
// does not warrant that functions included in the Materials will |
// meet the requirements of Licensee, or that the operation of the |
// Materials will be uninterrupted or error-free, or that defects |
// in the Materials will be corrected. Furthermore, Xilinx does |
// not warrant or make any representations regarding use, or the |
// results of the use, of the Materials in terms of correctness, |
// accuracy, reliability or otherwise. |
// |
// Xilinx products are not designed or intended to be fail-safe, |
// or for use in any application requiring fail-safe performance, |
// such as life-support or safety devices or systems, Class III |
// medical devices, nuclear facilities, applications related to |
// the deployment of airbags, or any other applications that could |
// lead to death, personal injury or severe property or |
// environmental damage (individually and collectively, "critical |
// applications"). Customer assumes the sole risk and liability |
// of any use of Xilinx products in critical applications, |
// subject only to applicable laws and regulations governing |
// limitations on product liability. |
// |
// Copyright 2006, 2007, 2008 Xilinx, Inc. |
// All rights reserved. |
// |
// This disclaimer and copyright notice must be retained as part |
// of this file at all times. |
//***************************************************************************** |
// ____ ____ |
// / /\/ / |
// /___/ \ / Vendor: Xilinx |
// \ \ \/ Version: 3.0 |
// \ \ Application: MIG |
// / / Filename: ddr2_usr_rd.v |
// /___/ /\ Date Last Modified: $Date: 2008/12/23 14:26:01 $ |
// \ \ / \ Date Created: Tue Aug 29 2006 |
// \___\/\___\ |
// |
//Device: Virtex-5 |
//Design Name: DDR2 |
//Purpose: |
// The delay between the read data with respect to the command issued is |
// calculted in terms of no. of clocks. This data is then stored into the |
// FIFOs and then read back and given as the ouput for comparison. |
//Reference: |
//Revision History: |
//***************************************************************************** |
|
`timescale 1ns/1ps |
|
module ddr2_usr_rd # |
( |
// Following parameters are for 72-bit RDIMM design (for ML561 Reference |
// board design). Actual values may be different. Actual parameters values |
// are passed from design top module ddr2_mig module. Please refer to |
// the ddr2_mig module for actual values. |
parameter DQ_PER_DQS = 8, |
parameter DQS_WIDTH = 9, |
parameter APPDATA_WIDTH = 144, |
parameter ECC_WIDTH = 72, |
parameter ECC_ENABLE = 0 |
) |
( |
input clk0, |
input rst0, |
input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise, |
input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall, |
input [DQS_WIDTH-1:0] ctrl_rden, |
input [DQS_WIDTH-1:0] ctrl_rden_sel, |
output reg [1:0] rd_ecc_error, |
output rd_data_valid, |
output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise, |
output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall |
); |
|
// determine number of FIFO72's to use based on data width |
localparam RDF_FIFO_NUM = ((APPDATA_WIDTH/2)+63)/64; |
|
reg [DQS_WIDTH-1:0] ctrl_rden_r; |
wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data; |
reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall_r; |
reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise_r; |
wire rden; |
reg [DQS_WIDTH-1:0] rden_sel_r |
/* synthesis syn_preserve=1 */; |
wire [DQS_WIDTH-1:0] rden_sel_mux; |
wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data; |
|
// ECC specific signals |
wire [((RDF_FIFO_NUM -1) *2)+1:0] db_ecc_error; |
reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data_r; |
reg fifo_rden_r0; |
reg fifo_rden_r1; |
reg fifo_rden_r2; |
reg fifo_rden_r3; |
reg fifo_rden_r4; |
reg fifo_rden_r5; |
reg fifo_rden_r6; |
wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall_temp; |
wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise_temp; |
reg rst_r; |
reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data_r; |
wire [((RDF_FIFO_NUM -1) *2)+1:0] sb_ecc_error; |
|
|
//*************************************************************************** |
|
always @(posedge clk0) begin |
rden_sel_r <= ctrl_rden_sel; |
ctrl_rden_r <= ctrl_rden; |
rd_data_in_rise_r <= rd_data_in_rise; |
rd_data_in_fall_r <= rd_data_in_fall; |
end |
|
// Instantiate primitive to allow this flop to be attached to multicycle |
// path constraint in UCF. Multicycle path allowed for data from read FIFO. |
// This is the same signal as RDEN_SEL_R, but is only used to select data |
// (does not affect control signals) |
genvar rd_i; |
generate |
for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rden_sel_mux |
FDRSE u_ff_rden_sel_mux |
( |
.Q (rden_sel_mux[rd_i]), |
.C (clk0), |
.CE (1'b1), |
.D (ctrl_rden_sel[rd_i]), |
.R (1'b0), |
.S (1'b0) |
) /* synthesis syn_preserve=1 */; |
end |
endgenerate |
|
// determine correct read data valid signal timing |
assign rden = (rden_sel_r[0]) ? ctrl_rden[0] : ctrl_rden_r[0]; |
|
// assign data based on the skew |
genvar data_i; |
generate |
for(data_i = 0; data_i < DQS_WIDTH; data_i = data_i+1) begin: gen_data |
assign rise_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): |
(data_i*DQ_PER_DQS)] |
= (rden_sel_mux[data_i]) ? |
rd_data_in_rise[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1) : |
(data_i*DQ_PER_DQS)] : |
rd_data_in_rise_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): |
(data_i*DQ_PER_DQS)]; |
assign fall_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): |
(data_i*DQ_PER_DQS)] |
= (rden_sel_mux[data_i]) ? |
rd_data_in_fall[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): |
(data_i*DQ_PER_DQS)] : |
rd_data_in_fall_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): |
(data_i*DQ_PER_DQS)]; |
end |
endgenerate |
|
// Generate RST for FIFO reset AND for read/write enable: |
// ECC FIFO always being read from and written to |
always @(posedge clk0) |
rst_r <= rst0; |
|
genvar rdf_i; |
generate |
if (ECC_ENABLE) begin |
always @(posedge clk0) begin |
rd_ecc_error[0] <= (|sb_ecc_error) & fifo_rden_r5; |
rd_ecc_error[1] <= (|db_ecc_error) & fifo_rden_r5; |
rd_data_out_rise <= rd_data_out_rise_temp; |
rd_data_out_fall <= rd_data_out_fall_temp; |
rise_data_r <= rise_data; |
fall_data_r <= fall_data; |
end |
|
// can use any of the read valids, they're all delayed by same amount |
assign rd_data_valid = fifo_rden_r6; |
|
// delay read valid to take into account max delay difference btw |
// the read enable coming from the different DQS groups |
always @(posedge clk0) begin |
if (rst0) begin |
fifo_rden_r0 <= 1'b0; |
fifo_rden_r1 <= 1'b0; |
fifo_rden_r2 <= 1'b0; |
fifo_rden_r3 <= 1'b0; |
fifo_rden_r4 <= 1'b0; |
fifo_rden_r5 <= 1'b0; |
fifo_rden_r6 <= 1'b0; |
end else begin |
fifo_rden_r0 <= rden; |
fifo_rden_r1 <= fifo_rden_r0; |
fifo_rden_r2 <= fifo_rden_r1; |
fifo_rden_r3 <= fifo_rden_r2; |
fifo_rden_r4 <= fifo_rden_r3; |
fifo_rden_r5 <= fifo_rden_r4; |
fifo_rden_r6 <= fifo_rden_r5; |
end |
end |
|
for (rdf_i = 0; rdf_i < RDF_FIFO_NUM; rdf_i = rdf_i + 1) begin: gen_rdf |
|
FIFO36_72 # // rise fifo |
( |
.ALMOST_EMPTY_OFFSET (9'h007), |
.ALMOST_FULL_OFFSET (9'h00F), |
.DO_REG (1), // extra CC output delay |
.EN_ECC_WRITE ("FALSE"), |
.EN_ECC_READ ("TRUE"), |
.EN_SYN ("FALSE"), |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_rdf |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (), |
.DBITERR (db_ecc_error[rdf_i + rdf_i]), |
.DO (rd_data_out_rise_temp[(64*(rdf_i+1))-1: |
(64 *rdf_i)]), |
.DOP (), |
.ECCPARITY (), |
.EMPTY (), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.SBITERR (sb_ecc_error[rdf_i + rdf_i]), |
.WRCOUNT (), |
.WRERR (), |
.DI (rise_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: |
(64 *rdf_i)+(rdf_i*8)]), |
.DIP (rise_data_r[(72*(rdf_i+1))-1: |
(64*(rdf_i+1))+ (8*rdf_i)]), |
.RDCLK (clk0), |
.RDEN (~rst_r), |
.RST (rst_r), |
.WRCLK (clk0), |
.WREN (~rst_r) |
); |
|
FIFO36_72 # // fall_fifo |
( |
.ALMOST_EMPTY_OFFSET (9'h007), |
.ALMOST_FULL_OFFSET (9'h00F), |
.DO_REG (1), // extra CC output delay |
.EN_ECC_WRITE ("FALSE"), |
.EN_ECC_READ ("TRUE"), |
.EN_SYN ("FALSE"), |
.FIRST_WORD_FALL_THROUGH ("FALSE") |
) |
u_rdf1 |
( |
.ALMOSTEMPTY (), |
.ALMOSTFULL (), |
.DBITERR (db_ecc_error[(rdf_i+1) + rdf_i]), |
.DO (rd_data_out_fall_temp[(64*(rdf_i+1))-1: |
(64 *rdf_i)]), |
.DOP (), |
.ECCPARITY (), |
.EMPTY (), |
.FULL (), |
.RDCOUNT (), |
.RDERR (), |
.SBITERR (sb_ecc_error[(rdf_i+1) + rdf_i]), |
.WRCOUNT (), |
.WRERR (), |
.DI (fall_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: |
(64*rdf_i)+(rdf_i*8)]), |
.DIP (fall_data_r[(72*(rdf_i+1))-1: |
(64*(rdf_i+1))+ (8*rdf_i)]), |
.RDCLK (clk0), |
.RDEN (~rst_r), |
.RST (rst_r), // or can use rst0 |
.WRCLK (clk0), |
.WREN (~rst_r) |
); |
end |
end // if (ECC_ENABLE) |
|
else begin |
assign rd_data_valid = fifo_rden_r0; |
always @(posedge clk0) begin |
rd_data_out_rise <= rise_data; |
rd_data_out_fall <= fall_data; |
fifo_rden_r0 <= rden; |
end |
end |
endgenerate |
|
endmodule |
/ml501_ddr2_params.vh
0,0 → 1,50
|
// memory controller parameters |
parameter BANK_WIDTH = 2; // # of memory bank addr bits |
parameter CKE_WIDTH = 2; // # of memory clock enable outputs |
parameter CLK_WIDTH = 2; // # of clock outputs |
parameter CLK_TYPE = "SINGLE_ENDED"; // # of clock type |
parameter COL_WIDTH = 10; // # of memory column bits |
parameter CS_NUM = 1; // # of separate memory chip selects |
parameter CS_WIDTH = 2; // # of total memory chip selects |
parameter CS_BITS = 0; // set to log2(CS_NUM) (rounded up) |
parameter DM_WIDTH = 8; // # of data mask bits |
parameter DQ_WIDTH = 64; // # of data width |
parameter DQ_PER_DQS = 8; // # of DQ data bits per strobe |
parameter DQS_WIDTH = 8; // # of DQS strobes |
parameter DQ_BITS = 6; // set to log2(DQS_WIDTH*DQ_PER_DQS) |
parameter DQS_BITS = 3; // set to log2(DQS_WIDTH) |
parameter HIGH_PERFORMANCE_MODE = "TRUE"; // Sets the performance mode for IODELAY elements |
parameter ODT_WIDTH = 2; // # of memory on-die term enables |
parameter ROW_WIDTH = 13; // # of memory row & # of addr bits |
// Can't change this!! |
parameter APPDATA_WIDTH = 128; // # of usr read/write data bus bits |
//parameter APPDATA_WIDTH = 32; // # of usr read/write data bus bits |
|
parameter ADDITIVE_LAT = 0; // additive write latency |
parameter BURST_LEN = 4; // burst length (in double words) |
parameter BURST_TYPE = 0; // burst type (=0 seq; =1 interlved) |
parameter CAS_LAT = 4; // CAS latency |
parameter ECC_ENABLE = 0; // enable ECC (=1 enable) |
parameter MULTI_BANK_EN = 1; // enable bank management |
parameter TWO_T_TIME_EN = 1; // 2t timing for unbuffered dimms |
parameter ODT_TYPE = 1; // ODT (=0(none),=1(75),=2(150),=3(50)) |
parameter REDUCE_DRV = 0; // reduced strength mem I/O (=1 yes) |
parameter REG_ENABLE = 0; // registered addr/ctrl (=1 yes) |
parameter TREFI_NS = 7800; // auto refresh interval (ns) |
parameter TRAS = 40000; // active->precharge delay |
parameter TRCD = 15000; // active->read/write delay |
parameter TRFC = 105000; // ref->ref, ref->active delay |
parameter TRP = 15000; // precharge->command delay |
parameter TRTP = 7500; // read->precharge delay |
parameter TWR = 15000; // used to determine wr->prech |
parameter TWTR = 7500; // write->read delay |
// Synthesize with this set to one if running post-synthesis simulations (don't have to wait forever for powerup delay on DDR2 controller) |
// parameter SIM_ONLY = 1; // = 0 to allow power up delay |
parameter SIM_ONLY = 0; // = 0 to allow power up delay |
parameter DEBUG_EN = 0; // Enable debug signals/controls |
parameter RST_ACT_LOW = 0; // =1 for active low reset, =0 for active high |
parameter DLL_FREQ_MODE = "HIGH"; // DCM Frequency range |
parameter CLK_PERIOD = 3750; // 266MHz Core/Mem clk period (in ps) |
// parameter CLK_PERIOD = 5000; // 200MHz Core/Mem clk period (in ps) |
|
/dummy_slave.v
0,0 → 1,33
/* |
Dummy Slave module |
|
Simply acks back a pre-determined value |
|
*/ |
|
module dummy_slave |
( dat_o, stb_i, cyc_i, ack_o, clk, rst ); |
|
|
output [31:0] dat_o; |
input stb_i; |
input cyc_i; |
output ack_o; |
input clk; |
input rst; |
|
reg ack_o; |
|
parameter [31:0] value = 32'hc0000000; |
|
assign dat_o = value; |
|
always @ (posedge clk or posedge rst) |
if (rst) |
ack_o <= 1'b0; |
else |
ack_o <= stb_i & cyc_i & !ack_o; |
|
endmodule // dummy_slave |
|
|
/reset_debounce.v
0,0 → 1,80
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Reset control/debouncer //// |
//// //// |
//// Description //// |
//// Debounce reset button signal. It is also sensitive to the //// |
//// user generated reset and DCM lock signals. //// |
//// //// |
//// To Do: //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
module reset_debounce |
( |
input sys_rst_in, |
input usr_rst_in, |
input sys_clk_in, |
output rst_dcm0, |
input dcm0_clk, |
input dcm0_locked, |
output rst |
); |
|
reg [9:0] debounce_count = 10'h000; |
wire sys_rst = !(sys_rst_in & usr_rst_in); // Either of these going low triggers reset |
reg debounced_rst; |
|
always @(posedge sys_clk_in) begin |
if (sys_rst) begin |
debounced_rst <= 1'b1; |
debounce_count <= 10'h3ff; |
end else begin |
if (debounce_count > 10'b0000000000) debounce_count <= debounce_count - 1'b1; |
if (debounce_count == 10'b0000000001) debounced_rst <= sys_rst; |
end |
end |
|
assign rst_dcm0 = debounced_rst; |
|
/* Hold reset for a little longer after the dcm locks */ |
reg [15:0] rst_dcm0_count; |
always @(posedge dcm0_clk or posedge debounced_rst) |
if (debounced_rst) |
rst_dcm0_count <= 16'hffff; |
else |
rst_dcm0_count <= {rst_dcm0_count[14:0], ~dcm0_locked}; |
|
|
assign rst = rst_dcm0_count[15]; |
|
endmodule // reset_debounce |
/ssram_controller.v
0,0 → 1,301
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx ML501 SSRAM controller with Wishbone Interface //// |
//// //// |
//// Description //// |
//// ZBT SSRAM controller for ML501 board part (or any ZBT RAM) //// |
//// Timing relies on definition of multi-cycle paths during //// |
//// synthesis. //// |
//// //// |
//// To Do: //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
/* |
* Controller for ZBT synchronous SRAM (ISSI IS61NLP25636A-200TQL) |
* Explicitly uses Xilinx primitives |
* Currently configured for a 1/4 ratio between bus/ssram clocks: 50 / 200 MHz |
* Requires declaration of some multi-cycle paths during synthesis. |
* |
* Note: clk_200 and bus clock should be in phase (from same DCM) |
* |
* Clocking/phase counting scheme (to change it to higher/lower ratio): |
* |
* We run a phase counter, checking the bus on the last cycle before we hit another multiple of the SSRAM clock to the bus clock (so cycle 3 if ratio is 4, or a 50MHz system bus and 200MHz SRAM), this gives the system bus signals almost another whole cycle to reach our 200MHz regs (and where we define one of the multi-cycle paths). Once we have the stuff registered it's business as usual on the bus to the SRAM. Then we let it sit in our register for a clock or two |
*/ |
module ssram_controller |
( |
// WB ports |
input [31:0] wb_adr_i, |
input wb_stb_i, |
input wb_cyc_i, |
input wb_we_i, |
input [3:0] wb_sel_i, |
input [31:0] wb_dat_i, |
output [31:0] wb_dat_o, |
output wb_ack_o, |
|
input wb_clk, |
input wb_rst, |
|
// SSRAM interface |
input clk_200, |
output wire sram_clk, |
input sram_clk_fb, |
output reg [21:1] sram_addr, |
inout [31:0] sram_dq_io, |
output reg sram_ce_l, |
output reg sram_oe_l, |
output reg sram_we_l, |
output reg [3:0] sram_bw_l, |
output reg sram_adv_ld_l, |
output sram_mode |
|
); |
|
wire [31:0] sram_dq_i; |
reg [31:0] sram_dq_o; |
reg ssram_controller_oe_l; |
|
wire dcm0_clk0_prebufg, dcm0_clk0; |
wire dcm0_locked; |
|
wire dcms_locked; |
|
reg wb_clk_r = 1'b0; |
reg wb_clk_r_d; |
wire wb_clk_edge; |
|
reg wb_ack_write; |
reg [2:0] wb_ack_read_shiftreg; |
|
reg [2:0] clk_200_phase; |
reg [4:0] clk_200_cycle_counter; |
|
reg [31:0] data_rd; |
wire [3:0] we; |
|
reg write_cycle; |
reg [3:0] we_r; |
reg reg_from_bus_domain, reg_from_bus_domain_r; |
|
assign dcms_locked = dcm0_locked; |
|
assign we = wb_sel_i & {4{wb_cyc_i & wb_stb_i & wb_we_i}}; |
|
assign sram_clk = dcm0_clk0; |
|
// Do wb_clk edge detection with this |
assign wb_clk_edge = wb_clk_r & ~wb_clk_r_d; |
|
assign sram_mode = 0; |
|
initial begin |
$display("* SSRAM controller instantiated at %m."); |
end |
|
// We ACK writes after one cycle |
always @(posedge wb_clk) |
wb_ack_write <= wb_cyc_i & wb_stb_i & wb_we_i & !wb_ack_write; |
|
// We ACK reads after 3 |
always @(posedge wb_clk) |
wb_ack_read_shiftreg <= {wb_ack_read_shiftreg[1:0], wb_cyc_i & wb_stb_i & !wb_we_i & !(|wb_ack_read_shiftreg)}; |
|
assign wb_ack_o = wb_we_i ? wb_ack_write : wb_ack_read_shiftreg[2]; |
|
// Push the bus clock through a register |
always @(posedge wb_clk) begin |
wb_clk_r <= ~wb_clk_r; |
end |
|
// Sample this with the 150 MHz clock |
always @(posedge clk_200) begin |
wb_clk_r_d <= wb_clk_r; |
end |
|
// Maintain a phase count, it goes 0->7 (8 phases, to be clear) |
always @(posedge clk_200) begin |
if (wb_clk_edge) begin |
// Will be at 1 next cycle |
clk_200_phase <= 3'd1; |
end else if (clk_200_phase < 3'd7 & dcms_locked) begin |
clk_200_phase <= clk_200_phase + 1; |
end else begin |
clk_200_phase <= 3'd0; |
end |
end |
|
// Multicycle trickery |
|
// Reads will happen like this: |
// * Read address is given 3 clk_200 cycles to settle |
// * It is put onto the bus for two cycles |
// * Read data is then registered |
// * It then has several phases to make it back to the bus register |
|
// Number of cycles we preload counter with, depending on access |
`define WRITE_CYCLES 5'h04 |
`define READ_CYCLES 5'h0c |
|
// We let the commands settle for 2 cycles (0, 1) and then sample |
// *but* data could have come on either cycle 0 _or_ 3, so check both |
`define REQ_CHECK_CYCLE ((clk_200_phase == 3'd3)||(clk_200_phase == 3'd7)) |
|
// Write OE - whole time, doesn't matter so much |
`define WRITE_OE_CYCLE (|clk_200_cycle_counter) |
// Read OE, just the first two cycles |
//`define READ_OE_CYCLE (clk_200_cycle_counter > (`READ_CYCLES - 5'h4)) |
`define READ_OE_CYCLE (|clk_200_cycle_counter) |
|
// Sample data from RAM 2 cycles after we sample the addr from system bus |
`define RAM_DATA_SAMPLE_CYCLE (!(|we_r) && clk_200_cycle_counter == (`READ_CYCLES - 5'h5)) |
|
// Cycle when we pull sram_we_l low |
`define WRITE_CE_CYCLE (reg_from_bus_domain & (|we)) |
// Cycle when we ouptut the CE |
`define READ_CE_CYCLE (reg_from_bus_domain & !(|we)) |
|
// Register stuff when we've just loaded the counter |
`define REG_FROM_BUS_DOMAIN reg_from_bus_domain |
|
// CE 2 cycles dring writes, only one during reads |
always @(posedge clk_200) |
sram_ce_l <= 0; |
//sram_ce_l <= ~((`WRITE_CE_CYCLE) || (`READ_CE_CYCLE )); |
|
|
always @(posedge clk_200) |
sram_adv_ld_l <= 0; |
//sram_adv_ld_l <= ~((`WRITE_CE_CYCLE) || (`READ_CE_CYCLE )); |
|
always @(posedge clk_200) |
sram_we_l <= ~(`WRITE_CE_CYCLE); |
|
always @(posedge clk_200) |
if (`REG_FROM_BUS_DOMAIN) |
sram_addr[21:1] <= wb_adr_i[22:2]; |
|
always @(posedge clk_200) |
if (`REG_FROM_BUS_DOMAIN) |
sram_dq_o <= wb_dat_i; |
|
always @(posedge clk_200) |
if (`REG_FROM_BUS_DOMAIN) |
sram_bw_l <= ~we; |
|
always @(posedge clk_200) |
sram_oe_l <= ~((`READ_OE_CYCLE) & !(|(we_r | we))); |
|
always @(posedge clk_200) |
ssram_controller_oe_l = ~((`WRITE_OE_CYCLE) & (|we_r)); |
|
// Register data from SSRAM |
always @(posedge clk_200) |
if (`RAM_DATA_SAMPLE_CYCLE) |
data_rd[31:0] <= sram_dq_i[31:0]; |
|
assign wb_dat_o = data_rd; |
|
// Determine if we've got a request |
// This logic means the bus' control signals are slightly |
// more constrained than the data and address. |
always @(posedge clk_200) |
begin |
if (|clk_200_cycle_counter) |
clk_200_cycle_counter <= clk_200_cycle_counter - 1; |
else if (`REQ_CHECK_CYCLE) |
if (wb_cyc_i & wb_stb_i) |
clk_200_cycle_counter <= wb_we_i ? |
`WRITE_CYCLES : `READ_CYCLES; |
else |
clk_200_cycle_counter <= 0; |
end // always @ (posedge clk_200) |
|
always @(posedge clk_200) |
begin |
reg_from_bus_domain <= ((`REQ_CHECK_CYCLE) & wb_cyc_i & wb_stb_i & !(|clk_200_cycle_counter)); |
reg_from_bus_domain_r <= reg_from_bus_domain; |
end |
|
// Must clear |
always @(posedge clk_200) |
if (`REG_FROM_BUS_DOMAIN) |
we_r <= we; |
else if (!(|clk_200_cycle_counter)) |
we_r <= 0; |
|
|
/* SSRAM Clocking configuration */ |
|
/* DCM de-skewing SSRAM clock via external trace */ |
DCM_BASE dcm0 |
(/*AUTOINST*/ |
// Outputs |
.CLK0 (dcm0_clk0_prebufg), |
.CLK180 (), |
.CLK270 (), |
.CLK2X180 (), |
.CLK2X (), |
.CLK90 (), |
.CLKDV (), |
.CLKFX180 (), |
.CLKFX (), |
.LOCKED (dcm0_locked), |
// Inputs |
.CLKFB (sram_clk_fb), |
.CLKIN (clk_200), |
.RST (wb_rst)); |
|
BUFG dcm0_clk0_bufg |
(// Outputs |
.O (dcm0_clk0), |
// Inputs |
.I (dcm0_clk0_prebufg)); |
|
/* Generate the DQ bus tristate buffers */ |
genvar i; |
generate |
for (i=0; i<32; i=i+1) begin: SSRAM_DQ_TRISTATE |
IOBUF U (.O(sram_dq_i[i]), |
.IO(sram_dq_io[i]), |
.I(sram_dq_o[i]), |
.T(ssram_controller_oe_l)); |
end |
endgenerate |
|
endmodule // ssram_controller |
|
|
// Local Variables: |
// verilog-library-directories:(".") |
// verilog-library-extensions:(".v" ".h") |
// End: |
/ml501_ddr2_wb_if.v.prev
0,0 → 1,570
/* |
* Simple interface to the Xilinx MIG generated DDR2 controller. |
* |
* The controller is capable of fast streams of accesses, and this |
* module aims to simply do the minimum amount to get the controller |
* working on the wishbone bus. |
* |
* This means, each read or write will incur a read of (minimum burst |
* x data-width) = 8 words, which will sit in a small bit of distram |
* until something else is read, outside of those 8 words. |
* Of course, reads will be scrapped and new data will be read over, |
* and in the case of writes, it has to be written back to the RAM. |
* |
* I will try to make this as parametisable as much as possible, allowing |
* greater caching, or perhaps greater associativity, so a few spots of |
* memory can be cached here at once, but at first it will be a simple |
* interface between wishbone and the Xilinx MIG DDR2 interface, implenting |
* as simple a interface as possible. |
*/ |
module ml501_ddr2_wb_if ( |
input [31:0] wb_adr_i, |
input wb_stb_i, |
input wb_cyc_i, |
input wb_we_i, |
input [3:0] wb_sel_i, |
input [31:0] wb_dat_i, |
output [31:0] wb_dat_o, |
output reg wb_ack_o, |
|
output [12:0] ddr2_a, |
output [1:0] ddr2_ba, |
output ddr2_ras_n, |
output ddr2_cas_n, |
output ddr2_we_n, |
output ddr2_cs_n, |
output ddr2_odt, |
output ddr2_cke, |
output [7:0] ddr2_dm, |
|
inout [63:0] ddr2_dq, |
inout [7:0] ddr2_dqs, |
inout [7:0] ddr2_dqs_n, |
output [1:0] ddr2_ck, |
output [1:0] ddr2_ck_n, |
|
input ddr2_if_clk, |
input clk200, |
input rst, |
|
input wb_clk, |
input wb_rst); |
|
|
`include "ml501_ddr2_params.v" |
|
|
parameter cache_lines = 1; |
parameter bits_per_word = 32; |
parameter bytes_per_word = 4; |
parameter words_per_line = 8; /* (ddr2 burst * ddr2 data width / bits_per_word) */ |
parameter bytes_per_line = 32; /* (words_per_line * bytes_per_word) */ |
parameter cache_byte_address_width = 5; /* log2(bytes_per_line) */ |
parameter cache_word_address_width = 3; /* log2(words_per_line) */ |
|
|
wire wb_req; |
reg wb_req_r; |
|
wire new_wb_req; |
reg new_wb_req_r; |
|
reg wb_req_addr_hit; |
|
// Current line's address |
reg [31:cache_byte_address_width] cached_address_line; |
|
reg cached_address_valid; |
reg cache_dirty; |
|
// Hopefully this turns into a dual-port RAM |
|
// synthesis attribute ram_style of mem is distributed |
reg [31:0] mem [0:words_per_line-1]; |
|
wire [31:0] cache_do_wb, cache_do_mig; |
|
// registered address for cache RAM |
reg [cache_word_address_width-1:0] cache_addr_wb, cache_addr_mig; |
wire cache_we_wb, cache_we_mig; |
|
wire [31:0] cache_di_wb; |
reg [31:0] cache_di_mig; // Is actually comb. |
|
reg [cache_word_address_width - 1: 0] writeback_counter, writeback_counter_r,writeback_counter_r_r; |
reg writeback_doing; |
reg writeback_data_we; |
|
reg [cache_word_address_width - 1: 0] readfrom_counter, readfrom_counter_r; |
reg readfrom_start; |
reg readfrom_doing; |
reg readfrom_doing_r; |
|
// Assemble the 128-bit words here when writing or store them |
// here when reading from SDRAM |
reg [127:0] app_holding_reg0, app_holding_reg1; |
reg app_holding_reg_sel; |
|
// DDR2 MIG interface wires |
wire app_af_afull; |
wire app_wdf_afull; |
wire app_wdf_wren; |
wire app_af_wren; |
wire [30:0] app_af_addr; |
wire [2:0] app_af_cmd; |
wire [(APPDATA_WIDTH)-1:0] app_wdf_data; |
wire [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data; |
wire rd_data_valid; |
wire [(APPDATA_WIDTH)-1:0] rd_data_fifo_out; |
wire phy_init_done; |
|
// mux for RMW on wishbone side |
assign cache_di_wb[31:24] = wb_sel_i[3] ? wb_dat_i[31:24] : cache_do_wb[31:24]; |
assign cache_di_wb[23:16] = wb_sel_i[2] ? wb_dat_i[23:16] : cache_do_wb[23:16]; |
assign cache_di_wb[15: 8] = wb_sel_i[1] ? wb_dat_i[15: 8] : cache_do_wb[15: 8]; |
assign cache_di_wb[ 7: 0] = wb_sel_i[0] ? wb_dat_i[ 7: 0] : cache_do_wb[ 7: 0]; |
|
// Cache's Wishbone-side r/w logic |
always @(posedge wb_clk) |
if (wb_req) |
cache_addr_wb <= wb_adr_i[(cache_word_address_width+2)-1:2]; |
|
assign cache_do_wb = mem[cache_addr_wb]; |
assign wb_dat_o = cache_do_wb; |
|
always @(posedge wb_clk) |
if (wb_req & wb_we_i & wb_req_addr_hit & wb_ack_o) |
mem[cache_addr_wb] <= cache_di_wb; |
|
|
// Wishbone request detection |
assign wb_req = wb_stb_i & wb_cyc_i & phy_init_done; |
always @(posedge wb_clk) |
wb_req_r <= wb_req; |
|
assign new_wb_req = wb_req & !wb_req_r; |
always @(posedge wb_clk) |
new_wb_req_r <= new_wb_req; |
|
// Register whether it's a hit or not |
// As more lines are added, add them to this check. |
always @(posedge wb_clk) |
if (wb_rst) |
wb_req_addr_hit <= 0; |
else |
wb_req_addr_hit <= wb_req & (cached_address_line == |
wb_adr_i[31:cache_byte_address_width]) & |
cached_address_valid; |
|
always @(posedge wb_clk) |
if (wb_rst) |
wb_ack_o <= 0; |
else |
wb_ack_o <= wb_req_addr_hit & !wb_ack_o; |
|
always @(posedge wb_clk) |
if (readfrom_counter_r == 1) /* Unsure about this */ |
cached_address_line <= wb_adr_i[31:cache_byte_address_width]; |
|
|
// Cache dirty signal |
always @(posedge wb_clk) |
if (wb_req & wb_we_i & wb_req_addr_hit & wb_ack_o) |
cache_dirty <= 1; |
else if (readfrom_counter_r == 1) |
cache_dirty <= 0; |
|
always @(posedge wb_clk) |
if (wb_rst) |
cached_address_valid <= 0; |
else if (readfrom_counter_r == 1) /* Unsure about this */ |
cached_address_valid <= 1; |
else if (writeback_counter_r_r == 1) |
cached_address_valid <= 0; |
|
/* |
* Cache writeback to DDR2 |
* |
* Load the words out of the cache into DDR2 MIG write data fifo. |
* On the last, also write in the address. |
* |
*/ |
|
`define WRITEBACK_CONDITION (new_wb_req_r && !wb_req_addr_hit && cached_address_valid && cache_dirty) |
// If burst length is 4 and SDRAM DQ is 64-bits, and the ddr2 MIG fifo is |
// 128-wide and we're loading from a 128-bit wide ram, then we need to do |
// (64 * 4) / 32 = 8 reads from our RAM, and we need to do a write to the |
// fifo every (128 / 32) = 4th word we pull out. |
|
`define WRITEBACK_COUNTER_LOAD (7) |
// Pulse app_wdf when writeback_counter_r == 4 or 0, but testing 0 is bad |
// so we'll test the registered, registered version for 5 and 1 ([1:0] == 1) |
`define WRITEBACK_FIFO_WE (writeback_counter_r_r[1:0] == 2'b01) |
|
// app_holding_reg0 load control |
always @(posedge wb_clk) |
if (writeback_counter_r[1:0] == 2'b11) |
app_holding_reg0[31:0] <= cache_do_mig; |
else if (writeback_counter_r[1:0] == 2'b10) |
app_holding_reg0[63:32] <= cache_do_mig; |
else if (writeback_counter_r[1:0] == 2'b01) |
app_holding_reg0[95:64] <= cache_do_mig; |
else if ((writeback_counter_r[1:0] == 2'b00) & `WRITEBACK_CONDITION) |
app_holding_reg0[127:96] <= cache_do_mig; |
else if ((app_holding_reg_sel == 0) && rd_data_valid) |
app_holding_reg0 <= rd_data_fifo_out; |
|
// app_holding_reg0 load control |
always @(posedge wb_clk) |
if ((app_holding_reg_sel == 1) && rd_data_valid) |
app_holding_reg1 <= rd_data_fifo_out; |
|
always @(posedge wb_clk) |
writeback_data_we <= (writeback_counter_r_r[1:0] == 2'b01); |
|
|
// Load for writeback sequence when we've got a miss, valid address |
// and dirty cache. |
always @(posedge wb_clk) |
if (wb_rst) |
writeback_counter <= 0; |
else if (|writeback_counter) |
writeback_counter <= writeback_counter - 1; |
else if `WRITEBACK_CONDITION |
writeback_counter <= `WRITEBACK_COUNTER_LOAD; |
|
always @(posedge wb_clk) |
writeback_counter_r <= writeback_counter; |
|
always @(posedge wb_clk) |
writeback_counter_r_r <= writeback_counter_r; |
|
always @(posedge wb_clk) |
writeback_doing <= ((|writeback_counter)|(|writeback_counter_r)|(|writeback_counter_r_r)); |
|
/* |
* Cache read from DDR2 |
* |
* Read will simply put the address onto the bus and await for |
* the fifo to start spitting things out. |
* |
*/ |
`define READFROM_CONDITION (new_wb_req_r && !wb_req_addr_hit && !cached_address_valid && !(|writeback_counter_r)) |
|
always @(posedge wb_clk) |
if (wb_rst) |
readfrom_doing <= 0; |
else if (wb_ack_o) |
readfrom_doing <= 0; |
else if (`READFROM_CONDITION) |
readfrom_doing <= 1; |
|
//assign readfrom_doing = `READFROM_CONDITION; |
|
always @(posedge wb_clk) |
readfrom_doing_r <= readfrom_doing; |
|
always @(posedge wb_clk) |
readfrom_start <= (!readfrom_doing_r & readfrom_doing); |
|
|
reg readfrom_start_r; |
always @(posedge wb_clk) |
readfrom_start_r <= readfrom_start; |
|
reg readfrom_counter_go, readfrom_counter_go_r; |
|
// Reg to indicate the counter should increment. |
// Also used as WE to the MIG side of the RAM |
always @(posedge wb_clk) |
if (wb_rst) |
readfrom_counter_go <= 0; |
else |
begin |
if (app_holding_reg_sel & rd_data_valid) |
readfrom_counter_go <= 1; |
else if (&readfrom_counter) |
readfrom_counter_go <= 0; |
end |
|
always @(posedge wb_clk) |
readfrom_counter_go_r <= readfrom_counter_go; |
|
// Readfrom counter |
// We use this counter to copy in the data from the holding registers |
|
always @(posedge wb_clk) |
if (readfrom_counter_go) |
readfrom_counter <= readfrom_counter + 1; |
else |
readfrom_counter <= 0; |
|
always @(posedge wb_clk) |
readfrom_counter_r <= readfrom_counter; |
|
always @(posedge wb_clk) |
if (wb_rst) |
app_holding_reg_sel <= 0; |
else if (rd_data_valid) |
app_holding_reg_sel <= ~app_holding_reg_sel; |
|
|
always @(/*AUTOSENSE*/app_holding_reg0 or app_holding_reg1 |
or readfrom_counter) |
case (readfrom_counter) |
3'b000 : cache_di_mig <= app_holding_reg0[31:0]; |
3'b001 : cache_di_mig <= app_holding_reg0[63:32]; |
3'b010 : cache_di_mig <= app_holding_reg0[95:64]; |
3'b011 : cache_di_mig <= app_holding_reg0[127:96]; |
3'b100 : cache_di_mig <= app_holding_reg1[31:0]; |
3'b101 : cache_di_mig <= app_holding_reg1[63:32]; |
3'b110 : cache_di_mig <= app_holding_reg1[95:64]; |
3'b111 : cache_di_mig <= app_holding_reg1[127:96]; |
default: cache_di_mig <= 0; |
endcase // case (readfrom_counter) |
|
//assign cache_di_mig = rd_data_fifo_out; |
assign cache_we_mig = readfrom_counter_go; |
|
// Address for MIG side of cache |
// Expect it to always go back to 0! |
always @(posedge wb_clk) |
if (wb_rst) |
cache_addr_mig <= 0; |
else if (readfrom_start) |
cache_addr_mig <= 0; |
else if ((|writeback_counter) | readfrom_counter_go) |
cache_addr_mig <= cache_addr_mig + 1; |
|
always @(posedge wb_clk) |
if (cache_we_mig) |
mem[cache_addr_mig] <= cache_di_mig; |
|
assign cache_do_mig = mem[cache_addr_mig]; |
|
// Whenever writeback counter is counting down, generate |
// the write-enable to the data fifo |
assign app_wdf_wren = (writeback_data_we); |
|
assign app_wdf_data = cache_do_mig; |
|
assign app_af_addr = (writeback_doing) ? |
{4'd0,cached_address_line} : |
{4'd0, wb_adr_i[31:cache_byte_address_width]} ; |
|
assign app_af_wren = ((writeback_data_we & !writeback_counter_r_r[2]) | |
(readfrom_start) & |
!app_af_afull ); |
/*readfrom_doing ) &*/ |
|
|
|
assign app_wdf_mask_data = 0; |
|
// CMD, 1 = read, 0 = write |
assign app_af_cmd[0] = |readfrom_doing; |
assign app_af_cmd[2:1] = 0; |
|
|
ml501_ddr2_wb_if_cache cache_mem0 |
(/*AUTOINST*/ |
// Outputs |
.wb_do (wb_do[31:0]), |
.ddr2_do (ddr2_do[127:0]), |
// Inputs |
.wb_clk (wb_clk), |
.wb_addr (wb_addr[2:0]), |
.wb_di (wb_di[31:0]), |
.wb_we (wb_we), |
.wb_sel (wb_sel[3:0]), |
.wb_en (), |
.ddr2_clk (ddr2_clk), |
.ddr2_addr (ddr2_addr), |
.ddr2_di (ddr2_di[127:0]), |
.ddr2_we (ddr2_we)); |
|
|
|
|
ddr2_mig # |
( |
.BANK_WIDTH (BANK_WIDTH), |
.CKE_WIDTH (CKE_WIDTH), |
.CLK_WIDTH (CLK_WIDTH), |
.COL_WIDTH (COL_WIDTH), |
.CS_NUM (CS_NUM), |
.CS_WIDTH (CS_WIDTH), |
.CS_BITS (CS_BITS), |
.DM_WIDTH (DM_WIDTH), |
.DQ_WIDTH (DQ_WIDTH), |
.DQ_PER_DQS (DQ_PER_DQS), |
.DQ_BITS (DQ_BITS), |
.DQS_WIDTH (DQS_WIDTH), |
.DQS_BITS (DQS_BITS), |
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), |
.ODT_WIDTH (ODT_WIDTH), |
.ROW_WIDTH (ROW_WIDTH), |
.APPDATA_WIDTH (APPDATA_WIDTH), |
.ADDITIVE_LAT (ADDITIVE_LAT), |
.BURST_LEN (BURST_LEN), |
.BURST_TYPE (BURST_TYPE), |
.CAS_LAT (CAS_LAT), |
.ECC_ENABLE (ECC_ENABLE), |
.MULTI_BANK_EN (MULTI_BANK_EN), |
.ODT_TYPE (ODT_TYPE), |
.REDUCE_DRV (REDUCE_DRV), |
.REG_ENABLE (REG_ENABLE), |
.TREFI_NS (TREFI_NS), |
.TRAS (TRAS), |
.TRCD (TRCD), |
.TRFC (TRFC), |
.TRP (TRP), |
.TRTP (TRTP), |
.TWR (TWR), |
.TWTR (TWTR), |
.SIM_ONLY (SIM_ONLY), |
.RST_ACT_LOW (RST_ACT_LOW), |
.CLK_TYPE (CLK_TYPE), |
.DLL_FREQ_MODE (DLL_FREQ_MODE), |
.CLK_PERIOD (CLK_PERIOD) |
) |
ddr2_mig0 |
( |
.sys_clk (ddr2_if_clk), |
.idly_clk_200 (clk200), |
.sys_rst_n (sys_rst_out), |
.ddr2_ras_n (ddr2_ras_n), |
.ddr2_cas_n (ddr2_cas_n), |
.ddr2_we_n (ddr2_we_n), |
.ddr2_cs_n (ddr2_cs_n), |
.ddr2_cke (ddr2_cke), |
.ddr2_odt (ddr2_odt), |
.ddr2_dm (ddr2_dm), |
.ddr2_dq (ddr2_dq), |
.ddr2_dqs (ddr2_dqs), |
.ddr2_dqs_n (ddr2_dqs_n), |
.ddr2_ck (ddr2_ck), |
.ddr2_ck_n (ddr2_ck_n), |
.ddr2_ba (ddr2_ba), |
.ddr2_a (ddr2_a), |
|
//.clk0_tb (wb_clk), |
//.rst0_tb (wb_rst), |
.usr_clk (wb_clk), |
.app_af_afull (app_af_afull), |
.app_wdf_afull (app_wdf_afull), |
.rd_data_valid (rd_data_valid), |
.rd_data_fifo_out (rd_data_fifo_out), |
.app_af_wren (app_af_wren), |
.app_af_cmd (app_af_cmd), |
.app_af_addr (app_af_addr), |
.app_wdf_wren (app_wdf_wren), |
.app_wdf_data (app_wdf_data), |
.app_wdf_mask_data (app_wdf_mask_data), |
.phy_init_done (phy_init_done) |
); |
|
|
endmodule // ml501_ddr2_wb_if |
// Local Variables: |
// verilog-library-directories:("." "ddr2_mig") |
// verilog-library-extensions:(".v" ".h") |
// End: |
|
|
|
|
|
module ml501_ddr2_wb_if_cache( |
wb_clk, |
wb_addr, |
wb_di, |
wb_do, |
wb_we, |
wb_sel, |
wb_en, |
|
ddr2_clk, |
ddr2_addr, |
ddr2_di, |
ddr2_do, |
ddr2_we |
); |
input wb_clk; |
input [2:0] wb_addr; |
input [31:0] wb_di; |
output [31:0] wb_do; |
input wb_we; |
input [3:0] wb_sel; |
input wb_en; |
|
input ddr2_clk; |
input ddr2_addr; |
input [127:0] ddr2_di; |
output [127:0] ddr2_do; |
input ddr2_we; |
|
wire [3:0] wb_sel_we; |
assign wb_sel_we = {4{wb_we}} & wb_sel; |
|
|
genvar i; |
generate |
for (i = 0; i < 4; i = i + 1) |
// RAMB36: 32k+4k Parity Paramatizable True Dual-Port BlockRAM |
// Virtex-5 |
// Xilinx HDL Libraries Guide, version 10.1.2 |
RAMB36 #( |
.SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details |
.DOA_REG(0), // Optional output registers on A port (0 or 1) |
.DOB_REG(0), // Optional output registers on B port (0 or 1) |
.INIT_A(36’h000000000), // Initial values on A output port |
.INIT_B(36’h000000000), // Initial values on B output port |
.RAM_EXTENSION_A("NONE"), // "UPPER", "LOWER" or "NONE" when cascaded |
.RAM_EXTENSION_B("NONE"), // "UPPER", "LOWER" or "NONE" when cascaded |
.READ_WIDTH_A(9), // Valid values are 1, 2, 4, 9, 18, or 36 |
.READ_WIDTH_B(36), // Valid values are 1, 2, 4, 9, 18, or 36 |
.SIM_COLLISION_CHECK("NONE"), // Collision check enable "ALL", "WARNING_ONLY", |
// "GENERATE_X_ONLY" or "NONE" |
.SRVAL_A(36’h000000000), // Set/Reset value for A port output |
.SRVAL_B(36’h000000000), // Set/Reset value for B port output |
.WRITE_MODE_A("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE" |
.WRITE_MODE_B("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE" |
.WRITE_WIDTH_A(9), // Valid values are 1, 2, 4, 9, 18, or 36 |
.WRITE_WIDTH_B(36), // Valid values are 1, 2, 4, 9, 18, or 36 |
) RAMB36_inst |
( |
//.CASCADEOUTLATA(CASCADEOUTLATA), // 1-bit cascade A latch output |
//.CASCADEOUTLATB(CASCADEOUTLATB), // 1-bit cascade B latch output |
//.CASCADEOUTREGA(CASCADEOUTREGA), // 1-bit cascade A register output |
//.CASCADEOUTREGB(CASCADEOUTREGB), // 1-bit cascade B register output |
.DOA(wb_do[(i+1)*8-1:(i*8)]), // 8-bit A port data output |
.DOB(ddr2_do[(i+1)*32-1:i*32]), // 32-bit B port data output |
// .DOPA(DOPA), // A port parity data output |
// .DOPB(DOPB), // B port parity data output |
.ADDRA(wb_addr), // A port address input |
.ADDRB(ddr2_addr), // B port address input |
.CASCADEINLATA(0), // 1-bit cascade A latch input |
.CASCADEINLATB(0), // 1-bit cascade B latch input |
.CASCADEINREGA(0), // 1-bit cascade A register input |
.CASCADEINREGB(0), // 1-bit cascade B register input |
.CLKA(wb_clk), // 1-bit A port clock input |
.CLKB(ddr2_clk), // 1-bit B port clock input |
.DIA(wb_di[(i+1)*8-1:(i*8)]), // 8-bit A port data input |
.DIB(ddr2_di[(i+1)*32-1:i*32]), // 32-bit B port data input |
.DIPA(0), // 4-bit A port parity data input |
.DIPB(0), // 4-bit B port parity data input |
.ENA(wb_en), // 1-bit A port enable input |
.ENB(1), // 1-bit B port enable input |
.REGCEA(0), // 1-bit A port register enable input |
.REGCEB(0), // 1-bit B port register enable input |
.SSRA(0), // 1-bit A port set/reset input |
.SSRB(0), // 1-bit B port set/reset input |
.WEA(wb_sel_we[i]), // 4-bit A port write enable input |
.WEB(ddr2_we) // 4-bit B port write enable input |
); |
|
endgenerate |
endmodule // ml501_ddr2_wb_if_cache |
|
|
/wb_lfsr.v
0,0 → 1,118
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Linear feedback shift register with Wishbone interface //// |
//// //// |
//// Description //// |
//// Simple LFSR module (feedback hardcoded) //// |
//// Two accessible registers: //// |
//// Address 0: LFSR Register (R/W) //// |
//// Address 4: Control register, active high, self resetting (WO)//// |
//// Bit[0]: lfsr shift enable //// |
//// Bit[1]: lfsr reset //// |
//// //// |
//// To Do: //// |
//// Perhaps make feedback parameterisable //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
module wb_lfsr( wb_clk, wb_rst, wb_adr_i, wb_dat_i, wb_cyc_i, wb_stb_i, wb_we_i, |
wb_dat_o, wb_ack_o); |
|
parameter width = 32; |
parameter lfsr_rst_value = 32'b0011_0001_0000_1010; |
|
input wb_clk; |
input wb_rst; |
input [2:0] wb_adr_i; |
input [width-1:0] wb_dat_i; |
input wb_cyc_i, wb_stb_i, wb_we_i; |
|
output [width-1:0] wb_dat_o; |
output reg wb_ack_o; |
|
wire wb_req; |
assign wb_req = wb_stb_i & wb_cyc_i; |
|
reg [width-1:0] lfsr; |
wire lfsr_feedback; |
|
assign wb_dat_o = lfsr; |
|
// Only 2 registers here, the lfsr itself and |
wire lfsr_sel; |
assign lfsr_sel = !wb_adr_i[2]; |
wire lfsr_control_reg_sel; |
assign lfsr_control_reg_sel = wb_adr_i[2]; |
|
// [0]: shift enable, [1]: reset |
reg [1:0] lfsr_control_reg; |
wire lfsr_control_enable; |
wire lfsr_control_rst; |
|
// Load the control reg when required, |
always @(posedge wb_clk) |
begin |
if (wb_rst) |
lfsr_control_reg <= 0; |
else if (wb_req & wb_we_i & lfsr_control_reg_sel & wb_ack_o) |
lfsr_control_reg <= wb_dat_i; |
|
if (lfsr_control_reg[0]) |
lfsr_control_reg[0] <= 0; |
if (lfsr_control_reg[1]) |
lfsr_control_reg[1] <= 0; |
end // always @ (posedge wb_clk) |
|
assign lfsr_control_enable = lfsr_control_reg[0]; |
assign lfsr_control_rst = lfsr_control_reg[1]; |
|
assign lfsr_feedback = !(((lfsr[27] ^ lfsr[13]) ^ lfsr[8]) ^ lfsr[5]); |
|
always @(posedge wb_clk) |
if (wb_rst) |
lfsr <= lfsr_rst_value; |
else if (lfsr_control_rst) |
lfsr <= lfsr_rst_value; |
else if (wb_req & wb_we_i & lfsr_sel & wb_ack_o) // Set lfsr |
lfsr <= wb_dat_i; |
else if (lfsr_control_enable) |
lfsr <= {lfsr[width-2:0], lfsr_feedback}; |
|
always @(posedge wb_clk) |
if (wb_rst) |
wb_ack_o <= 0; |
else if (wb_req & !wb_ack_o) |
wb_ack_o <= 1; |
else if (wb_ack_o) |
wb_ack_o <= 0; |
|
|
endmodule // lfsr |
/usr_rst.v
0,0 → 1,61
////////////////////////////////////////////////////////////////////// |
//// //// |
//// User controllable reset generation //// |
//// //// |
//// Description //// |
//// Pulls a signal low when accessed. This signal should be //// |
//// looped back out of the design and back into the reset //// |
//// module, resetting the system. //// |
//// //// |
//// To Do: //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
module usr_rst(wb_clk, wb_rst, wb_cyc_i, wb_stb_i, wb_ack_o, usr_rst_out); |
|
input wb_clk, wb_rst, wb_cyc_i, wb_stb_i; |
output reg wb_ack_o; |
output usr_rst_out; |
|
|
always @(posedge wb_clk) |
if (wb_rst) |
wb_ack_o <= 0; |
else if (wb_cyc_i & wb_stb_i & !wb_ack_o) |
wb_ack_o <= 1; |
else |
wb_ack_o <= 0; |
|
// Generate an active low reset pulse when this module is accessed. |
// We don't generate ACKs because the thing will be reset anyway... |
assign usr_rst_out = !(wb_cyc_i & wb_stb_i & !wb_rst); |
|
endmodule // usr_rst |
/ml501_ddr2_wb_if_cache.v
0,0 → 1,252
/******************************************************************************* |
* This file is owned and controlled by Xilinx and must be used * |
* solely for design, simulation, implementation and creation of * |
* design files limited to Xilinx devices or technologies. Use * |
* with non-Xilinx devices or technologies is expressly prohibited * |
* and immediately terminates your license. * |
* * |
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" * |
* SOLELY FOR USE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR * |
* XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION * |
* AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION * |
* OR STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS * |
* IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, * |
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE * |
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY * |
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE * |
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR * |
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF * |
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * |
* FOR A PARTICULAR PURPOSE. * |
* * |
* Xilinx products are not intended for use in life support * |
* appliances, devices, or systems. Use in such applications are * |
* expressly prohibited. * |
* * |
* (c) Copyright 1995-2009 Xilinx, Inc. * |
* All rights reserved. * |
*******************************************************************************/ |
// The synthesis directives "translate_off/translate_on" specified below are |
// supported by Xilinx, Mentor Graphics and Synplicity synthesis |
// tools. Ensure they are correct for your synthesis tool(s). |
|
// You must compile the wrapper file ml501_ddr2_wb_if_cache.v when simulating |
// the core, ml501_ddr2_wb_if_cache. When compiling the wrapper file, be sure to |
// reference the XilinxCoreLib Verilog simulation library. For detailed |
// instructions, please refer to the "CORE Generator Help". |
|
`timescale 1ns/1ps |
|
module ml501_ddr2_wb_if_cache( |
clka, |
ena, |
wea, |
addra, |
dina, |
douta, |
clkb, |
enb, |
web, |
addrb, |
dinb, |
doutb); |
|
|
input clka; |
input ena; |
input [3 : 0] wea; |
input [2 : 0] addra; |
input [31 : 0] dina; |
output [31 : 0] douta; |
input clkb; |
input enb; |
input [15 : 0] web; |
input [0 : 0] addrb; |
input [127 : 0] dinb; |
output [127 : 0] doutb; |
|
// synthesis translate_off |
|
BLK_MEM_GEN_V3_1 #( |
.C_ADDRA_WIDTH(3), |
.C_ADDRB_WIDTH(1), |
.C_ALGORITHM(1), |
.C_BYTE_SIZE(8), |
.C_COMMON_CLK(0), |
.C_DEFAULT_DATA("0"), |
.C_DISABLE_WARN_BHV_COLL(0), |
.C_DISABLE_WARN_BHV_RANGE(0), |
.C_FAMILY("virtex5"), |
.C_HAS_ENA(1), |
.C_HAS_ENB(1), |
.C_HAS_INJECTERR(0), |
.C_HAS_MEM_OUTPUT_REGS_A(0), |
.C_HAS_MEM_OUTPUT_REGS_B(0), |
.C_HAS_MUX_OUTPUT_REGS_A(0), |
.C_HAS_MUX_OUTPUT_REGS_B(0), |
.C_HAS_REGCEA(0), |
.C_HAS_REGCEB(0), |
.C_HAS_RSTA(0), |
.C_HAS_RSTB(0), |
.C_INITA_VAL("0"), |
.C_INITB_VAL("0"), |
.C_INIT_FILE_NAME("no_coe_file_loaded"), |
.C_LOAD_INIT_FILE(0), |
.C_MEM_TYPE(2), |
.C_MUX_PIPELINE_STAGES(0), |
.C_PRIM_TYPE(1), |
.C_READ_DEPTH_A(8), |
.C_READ_DEPTH_B(2), |
.C_READ_WIDTH_A(32), |
.C_READ_WIDTH_B(128), |
.C_RSTRAM_A(0), |
.C_RSTRAM_B(0), |
.C_RST_PRIORITY_A("CE"), |
.C_RST_PRIORITY_B("CE"), |
.C_RST_TYPE("SYNC"), |
.C_SIM_COLLISION_CHECK("NONE"), |
.C_USE_BYTE_WEA(1), |
.C_USE_BYTE_WEB(1), |
.C_USE_DEFAULT_DATA(0), |
.C_USE_ECC(0), |
.C_WEA_WIDTH(4), |
.C_WEB_WIDTH(16), |
.C_WRITE_DEPTH_A(8), |
.C_WRITE_DEPTH_B(2), |
.C_WRITE_MODE_A("WRITE_FIRST"), |
.C_WRITE_MODE_B("WRITE_FIRST"), |
.C_WRITE_WIDTH_A(32), |
.C_WRITE_WIDTH_B(128), |
.C_XDEVICEFAMILY("virtex5")) |
inst ( |
.CLKA(clka), |
.ENA(ena), |
.WEA(wea), |
.ADDRA(addra), |
.DINA(dina), |
.DOUTA(douta), |
.CLKB(clkb), |
.ENB(enb), |
.WEB(web), |
.ADDRB(addrb), |
.DINB(dinb), |
.DOUTB(doutb), |
.RSTA(), |
.REGCEA(), |
.RSTB(), |
.REGCEB(), |
.INJECTSBITERR(), |
.INJECTDBITERR(), |
.SBITERR(), |
.DBITERR(), |
.RDADDRECC()); |
|
|
// synthesis translate_on |
|
// XST black box declaration |
// box_type "black_box" |
// synthesis attribute box_type of ml501_ddr2_wb_if_cache is "black_box" |
|
endmodule |
|
/* |
|
|
|
|
module ml501_ddr2_wb_if_cache( |
wb_clk, |
wb_addr, |
wb_di, |
wb_do, |
wb_we, |
wb_sel, |
wb_en, |
|
ddr2_clk, |
ddr2_addr, |
ddr2_di, |
ddr2_do, |
ddr2_we |
); |
input wb_clk; |
input [2:0] wb_addr; |
input [31:0] wb_di; |
output [31:0] wb_do; |
input wb_we; |
input [3:0] wb_sel; |
input wb_en; |
|
input ddr2_clk; |
input ddr2_addr; |
input [127:0] ddr2_di; |
output [127:0] ddr2_do; |
input ddr2_we; |
|
wire [3:0] wb_sel_we; |
assign wb_sel_we = {4{wb_we}} & wb_sel; |
|
// Didn't want to work!? |
|
genvar i; |
generate |
for (i = 0; i < 4; i = i + 1) begin: gen_rambs |
|
// RAMB36: 32k+4k Parity Paramatizable True Dual-Port BlockRAM |
// Virtex-5 |
// Xilinx HDL Libraries Guide, version 10.1.2 |
RAMB36 #( |
.SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details |
.DOA_REG(0), // Optional output registers on A port (0 or 1) |
.DOB_REG(0), // Optional output registers on B port (0 or 1) |
.INIT_A(36'h000000000), // Initial values on A output port |
.INIT_B(36'h000000000), // Initial values on B output port |
.RAM_EXTENSION_A("NONE"), // "UPPER", "LOWER" or "NONE" when cascaded |
.RAM_EXTENSION_B("NONE"), // "UPPER", "LOWER" or "NONE" when cascaded |
.READ_WIDTH_A(9), // Valid values are 1, 2, 4, 9, 18, or 36 |
.READ_WIDTH_B(36), // Valid values are 1, 2, 4, 9, 18, or 36 |
.SIM_COLLISION_CHECK("NONE"), // Collision check enable "ALL", "WARNING_ONLY", |
// "GENERATE_X_ONLY" or "NONE" |
.SRVAL_A(36'h000000000), // Set/Reset value for A port output |
.SRVAL_B(36'h000000000), // Set/Reset value for B port output |
.WRITE_MODE_A("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE" |
.WRITE_MODE_B("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE" |
.WRITE_WIDTH_A(9), // Valid values are 1, 2, 4, 9, 18, or 36 |
.WRITE_WIDTH_B(36) // Valid values are 1, 2, 4, 9, 18, or 36 |
) ddr2_if_cache0 |
( |
//.CASCADEOUTLATA(CASCADEOUTLATA), // 1-bit cascade A latch output |
//.CASCADEOUTLATB(CASCADEOUTLATB), // 1-bit cascade B latch output |
//.CASCADEOUTREGA(CASCADEOUTREGA), // 1-bit cascade A register output |
//.CASCADEOUTREGB(CASCADEOUTREGB), // 1-bit cascade B register output |
.DOA(wb_do[(i+1)*8-1:(i*8)]), // 8-bit A port data output |
.DOB(ddr2_do[(i+1)*32-1:i*32]), // 32-bit B port data output |
// .DOPA(DOPA), // A port parity data output |
// .DOPB(DOPB), // B port parity data output |
.ADDRA(wb_addr), // A port address input |
.ADDRB(ddr2_addr), // B port address input |
.CASCADEINLATA(0), // 1-bit cascade A latch input |
.CASCADEINLATB(0), // 1-bit cascade B latch input |
.CASCADEINREGA(0), // 1-bit cascade A register input |
.CASCADEINREGB(0), // 1-bit cascade B register input |
.CLKA(wb_clk), // 1-bit A port clock input |
.CLKB(ddr2_clk), // 1-bit B port clock input |
.DIA(wb_di[(i+1)*8-1:(i*8)]), // 8-bit A port data input |
.DIB(ddr2_di[(i+1)*32-1:i*32]), // 32-bit B port data input |
.DIPA(0), // 4-bit A port parity data input |
.DIPB(0), // 4-bit B port parity data input |
.ENA(wb_en), // 1-bit A port enable input |
.ENB(~wb_en), // 1-bit B port enable input |
.REGCEA(0), // 1-bit A port register enable input |
.REGCEB(0), // 1-bit B port register enable input |
.SSRA(0), // 1-bit A port set/reset input |
.SSRB(0), // 1-bit B port set/reset input |
.WEA(wb_sel_we[i]), // 4-bit A port write enable input |
.WEB(ddr2_we) // 4-bit B port write enable input |
); |
end // for (i = 0; i < 4; i = i + 1) |
endgenerate |
*/ |
|
|
/uart_defines.v
0,0 → 1,253
////////////////////////////////////////////////////////////////////// |
//// //// |
//// uart_defines.v //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/cores/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// - http://www.opencores.org/cores/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Defines of the Core //// |
//// //// |
//// Known problems (limits): //// |
//// None //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - gorban@opencores.org //// |
//// - Jacob Gorban //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created: 2001/05/12 //// |
//// Last Updated: 2001/05/17 //// |
//// (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000, 2001 Authors //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: uart_defines.v,v $ |
// Revision 1.14 2003/09/12 07:26:58 dries |
// adjusted comment + define |
// |
// Revision 1.13 2003/06/11 16:37:47 gorban |
// This fixes errors in some cases when data is being read and put to the FIFO at the same time. Patch is submitted by Scott Furman. Update is very recommended. |
// |
// Revision 1.12 2002/07/22 23:02:23 gorban |
// Bug Fixes: |
// * Possible loss of sync and bad reception of stop bit on slow baud rates fixed. |
// Problem reported by Kenny.Tung. |
// * Bad (or lack of ) loopback handling fixed. Reported by Cherry Withers. |
// |
// Improvements: |
// * Made FIFO's as general inferrable memory where possible. |
// So on FPGA they should be inferred as RAM (Distributed RAM on Xilinx). |
// This saves about 1/3 of the Slice count and reduces P&R and synthesis times. |
// |
// * Added optional baudrate output (baud_o). |
// This is identical to BAUDOUT* signal on 16550 chip. |
// It outputs 16xbit_clock_rate - the divided clock. |
// It's disabled by default. Define UART_HAS_BAUDRATE_OUTPUT to use. |
// |
// Revision 1.10 2001/12/11 08:55:40 mohor |
// Scratch register define added. |
// |
// Revision 1.9 2001/12/03 21:44:29 gorban |
// Updated specification documentation. |
// Added full 32-bit data bus interface, now as default. |
// Address is 5-bit wide in 32-bit data bus mode. |
// Added wb_sel_i input to the core. It's used in the 32-bit mode. |
// Added debug interface with two 32-bit read-only registers in 32-bit mode. |
// Bits 5 and 6 of LSR are now only cleared on TX FIFO write. |
// My small test bench is modified to work with 32-bit mode. |
// |
// Revision 1.8 2001/11/26 21:38:54 gorban |
// Lots of fixes: |
// Break condition wasn't handled correctly at all. |
// LSR bits could lose their values. |
// LSR value after reset was wrong. |
// Timing of THRE interrupt signal corrected. |
// LSR bit 0 timing corrected. |
// |
// Revision 1.7 2001/08/24 21:01:12 mohor |
// Things connected to parity changed. |
// Clock devider changed. |
// |
// Revision 1.6 2001/08/23 16:05:05 mohor |
// Stop bit bug fixed. |
// Parity bug fixed. |
// WISHBONE read cycle bug fixed, |
// OE indicator (Overrun Error) bug fixed. |
// PE indicator (Parity Error) bug fixed. |
// Register read bug fixed. |
// |
// Revision 1.5 2001/05/31 20:08:01 gorban |
// FIFO changes and other corrections. |
// |
// Revision 1.4 2001/05/21 19:12:02 gorban |
// Corrected some Linter messages. |
// |
// Revision 1.3 2001/05/17 18:34:18 gorban |
// First 'stable' release. Should be sythesizable now. Also added new header. |
// |
// Revision 1.0 2001-05-17 21:27:11+02 jacob |
// Initial revision |
// |
// |
|
// Uncomment to get synchronous read memories. Note read on neg edge |
//`define SYNC_RAM |
|
// remove comments to restore to use the new version with 8 data bit interface |
// in 32bit-bus mode, the wb_sel_i signal is used to put data in correct place |
// also, in 8-bit version there'll be no debugging features included |
// CAUTION: doesn't work with current version of OR1200 |
//`define DATA_BUS_WIDTH_8 |
|
`ifdef DATA_BUS_WIDTH_8 |
`define UART_ADDR_WIDTH 3 |
`define UART_DATA_WIDTH 8 |
`else |
`define UART_ADDR_WIDTH 5 |
`define UART_DATA_WIDTH 32 |
`endif |
|
// Uncomment this if you want your UART to have |
// 16xBaudrate output port. |
// If defined, the enable signal will be used to drive baudrate_o signal |
// It's frequency is 16xbaudrate |
|
// `define UART_HAS_BAUDRATE_OUTPUT |
|
// Register addresses |
`define UART_REG_RB `UART_ADDR_WIDTH'd0 // receiver buffer |
`define UART_REG_TR `UART_ADDR_WIDTH'd0 // transmitter |
`define UART_REG_IE `UART_ADDR_WIDTH'd1 // Interrupt enable |
`define UART_REG_II `UART_ADDR_WIDTH'd2 // Interrupt identification |
`define UART_REG_FC `UART_ADDR_WIDTH'd2 // FIFO control |
`define UART_REG_LC `UART_ADDR_WIDTH'd3 // Line Control |
`define UART_REG_MC `UART_ADDR_WIDTH'd4 // Modem control |
`define UART_REG_LS `UART_ADDR_WIDTH'd5 // Line status |
`define UART_REG_MS `UART_ADDR_WIDTH'd6 // Modem status |
`define UART_REG_SR `UART_ADDR_WIDTH'd7 // Scratch register |
`define UART_REG_DL1 `UART_ADDR_WIDTH'd0 // Divisor latch bytes (1-2) |
`define UART_REG_DL2 `UART_ADDR_WIDTH'd1 |
|
// Interrupt Enable register bits |
`define UART_IE_RDA 0 // Received Data available interrupt |
`define UART_IE_THRE 1 // Transmitter Holding Register empty interrupt |
`define UART_IE_RLS 2 // Receiver Line Status Interrupt |
`define UART_IE_MS 3 // Modem Status Interrupt |
|
// Interrupt Identification register bits |
`define UART_II_IP 0 // Interrupt pending when 0 |
`define UART_II_II 3:1 // Interrupt identification |
|
// Interrupt identification values for bits 3:1 |
`define UART_II_RLS 3'b011 // Receiver Line Status |
`define UART_II_RDA 3'b010 // Receiver Data available |
`define UART_II_TI 3'b110 // Timeout Indication |
`define UART_II_THRE 3'b001 // Transmitter Holding Register empty |
`define UART_II_MS 3'b000 // Modem Status |
|
// FIFO Control Register bits |
`define UART_FC_TL 1:0 // Trigger level |
|
// FIFO trigger level values |
`define UART_FC_1 2'b00 |
`define UART_FC_4 2'b01 |
`define UART_FC_8 2'b10 |
`define UART_FC_14 2'b11 |
|
// Line Control register bits |
`define UART_LC_BITS 1:0 // bits in character |
`define UART_LC_SB 2 // stop bits |
`define UART_LC_PE 3 // parity enable |
`define UART_LC_EP 4 // even parity |
`define UART_LC_SP 5 // stick parity |
`define UART_LC_BC 6 // Break control |
`define UART_LC_DL 7 // Divisor Latch access bit |
|
// Modem Control register bits |
`define UART_MC_DTR 0 |
`define UART_MC_RTS 1 |
`define UART_MC_OUT1 2 |
`define UART_MC_OUT2 3 |
`define UART_MC_LB 4 // Loopback mode |
|
// Line Status Register bits |
`define UART_LS_DR 0 // Data ready |
`define UART_LS_OE 1 // Overrun Error |
`define UART_LS_PE 2 // Parity Error |
`define UART_LS_FE 3 // Framing Error |
`define UART_LS_BI 4 // Break interrupt |
`define UART_LS_TFE 5 // Transmit FIFO is empty |
`define UART_LS_TE 6 // Transmitter Empty indicator |
`define UART_LS_EI 7 // Error indicator |
|
// Modem Status Register bits |
`define UART_MS_DCTS 0 // Delta signals |
`define UART_MS_DDSR 1 |
`define UART_MS_TERI 2 |
`define UART_MS_DDCD 3 |
`define UART_MS_CCTS 4 // Complement signals |
`define UART_MS_CDSR 5 |
`define UART_MS_CRI 6 |
`define UART_MS_CDCD 7 |
|
// FIFO parameter defines |
|
`define UART_FIFO_WIDTH 8 |
`define UART_FIFO_DEPTH 16 |
`define UART_FIFO_POINTER_W 4 |
`define UART_FIFO_COUNTER_W 5 |
// receiver fifo has width 11 because it has break, parity and framing error bits |
`define UART_FIFO_REC_WIDTH 11 |
|
|
`define VERBOSE_WB 0 // All activity on the WISHBONE is recorded |
`define VERBOSE_LINE_STATUS 0 // Details about the lsr (line status register) |
`define FAST_TEST 1 // 64/1024 packets are sent |
|
|
|
|
|
|
|