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 69 to Rev 412
- ↔ Reverse comparison
Rev 69 → Rev 412
/ml501_startup.v
File deleted
/ml501_ddr2_wb_if.v
File deleted
/reset_debounce.v
File deleted
/ml501_ddr2_params.vh
File deleted
/ml501_gpio.v
File deleted
/eth_defines.v
File deleted
\ No newline at end of file
/ml501_ddr2_wb_if_cache.v
File deleted
\ No newline at end of file
/usr_rst.v
File deleted
/ml501_mc.v
File deleted
/ssram_controller.v
File deleted
/ml501_ddr2_wb_if.v.prev
File deleted
\ No newline at end of file
/dummy_slave.v
File deleted
/or1200_defines.v
File deleted
/wb_lfsr.v
File deleted
/ml501.v
File deleted
/uart_defines.v
File deleted
/ml501_defines.v
File deleted
/wb_conbus_defines.v
File deleted
/ddr2_mig/ddr2_phy_dqs_iob.v
File deleted
/ddr2_mig/ddr2_mem_if_top.v
File deleted
/ddr2_mig/ddr2_usr_wr.v
File deleted
/ddr2_mig/ddr2_ctrl.v
File deleted
/ddr2_mig/ddr2_usr_addr_fifo.v
File deleted
/ddr2_mig/ddr2_phy_top.v
File deleted
/ddr2_mig/ddr2_usr_top.v
File deleted
\ No newline at end of file
/ddr2_mig/ddr2_phy_write.v
File deleted
/ddr2_mig/ddr2_mig.v
File deleted
/ddr2_mig/ddr2_phy_dm_iob.v
File deleted
/ddr2_mig/ddr2_phy_ctl_io.v
File deleted
/ddr2_mig/ddr2_idelay_ctrl.v
File deleted
/ddr2_mig/ddr2_top.v
File deleted
/ddr2_mig/ddr2_phy_dq_iob.v
File deleted
/ddr2_mig/ddr2_chipscope.v
File deleted
\ No newline at end of file
/ddr2_mig/ddr2_phy_io.v
File deleted
/ddr2_mig/ddr2_usr_rd.v
File deleted
/ddr2_mig/ddr2_phy_init.v
File deleted
/ddr2_mig/ddr2_infrastructure.v
File deleted
/ddr2_mig/ddr2_phy_calib.v
File deleted
/verilog/xilinx_ssram/xilinx_ssram.v
0,0 → 1,300
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 xilinx_ssram |
( |
// 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 // xilinx_ssram |
|
// Local Variables: |
// verilog-library-directories:(".") |
// verilog-library-extensions:(".v" ".h") |
// End: |
/verilog/clkgen/clkgen.v
0,0 → 1,205
/* |
* |
* Clock, reset generation unit for ML501 board |
* |
* Implements clock generation according to design defines |
* |
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
`include "orpsoc-defines.v" |
`include "synthesis-defines.v" |
|
module clkgen |
( |
// Main clocks in, depending on board |
sys_clk_in_p, sys_clk_in_n, |
|
// Wishbone clock and reset out |
wb_clk_o, |
wb_rst_o, |
|
// JTAG clock |
`ifdef JTAG_DEBUG |
tck_pad_i, |
dbg_tck_o, |
`endif |
// Main memory clocks |
`ifdef XILINX_DDR2 |
ddr2_if_clk_o, |
ddr2_if_rst_o, |
clk200_o, |
`endif |
|
// Asynchronous, active low reset in |
rst_n_pad_i |
|
); |
|
input sys_clk_in_p,sys_clk_in_n; |
|
output wb_rst_o; |
output wb_clk_o; |
|
`ifdef JTAG_DEBUG |
input tck_pad_i; |
output dbg_tck_o; |
`endif |
|
`ifdef XILINX_DDR2 |
output ddr2_if_clk_o; |
output ddr2_if_rst_o; |
output clk200_o; |
`endif |
|
// Asynchronous, active low reset (pushbutton, typically) |
input rst_n_pad_i; |
|
// First, deal with the asychronous reset |
wire async_rst; |
wire async_rst_n; |
|
// Xilinx synthesis tools appear cluey enough to instantiate buffers when and |
// where they're needed, so we do simple assigns for this tech. |
assign async_rst_n = rst_n_pad_i; |
|
// Everyone likes active-high reset signals... |
assign async_rst = ~async_rst_n; |
|
|
`ifdef JTAG_DEBUG |
assign dbg_tck_o = tck_pad_i; |
`endif |
|
// |
// Declare synchronous reset wires here |
// |
|
// An active-low synchronous reset signal (usually a PLL lock signal) |
wire sync_rst_n; |
|
// An active-low synchronous reset from ethernet PLL |
wire sync_eth_rst_n; |
|
|
wire sys_clk_in_200; |
/* DCM0 wires */ |
wire dcm0_clk0_prebufg, dcm0_clk0; |
wire dcm0_clkfx_prebufg, dcm0_clkfx; |
wire dcm0_clkdv_prebufg, dcm0_clkdv; |
wire dcm0_locked; |
|
/* Dif. input buffer for 200MHz board clock, generate SE 200MHz */ |
IBUFGDS_LVPECL_25 sys_clk_in_ibufds |
( |
.O(sys_clk_in_200), |
.I(sys_clk_in_p), |
.IB(sys_clk_in_n)); |
|
/* 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 (1'b0)); |
|
// 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)); |
|
assign wb_clk_o = dcm0_clkdv; |
assign sync_rst_n = dcm0_locked; |
|
`ifdef XILINX_DDR2 |
assign ddr2_if_clk_o = dcm0_clkfx; // 266MHz |
assign clk200_o = dcm0_clk0; // 200MHz |
`endif |
|
// |
// Reset generation |
// |
// |
|
// Reset generation for wishbone |
reg [15:0] wb_rst_shr; |
always @(posedge wb_clk_o or posedge async_rst) |
if (async_rst) |
wb_rst_shr <= 16'hffff; |
else |
wb_rst_shr <= {wb_rst_shr[14:0], ~(sync_rst_n)}; |
|
assign wb_rst_o = wb_rst_shr[15]; |
|
|
`ifdef XILINX_DDR2 |
// Reset generation for DDR2 controller |
reg [15:0] ddr2_if_rst_shr; |
always @(posedge ddr2_if_clk_o or posedge async_rst) |
if (async_rst) |
ddr2_if_rst_shr <= 16'hffff; |
else |
ddr2_if_rst_shr <= {ddr2_if_rst_shr[14:0], ~(sync_rst_n)}; |
|
assign ddr2_if_rst_o = ddr2_if_rst_shr[15]; |
`endif |
|
|
endmodule // clkgen |
/verilog/include/ethmac_defines.v
0,0 → 1,255
////////////////////////////////////////////////////////////////////// |
//// //// |
//// eth_defines.v //// |
//// //// |
//// This file is part of the Ethernet IP core project //// |
//// http://opencores.org/project,ethmac //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorM@opencores.org) //// |
//// //// |
//// Modified by: //// |
//// - Julius Baxter (julius@opencores.org) //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
|
|
//`define ETH_BIST // Bist for usage with Virtual Silicon RAMS |
|
`define ETH_MBIST_CTRL_WIDTH 3 // width of MBIST control bus |
|
// Generic FIFO implementation - hopefully synthesizable with Synplify |
`define ETH_FIFO_GENERIC |
// 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_DBG_ADR 8'h16 // 0x58 |
|
|
`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_DATA_WIDTH 32 |
|
// Defines for ethernet TX fifo size - impacts FPGA resource usage |
//`define ETH_TX_FULL_PACKET_FIFO // Full 1500 byte TX buffer - uncomment this |
//`define ETH_TX_256BYTE_FIFO // 256 byte TX buffer - uncomment this |
//`define ETH_TX_512BYTE_FIFO // 512 byte TX buffer - uncomment this |
`define ETH_TX_1KBYTE_FIFO // 1024 byte TX buffer - uncomment this |
|
`ifdef ETH_TX_FULL_PACKET_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 11 |
`define ETH_TX_FIFO_DEPTH 375 |
`else |
`ifdef ETH_TX_1KBYTE_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 9 |
`define ETH_TX_FIFO_DEPTH 256 |
`else |
`ifdef ETH_TX_512BYTE_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 8 |
`define ETH_TX_FIFO_DEPTH 128 |
`else |
`ifdef ETH_TX_256BYTE_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 7 |
`define ETH_TX_FIFO_DEPTH 64 |
`else |
// Default is 64 bytes |
`define ETH_TX_FIFO_CNT_WIDTH 5 |
`define ETH_TX_FIFO_DEPTH 16 |
`endif |
`endif |
`endif // !`ifdef ETH_TX_512BYTE_FIFO |
`endif // !`ifdef ETH_TX_FULL_PACKET_FIFO |
|
|
|
// Settings for RX FIFO |
`define ETH_RX_FIFO_CNT_WIDTH 9 |
`define ETH_RX_FIFO_DEPTH 256 |
//`define ETH_RX_FIFO_CNT_WIDTH 8 |
//`define ETH_RX_FIFO_DEPTH 128 |
//`define ETH_RX_FIFO_CNT_WIDTH 7 |
//`define ETH_RX_FIFO_DEPTH 64 |
//`define ETH_RX_FIFO_CNT_WIDTH 6 |
//`define ETH_RX_FIFO_DEPTH 32 |
//`define ETH_RX_FIFO_CNT_WIDTH 5 |
//`define ETH_RX_FIFO_DEPTH 16 |
|
`define ETH_RX_FIFO_DATA_WIDTH 32 |
|
// Burst length |
`define BURST_4BEAT |
`ifdef BURST_4BEAT |
`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 |
`endif |
|
//`define ETH_BURST_LENGTH 32 // Change also ETH_BURST_CNT_WIDTH |
//`define ETH_BURST_CNT_WIDTH 7 // The counter must be width enough to count to ETH_BURST_LENGTH |
|
// Undefine this to enable bursting for RX (writing to memory) |
`define ETH_RX_BURST_EN |
|
|
// WISHBONE interface is Revision B3 compliant (uncomment when needed) |
`define ETH_WISHBONE_B3 |
|
// Hack where the transmit logic polls each of the TX buffers instead of having to keep track of what's going on |
//`define TXBD_POLL |
|
// Define this to allow reading of the Wishbone control state machine on reg |
// address 0x58 |
`define WISHBONE_DEBUG |
/verilog/include/i2c_master_slave_defines.v
0,0 → 1,66
///////////////////////////////////////////////////////////////////// |
//// //// |
//// WISHBONE rev.B2 compliant I2C Master controller defines //// |
//// //// |
//// //// |
//// Author: Richard Herveille //// |
//// richard@asics.ws //// |
//// www.asics.ws //// |
//// //// |
//// Downloaded from: http://www.opencores.org/projects/i2c/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 Richard Herveille //// |
//// richard@asics.ws //// |
//// //// |
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: i2c_master_defines.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $ |
// |
// $Date: 2001-11-05 11:59:25 $ |
// $Revision: 1.3 $ |
// $Author: rherveille $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
|
|
// I2C registers wishbone addresses |
|
// bitcontroller states |
`define I2C_CMD_NOP 4'b0000 |
`define I2C_CMD_START 4'b0001 |
`define I2C_CMD_STOP 4'b0010 |
`define I2C_CMD_WRITE 4'b0100 |
`define I2C_CMD_READ 4'b1000 |
|
`define I2C_SLAVE_CMD_WRITE 2'b01 |
`define I2C_SLAVE_CMD_READ 2'b10 |
`define I2C_SLAVE_CMD_NOP 2'b00 |
|
|
|
/verilog/include/dbg_cpu_defines.v
0,0 → 1,85
////////////////////////////////////////////////////////////////////// |
//// //// |
//// dbg_cpu_defines.v //// |
//// //// |
//// //// |
//// This file is part of the SoC Debug Interface. //// |
//// http://www.opencores.org/projects/DebugInterface/ //// |
//// //// |
//// Author(s): //// |
//// Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 - 2004 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
// Defining length of the command |
`define DBG_CPU_CMD_LEN 3'd4 |
`define DBG_CPU_CMD_CNT_WIDTH 3 |
|
// Defining length of the access_type field |
`define DBG_CPU_ACC_TYPE_LEN 4 |
|
// Defining length of the address |
`define DBG_CPU_ADR_LEN 32 |
|
// Defining length of the length register |
`define DBG_CPU_LEN_LEN 16 |
|
// Defining total length of the DR needed |
`define DBG_CPU_DR_LEN (`DBG_CPU_ACC_TYPE_LEN + `DBG_CPU_ADR_LEN + `DBG_CPU_LEN_LEN) |
// Defining length of the CRC |
`define DBG_CPU_CRC_LEN 6'd32 |
`define DBG_CPU_CRC_CNT_WIDTH 6 |
|
// Defining length of status |
`define DBG_CPU_STATUS_LEN 3'd4 |
`define DBG_CPU_STATUS_CNT_WIDTH 3 |
|
// Defining length of the data |
//define DBG_CPU_DATA_CNT_WIDTH `DBG_CPU_LEN_LEN + 3 |
`define DBG_CPU_DATA_CNT_WIDTH 19 |
//define DBG_CPU_DATA_CNT_LIM_WIDTH `DBG_CPU_LEN_LEN |
`define DBG_CPU_DATA_CNT_LIM_WIDTH 16 |
// Defining length of the control register |
`define DBG_CPU_CTRL_LEN 2 |
|
//Defining commands |
`define DBG_CPU_GO 4'h0 |
`define DBG_CPU_RD_COMM 4'h1 |
`define DBG_CPU_WR_COMM 4'h2 |
`define DBG_CPU_RD_CTRL 4'h3 |
`define DBG_CPU_WR_CTRL 4'h4 |
|
// Defining access types for wishbone |
`define DBG_CPU_WRITE 4'h2 |
`define DBG_CPU_READ 4'h6 |
|
|
/verilog/include/or1200_defines.v
0,0 → 1,1732
////////////////////////////////////////////////////////////////////// |
//// //// |
//// OR1200's definitions //// |
//// //// |
//// This file is part of the OpenRISC 1200 project //// |
//// http://opencores.org/project,or1k //// |
//// //// |
//// Description //// |
//// Defines for 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// $Log: or1200_defines.v,v $ |
// Revision 2.0 2010/06/30 11:00:00 ORSoC |
// Minor update: |
// Defines added, bugs fixed. |
|
// |
// 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 |
// Generic models should infer RAM blocks at synthesis time (not only effects |
// single port ram.) |
`define OR1200_GENERIC |
|
// |
// 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 |
// |
|
// |
// Reset active low |
// |
//`define OR1200_RST_ACT_LOW |
|
// |
// 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 l.sub instruction |
// |
// By default implementation of l.sub instructions |
// is enabled to be compliant with the simulator. |
// If you don't use carry bit, then disable |
// implementation to save area. |
// |
`define OR1200_IMPL_SUB |
|
// |
// 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/l.sub |
// instructions and if these three insns are not |
// implemented there is not much point having SR[CY]. |
// |
//`define OR1200_IMPL_CY |
|
// |
// 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 Find First/Last '1' |
// |
`define OR1200_IMPL_ALU_FFL1 |
|
// |
// 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 |
|
// |
// 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, both multiplier and MAC needs to be implemented. |
// |
`define OR1200_DIV_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.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 |
|
// |
// Reset value and event |
// |
`ifdef OR1200_RST_ACT_LOW |
`define OR1200_RST_VALUE (1'b0) |
`define OR1200_RST_EVENT negedge |
`else |
`define OR1200_RST_VALUE (1'b1) |
`define OR1200_RST_EVENT posedge |
`endif |
|
// |
// 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_FFL1 4'd15 |
|
|
// ALU instructions second opcode field (previously multicycle field in |
// machine word) |
`define OR1200_ALUOP2_POS 9:8 |
`define OR1200_ALUOP2_WIDTH 2 |
|
|
// |
// MACOPs |
// |
`define OR1200_MACOP_WIDTH 3 |
`define OR1200_MACOP_NOP 3'b000 |
`define OR1200_MACOP_MAC 3'b001 |
`define OR1200_MACOP_MSB 3'b010 |
|
// |
// 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 |
|
// Execution control which will "wait on" a module to finish |
`define OR1200_WAIT_ON_WIDTH 2 |
`define OR1200_WAIT_ON_FPU `OR1200_WAIT_ON_WIDTH'd1 |
`define OR1200_WAIT_ON_MTSPR `OR1200_WAIT_ON_WIDTH'd2 |
|
// 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 |
|
// Number of bits of load/store EA precalculated in ID stage |
// for balancing ID and EX stages. |
// |
// Valid range: 2,3,...,30,31 |
`define OR1200_LSUEA_PRECALC 2 |
|
// FETCHOPs |
`define OR1200_FETCHOP_WIDTH 1 |
`define OR1200_FETCHOP_NOP 1'b0 |
`define OR1200_FETCHOP_LW 1'b1 |
|
// |
// Register File Write-Back OPs |
// |
// 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 |
|
// 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 |
|
// |
// FP OPs |
// |
// MSbit indicates FPU operation valid |
// |
`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 |
|
// |
// 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 |
|
// |
// 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 |
`define OR1200_OR32_FLOAT 6'b110010 |
/* */ |
`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_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 |
`define OR1200_SPR_GROUP_FPU 5'd11 |
|
///////////////////////////////////////////////////// |
// |
// 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 |
`define OR1200_SPR_FPCSR 11'd20 |
`define OR1200_SPR_EPCR 11'd32 |
`define OR1200_SPR_EEAR 11'd48 |
`define OR1200_SPR_ESR 11'd64 |
|
// |
// SR bits |
// |
`define OR1200_SR_WIDTH 17 |
`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_TED 16 |
`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 if HW breakpoints enabled |
// Comment / uncomment DU_DVRn / DU_DCRn pairs bellow according to this number ! |
// DU_DVR0..DU_DVR7 should be uncommented for 8 DU_DVRDCR_PAIRS |
`define OR1200_DU_DVRDCR_PAIRS 8 |
|
// Define if you want trace buffer |
// (for now only available for Xilinx Virtex FPGAs) |
//`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'h1?? |
`define OR1200_DU_TBIM 11'h2?? |
`define OR1200_DU_TBAR 11'h3?? |
`define OR1200_DU_TBTS 11'h4?? |
`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 12:2 |
`define OR1200_DU_DMR2_WGB 23:13 |
|
// 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 31 |
|
// 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_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 enable default behavior of cache as write through |
// Turning this off enabled write back statergy |
// |
`define OR1200_DC_WRITETHROUGH |
|
// Define to enable stores from the stack not doing writethrough. |
// EXPERIMENTAL |
//`define OR1200_DC_NOSTACKWRITETHROUGH |
|
// Data cache SPR definitions |
`define OR1200_SPRGRP_DC_ADR_WIDTH 3 |
// Data cache group SPR addresses |
`define OR1200_SPRGRP_DC_DCCR 3'd0 // Not implemented |
`define OR1200_SPRGRP_DC_DCBPR 3'd1 // Not implemented |
`define OR1200_SPRGRP_DC_DCBFR 3'd2 |
`define OR1200_SPRGRP_DC_DCBIR 3'd3 |
`define OR1200_SPRGRP_DC_DCBWR 3'd4 // Not implemented |
`define OR1200_SPRGRP_DC_DCBLR 3'd5 // Not implemented |
|
// |
// 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'h08 |
`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_FPP_BITS 11 |
`define OR1200_UPR_RES1_BITS 23:12 |
`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 |
`ifdef OR1200_MAC_IMPLEMENTED |
`define OR1200_UPR_MP 1'b1 |
`else |
`define OR1200_UPR_MP 1'b0 |
`endif |
`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_PM_IMPLEMENTED |
`define OR1200_UPR_PMP 1'b1 |
`else |
`define OR1200_UPR_PMP 1'b0 |
`endif |
`ifdef OR1200_PIC_IMPLEMENTED |
`define OR1200_UPR_PICP 1'b1 |
`else |
`define OR1200_UPR_PICP 1'b0 |
`endif |
`ifdef OR1200_TT_IMPLEMENTED |
`define OR1200_UPR_TTP 1'b1 |
`else |
`define OR1200_UPR_TTP 1'b0 |
`endif |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_UPR_FPP 1'b1 |
`else |
`define OR1200_UPR_FPP 1'b0 |
`endif |
`define OR1200_UPR_RES1 12'h000 |
`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 |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_CPUCFGR_OF32S 1'b1 |
`else |
`define OR1200_CPUCFGR_OF32S 1'b0 |
`endif |
|
`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'b0 // Irrelevant |
`define OR1200_DCCFGR_CBIRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CBPRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CBLRI 1'b0 // Irrelevant |
`define OR1200_DCCFGR_CBFRI 1'b0 // 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 ? 1'b0 : 1'b1 // 16 byte cache block |
`ifdef OR1200_DC_WRITETHROUGH |
`define OR1200_DCCFGR_CWS 1'b0 // Write-through strategy |
`else |
`define OR1200_DCCFGR_CWS 1'b1 // Write-back strategy |
`endif |
`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. |
`ifdef OR1200_DC_WRITETHROUGH |
`define OR1200_DCCFGR_CBWBRI 1'b0 // Cache block WB reg not impl. |
`else |
`define OR1200_DCCFGR_CBWBRI 1'b1 // Cache block WB reg impl. |
`endif |
`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 ? 1'b0: 1'b1 // 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 3:0 |
`define OR1200_DCFGR_WPCI_BITS 4 |
`define OR1200_DCFGR_RES1_BITS 31:5 |
|
// DCFGR values |
`ifdef OR1200_DU_HWBKPTS |
`define OR1200_DCFGR_NDP 4'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 4'h0 // Zero DVR/DCR pairs |
`define OR1200_DCFGR_WPCI 1'b0 // WP counters not impl. |
`endif |
`define OR1200_DCFGR_RES1 27'd0 |
|
/////////////////////////////////////////////////////////////////////////////// |
// Boot Address Selection // |
// This only changes where the initial reset occurs. EPH setting is still // |
// used to determine where vectors are located. // |
/////////////////////////////////////////////////////////////////////////////// |
// Boot from 0xf0000100 |
//`define OR1200_BOOT_PCREG_DEFAULT 30'h3c00003f |
//`define OR1200_BOOT_ADR 32'hf0000100 |
// Boot from 0x100 |
`define OR1200_BOOT_PCREG_DEFAULT 30'h0000003f |
`define OR1200_BOOT_ADR 32'h00000100 |
/verilog/include/orpsoc-defines.v
0,0 → 1,89
////////////////////////////////////////////////////////////////////// |
//// //// |
//// orpsoc-defines //// |
//// //// |
//// Top level ORPSoC defines file //// |
//// //// |
//// Included in toplevel and testbench //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
////////////////////////////////////////////////////////////////////// |
// |
// Uncomment a `define BOARD_XYZ to configure design RTL for it. |
// |
// Mainly presets are for internal frequency settings, and what |
// external oscillator is expected (ordb1's were made with various |
// XTALs.) |
// |
////////////////////////////////////////////////////////////////////// |
|
`define XILINX |
`define XILINX_PLL |
`define FPGA_BOARD_XILINX_ML501 |
`define IOCONFIG_XILINX_ML501 |
`define BOARD_CLOCK_PERIOD 5000 // 200MHz (pS accuracy for Xilinx sims.) |
|
`define JTAG_DEBUG |
// `define RAM_WB |
// `define XILINX_SSRAM |
`define XILINX_DDR2 |
`define UART0 |
`define GPIO0 |
`define SPI0 |
`define I2C0 |
`define I2C1 |
`define ETH0 |
`define ETH0_PHY_RST |
|
// end of included module defines - keep this comment line here, scripts depend on it!! |
|
|
// |
// Arbiter defines |
// |
|
// Uncomment to register things through arbiter (hopefully quicker design) |
// Instruction bus arbiter |
//`define ARBITER_IBUS_REGISTERING |
`define ARBITER_IBUS_WATCHDOG |
// Watchdog timeout: 2^(ARBITER_IBUS_WATCHDOG_TIMER_WIDTH+1) cycles |
`define ARBITER_IBUS_WATCHDOG_TIMER_WIDTH 12 |
|
// Data bus arbiter |
|
//`define ARBITER_DBUS_REGISTERING |
`define ARBITER_DBUS_WATCHDOG |
// Watchdog timeout: 2^(ARBITER_DBUS_WATCHDOG_TIMER_WIDTH+1) cycles |
`define ARBITER_DBUS_WATCHDOG_TIMER_WIDTH 12 |
|
// Byte bus (peripheral bus) arbiter |
// Don't really need the watchdog here - the databus will pick it up |
//`define ARBITER_BYTEBUS_WATCHDOG |
// Watchdog timeout: 2^(ARBITER_BYTEBUS_WATCHDOG_TIMER_WIDTH+1) cycles |
`define ARBITER_BYTEBUS_WATCHDOG_TIMER_WIDTH 9 |
|
/verilog/include/dbg_wb_defines.v
0,0 → 1,113
////////////////////////////////////////////////////////////////////// |
//// //// |
//// dbg_wb_defines.v //// |
//// //// |
//// //// |
//// This file is part of the SoC Debug Interface. //// |
//// http://www.opencores.org/projects/DebugInterface/ //// |
//// //// |
//// Author(s): //// |
//// Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 - 2004 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: dbg_wb_defines.v,v $ |
// Revision 1.7 2004/03/31 14:34:08 igorm |
// data_cnt_lim length changed to reduce number of warnings. |
// |
// Revision 1.6 2004/03/28 20:27:02 igorm |
// New release of the debug interface (3rd. release). |
// |
// Revision 1.5 2004/03/22 16:35:46 igorm |
// Temp version before changing dbg interface. |
// |
// Revision 1.4 2004/01/16 14:51:33 mohor |
// cpu registers added. |
// |
// Revision 1.3 2004/01/08 17:53:36 mohor |
// tmp version. |
// |
// Revision 1.2 2004/01/06 17:15:19 mohor |
// temp3 version. |
// |
// Revision 1.1 2003/12/23 15:09:04 mohor |
// New directory structure. New version of the debug interface. |
// |
// |
// |
|
// Defining length of the command |
`define DBG_WB_CMD_LEN 3'd4 |
`define DBG_WB_CMD_LEN_INT 4 |
`define DBG_WB_CMD_CNT_WIDTH 3 |
|
// Defining length of the access_type field |
`define DBG_WB_ACC_TYPE_LEN 4 |
|
|
// Defining length of the address |
`define DBG_WB_ADR_LEN 32 |
|
// Defining length of the length register |
`define DBG_WB_LEN_LEN 16 |
|
// Defining total length of the DR needed |
`define DBG_WB_DR_LEN (`DBG_WB_ACC_TYPE_LEN + `DBG_WB_ADR_LEN + `DBG_WB_LEN_LEN) |
|
// Defining length of the CRC |
`define DBG_WB_CRC_LEN 6'd32 |
`define DBG_WB_CRC_CNT_WIDTH 6 |
|
// Defining length of status |
`define DBG_WB_STATUS_LEN 3'd4 |
`define DBG_WB_STATUS_CNT_WIDTH 3 |
|
// Defining length of the data |
`define DBG_WB_DATA_CNT_WIDTH (`DBG_WB_LEN_LEN + 3) |
`define DBG_WB_DATA_CNT_LIM_WIDTH `DBG_WB_LEN_LEN |
|
//Defining commands |
`define DBG_WB_GO 4'h0 |
`define DBG_WB_RD_COMM 4'h1 |
`define DBG_WB_WR_COMM 4'h2 |
|
// Defining access types for wishbone |
`define DBG_WB_WRITE8 4'h0 |
`define DBG_WB_WRITE16 4'h1 |
`define DBG_WB_WRITE32 4'h2 |
`define DBG_WB_READ8 4'h4 |
`define DBG_WB_READ16 4'h5 |
`define DBG_WB_READ32 4'h6 |
|
|
/verilog/include/tap_defines.v
0,0 → 1,69
////////////////////////////////////////////////////////////////////// |
//// //// |
//// tap_defines.v //// |
//// //// |
//// //// |
//// This file is part of the JTAG Test Access Port (TAP) //// |
//// http://www.opencores.org/projects/jtag/ //// |
//// //// |
//// Author(s): //// |
//// Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 - 2003 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: tap_defines.v,v $ |
// Revision 1.2 2004/01/27 10:00:33 mohor |
// Unused registers removed. |
// |
// Revision 1.1 2003/12/23 14:52:14 mohor |
// Directory structure changed. New version of TAP. |
// |
// |
// |
|
|
// Define IDCODE Value |
`define IDCODE_VALUE 32'h14951185 |
|
// Length of the Instruction register |
`define IR_LENGTH 4 |
|
// Supported Instructions |
`define EXTEST 4'b0000 |
`define SAMPLE_PRELOAD 4'b0001 |
`define IDCODE 4'b0010 |
`define DEBUG 4'b1000 |
`define MBIST 4'b1001 |
`define BYPASS 4'b1111 |
|
/verilog/include/orpsoc-params.v
0,0 → 1,165
////////////////////////////////////////////////////////////////////// |
//// //// |
//// orpsoc-params //// |
//// //// |
//// Top level ORPSoC parameters file //// |
//// //// |
//// Included in toplevel and testbench //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
/////////////////////////// |
// // |
// Peripheral parameters // |
// // |
/////////////////////////// |
|
// SPI 0 params |
parameter spi0_ss_width = 1; |
parameter spi0_wb_adr = 8'hb0; |
parameter wbs_d_spi0_data_width = 8; |
parameter spi0_wb_adr_width = 3; |
|
// i2c master slave params |
// Slave addresses |
parameter HV0_SADR = 8'h44; |
parameter HV1_SADR = 8'h45; |
parameter HV2_SADR = 8'h46; |
parameter HV3_SADR = 8'h47; |
|
// i2c 0 params |
parameter i2c_0_wb_adr = 8'ha0; |
parameter i2c_0_wb_adr_width = 3; |
parameter wbs_d_i2c0_data_width = 8; |
|
// i2c 1 params |
parameter i2c_1_wb_adr = 8'ha1; |
parameter i2c_1_wb_adr_width = 3; |
parameter wbs_d_i2c1_data_width = 8; |
|
|
// GPIO 0 params |
parameter wbs_d_gpio0_data_width = 8; |
parameter gpio0_wb_adr_width = 3; |
parameter gpio0_io_width = 24; |
parameter gpio0_wb_adr = 8'h91; |
parameter gpio0_dir_reset_val = 0; |
parameter gpio0_o_reset_val = 0; |
|
// UART 0 params |
parameter wbs_d_uart0_data_width = 8; |
parameter uart0_wb_adr = 8'h90; |
parameter uart0_data_width = 8; |
parameter uart0_addr_width = 3; |
|
// ROM |
parameter wbs_i_rom0_data_width = 32; |
parameter wbs_i_rom0_addr_width = 6; |
parameter rom0_wb_adr = 4'hf; |
|
// MC0 (SDRAM, or other) |
parameter wbs_i_mc0_data_width = 32; |
parameter wbs_d_mc0_data_width = 32; |
|
// ETH0 defines |
parameter eth0_wb_adr = 8'h92; |
parameter wbs_d_eth0_data_width = 32; |
parameter wbs_d_eth0_addr_width = 12; |
parameter wbm_eth0_data_width = 32; |
parameter wbm_eth0_addr_width = 32; |
|
// Memory sizing for synthesis (small) |
parameter internal_sram_mem_span = 32'h0080_0000; |
parameter internal_sram_adr_width_for_span = 23; |
|
////////////////////////////////////////////////////// |
// // |
// Wishbone bus parameters // |
// // |
////////////////////////////////////////////////////// |
|
//////////////////////// |
// // |
// Arbiter parameters // |
// // |
//////////////////////// |
|
parameter wb_dw = 32; // Default Wishbone full word width |
parameter wb_aw = 32; // Default Wishbone full address width |
|
/////////////////////////// |
// // |
// Instruction bus // |
// // |
/////////////////////////// |
parameter ibus_arb_addr_match_width = 4; |
// Slave addresses |
parameter ibus_arb_slave0_adr = rom0_wb_adr; // FLASH ROM |
parameter ibus_arb_slave1_adr = 4'h0; // Main memory (SDRAM/FPGA SRAM) |
|
/////////////////////////// |
// // |
// Data bus // |
// // |
/////////////////////////// |
// Has auto foward to last slave when no address hits |
parameter dbus_arb_wb_addr_match_width = 8; |
parameter dbus_arb_wb_num_slaves = 5; |
// Slave addresses |
parameter dbus_arb_slave0_adr = 4'h0; // Main memory (SDRAM/FPGA SRAM) |
parameter dbus_arb_slave1_adr = eth0_wb_adr; // Ethernet 0 |
|
/////////////////////////////// |
// // |
// Byte-wide peripheral bus // |
// // |
/////////////////////////////// |
parameter bbus_arb_wb_addr_match_width = 8; |
parameter bbus_arb_wb_num_slaves = 5; // Update this when changing slaves! |
// Slave addresses |
parameter bbus_arb_slave0_adr = uart0_wb_adr; |
parameter bbus_arb_slave1_adr = gpio0_wb_adr; |
parameter bbus_arb_slave2_adr = i2c_0_wb_adr; |
parameter bbus_arb_slave3_adr = i2c_1_wb_adr; |
parameter bbus_arb_slave4_adr = spi0_wb_adr; |
parameter bbus_arb_slave5_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave6_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave7_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave8_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave9_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave10_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave11_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave12_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave13_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave14_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave15_adr = 0 /* UNASSIGNED */; |
parameter bbus_arb_slave16_adr = 0 /* UNASSIGNED */; |
|
|
|
|
/verilog/include/uart_defines.v
0,0 → 1,250
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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: not supported by cvs2svn $ |
// 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 |
// |
// |
|
// 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 |
|
// Defines hard baud prescaler register - uncomment to enable |
`define PRESCALER_PRESET_HARD |
// 115200 baud preset values |
// 20MHz: prescaler 10.8 (11, rounded up) |
//`define PRESCALER_HIGH_PRESET 8'd0 |
//`define PRESCALER_LOW_PRESET 8'd11 |
// 50MHz: prescaler 27.1 |
`define PRESCALER_HIGH_PRESET 8'd0 |
`define PRESCALER_LOW_PRESET 8'd27 |
/verilog/include/dbg_defines.v
0,0 → 1,153
////////////////////////////////////////////////////////////////////// |
//// //// |
//// dbg_defines.v //// |
//// //// |
//// //// |
//// This file is part of the SoC Debug Interface. //// |
//// http://www.opencores.org/projects/DebugInterface/ //// |
//// //// |
//// Author(s): //// |
//// Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 - 2004 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: dbg_defines.v,v $ |
// Revision 1.20 2004/04/01 11:56:59 igorm |
// Port names and defines for the supported CPUs changed. |
// |
// Revision 1.19 2004/03/28 20:27:02 igorm |
// New release of the debug interface (3rd. release). |
// |
// Revision 1.18 2004/03/22 16:35:46 igorm |
// Temp version before changing dbg interface. |
// |
// Revision 1.17 2004/01/30 10:24:30 mohor |
// Defines WISHBONE_SUPPORTED and CPU_SUPPORTED added. By default both are |
// turned on. |
// |
// Revision 1.16 2004/01/20 14:23:45 mohor |
// Define name changed. |
// |
// Revision 1.15 2003/12/23 15:07:34 mohor |
// New directory structure. New version of the debug interface. |
// Files that are not needed removed. |
// |
// Revision 1.14 2003/10/23 16:17:00 mohor |
// CRC logic changed. |
// |
// Revision 1.13 2003/10/21 09:48:31 simons |
// Mbist support added. |
// |
// Revision 1.12 2003/09/17 14:38:57 simons |
// WB_CNTL register added, some syncronization fixes. |
// |
// Revision 1.11 2003/08/28 13:55:21 simons |
// Three more chains added for cpu debug access. |
// |
// Revision 1.10 2003/07/31 12:19:49 simons |
// Multiple cpu support added. |
// |
// Revision 1.9 2002/05/07 14:43:59 mohor |
// mon_cntl_o signals that controls monitor mux added. |
// |
// Revision 1.8 2002/01/25 07:58:34 mohor |
// IDCODE bug fixed, chains reused to decreas size of core. Data is shifted-in |
// not filled-in. Tested in hw. |
// |
// Revision 1.7 2001/12/06 10:08:06 mohor |
// Warnings from synthesys tools fixed. |
// |
// Revision 1.6 2001/11/28 09:38:30 mohor |
// Trace disabled by default. |
// |
// Revision 1.5 2001/10/15 09:55:47 mohor |
// Wishbone interface added, few fixes for better performance, |
// hooks for boundary scan testing added. |
// |
// Revision 1.4 2001/09/24 14:06:42 mohor |
// Changes connected to the OpenRISC access (SPR read, SPR write). |
// |
// Revision 1.3 2001/09/20 10:11:25 mohor |
// Working version. Few bugs fixed, comments added. |
// |
// Revision 1.2 2001/09/18 14:13:47 mohor |
// Trace fixed. Some registers changed, trace simplified. |
// |
// Revision 1.1.1.1 2001/09/13 13:49:19 mohor |
// Initial official release. |
// |
// Revision 1.3 2001/06/01 22:22:35 mohor |
// This is a backup. It is not a fully working version. Not for use, yet. |
// |
// Revision 1.2 2001/05/18 13:10:00 mohor |
// Headers changed. All additional information is now avaliable in the README.txt file. |
// |
// Revision 1.1.1.1 2001/05/18 06:35:08 mohor |
// Initial release |
// |
// |
|
|
// Length of the MODULE ID register |
`define DBG_TOP_MODULE_ID_LENGTH 4 |
|
// Length of data |
`define DBG_TOP_MODULE_DATA_LEN `DBG_TOP_MODULE_ID_LENGTH + 1 |
`define DBG_TOP_DATA_CNT 3 |
|
// Length of status |
`define DBG_TOP_STATUS_LEN 3'd4 |
`define DBG_TOP_STATUS_CNT_WIDTH 3 |
|
// Length of the CRC |
`define DBG_TOP_CRC_LEN 32 |
`define DBG_TOP_CRC_CNT 6 |
|
// Chains |
`define DBG_TOP_WISHBONE_DEBUG_MODULE 4'h0 |
`define DBG_TOP_CPU0_DEBUG_MODULE 4'h1 |
`define DBG_TOP_CPU1_DEBUG_MODULE 4'h2 |
|
// If WISHBONE sub-module is supported uncomment the folowing line |
`define DBG_WISHBONE_SUPPORTED |
|
// If CPU_0 sub-module is supported uncomment the folowing line |
`define DBG_CPU0_SUPPORTED |
|
// If CPU_1 sub-module is supported uncomment the folowing line |
//`define DBG_CPU1_SUPPORTED |
|
// If more debug info is needed, uncomment the follofing line |
//`define DBG_MORE_INFO |
|
/verilog/include/xilinx_ddr2_params.v
0,0 → 1,53
|
// 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 |
// Controller with cache! |
parameter BURST_LEN = 8; // burst length (in double words) |
// Old controller |
// 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) |
|
/verilog/lfsr/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/ddr2_ctrl.v
0,0 → 1,1239
//***************************************************************************** |
// 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 this when approaching refresh and not in an access |
reg ref_approaching; |
always @(posedge clk) |
ref_approaching <= (refi_cnt_r >= (TREFI_COUNT -80)) & ~af_valid_r2; |
|
reg ref_just_happened; |
always @(posedge clk) |
ref_just_happened <= (refi_cnt_r < 12'h30) & ~af_valid_r2; |
|
|
// assert read flag to the adress FIFO |
assign ctrl_af_rden = (sm_rden || rd_af_flag_r) & !(ref_approaching | ref_just_happened); |
|
// 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 (rd_af_flag_r) // jb - probably should find a way to stop this toggling all the time |
rd_af_flag_r <= 0; // jb |
else if((ctrl_af_rden_r) || |
(/*rd_af_flag_r &&*/ (af_valid_r || af_valid_r1))) // Fixed bug where third addresses would get lost (pulled off fifo and then clobbered by other value later, thus ignored/skipped) - just make sure we don't get too excited and pull too many off at once - jb |
rd_af_flag_r <= 1'd0; |
else if (~af_valid_r1 || ~af_valid_r) |
rd_af_flag_r <= 1'd1; |
|
end // always @ (posedge clk) |
|
|
|
// 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 |
|
/verilog/xilinx_ddr2/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 FALSE - 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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/xilinx_ddr2.v
0,0 → 1,214
/* |
* Wrapper for Xilinx MIG'd DDR2 controller, allowing 3 masters |
* to contol the single interface. |
*/ |
|
module xilinx_ddr2 |
( |
// Inputs |
input [31:0] wbm0_adr_i, |
input [1:0] wbm0_bte_i, |
input [2:0] wbm0_cti_i, |
input wbm0_cyc_i, |
input [31:0] wbm0_dat_i, |
input [3:0] wbm0_sel_i, |
|
input wbm0_stb_i, |
input wbm0_we_i, |
|
// Outputs |
output wbm0_ack_o, |
output wbm0_err_o, |
output wbm0_rty_o, |
output [31:0] wbm0_dat_o, |
|
|
// Inputs |
input [31:0] wbm1_adr_i, |
input [1:0] wbm1_bte_i, |
input [2:0] wbm1_cti_i, |
input wbm1_cyc_i, |
input [31:0] wbm1_dat_i, |
input [3:0] wbm1_sel_i, |
|
input wbm1_stb_i, |
input wbm1_we_i, |
|
// Outputs |
output wbm1_ack_o, |
output wbm1_err_o, |
output wbm1_rty_o, |
output [31:0] wbm1_dat_o, |
|
|
|
// Inputs |
input [31:0] wbm2_adr_i, |
input [1:0] wbm2_bte_i, |
input [2:0] wbm2_cti_i, |
input wbm2_cyc_i, |
input [31:0] wbm2_dat_i, |
input [3:0] wbm2_sel_i, |
|
input wbm2_stb_i, |
input wbm2_we_i, |
|
// Outputs |
output wbm2_ack_o, |
output wbm2_err_o, |
output wbm2_rty_o, |
output [31:0] wbm2_dat_o, |
|
input wb_clk, |
input wb_rst, |
|
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 clk200, |
input ddr2_if_rst |
|
); |
|
// Internal wires to actual RAM |
wire [31:0] wbs_ram_adr_i; |
wire [1:0] wbs_ram_bte_i; |
wire [2:0] wbs_ram_cti_i; |
wire wbs_ram_cyc_i; |
wire [31:0] wbs_ram_dat_i; |
wire [3:0] wbs_ram_sel_i; |
wire wbs_ram_stb_i; |
wire wbs_ram_we_i; |
|
wire wbs_ram_ack_o; |
wire [31:0] wbs_ram_dat_o; |
|
reg [2:0] input_select, last_selected; |
wire arb_for_wbm0, arb_for_wbm1, arb_for_wbm2; |
// Wires allowing selection of new input |
assign arb_for_wbm0 = (last_selected[1] | last_selected[2] | |
!wbm1_cyc_i | !wbm2_cyc_i) & !(|input_select); |
assign arb_for_wbm1 = (last_selected[0] | last_selected[2] | |
!wbm0_cyc_i | !wbm2_cyc_i) & !(|input_select); |
assign arb_for_wbm2 = (last_selected[0] | last_selected[1] | |
!wbm0_cyc_i | !wbm1_cyc_i) & !(|input_select); |
|
// Master select logic |
always @(posedge wb_clk) |
if (wb_rst) |
input_select <= 0; |
else if ((input_select[0] & !wbm0_cyc_i) | (input_select[1] & !wbm1_cyc_i) |
| (input_select[2] & !wbm2_cyc_i)) |
input_select <= 0; |
else if (!(&input_select) & wbm0_cyc_i & arb_for_wbm0) |
input_select <= 3'b001; |
else if (!(&input_select) & wbm1_cyc_i & arb_for_wbm1) |
input_select <= 3'b010; |
else if (!(&input_select) & wbm2_cyc_i & arb_for_wbm2) |
input_select <= 3'b100; |
|
always @(posedge wb_clk) |
if (wb_rst) |
last_selected <= 0; |
else if (!(&input_select) & wbm0_cyc_i & arb_for_wbm0) |
last_selected <= 3'b001; |
else if (!(&input_select) & wbm1_cyc_i & arb_for_wbm1) |
last_selected <= 3'b010; |
else if (!(&input_select) & wbm2_cyc_i & arb_for_wbm2) |
last_selected <= 3'b100; |
|
// Mux input signals to RAM (default to wbm0) |
assign wbs_ram_adr_i = (input_select[2]) ? wbm2_adr_i : |
(input_select[1]) ? wbm1_adr_i : |
(input_select[0]) ? wbm0_adr_i : 0; |
assign wbs_ram_bte_i = (input_select[2]) ? wbm2_bte_i : |
(input_select[1]) ? wbm1_bte_i : |
(input_select[0]) ? wbm0_bte_i : 0; |
assign wbs_ram_cti_i = (input_select[2]) ? wbm2_cti_i : |
(input_select[1]) ? wbm1_cti_i : |
(input_select[0]) ? wbm0_cti_i : 0; |
assign wbs_ram_cyc_i = (input_select[2]) ? wbm2_cyc_i : |
(input_select[1]) ? wbm1_cyc_i : |
(input_select[0]) ? wbm0_cyc_i : 0; |
assign wbs_ram_dat_i = (input_select[2]) ? wbm2_dat_i : |
(input_select[1]) ? wbm1_dat_i : |
(input_select[0]) ? wbm0_dat_i : 0; |
assign wbs_ram_sel_i = (input_select[2]) ? wbm2_sel_i : |
(input_select[1]) ? wbm1_sel_i : |
(input_select[0]) ? wbm0_sel_i : 0; |
assign wbs_ram_stb_i = (input_select[2]) ? wbm2_stb_i : |
(input_select[1]) ? wbm1_stb_i : |
(input_select[0]) ? wbm0_stb_i : 0; |
assign wbs_ram_we_i = (input_select[2]) ? wbm2_we_i : |
(input_select[1]) ? wbm1_we_i : |
(input_select[0]) ? wbm0_we_i : 0; |
|
// Output from RAM, gate the ACK, ERR, RTY signals appropriately |
assign wbm0_dat_o = wbs_ram_dat_o; |
assign wbm0_ack_o = wbs_ram_ack_o & input_select[0]; |
assign wbm0_err_o = 0; |
assign wbm0_rty_o = 0; |
|
assign wbm1_dat_o = wbs_ram_dat_o; |
assign wbm1_ack_o = wbs_ram_ack_o & input_select[1]; |
assign wbm1_err_o = 0; |
assign wbm1_rty_o = 0; |
|
assign wbm2_dat_o = wbs_ram_dat_o; |
assign wbm2_ack_o = wbs_ram_ack_o & input_select[2]; |
assign wbm2_err_o = 0; |
assign wbm2_rty_o = 0; |
|
|
xilinx_ddr2_if xilinx_ddr2_if0 |
( |
|
.wb_dat_o (wbs_ram_dat_o), |
.wb_ack_o (wbs_ram_ack_o), |
.wb_adr_i (wbs_ram_adr_i[31:0]), |
.wb_stb_i (wbs_ram_stb_i), |
.wb_cyc_i (wbs_ram_cyc_i), |
.wb_we_i (wbs_ram_we_i), |
.wb_sel_i (wbs_ram_sel_i[3:0]), |
.wb_dat_i (wbs_ram_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 (ddr2_if_clk), |
.idly_clk_200 (clk200), |
.ddr2_if_rst (ddr2_if_rst), |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
|
|
|
endmodule |
|
/verilog/xilinx_ddr2/xilinx_ddr2_if_cache.v
0,0 → 1,152
/******************************************************************************* |
* 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 xilinx_ddr2_if_cache.v when simulating |
// the core, xilinx_ddr2_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 xilinx_ddr2_if_cache( |
clka, |
ena, |
wea, |
addra, |
dina, |
douta, |
clkb, |
enb, |
web, |
addrb, |
dinb, |
doutb); |
|
|
input clka; |
input ena; |
input [3 : 0] wea; |
input [11 : 0] addra; |
input [31 : 0] dina; |
output [31 : 0] douta; |
input clkb; |
input enb; |
input [15 : 0] web; |
input [9 : 0] addrb; |
input [127 : 0] dinb; |
output [127 : 0] doutb; |
|
// synthesis translate_off |
|
BLK_MEM_GEN_V3_1 #( |
.C_ADDRA_WIDTH(12), |
.C_ADDRB_WIDTH(10), |
.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(4096), |
.C_READ_DEPTH_B(1024), |
.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("ALL"), |
.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(4096), |
.C_WRITE_DEPTH_B(1024), |
.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_if_cache is "black_box" |
|
endmodule |
|
/verilog/xilinx_ddr2/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 |
`ifdef XILINX_DDR2_CHIPSCOPE |
//***************************************************************** |
// 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 |
|
`endif // `ifdef XILINX_DDR2_CHIPSCOPE |
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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/README
0,0 → 1,17
Xilinx DDR2 controller with Wishbone interface |
|
This is a Xilinx technology-dependent DDR2 memory controller, based on a |
controller from Xilinx's memory interface generator (MIG), with a small cache |
memory and Wishbone wrapper. |
|
The xilinx_ddr2_wb_if.v is a 3-master arbiter for the controller. |
The xilinx_ddr2_if.v is the actual interface between the Wishbone bus and |
Xilinx MIG control interface. |
|
When synthesizing, take note of the xilinx_ddr2_if_cache module, that is a |
dual-port memory, with different aspects on each size, and cannot be inferred. |
The NGC should be in the appropriate place in the synthesis or backend |
directories. |
|
Wishbone B3-compliant bursting is yet to be implemented. |
|
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/xilinx_ddr2_if.v
0,0 → 1,488
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Xilinx 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 xilinx_ddr2_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 ddr2_if_rst, |
input idly_clk_200, |
input wb_clk, |
input wb_rst); |
|
`include "xilinx_ddr2_params.v" |
|
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:6] 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 [7:0] do_writeback_ddr2_shifter; |
reg [7: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 [1:0] 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:6]) & 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:6]; |
|
// 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:6],3'd0} : |
{2'd0,cached_addr,3'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]) | |
(do_writeback_ddr2_shifter_r[4]) | |
(do_writeback_ddr2_shifter_r[6]); |
|
// 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[6:0], 1'b0}; |
else if (!(|ddr2_clk_phase) & do_writeback & !ddr2_write_done) // sample WB domain |
do_writeback_ddr2_shifter <= 1; |
|
|
|
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[7]) |
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 + 1; |
|
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 [3:0] wb_cache_adr; |
assign wb_cache_adr = wb_adr_i[5: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 |
xilinx_ddr2_if_cache cache_mem0 |
( |
// Wishbone side |
.clka(wb_clk), |
.ena(wb_cache_en), |
.wea(wb_cache_sel_we), |
.addra({8'd0,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({8'd0,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 (ddr2_if_rst), // Act. high, sync. to ddr2_if_clk |
.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_if |
// Local Variables: |
// verilog-library-directories:("." "ddr2_mig") |
// verilog-library-extensions:(".v" ".h") |
// End: |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/xilinx_ddr2/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 |
/verilog/orpsoc_top/orpsoc_top.v
0,0 → 1,1562
////////////////////////////////////////////////////////////////////// |
/// //// |
/// ORPSoC top for ML501 board //// |
/// //// |
/// Instantiates modules, depending on ORPSoC defines file //// |
/// //// |
/// Julius Baxter, julius@opencores.org //// |
/// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
`include "orpsoc-defines.v" |
`include "synthesis-defines.v" |
module orpsoc_top |
( |
`ifdef JTAG_DEBUG |
tdo_pad_o, tms_pad_i, tck_pad_i, tdi_pad_i, |
`endif |
`ifdef XILINX_DDR2 |
ddr2_a, ddr2_ba, ddr2_ras_n, ddr2_cas_n, ddr2_we_n, |
ddr2_cs_n, ddr2_odt, ddr2_cke, ddr2_dm, |
ddr2_dq, ddr2_dqs, ddr2_dqs_n, ddr2_ck, ddr2_ck_n, |
`endif |
`ifdef XILINX_SSRAM |
sram_clk, sram_clk_fb, sram_flash_addr, sram_flash_data, |
sram_cen, sram_flash_oe_n, sram_flash_we_n, sram_bw, |
sram_adv_ld_n, sram_mode, |
`endif |
`ifdef UART0 |
uart0_srx_pad_i, uart0_stx_pad_o, |
uart0_srx_expheader_pad_i, uart0_stx_expheader_pad_o, |
`endif |
`ifdef SPI0 |
spi0_sck_o, spi0_mosi_o, spi0_miso_i, spi0_ss_o, |
`endif |
`ifdef I2C0 |
i2c0_sda_io, i2c0_scl_io, |
`endif |
`ifdef I2C1 |
i2c1_sda_io, i2c1_scl_io, |
`endif |
`ifdef GPIO0 |
gpio0_io, |
`endif |
|
`ifdef ETH0 |
eth0_tx_clk, eth0_tx_data, eth0_tx_en, eth0_tx_er, |
eth0_rx_clk, eth0_rx_data, eth0_dv, eth0_rx_er, |
eth0_col, eth0_crs, |
eth0_mdc_pad_o, eth0_md_pad_io, |
`ifdef ETH0_PHY_RST |
eth0_rst_n_o, |
`endif |
`endif |
|
sys_clk_in_p,sys_clk_in_n, |
|
rst_n_pad_i |
|
); |
|
`include "orpsoc-params.v" |
|
input sys_clk_in_p,sys_clk_in_n; |
|
input rst_n_pad_i; |
|
`ifdef JTAG_DEBUG |
output tdo_pad_o; |
input tms_pad_i; |
input tck_pad_i; |
input tdi_pad_i; |
`endif |
`ifdef XILINX_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; |
`endif |
`ifdef XILINX_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 UART0 |
input uart0_srx_pad_i; |
output uart0_stx_pad_o; |
// Duplicates of the UART signals, this time to the USB debug cable |
input uart0_srx_expheader_pad_i; |
output uart0_stx_expheader_pad_o; |
`endif |
`ifdef SPI0 |
output spi0_sck_o; |
output spi0_mosi_o; |
output [spi0_ss_width-1:0] spi0_ss_o; |
input spi0_miso_i; |
`endif |
`ifdef I2C0 |
inout i2c0_sda_io, i2c0_scl_io; |
`endif |
`ifdef I2C1 |
inout i2c1_sda_io, i2c1_scl_io; |
`endif |
`ifdef GPIO0 |
inout [gpio0_io_width-1:0] gpio0_io; |
`endif |
`ifdef ETH0 |
input eth0_tx_clk; |
output [3:0] eth0_tx_data; |
output eth0_tx_en; |
output eth0_tx_er; |
input eth0_rx_clk; |
input [3:0] eth0_rx_data; |
input eth0_dv; |
input eth0_rx_er; |
input eth0_col; |
input eth0_crs; |
output eth0_mdc_pad_o; |
inout eth0_md_pad_io; |
`ifdef ETH0_PHY_RST |
output eth0_rst_n_o; |
`endif |
`endif // `ifdef ETH0 |
|
//////////////////////////////////////////////////////////////////////// |
// |
// Clock and reset generation module |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire wb_clk, wb_rst; |
wire ddr2_if_clk, ddr2_if_rst; |
wire clk200; |
wire dbg_tck; |
|
|
clkgen clkgen0 |
( |
.sys_clk_in_p (sys_clk_in_p), |
.sys_clk_in_n (sys_clk_in_n), |
|
.wb_clk_o (wb_clk), |
.wb_rst_o (wb_rst), |
|
`ifdef JTAG_DEBUG |
.tck_pad_i (tck_pad_i), |
.dbg_tck_o (dbg_tck), |
`endif |
`ifdef XILINX_DDR2 |
.ddr2_if_clk_o (ddr2_if_clk), |
.ddr2_if_rst_o (ddr2_if_rst), |
.clk200_o (clk200), |
`endif |
|
// Asynchronous active low reset |
.rst_n_pad_i (rst_n_pad_i) |
); |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// Arbiter |
// |
//////////////////////////////////////////////////////////////////////// |
|
// Wire naming convention: |
// First: wishbone master or slave (wbm/wbs) |
// Second: Which bus it's on instruction or data (i/d) |
// Third: Between which module and the arbiter the wires are |
// Fourth: Signal name |
// Fifth: Direction relative to module (not bus/arbiter!) |
// ie. wbm_d_or12_adr_o is address OUT from the or1200 |
|
// OR1200 instruction bus wires |
wire [wb_aw-1:0] wbm_i_or12_adr_o; |
wire [wb_dw-1:0] wbm_i_or12_dat_o; |
wire [3:0] wbm_i_or12_sel_o; |
wire wbm_i_or12_we_o; |
wire wbm_i_or12_cyc_o; |
wire wbm_i_or12_stb_o; |
wire [2:0] wbm_i_or12_cti_o; |
wire [1:0] wbm_i_or12_bte_o; |
|
wire [wb_dw-1:0] wbm_i_or12_dat_i; |
wire wbm_i_or12_ack_i; |
wire wbm_i_or12_err_i; |
wire wbm_i_or12_rty_i; |
|
// OR1200 data bus wires |
wire [wb_aw-1:0] wbm_d_or12_adr_o; |
wire [wb_dw-1:0] wbm_d_or12_dat_o; |
wire [3:0] wbm_d_or12_sel_o; |
wire wbm_d_or12_we_o; |
wire wbm_d_or12_cyc_o; |
wire wbm_d_or12_stb_o; |
wire [2:0] wbm_d_or12_cti_o; |
wire [1:0] wbm_d_or12_bte_o; |
|
wire [wb_dw-1:0] wbm_d_or12_dat_i; |
wire wbm_d_or12_ack_i; |
wire wbm_d_or12_err_i; |
wire wbm_d_or12_rty_i; |
|
// Debug interface bus wires |
wire [wb_aw-1:0] wbm_d_dbg_adr_o; |
wire [wb_dw-1:0] wbm_d_dbg_dat_o; |
wire [3:0] wbm_d_dbg_sel_o; |
wire wbm_d_dbg_we_o; |
wire wbm_d_dbg_cyc_o; |
wire wbm_d_dbg_stb_o; |
wire [2:0] wbm_d_dbg_cti_o; |
wire [1:0] wbm_d_dbg_bte_o; |
|
wire [wb_dw-1:0] wbm_d_dbg_dat_i; |
wire wbm_d_dbg_ack_i; |
wire wbm_d_dbg_err_i; |
wire wbm_d_dbg_rty_i; |
|
// Byte bus bridge master signals |
wire [wb_aw-1:0] wbm_b_d_adr_o; |
wire [wb_dw-1:0] wbm_b_d_dat_o; |
wire [3:0] wbm_b_d_sel_o; |
wire wbm_b_d_we_o; |
wire wbm_b_d_cyc_o; |
wire wbm_b_d_stb_o; |
wire [2:0] wbm_b_d_cti_o; |
wire [1:0] wbm_b_d_bte_o; |
|
wire [wb_dw-1:0] wbm_b_d_dat_i; |
wire wbm_b_d_ack_i; |
wire wbm_b_d_err_i; |
wire wbm_b_d_rty_i; |
|
// Instruction bus slave wires // |
|
// rom0 instruction bus wires |
wire [31:0] wbs_i_rom0_adr_i; |
wire [wbs_i_rom0_data_width-1:0] wbs_i_rom0_dat_i; |
wire [3:0] wbs_i_rom0_sel_i; |
wire wbs_i_rom0_we_i; |
wire wbs_i_rom0_cyc_i; |
wire wbs_i_rom0_stb_i; |
wire [2:0] wbs_i_rom0_cti_i; |
wire [1:0] wbs_i_rom0_bte_i; |
wire [wbs_i_rom0_data_width-1:0] wbs_i_rom0_dat_o; |
wire wbs_i_rom0_ack_o; |
wire wbs_i_rom0_err_o; |
wire wbs_i_rom0_rty_o; |
|
// mc0 instruction bus wires |
wire [31:0] wbs_i_mc0_adr_i; |
wire [wbs_i_mc0_data_width-1:0] wbs_i_mc0_dat_i; |
wire [3:0] wbs_i_mc0_sel_i; |
wire wbs_i_mc0_we_i; |
wire wbs_i_mc0_cyc_i; |
wire wbs_i_mc0_stb_i; |
wire [2:0] wbs_i_mc0_cti_i; |
wire [1:0] wbs_i_mc0_bte_i; |
wire [wbs_i_mc0_data_width-1:0] wbs_i_mc0_dat_o; |
wire wbs_i_mc0_ack_o; |
wire wbs_i_mc0_err_o; |
wire wbs_i_mc0_rty_o; |
|
// Data bus slave wires // |
|
// mc0 data bus wires |
wire [31:0] wbs_d_mc0_adr_i; |
wire [wbs_d_mc0_data_width-1:0] wbs_d_mc0_dat_i; |
wire [3:0] wbs_d_mc0_sel_i; |
wire wbs_d_mc0_we_i; |
wire wbs_d_mc0_cyc_i; |
wire wbs_d_mc0_stb_i; |
wire [2:0] wbs_d_mc0_cti_i; |
wire [1:0] wbs_d_mc0_bte_i; |
wire [wbs_d_mc0_data_width-1:0] wbs_d_mc0_dat_o; |
wire wbs_d_mc0_ack_o; |
wire wbs_d_mc0_err_o; |
wire wbs_d_mc0_rty_o; |
|
// i2c0 wires |
wire [31:0] wbs_d_i2c0_adr_i; |
wire [wbs_d_i2c0_data_width-1:0] wbs_d_i2c0_dat_i; |
wire [3:0] wbs_d_i2c0_sel_i; |
wire wbs_d_i2c0_we_i; |
wire wbs_d_i2c0_cyc_i; |
wire wbs_d_i2c0_stb_i; |
wire [2:0] wbs_d_i2c0_cti_i; |
wire [1:0] wbs_d_i2c0_bte_i; |
wire [wbs_d_i2c0_data_width-1:0] wbs_d_i2c0_dat_o; |
wire wbs_d_i2c0_ack_o; |
wire wbs_d_i2c0_err_o; |
wire wbs_d_i2c0_rty_o; |
|
// i2c1 wires |
wire [31:0] wbs_d_i2c1_adr_i; |
wire [wbs_d_i2c1_data_width-1:0] wbs_d_i2c1_dat_i; |
wire [3:0] wbs_d_i2c1_sel_i; |
wire wbs_d_i2c1_we_i; |
wire wbs_d_i2c1_cyc_i; |
wire wbs_d_i2c1_stb_i; |
wire [2:0] wbs_d_i2c1_cti_i; |
wire [1:0] wbs_d_i2c1_bte_i; |
wire [wbs_d_i2c1_data_width-1:0] wbs_d_i2c1_dat_o; |
wire wbs_d_i2c1_ack_o; |
wire wbs_d_i2c1_err_o; |
wire wbs_d_i2c1_rty_o; |
|
// spi0 wires |
wire [31:0] wbs_d_spi0_adr_i; |
wire [wbs_d_spi0_data_width-1:0] wbs_d_spi0_dat_i; |
wire [3:0] wbs_d_spi0_sel_i; |
wire wbs_d_spi0_we_i; |
wire wbs_d_spi0_cyc_i; |
wire wbs_d_spi0_stb_i; |
wire [2:0] wbs_d_spi0_cti_i; |
wire [1:0] wbs_d_spi0_bte_i; |
wire [wbs_d_spi0_data_width-1:0] wbs_d_spi0_dat_o; |
wire wbs_d_spi0_ack_o; |
wire wbs_d_spi0_err_o; |
wire wbs_d_spi0_rty_o; |
|
// uart0 wires |
wire [31:0] wbs_d_uart0_adr_i; |
wire [wbs_d_uart0_data_width-1:0] wbs_d_uart0_dat_i; |
wire [3:0] wbs_d_uart0_sel_i; |
wire wbs_d_uart0_we_i; |
wire wbs_d_uart0_cyc_i; |
wire wbs_d_uart0_stb_i; |
wire [2:0] wbs_d_uart0_cti_i; |
wire [1:0] wbs_d_uart0_bte_i; |
wire [wbs_d_uart0_data_width-1:0] wbs_d_uart0_dat_o; |
wire wbs_d_uart0_ack_o; |
wire wbs_d_uart0_err_o; |
wire wbs_d_uart0_rty_o; |
|
// gpio0 wires |
wire [31:0] wbs_d_gpio0_adr_i; |
wire [wbs_d_gpio0_data_width-1:0] wbs_d_gpio0_dat_i; |
wire [3:0] wbs_d_gpio0_sel_i; |
wire wbs_d_gpio0_we_i; |
wire wbs_d_gpio0_cyc_i; |
wire wbs_d_gpio0_stb_i; |
wire [2:0] wbs_d_gpio0_cti_i; |
wire [1:0] wbs_d_gpio0_bte_i; |
wire [wbs_d_gpio0_data_width-1:0] wbs_d_gpio0_dat_o; |
wire wbs_d_gpio0_ack_o; |
wire wbs_d_gpio0_err_o; |
wire wbs_d_gpio0_rty_o; |
|
// eth0 slave wires |
wire [31:0] wbs_d_eth0_adr_i; |
wire [wbs_d_eth0_data_width-1:0] wbs_d_eth0_dat_i; |
wire [3:0] wbs_d_eth0_sel_i; |
wire wbs_d_eth0_we_i; |
wire wbs_d_eth0_cyc_i; |
wire wbs_d_eth0_stb_i; |
wire [2:0] wbs_d_eth0_cti_i; |
wire [1:0] wbs_d_eth0_bte_i; |
wire [wbs_d_eth0_data_width-1:0] wbs_d_eth0_dat_o; |
wire wbs_d_eth0_ack_o; |
wire wbs_d_eth0_err_o; |
wire wbs_d_eth0_rty_o; |
|
// eth0 master wires |
wire [wbm_eth0_addr_width-1:0] wbm_eth0_adr_o; |
wire [wbm_eth0_data_width-1:0] wbm_eth0_dat_o; |
wire [3:0] wbm_eth0_sel_o; |
wire wbm_eth0_we_o; |
wire wbm_eth0_cyc_o; |
wire wbm_eth0_stb_o; |
wire [2:0] wbm_eth0_cti_o; |
wire [1:0] wbm_eth0_bte_o; |
wire [wbm_eth0_data_width-1:0] wbm_eth0_dat_i; |
wire wbm_eth0_ack_i; |
wire wbm_eth0_err_i; |
wire wbm_eth0_rty_i; |
|
|
|
// |
// Wishbone instruction bus arbiter |
// |
|
arbiter_ibus arbiter_ibus0 |
( |
// Instruction Bus Master |
// Inputs to arbiter from master |
.wbm_adr_o (wbm_i_or12_adr_o), |
.wbm_dat_o (wbm_i_or12_dat_o), |
.wbm_sel_o (wbm_i_or12_sel_o), |
.wbm_we_o (wbm_i_or12_we_o), |
.wbm_cyc_o (wbm_i_or12_cyc_o), |
.wbm_stb_o (wbm_i_or12_stb_o), |
.wbm_cti_o (wbm_i_or12_cti_o), |
.wbm_bte_o (wbm_i_or12_bte_o), |
// Outputs to master from arbiter |
.wbm_dat_i (wbm_i_or12_dat_i), |
.wbm_ack_i (wbm_i_or12_ack_i), |
.wbm_err_i (wbm_i_or12_err_i), |
.wbm_rty_i (wbm_i_or12_rty_i), |
|
// Slave 0 |
// Inputs to slave from arbiter |
.wbs0_adr_i (wbs_i_rom0_adr_i), |
.wbs0_dat_i (wbs_i_rom0_dat_i), |
.wbs0_sel_i (wbs_i_rom0_sel_i), |
.wbs0_we_i (wbs_i_rom0_we_i), |
.wbs0_cyc_i (wbs_i_rom0_cyc_i), |
.wbs0_stb_i (wbs_i_rom0_stb_i), |
.wbs0_cti_i (wbs_i_rom0_cti_i), |
.wbs0_bte_i (wbs_i_rom0_bte_i), |
// Outputs from slave to arbiter |
.wbs0_dat_o (wbs_i_rom0_dat_o), |
.wbs0_ack_o (wbs_i_rom0_ack_o), |
.wbs0_err_o (wbs_i_rom0_err_o), |
.wbs0_rty_o (wbs_i_rom0_rty_o), |
|
// Slave 1 |
// Inputs to slave from arbiter |
.wbs1_adr_i (wbs_i_mc0_adr_i), |
.wbs1_dat_i (wbs_i_mc0_dat_i), |
.wbs1_sel_i (wbs_i_mc0_sel_i), |
.wbs1_we_i (wbs_i_mc0_we_i), |
.wbs1_cyc_i (wbs_i_mc0_cyc_i), |
.wbs1_stb_i (wbs_i_mc0_stb_i), |
.wbs1_cti_i (wbs_i_mc0_cti_i), |
.wbs1_bte_i (wbs_i_mc0_bte_i), |
// Outputs from slave to arbiter |
.wbs1_dat_o (wbs_i_mc0_dat_o), |
.wbs1_ack_o (wbs_i_mc0_ack_o), |
.wbs1_err_o (wbs_i_mc0_err_o), |
.wbs1_rty_o (wbs_i_mc0_rty_o), |
|
// Clock, reset inputs |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
defparam arbiter_ibus0.wb_addr_match_width = ibus_arb_addr_match_width; |
|
defparam arbiter_ibus0.slave0_adr = ibus_arb_slave0_adr; // FLASH ROM |
defparam arbiter_ibus0.slave1_adr = ibus_arb_slave1_adr; // Main memory |
|
// |
// Wishbone data bus arbiter |
// |
|
arbiter_dbus arbiter_dbus0 |
( |
// Master 0 |
// Inputs to arbiter from master |
.wbm0_adr_o (wbm_d_or12_adr_o), |
.wbm0_dat_o (wbm_d_or12_dat_o), |
.wbm0_sel_o (wbm_d_or12_sel_o), |
.wbm0_we_o (wbm_d_or12_we_o), |
.wbm0_cyc_o (wbm_d_or12_cyc_o), |
.wbm0_stb_o (wbm_d_or12_stb_o), |
.wbm0_cti_o (wbm_d_or12_cti_o), |
.wbm0_bte_o (wbm_d_or12_bte_o), |
// Outputs to master from arbiter |
.wbm0_dat_i (wbm_d_or12_dat_i), |
.wbm0_ack_i (wbm_d_or12_ack_i), |
.wbm0_err_i (wbm_d_or12_err_i), |
.wbm0_rty_i (wbm_d_or12_rty_i), |
|
// Master 0 |
// Inputs to arbiter from master |
.wbm1_adr_o (wbm_d_dbg_adr_o), |
.wbm1_dat_o (wbm_d_dbg_dat_o), |
.wbm1_we_o (wbm_d_dbg_we_o), |
.wbm1_cyc_o (wbm_d_dbg_cyc_o), |
.wbm1_sel_o (wbm_d_dbg_sel_o), |
.wbm1_stb_o (wbm_d_dbg_stb_o), |
.wbm1_cti_o (wbm_d_dbg_cti_o), |
.wbm1_bte_o (wbm_d_dbg_bte_o), |
// Outputs to master from arbiter |
.wbm1_dat_i (wbm_d_dbg_dat_i), |
.wbm1_ack_i (wbm_d_dbg_ack_i), |
.wbm1_err_i (wbm_d_dbg_err_i), |
.wbm1_rty_i (wbm_d_dbg_rty_i), |
|
// Slaves |
|
.wbs0_adr_i (wbs_d_mc0_adr_i), |
.wbs0_dat_i (wbs_d_mc0_dat_i), |
.wbs0_sel_i (wbs_d_mc0_sel_i), |
.wbs0_we_i (wbs_d_mc0_we_i), |
.wbs0_cyc_i (wbs_d_mc0_cyc_i), |
.wbs0_stb_i (wbs_d_mc0_stb_i), |
.wbs0_cti_i (wbs_d_mc0_cti_i), |
.wbs0_bte_i (wbs_d_mc0_bte_i), |
.wbs0_dat_o (wbs_d_mc0_dat_o), |
.wbs0_ack_o (wbs_d_mc0_ack_o), |
.wbs0_err_o (wbs_d_mc0_err_o), |
.wbs0_rty_o (wbs_d_mc0_rty_o), |
|
.wbs1_adr_i (wbs_d_eth0_adr_i), |
.wbs1_dat_i (wbs_d_eth0_dat_i), |
.wbs1_sel_i (wbs_d_eth0_sel_i), |
.wbs1_we_i (wbs_d_eth0_we_i), |
.wbs1_cyc_i (wbs_d_eth0_cyc_i), |
.wbs1_stb_i (wbs_d_eth0_stb_i), |
.wbs1_cti_i (wbs_d_eth0_cti_i), |
.wbs1_bte_i (wbs_d_eth0_bte_i), |
.wbs1_dat_o (wbs_d_eth0_dat_o), |
.wbs1_ack_o (wbs_d_eth0_ack_o), |
.wbs1_err_o (wbs_d_eth0_err_o), |
.wbs1_rty_o (wbs_d_eth0_rty_o), |
|
.wbs2_adr_i (wbm_b_d_adr_o), |
.wbs2_dat_i (wbm_b_d_dat_o), |
.wbs2_sel_i (wbm_b_d_sel_o), |
.wbs2_we_i (wbm_b_d_we_o), |
.wbs2_cyc_i (wbm_b_d_cyc_o), |
.wbs2_stb_i (wbm_b_d_stb_o), |
.wbs2_cti_i (wbm_b_d_cti_o), |
.wbs2_bte_i (wbm_b_d_bte_o), |
.wbs2_dat_o (wbm_b_d_dat_i), |
.wbs2_ack_o (wbm_b_d_ack_i), |
.wbs2_err_o (wbm_b_d_err_i), |
.wbs2_rty_o (wbm_b_d_rty_i), |
|
// Clock, reset inputs |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
// These settings are from top level params file |
defparam arbiter_dbus0.wb_addr_match_width = dbus_arb_wb_addr_match_width; |
defparam arbiter_dbus0.wb_num_slaves = dbus_arb_wb_num_slaves; |
defparam arbiter_dbus0.slave0_adr = dbus_arb_slave0_adr; |
defparam arbiter_dbus0.slave1_adr = dbus_arb_slave1_adr; |
|
// |
// Wishbone byte-wide bus arbiter |
// |
|
arbiter_bytebus arbiter_bytebus0 |
( |
|
// Master 0 |
// Inputs to arbiter from master |
.wbm0_adr_o (wbm_b_d_adr_o), |
.wbm0_dat_o (wbm_b_d_dat_o), |
.wbm0_sel_o (wbm_b_d_sel_o), |
.wbm0_we_o (wbm_b_d_we_o), |
.wbm0_cyc_o (wbm_b_d_cyc_o), |
.wbm0_stb_o (wbm_b_d_stb_o), |
.wbm0_cti_o (wbm_b_d_cti_o), |
.wbm0_bte_o (wbm_b_d_bte_o), |
// Outputs to master from arbiter |
.wbm0_dat_i (wbm_b_d_dat_i), |
.wbm0_ack_i (wbm_b_d_ack_i), |
.wbm0_err_i (wbm_b_d_err_i), |
.wbm0_rty_i (wbm_b_d_rty_i), |
|
// Byte bus slaves |
|
.wbs0_adr_i (wbs_d_uart0_adr_i), |
.wbs0_dat_i (wbs_d_uart0_dat_i), |
.wbs0_we_i (wbs_d_uart0_we_i), |
.wbs0_cyc_i (wbs_d_uart0_cyc_i), |
.wbs0_stb_i (wbs_d_uart0_stb_i), |
.wbs0_cti_i (wbs_d_uart0_cti_i), |
.wbs0_bte_i (wbs_d_uart0_bte_i), |
.wbs0_dat_o (wbs_d_uart0_dat_o), |
.wbs0_ack_o (wbs_d_uart0_ack_o), |
.wbs0_err_o (wbs_d_uart0_err_o), |
.wbs0_rty_o (wbs_d_uart0_rty_o), |
|
.wbs1_adr_i (wbs_d_gpio0_adr_i), |
.wbs1_dat_i (wbs_d_gpio0_dat_i), |
.wbs1_we_i (wbs_d_gpio0_we_i), |
.wbs1_cyc_i (wbs_d_gpio0_cyc_i), |
.wbs1_stb_i (wbs_d_gpio0_stb_i), |
.wbs1_cti_i (wbs_d_gpio0_cti_i), |
.wbs1_bte_i (wbs_d_gpio0_bte_i), |
.wbs1_dat_o (wbs_d_gpio0_dat_o), |
.wbs1_ack_o (wbs_d_gpio0_ack_o), |
.wbs1_err_o (wbs_d_gpio0_err_o), |
.wbs1_rty_o (wbs_d_gpio0_rty_o), |
|
.wbs2_adr_i (wbs_d_i2c0_adr_i), |
.wbs2_dat_i (wbs_d_i2c0_dat_i), |
.wbs2_we_i (wbs_d_i2c0_we_i), |
.wbs2_cyc_i (wbs_d_i2c0_cyc_i), |
.wbs2_stb_i (wbs_d_i2c0_stb_i), |
.wbs2_cti_i (wbs_d_i2c0_cti_i), |
.wbs2_bte_i (wbs_d_i2c0_bte_i), |
.wbs2_dat_o (wbs_d_i2c0_dat_o), |
.wbs2_ack_o (wbs_d_i2c0_ack_o), |
.wbs2_err_o (wbs_d_i2c0_err_o), |
.wbs2_rty_o (wbs_d_i2c0_rty_o), |
|
.wbs3_adr_i (wbs_d_i2c1_adr_i), |
.wbs3_dat_i (wbs_d_i2c1_dat_i), |
.wbs3_we_i (wbs_d_i2c1_we_i), |
.wbs3_cyc_i (wbs_d_i2c1_cyc_i), |
.wbs3_stb_i (wbs_d_i2c1_stb_i), |
.wbs3_cti_i (wbs_d_i2c1_cti_i), |
.wbs3_bte_i (wbs_d_i2c1_bte_i), |
.wbs3_dat_o (wbs_d_i2c1_dat_o), |
.wbs3_ack_o (wbs_d_i2c1_ack_o), |
.wbs3_err_o (wbs_d_i2c1_err_o), |
.wbs3_rty_o (wbs_d_i2c1_rty_o), |
|
.wbs4_adr_i (wbs_d_spi0_adr_i), |
.wbs4_dat_i (wbs_d_spi0_dat_i), |
.wbs4_we_i (wbs_d_spi0_we_i), |
.wbs4_cyc_i (wbs_d_spi0_cyc_i), |
.wbs4_stb_i (wbs_d_spi0_stb_i), |
.wbs4_cti_i (wbs_d_spi0_cti_i), |
.wbs4_bte_i (wbs_d_spi0_bte_i), |
.wbs4_dat_o (wbs_d_spi0_dat_o), |
.wbs4_ack_o (wbs_d_spi0_ack_o), |
.wbs4_err_o (wbs_d_spi0_err_o), |
.wbs4_rty_o (wbs_d_spi0_rty_o), |
|
// Clock, reset inputs |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
defparam arbiter_bytebus0.wb_addr_match_width = bbus_arb_wb_addr_match_width; |
defparam arbiter_bytebus0.wb_num_slaves = bbus_arb_wb_num_slaves; |
|
defparam arbiter_bytebus0.slave0_adr = bbus_arb_slave0_adr; |
defparam arbiter_bytebus0.slave1_adr = bbus_arb_slave1_adr; |
defparam arbiter_bytebus0.slave2_adr = bbus_arb_slave2_adr; |
defparam arbiter_bytebus0.slave3_adr = bbus_arb_slave3_adr; |
defparam arbiter_bytebus0.slave4_adr = bbus_arb_slave4_adr; |
|
|
`ifdef JTAG_DEBUG |
//////////////////////////////////////////////////////////////////////// |
// |
// JTAG TAP |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire dbg_if_select; |
wire dbg_if_tdo; |
wire jtag_tap_tdo; |
wire jtag_tap_shift_dr, jtag_tap_pause_dr, |
jtag_tap_upate_dr, jtag_tap_capture_dr; |
// |
// Instantiation |
// |
|
jtag_tap jtag_tap0 |
( |
// Ports to pads |
.tdo_pad_o (tdo_pad_o), |
.tms_pad_i (tms_pad_i), |
.tck_pad_i (dbg_tck), |
.trst_pad_i (async_rst), |
.tdi_pad_i (tdi_pad_i), |
|
.tdo_padoe_o (tdo_padoe_o), |
|
.tdo_o (jtag_tap_tdo), |
|
.shift_dr_o (jtag_tap_shift_dr), |
.pause_dr_o (jtag_tap_pause_dr), |
.update_dr_o (jtag_tap_update_dr), |
.capture_dr_o (jtag_tap_capture_dr), |
|
.extest_select_o (), |
.sample_preload_select_o (), |
.mbist_select_o (), |
.debug_select_o (dbg_if_select), |
|
|
.bs_chain_tdi_i (1'b0), |
.mbist_tdi_i (1'b0), |
.debug_tdi_i (dbg_if_tdo) |
|
); |
|
//////////////////////////////////////////////////////////////////////// |
`endif // `ifdef JTAG_DEBUG |
|
//////////////////////////////////////////////////////////////////////// |
// |
// OpenRISC processor |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
|
wire [30:0] or1200_pic_ints; |
|
wire [31:0] or1200_dbg_dat_i; |
wire [31:0] or1200_dbg_adr_i; |
wire or1200_dbg_we_i; |
wire or1200_dbg_stb_i; |
wire or1200_dbg_ack_o; |
wire [31:0] or1200_dbg_dat_o; |
|
wire or1200_dbg_stall_i; |
wire or1200_dbg_ewt_i; |
wire [3:0] or1200_dbg_lss_o; |
wire [1:0] or1200_dbg_is_o; |
wire [10:0] or1200_dbg_wp_o; |
wire or1200_dbg_bp_o; |
wire or1200_dbg_rst; |
|
wire or1200_clk, or1200_rst; |
wire sig_tick; |
|
// |
// Assigns |
// |
assign or1200_clk = wb_clk; |
assign or1200_rst = wb_rst | or1200_dbg_rst; |
|
// |
// Instantiation |
// |
or1200_top or1200_top0 |
( |
// Instruction bus, clocks, reset |
.iwb_clk_i (wb_clk), |
.iwb_rst_i (wb_rst), |
.iwb_ack_i (wbm_i_or12_ack_i), |
.iwb_err_i (wbm_i_or12_err_i), |
.iwb_rty_i (wbm_i_or12_rty_i), |
.iwb_dat_i (wbm_i_or12_dat_i), |
|
.iwb_cyc_o (wbm_i_or12_cyc_o), |
.iwb_adr_o (wbm_i_or12_adr_o), |
.iwb_stb_o (wbm_i_or12_stb_o), |
.iwb_we_o (wbm_i_or12_we_o), |
.iwb_sel_o (wbm_i_or12_sel_o), |
.iwb_dat_o (wbm_i_or12_dat_o), |
.iwb_cti_o (wbm_i_or12_cti_o), |
.iwb_bte_o (wbm_i_or12_bte_o), |
|
// Data bus, clocks, reset |
.dwb_clk_i (wb_clk), |
.dwb_rst_i (wb_rst), |
.dwb_ack_i (wbm_d_or12_ack_i), |
.dwb_err_i (wbm_d_or12_err_i), |
.dwb_rty_i (wbm_d_or12_rty_i), |
.dwb_dat_i (wbm_d_or12_dat_i), |
|
.dwb_cyc_o (wbm_d_or12_cyc_o), |
.dwb_adr_o (wbm_d_or12_adr_o), |
.dwb_stb_o (wbm_d_or12_stb_o), |
.dwb_we_o (wbm_d_or12_we_o), |
.dwb_sel_o (wbm_d_or12_sel_o), |
.dwb_dat_o (wbm_d_or12_dat_o), |
.dwb_cti_o (wbm_d_or12_cti_o), |
.dwb_bte_o (wbm_d_or12_bte_o), |
|
// Debug interface ports |
.dbg_stall_i (or1200_dbg_stall_i), |
//.dbg_ewt_i (or1200_dbg_ewt_i), |
.dbg_ewt_i (1'b0), |
.dbg_lss_o (or1200_dbg_lss_o), |
.dbg_is_o (or1200_dbg_is_o), |
.dbg_wp_o (or1200_dbg_wp_o), |
.dbg_bp_o (or1200_dbg_bp_o), |
|
.dbg_adr_i (or1200_dbg_adr_i), |
.dbg_we_i (or1200_dbg_we_i ), |
.dbg_stb_i (or1200_dbg_stb_i), |
.dbg_dat_i (or1200_dbg_dat_i), |
.dbg_dat_o (or1200_dbg_dat_o), |
.dbg_ack_o (or1200_dbg_ack_o), |
|
.pm_clksd_o (), |
.pm_dc_gate_o (), |
.pm_ic_gate_o (), |
.pm_dmmu_gate_o (), |
.pm_immu_gate_o (), |
.pm_tt_gate_o (), |
.pm_cpu_gate_o (), |
.pm_wakeup_o (), |
.pm_lvolt_o (), |
|
// Core clocks, resets |
.clk_i (or1200_clk), |
.rst_i (or1200_rst), |
|
.clmode_i (2'b00), |
// Interrupts |
.pic_ints_i (or1200_pic_ints), |
.sig_tick(sig_tick), |
/* |
.mbist_so_o (), |
.mbist_si_i (0), |
.mbist_ctrl_i (0), |
*/ |
|
.pm_cpustall_i (1'b0) |
|
); |
|
//////////////////////////////////////////////////////////////////////// |
|
|
`ifdef JTAG_DEBUG |
//////////////////////////////////////////////////////////////////////// |
// |
// OR1200 Debug Interface |
// |
//////////////////////////////////////////////////////////////////////// |
|
dbg_if dbg_if0 |
( |
// OR1200 interface |
.cpu0_clk_i (or1200_clk), |
.cpu0_rst_o (or1200_dbg_rst), |
.cpu0_addr_o (or1200_dbg_adr_i), |
.cpu0_data_o (or1200_dbg_dat_i), |
.cpu0_stb_o (or1200_dbg_stb_i), |
.cpu0_we_o (or1200_dbg_we_i), |
.cpu0_data_i (or1200_dbg_dat_o), |
.cpu0_ack_i (or1200_dbg_ack_o), |
|
|
.cpu0_stall_o (or1200_dbg_stall_i), |
.cpu0_bp_i (or1200_dbg_bp_o), |
|
// TAP interface |
.tck_i (dbg_tck), |
.tdi_i (jtag_tap_tdo), |
.tdo_o (dbg_if_tdo), |
.rst_i (wb_rst), |
.shift_dr_i (jtag_tap_shift_dr), |
.pause_dr_i (jtag_tap_pause_dr), |
.update_dr_i (jtag_tap_update_dr), |
.debug_select_i (dbg_if_select), |
|
// Wishbone debug master |
.wb_clk_i (wb_clk), |
.wb_dat_i (wbm_d_dbg_dat_i), |
.wb_ack_i (wbm_d_dbg_ack_i), |
.wb_err_i (wbm_d_dbg_err_i), |
.wb_adr_o (wbm_d_dbg_adr_o), |
.wb_dat_o (wbm_d_dbg_dat_o), |
.wb_cyc_o (wbm_d_dbg_cyc_o), |
.wb_stb_o (wbm_d_dbg_stb_o), |
.wb_sel_o (wbm_d_dbg_sel_o), |
.wb_we_o (wbm_d_dbg_we_o ), |
.wb_cti_o (wbm_d_dbg_cti_o), |
.wb_cab_o (/* UNUSED */), |
.wb_bte_o (wbm_d_dbg_bte_o) |
); |
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef JTAG_DEBUG |
|
assign wbm_d_dbg_adr_o = 0; |
assign wbm_d_dbg_dat_o = 0; |
assign wbm_d_dbg_cyc_o = 0; |
assign wbm_d_dbg_stb_o = 0; |
assign wbm_d_dbg_sel_o = 0; |
assign wbm_d_dbg_we_o = 0; |
assign wbm_d_dbg_cti_o = 0; |
assign wbm_d_dbg_bte_o = 0; |
|
assign or1200_dbg_adr_i = 0; |
assign or1200_dbg_dat_i = 0; |
assign or1200_dbg_stb_i = 0; |
assign or1200_dbg_we_i = 0; |
assign or1200_dbg_stall_i = 0; |
|
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef JTAG_DEBUG |
|
`ifdef XILINX_DDR2 |
//////////////////////////////////////////////////////////////////////// |
// |
// Xilinx MIG DDR2 controller, Wishbone interface |
// |
//////////////////////////////////////////////////////////////////////// |
xilinx_ddr2 xilinx_ddr2_0 |
( |
.wbm0_adr_i (wbm_eth0_adr_o), |
.wbm0_bte_i (wbm_eth0_bte_o), |
.wbm0_cti_i (wbm_eth0_cti_o), |
.wbm0_cyc_i (wbm_eth0_cyc_o), |
.wbm0_dat_i (wbm_eth0_dat_o), |
.wbm0_sel_i (wbm_eth0_sel_o), |
.wbm0_stb_i (wbm_eth0_stb_o), |
.wbm0_we_i (wbm_eth0_we_o), |
.wbm0_ack_o (wbm_eth0_ack_i), |
.wbm0_err_o (wbm_eth0_err_i), |
.wbm0_rty_o (wbm_eth0_rty_i), |
.wbm0_dat_o (wbm_eth0_dat_i), |
|
.wbm1_adr_i (wbs_d_mc0_adr_i), |
.wbm1_bte_i (wbs_d_mc0_bte_i), |
.wbm1_cti_i (wbs_d_mc0_cti_i), |
.wbm1_cyc_i (wbs_d_mc0_cyc_i), |
.wbm1_dat_i (wbs_d_mc0_dat_i), |
.wbm1_sel_i (wbs_d_mc0_sel_i), |
.wbm1_stb_i (wbs_d_mc0_stb_i), |
.wbm1_we_i (wbs_d_mc0_we_i), |
.wbm1_ack_o (wbs_d_mc0_ack_o), |
.wbm1_err_o (wbs_d_mc0_err_o), |
.wbm1_rty_o (wbs_d_mc0_rty_o), |
.wbm1_dat_o (wbs_d_mc0_dat_o), |
|
.wbm2_adr_i (wbs_i_mc0_adr_i), |
.wbm2_bte_i (wbs_i_mc0_bte_i), |
.wbm2_cti_i (wbs_i_mc0_cti_i), |
.wbm2_cyc_i (wbs_i_mc0_cyc_i), |
.wbm2_dat_i (wbs_i_mc0_dat_i), |
.wbm2_sel_i (wbs_i_mc0_sel_i), |
.wbm2_stb_i (wbs_i_mc0_stb_i), |
.wbm2_we_i (wbs_i_mc0_we_i), |
.wbm2_ack_o (wbs_i_mc0_ack_o), |
.wbm2_err_o (wbs_i_mc0_err_o), |
.wbm2_rty_o (wbs_i_mc0_rty_o), |
.wbm2_dat_o (wbs_i_mc0_dat_o), |
|
.wb_clk (wb_clk), |
.wb_rst (wb_rst), |
|
.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 (ddr2_if_clk), |
.clk200 (clk200), |
.ddr2_if_rst (ddr2_if_rst) |
); |
|
`endif |
|
|
//////////////////////////////////////////////////////////////////////// |
// |
// ROM |
// |
//////////////////////////////////////////////////////////////////////// |
|
rom rom0 |
( |
.wb_dat_o (wbs_i_rom0_dat_o), |
.wb_ack_o (wbs_i_rom0_ack_o), |
.wb_adr_i (wbs_i_rom0_adr_i[(wbs_i_rom0_addr_width+2)-1:2]), |
.wb_stb_i (wbs_i_rom0_stb_i), |
.wb_cyc_i (wbs_i_rom0_cyc_i), |
.wb_cti_i (wbs_i_rom0_cti_i), |
.wb_bte_i (wbs_i_rom0_bte_i), |
.wb_clk (wb_clk), |
.wb_rst (wb_rst)); |
|
defparam rom0.addr_width = wbs_i_rom0_addr_width; |
|
assign wbs_i_rom0_err_o = 0; |
assign wbs_i_rom0_rty_o = 0; |
|
//////////////////////////////////////////////////////////////////////// |
|
`ifdef RAM_WB |
//////////////////////////////////////////////////////////////////////// |
// |
// Generic RAM |
// |
//////////////////////////////////////////////////////////////////////// |
|
ram_wb ram_wb0 |
( |
// Wishbone slave interface 0 |
.wbm0_dat_i (wbs_i_mc0_dat_i), |
.wbm0_adr_i (wbs_i_mc0_adr_i), |
.wbm0_sel_i (wbs_i_mc0_sel_i), |
.wbm0_cti_i (wbs_i_mc0_cti_i), |
.wbm0_bte_i (wbs_i_mc0_bte_i), |
.wbm0_we_i (wbs_i_mc0_we_i ), |
.wbm0_cyc_i (wbs_i_mc0_cyc_i), |
.wbm0_stb_i (wbs_i_mc0_stb_i), |
.wbm0_dat_o (wbs_i_mc0_dat_o), |
.wbm0_ack_o (wbs_i_mc0_ack_o), |
.wbm0_err_o (), |
.wbm0_rty_o (), |
// Wishbone slave interface 1 |
.wbm1_dat_i (wbs_d_mc0_dat_i), |
.wbm1_adr_i (wbs_d_mc0_adr_i), |
.wbm1_sel_i (wbs_d_mc0_sel_i), |
.wbm1_cti_i (wbs_d_mc0_cti_i), |
.wbm1_bte_i (wbs_d_mc0_bte_i), |
.wbm1_we_i (wbs_d_mc0_we_i ), |
.wbm1_cyc_i (wbs_d_mc0_cyc_i), |
.wbm1_stb_i (wbs_d_mc0_stb_i), |
.wbm1_dat_o (wbs_d_mc0_dat_o), |
.wbm1_ack_o (wbs_d_mc0_ack_o), |
.wbm1_err_o (), |
.wbm1_rty_o (), |
// Clock, reset |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst)); |
|
assign wbs_i_mc0_err_o = 0; |
assign wbs_i_mc0_rty_o = 0; |
|
assign wbs_d_mc0_err_o = 0; |
assign wbs_d_mc0_rty_o = 0; |
|
defparam ram_wb0.aw = wb_aw; |
defparam ram_wb0.dw = wb_dw; |
defparam ram_wb0.mem_span = internal_sram_mem_span; |
defparam ram_wb0.adr_width_for_span = internal_sram_adr_width_for_span; |
//////////////////////////////////////////////////////////////////////// |
`endif // `ifdef RAM_WB |
|
|
`ifdef ETH0 |
|
// |
// Wires |
// |
wire eth0_irq; |
wire [3:0] eth0_mtxd; |
wire eth0_mtxen; |
wire eth0_mtxerr; |
wire eth0_mtx_clk; |
wire eth0_mrx_clk; |
wire [3:0] eth0_mrxd; |
wire eth0_mrxdv; |
wire eth0_mrxerr; |
wire eth0_mcoll; |
wire eth0_mcrs; |
wire eth0_speed; |
wire eth0_duplex; |
wire eth0_link; |
// Management interface wires |
wire eth0_md_i; |
wire eth0_md_o; |
wire eth0_md_oe; |
|
|
// |
// assigns |
|
// Hook up MII wires |
assign eth0_mtx_clk = eth0_tx_clk; |
assign eth0_tx_data = eth0_mtxd[3:0]; |
assign eth0_tx_en = eth0_mtxen; |
assign eth0_tx_er = eth0_mtxerr; |
assign eth0_mrxd[3:0] = eth0_rx_data; |
assign eth0_mrxdv = eth0_dv; |
assign eth0_mrxerr = eth0_rx_er; |
assign eth0_mrx_clk = eth0_rx_clk; |
assign eth0_mcoll = eth0_col; |
assign eth0_mcrs = eth0_crs; |
|
`ifdef XILINX |
// Xilinx primitive for MDIO tristate |
IOBUF iobuf_phy_smi_data |
( |
// Outputs |
.O (eth0_md_i), |
// Inouts |
.IO (eth0_md_pad_io), |
// Inputs |
.I (eth0_md_o), |
.T (!eth0_md_oe)); |
`else // !`ifdef XILINX |
|
// Generic technology tristate control for management interface |
assign eth0_md_pad_io = eth0_md_oe ? eth0_md_o : 1'bz; |
assign eth0_md_i = eth0_md_pad_io; |
|
`endif // !`ifdef XILINX |
|
`ifdef ETH0_PHY_RST |
assign eth0_rst_n_o = !wb_rst; |
`endif |
|
ethmac ethmac0 |
( |
// Wishbone Slave interface |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst), |
.wb_dat_i (wbs_d_eth0_dat_i[31:0]), |
.wb_adr_i (wbs_d_eth0_adr_i[wbs_d_eth0_addr_width-1:2]), |
.wb_sel_i (wbs_d_eth0_sel_i[3:0]), |
.wb_we_i (wbs_d_eth0_we_i), |
.wb_cyc_i (wbs_d_eth0_cyc_i), |
.wb_stb_i (wbs_d_eth0_stb_i), |
.wb_dat_o (wbs_d_eth0_dat_o[31:0]), |
.wb_err_o (wbs_d_eth0_err_o), |
.wb_ack_o (wbs_d_eth0_ack_o), |
// Wishbone Master Interface |
.m_wb_adr_o (wbm_eth0_adr_o[31:0]), |
.m_wb_sel_o (wbm_eth0_sel_o[3:0]), |
.m_wb_we_o (wbm_eth0_we_o), |
.m_wb_dat_o (wbm_eth0_dat_o[31:0]), |
.m_wb_cyc_o (wbm_eth0_cyc_o), |
.m_wb_stb_o (wbm_eth0_stb_o), |
.m_wb_cti_o (wbm_eth0_cti_o[2:0]), |
.m_wb_bte_o (wbm_eth0_bte_o[1:0]), |
.m_wb_dat_i (wbm_eth0_dat_i[31:0]), |
.m_wb_ack_i (wbm_eth0_ack_i), |
.m_wb_err_i (wbm_eth0_err_i), |
|
// Ethernet MII interface |
// Transmit |
.mtxd_pad_o (eth0_mtxd[3:0]), |
.mtxen_pad_o (eth0_mtxen), |
.mtxerr_pad_o (eth0_mtxerr), |
.mtx_clk_pad_i (eth0_mtx_clk), |
// Receive |
.mrx_clk_pad_i (eth0_mrx_clk), |
.mrxd_pad_i (eth0_mrxd[3:0]), |
.mrxdv_pad_i (eth0_mrxdv), |
.mrxerr_pad_i (eth0_mrxerr), |
.mcoll_pad_i (eth0_mcoll), |
.mcrs_pad_i (eth0_mcrs), |
// Management interface |
.md_pad_i (eth0_md_i), |
.mdc_pad_o (eth0_mdc_pad_o), |
.md_pad_o (eth0_md_o), |
.md_padoe_o (eth0_md_oe), |
|
// Processor interrupt |
.int_o (eth0_irq) |
|
/* |
.mbist_so_o (), |
.mbist_si_i (), |
.mbist_ctrl_i () |
*/ |
|
); |
|
assign wbs_d_eth0_rty_o = 0; |
|
`else |
assign wbs_d_eth0_dat_o = 0; |
assign wbs_d_eth0_err_o = 0; |
assign wbs_d_eth0_ack_o = 0; |
assign wbs_d_eth0_rty_o = 0; |
assign wbm_eth0_adr_o = 0; |
assign wbm_eth0_sel_o = 0; |
assign wbm_eth0_we_o = 0; |
assign wbm_eth0_dat_o = 0; |
assign wbm_eth0_cyc_o = 0; |
assign wbm_eth0_stb_o = 0; |
assign wbm_eth0_cti_o = 0; |
assign wbm_eth0_bte_o = 0; |
`endif |
|
`ifdef UART0 |
//////////////////////////////////////////////////////////////////////// |
// |
// UART0 |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire uart0_srx; |
wire uart0_stx; |
|
wire uart0_irq; |
|
// |
// Assigns |
// |
assign wbs_d_uart0_err_o = 0; |
assign wbs_d_uart0_rty_o = 0; |
|
// Two UART lines coming to single one (ensure they go high when unconnected) |
assign uart_srx = uart0_srx_pad_i & uart0_srx_expheader_pad_i; |
assign uart0_stx_pad_o = uart0_stx; |
assign uart0_stx_expheader_pad_o = uart0_stx; |
|
|
uart16550 uart16550_0 |
( |
// Wishbone slave interface |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst), |
.wb_adr_i (wbs_d_uart0_adr_i[uart0_addr_width-1:0]), |
.wb_dat_i (wbs_d_uart0_dat_i), |
.wb_we_i (wbs_d_uart0_we_i), |
.wb_stb_i (wbs_d_uart0_stb_i), |
.wb_cyc_i (wbs_d_uart0_cyc_i), |
//.wb_sel_i (), |
.wb_dat_o (wbs_d_uart0_dat_o), |
.wb_ack_o (wbs_d_uart0_ack_o), |
|
.int_o (uart0_irq), |
.stx_pad_o (uart0_stx), |
.rts_pad_o (), |
.dtr_pad_o (), |
// .baud_o (), |
// Inputs |
.srx_pad_i (uart0_srx), |
.cts_pad_i (1'b0), |
.dsr_pad_i (1'b0), |
.ri_pad_i (1'b0), |
.dcd_pad_i (1'b0)); |
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef UART0 |
|
// |
// Assigns |
// |
assign wbs_d_uart0_err_o = 0; |
assign wbs_d_uart0_rty_o = 0; |
assign wbs_d_uart0_ack_o = 0; |
assign wbs_d_uart0_dat_o = 0; |
|
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef UART0 |
|
`ifdef SPI0 |
//////////////////////////////////////////////////////////////////////// |
// |
// SPI0 controller |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire spi0_irq; |
|
// |
// Assigns |
// |
assign wbs_d_spi0_err_o = 0; |
assign wbs_d_spi0_rty_o = 0; |
//assign spi0_hold_n_o = 1; |
//assign spi0_w_n_o = 1; |
|
|
simple_spi spi0 |
( |
// Wishbone slave interface |
.clk_i (wb_clk), |
.rst_i (wb_rst), |
.cyc_i (wbs_d_spi0_cyc_i), |
.stb_i (wbs_d_spi0_stb_i), |
.adr_i (wbs_d_spi0_adr_i[spi0_wb_adr_width-1:0]), |
.we_i (wbs_d_spi0_we_i), |
.dat_i (wbs_d_spi0_dat_i), |
.dat_o (wbs_d_spi0_dat_o), |
.ack_o (wbs_d_spi0_ack_o), |
// SPI IRQ |
.inta_o (spi0_irq), |
// External SPI interface |
.sck_o (spi0_sck_o), |
.ss_o (spi0_ss_o), |
.mosi_o (spi0_mosi_o), |
.miso_i (spi0_miso_i) |
); |
|
defparam spi0.slave_select_width = spi0_ss_width; |
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef SPI0 |
|
// |
// Assigns |
// |
assign wbs_d_spi0_dat_o = 0; |
assign wbs_d_spi0_ack_o = 0; |
assign wbs_d_spi0_err_o = 0; |
assign wbs_d_spi0_rty_o = 0; |
|
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef SPI0 |
|
|
`ifdef I2C0 |
//////////////////////////////////////////////////////////////////////// |
// |
// i2c controller 0 |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire i2c0_irq; |
wire scl0_pad_o; |
wire scl0_padoen_o; |
wire sda0_pad_o; |
wire sda0_padoen_o; |
|
i2c_master_slave |
# |
( |
.DEFAULT_SLAVE_ADDR(HV0_SADR) |
) |
i2c_master_slave0 |
( |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst), |
.arst_i (wb_rst), |
.wb_adr_i (wbs_d_i2c0_adr_i[i2c_0_wb_adr_width-1:0]), |
.wb_dat_i (wbs_d_i2c0_dat_i), |
.wb_we_i (wbs_d_i2c0_we_i ), |
.wb_cyc_i (wbs_d_i2c0_cyc_i), |
.wb_stb_i (wbs_d_i2c0_stb_i), |
.wb_dat_o (wbs_d_i2c0_dat_o), |
.wb_ack_o (wbs_d_i2c0_ack_o), |
.scl_pad_i (i2c0_scl_io ), |
.scl_pad_o (scl0_pad_o ), |
.scl_padoen_o (scl0_padoen_o ), |
.sda_pad_i (i2c0_sda_io ), |
.sda_pad_o (sda0_pad_o ), |
.sda_padoen_o (sda0_padoen_o ), |
|
// Interrupt |
.wb_inta_o (i2c0_irq) |
|
); |
|
assign wbs_d_i2c0_err_o = 0; |
assign wbs_d_i2c0_rty_o = 0; |
|
// i2c phy lines |
assign i2c0_scl_io = scl0_padoen_o ? 1'bz : scl0_pad_o; |
assign i2c0_sda_io = sda0_padoen_o ? 1'bz : sda0_pad_o; |
|
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef I2C0 |
|
assign wbs_d_i2c0_dat_o = 0; |
assign wbs_d_i2c0_ack_o = 0; |
assign wbs_d_i2c0_err_o = 0; |
assign wbs_d_i2c0_rty_o = 0; |
|
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef I2C0 |
|
`ifdef I2C1 |
//////////////////////////////////////////////////////////////////////// |
// |
// i2c controller 1 |
// |
//////////////////////////////////////////////////////////////////////// |
|
// |
// Wires |
// |
wire i2c1_irq; |
wire scl1_pad_o; |
wire scl1_padoen_o; |
wire sda1_pad_o; |
wire sda1_padoen_o; |
|
i2c_master_slave |
# |
( |
.DEFAULT_SLAVE_ADDR(HV1_SADR) |
) |
i2c_master_slave1 |
( |
.wb_clk_i (wb_clk), |
.wb_rst_i (wb_rst), |
.arst_i (wb_rst), |
.wb_adr_i (wbs_d_i2c1_adr_i[i2c_1_wb_adr_width-1:0]), |
.wb_dat_i (wbs_d_i2c1_dat_i), |
.wb_we_i (wbs_d_i2c1_we_i ), |
.wb_cyc_i (wbs_d_i2c1_cyc_i), |
.wb_stb_i (wbs_d_i2c1_stb_i), |
.wb_dat_o (wbs_d_i2c1_dat_o), |
.wb_ack_o (wbs_d_i2c1_ack_o), |
.scl_pad_i (i2c1_scl_io ), |
.scl_pad_o (scl1_pad_o ), |
.scl_padoen_o (scl1_padoen_o ), |
.sda_pad_i (i2c1_sda_io ), |
.sda_pad_o (sda1_pad_o ), |
.sda_padoen_o (sda1_padoen_o ), |
|
// Interrupt |
.wb_inta_o (i2c1_irq) |
|
); |
|
assign wbs_d_i2c1_err_o = 0; |
assign wbs_d_i2c1_rty_o = 0; |
|
// i2c phy lines |
assign i2c1_scl_io = scl1_padoen_o ? 1'bz : scl1_pad_o; |
assign i2c1_sda_io = sda1_padoen_o ? 1'bz : sda1_pad_o; |
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef I2C1 |
|
assign wbs_d_i2c1_dat_o = 0; |
assign wbs_d_i2c1_ack_o = 0; |
assign wbs_d_i2c1_err_o = 0; |
assign wbs_d_i2c1_rty_o = 0; |
|
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef I2C1 |
|
`ifdef GPIO0 |
//////////////////////////////////////////////////////////////////////// |
// |
// GPIO 0 |
// |
//////////////////////////////////////////////////////////////////////// |
|
gpio gpio0 |
( |
// GPIO bus |
.gpio_io (gpio0_io[gpio0_io_width-1:0]), |
// Wishbone slave interface |
.wb_adr_i (wbs_d_gpio0_adr_i[gpio0_wb_adr_width-1:0]), |
.wb_dat_i (wbs_d_gpio0_dat_i), |
.wb_we_i (wbs_d_gpio0_we_i), |
.wb_cyc_i (wbs_d_gpio0_cyc_i), |
.wb_stb_i (wbs_d_gpio0_stb_i), |
.wb_cti_i (wbs_d_gpio0_cti_i), |
.wb_bte_i (wbs_d_gpio0_bte_i), |
.wb_dat_o (wbs_d_gpio0_dat_o), |
.wb_ack_o (wbs_d_gpio0_ack_o), |
.wb_err_o (wbs_d_gpio0_err_o), |
.wb_rty_o (wbs_d_gpio0_rty_o), |
|
.wb_clk (wb_clk), |
.wb_rst (wb_rst) |
); |
|
defparam gpio0.gpio_io_width = gpio0_io_width; |
defparam gpio0.gpio_dir_reset_val = gpio0_dir_reset_val; |
defparam gpio0.gpio_o_reset_val = gpio0_o_reset_val; |
|
//////////////////////////////////////////////////////////////////////// |
`else // !`ifdef GPIO0 |
assign wbs_d_gpio0_dat_o = 0; |
assign wbs_d_gpio0_ack_o = 0; |
assign wbs_d_gpio0_err_o = 0; |
assign wbs_d_gpio0_rty_o = 0; |
//////////////////////////////////////////////////////////////////////// |
`endif // !`ifdef GPIO0 |
|
//////////////////////////////////////////////////////////////////////// |
// |
// OR1200 Interrupt assignment |
// |
//////////////////////////////////////////////////////////////////////// |
|
assign or1200_pic_ints[0] = 0; // Non-maskable inside OR1200 |
assign or1200_pic_ints[1] = 0; // Non-maskable inside OR1200 |
`ifdef UART0 |
assign or1200_pic_ints[2] = uart0_irq; |
`else |
assign or1200_pic_ints[2] = 0; |
`endif |
assign or1200_pic_ints[3] = 0; |
`ifdef ETH0 |
assign or1200_pic_ints[4] = eth0_irq; |
`else |
assign or1200_pic_ints[4] = 0; |
`endif |
assign or1200_pic_ints[5] = 0; |
`ifdef SPI0 |
assign or1200_pic_ints[6] = spi0_irq; |
`else |
assign or1200_pic_ints[6] = 0; |
`endif |
assign or1200_pic_ints[7] = 0; |
assign or1200_pic_ints[8] = 0; |
assign or1200_pic_ints[9] = 0; |
`ifdef I2C0 |
assign or1200_pic_ints[10] = i2c0_irq; |
`else |
assign or1200_pic_ints[10] = 0; |
`endif |
`ifdef I2C1 |
assign or1200_pic_ints[11] = i2c1_irq; |
`else |
assign or1200_pic_ints[11] = 0; |
`endif |
assign or1200_pic_ints[12] = 0; |
assign or1200_pic_ints[13] = 0; |
assign or1200_pic_ints[14] = 0; |
assign or1200_pic_ints[15] = 0; |
assign or1200_pic_ints[16] = 0; |
assign or1200_pic_ints[17] = 0; |
assign or1200_pic_ints[18] = 0; |
assign or1200_pic_ints[19] = 0; |
assign or1200_pic_ints[20] = 0; |
assign or1200_pic_ints[21] = 0; |
assign or1200_pic_ints[22] = 0; |
assign or1200_pic_ints[23] = 0; |
assign or1200_pic_ints[24] = 0; |
assign or1200_pic_ints[25] = 0; |
assign or1200_pic_ints[26] = 0; |
assign or1200_pic_ints[27] = 0; |
assign or1200_pic_ints[28] = 0; |
assign or1200_pic_ints[29] = 0; |
assign or1200_pic_ints[30] = 0; |
|
endmodule // orpsoc_top |
|
|
/verilog/arbiter/arbiter_bytebus.v
0,0 → 1,1192
////////////////////////////////////////////////////////////////////// |
/// //// |
/// Wishbone arbiter, byte-wide data path, no bursting //// |
/// //// |
/// Simple arbiter, single master, multiple slave, for byte-wide //// |
/// peripherals //// |
/// //// |
/// Julius Baxter, julius@opencores.org //// |
/// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
// |
// Things to update when changing slave config: |
// |
// 1. Port list |
// 2. Port specification |
// 3. Slave addr select parameter |
// 4. Slave addr selects |
// 5. Slave input mux logic |
// 6. The four different master out mux logics (dat_o mux, and ack, rty & err) |
// |
`include "orpsoc-defines.v" |
module arbiter_bytebus |
( |
|
// Master in |
wbm0_adr_o, |
wbm0_dat_o, |
wbm0_sel_o, |
wbm0_we_o, |
wbm0_cyc_o, |
wbm0_stb_o, |
wbm0_cti_o, |
wbm0_bte_o, |
wbm0_dat_i, |
wbm0_ack_i, |
wbm0_err_i, |
wbm0_rty_i, |
|
// Slave one |
// Wishbone Slave interface |
wbs0_adr_i, |
wbs0_dat_i, |
wbs0_we_i, |
wbs0_cyc_i, |
wbs0_stb_i, |
wbs0_cti_i, |
wbs0_bte_i, |
wbs0_dat_o, |
wbs0_ack_o, |
wbs0_err_o, |
wbs0_rty_o, |
|
// Slave two |
// Wishbone Slave interface |
wbs1_adr_i, |
wbs1_dat_i, |
wbs1_we_i, |
wbs1_cyc_i, |
wbs1_stb_i, |
wbs1_cti_i, |
wbs1_bte_i, |
wbs1_dat_o, |
wbs1_ack_o, |
wbs1_err_o, |
wbs1_rty_o, |
|
// Slave three |
// Wishbone Slave interface |
wbs2_adr_i, |
wbs2_dat_i, |
wbs2_we_i, |
wbs2_cyc_i, |
wbs2_stb_i, |
wbs2_cti_i, |
wbs2_bte_i, |
wbs2_dat_o, |
wbs2_ack_o, |
wbs2_err_o, |
wbs2_rty_o, |
|
// Slave four |
// Wishbone Slave interface |
wbs3_adr_i, |
wbs3_dat_i, |
wbs3_we_i, |
wbs3_cyc_i, |
wbs3_stb_i, |
wbs3_cti_i, |
wbs3_bte_i, |
wbs3_dat_o, |
wbs3_ack_o, |
wbs3_err_o, |
wbs3_rty_o, |
|
// Slave five |
// Wishbone Slave interface |
wbs4_adr_i, |
wbs4_dat_i, |
wbs4_we_i, |
wbs4_cyc_i, |
wbs4_stb_i, |
wbs4_cti_i, |
wbs4_bte_i, |
wbs4_dat_o, |
wbs4_ack_o, |
wbs4_err_o, |
wbs4_rty_o, |
/* |
// Slave six |
// Wishbone Slave interface |
wbs5_adr_i, |
wbs5_dat_i, |
wbs5_we_i, |
wbs5_cyc_i, |
wbs5_stb_i, |
wbs5_cti_i, |
wbs5_bte_i, |
wbs5_dat_o, |
wbs5_ack_o, |
wbs5_err_o, |
wbs5_rty_o, |
|
// Slave seven |
// Wishbone Slave interface |
wbs6_adr_i, |
wbs6_dat_i, |
wbs6_we_i, |
wbs6_cyc_i, |
wbs6_stb_i, |
wbs6_cti_i, |
wbs6_bte_i, |
wbs6_dat_o, |
wbs6_ack_o, |
wbs6_err_o, |
wbs6_rty_o, |
|
// Slave eight |
// Wishbone Slave interface |
wbs7_adr_i, |
wbs7_dat_i, |
wbs7_we_i, |
wbs7_cyc_i, |
wbs7_stb_i, |
wbs7_cti_i, |
wbs7_bte_i, |
wbs7_dat_o, |
wbs7_ack_o, |
wbs7_err_o, |
wbs7_rty_o, |
|
// Slave nine |
// Wishbone Slave interface |
wbs8_adr_i, |
wbs8_dat_i, |
wbs8_we_i, |
wbs8_cyc_i, |
wbs8_stb_i, |
wbs8_cti_i, |
wbs8_bte_i, |
wbs8_dat_o, |
wbs8_ack_o, |
wbs8_err_o, |
wbs8_rty_o, |
|
// Slave ten |
// Wishbone Slave interface |
wbs9_adr_i, |
wbs9_dat_i, |
wbs9_we_i, |
wbs9_cyc_i, |
wbs9_stb_i, |
wbs9_cti_i, |
wbs9_bte_i, |
wbs9_dat_o, |
wbs9_ack_o, |
wbs9_err_o, |
wbs9_rty_o, |
|
// Slave eleven |
// Wishbone Slave interface |
wbs10_adr_i, |
wbs10_dat_i, |
wbs10_we_i, |
wbs10_cyc_i, |
wbs10_stb_i, |
wbs10_cti_i, |
wbs10_bte_i, |
wbs10_dat_o, |
wbs10_ack_o, |
wbs10_err_o, |
wbs10_rty_o, |
|
// Slave twelve |
// Wishbone Slave interface |
wbs11_adr_i, |
wbs11_dat_i, |
wbs11_we_i, |
wbs11_cyc_i, |
wbs11_stb_i, |
wbs11_cti_i, |
wbs11_bte_i, |
wbs11_dat_o, |
wbs11_ack_o, |
wbs11_err_o, |
wbs11_rty_o, |
|
// Slave thirteen |
// Wishbone Slave interface |
wbs12_adr_i, |
wbs12_dat_i, |
wbs12_we_i, |
wbs12_cyc_i, |
wbs12_stb_i, |
wbs12_cti_i, |
wbs12_bte_i, |
wbs12_dat_o, |
wbs12_ack_o, |
wbs12_err_o, |
wbs12_rty_o, |
|
// Slave fourteen |
// Wishbone Slave interface |
wbs13_adr_i, |
wbs13_dat_i, |
wbs13_we_i, |
wbs13_cyc_i, |
wbs13_stb_i, |
wbs13_cti_i, |
wbs13_bte_i, |
wbs13_dat_o, |
wbs13_ack_o, |
wbs13_err_o, |
wbs13_rty_o, |
|
// Slave fifteen |
// Wishbone Slave interface |
wbs14_adr_i, |
wbs14_dat_i, |
wbs14_we_i, |
wbs14_cyc_i, |
wbs14_stb_i, |
wbs14_cti_i, |
wbs14_bte_i, |
wbs14_dat_o, |
wbs14_ack_o, |
wbs14_err_o, |
wbs14_rty_o, |
|
// Slave sixteen |
// Wishbone Slave interface |
wbs15_adr_i, |
wbs15_dat_i, |
wbs15_we_i, |
wbs15_cyc_i, |
wbs15_stb_i, |
wbs15_cti_i, |
wbs15_bte_i, |
|
wbs15_dat_o, |
wbs15_ack_o, |
wbs15_err_o, |
wbs15_rty_o, |
|
// Slave seventeen |
// Wishbone Slave interface |
wbs16_adr_i, |
wbs16_dat_i, |
wbs16_we_i, |
wbs16_cyc_i, |
wbs16_stb_i, |
wbs16_cti_i, |
wbs16_bte_i, |
|
wbs16_dat_o, |
wbs16_ack_o, |
wbs16_err_o, |
wbs16_rty_o, |
|
|
// Slave eighteen |
// Wishbone Slave interface |
wbs17_adr_i, |
wbs17_dat_i, |
wbs17_we_i, |
wbs17_cyc_i, |
wbs17_stb_i, |
wbs17_cti_i, |
wbs17_bte_i, |
|
wbs17_dat_o, |
wbs17_ack_o, |
wbs17_err_o, |
wbs17_rty_o, |
|
// Slave nineteen |
// Wishbone Slave interface |
wbs18_adr_i, |
wbs18_dat_i, |
wbs18_we_i, |
wbs18_cyc_i, |
wbs18_stb_i, |
wbs18_cti_i, |
wbs18_bte_i, |
|
wbs18_dat_o, |
wbs18_ack_o, |
wbs18_err_o, |
wbs18_rty_o, |
|
// Slave twenty |
// Wishbone Slave interface |
wbs19_adr_i, |
wbs19_dat_i, |
wbs19_we_i, |
wbs19_cyc_i, |
wbs19_stb_i, |
wbs19_cti_i, |
wbs19_bte_i, |
|
wbs19_dat_o, |
wbs19_ack_o, |
wbs19_err_o, |
wbs19_rty_o, |
|
*/ |
|
wb_clk, wb_rst |
); |
|
|
parameter wb_dat_width = 32; |
parameter wbs_dat_width = 8; |
parameter wb_adr_width = 32; |
|
parameter wb_addr_match_width = 8; |
|
parameter wb_num_slaves = 20; // Currently can handle up to 20 |
|
// Slave addresses |
|
parameter slave0_adr = 8'h00; |
parameter slave1_adr = 8'h00; |
parameter slave2_adr = 8'h00; |
parameter slave3_adr = 8'h00; |
parameter slave4_adr = 8'h00; |
parameter slave5_adr = 8'h00; |
parameter slave6_adr = 8'h00; |
parameter slave7_adr = 8'h00; |
parameter slave8_adr = 8'h00; |
parameter slave9_adr = 8'h00; |
parameter slave10_adr = 8'h00; |
parameter slave11_adr = 8'h00; |
parameter slave12_adr = 8'h00; |
parameter slave13_adr = 8'h00; |
parameter slave14_adr = 8'h00; |
parameter slave15_adr = 8'h00; |
parameter slave16_adr = 8'h00; |
parameter slave17_adr = 8'h00; |
parameter slave18_adr = 8'h00; |
parameter slave19_adr = 8'h00; |
|
|
`define WB_ARB_ADDR_MATCH_SEL wb_adr_width-1:wb_adr_width-wb_addr_match_width |
|
input wb_clk; |
input wb_rst; |
|
// WB Master one |
input [wb_adr_width-1:0] wbm0_adr_o; |
input [wb_dat_width-1:0] wbm0_dat_o; |
input [3:0] wbm0_sel_o; |
input wbm0_we_o; |
input wbm0_cyc_o; |
input wbm0_stb_o; |
input [2:0] wbm0_cti_o; |
input [1:0] wbm0_bte_o; |
output [wb_dat_width-1:0] wbm0_dat_i; |
output wbm0_ack_i; |
output wbm0_err_i; |
output wbm0_rty_i; |
|
|
// Slave one |
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs0_adr_i; |
output [wbs_dat_width-1:0] wbs0_dat_i; |
output wbs0_we_i; |
output wbs0_cyc_i; |
output wbs0_stb_i; |
output [2:0] wbs0_cti_i; |
output [1:0] wbs0_bte_i; |
input [wbs_dat_width-1:0] wbs0_dat_o; |
input wbs0_ack_o; |
input wbs0_err_o; |
input wbs0_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs1_adr_i; |
output [wbs_dat_width-1:0] wbs1_dat_i; |
output wbs1_we_i; |
output wbs1_cyc_i; |
output wbs1_stb_i; |
output [2:0] wbs1_cti_i; |
output [1:0] wbs1_bte_i; |
input [wbs_dat_width-1:0] wbs1_dat_o; |
input wbs1_ack_o; |
input wbs1_err_o; |
input wbs1_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs2_adr_i; |
output [wbs_dat_width-1:0] wbs2_dat_i; |
output wbs2_we_i; |
output wbs2_cyc_i; |
output wbs2_stb_i; |
output [2:0] wbs2_cti_i; |
output [1:0] wbs2_bte_i; |
input [wbs_dat_width-1:0] wbs2_dat_o; |
input wbs2_ack_o; |
input wbs2_err_o; |
input wbs2_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs3_adr_i; |
output [wbs_dat_width-1:0] wbs3_dat_i; |
output wbs3_we_i; |
output wbs3_cyc_i; |
output wbs3_stb_i; |
output [2:0] wbs3_cti_i; |
output [1:0] wbs3_bte_i; |
input [wbs_dat_width-1:0] wbs3_dat_o; |
input wbs3_ack_o; |
input wbs3_err_o; |
input wbs3_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs4_adr_i; |
output [wbs_dat_width-1:0] wbs4_dat_i; |
output wbs4_we_i; |
output wbs4_cyc_i; |
output wbs4_stb_i; |
output [2:0] wbs4_cti_i; |
output [1:0] wbs4_bte_i; |
input [wbs_dat_width-1:0] wbs4_dat_o; |
input wbs4_ack_o; |
input wbs4_err_o; |
input wbs4_rty_o; |
|
/* |
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs5_adr_i; |
output [wbs_dat_width-1:0] wbs5_dat_i; |
output wbs5_we_i; |
output wbs5_cyc_i; |
output wbs5_stb_i; |
output [2:0] wbs5_cti_i; |
output [1:0] wbs5_bte_i; |
input [wbs_dat_width-1:0] wbs5_dat_o; |
input wbs5_ack_o; |
input wbs5_err_o; |
input wbs5_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs6_adr_i; |
output [wbs_dat_width-1:0] wbs6_dat_i; |
output wbs6_we_i; |
output wbs6_cyc_i; |
output wbs6_stb_i; |
output [2:0] wbs6_cti_i; |
output [1:0] wbs6_bte_i; |
input [wbs_dat_width-1:0] wbs6_dat_o; |
input wbs6_ack_o; |
input wbs6_err_o; |
input wbs6_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs7_adr_i; |
output [wbs_dat_width-1:0] wbs7_dat_i; |
output wbs7_we_i; |
output wbs7_cyc_i; |
output wbs7_stb_i; |
output [2:0] wbs7_cti_i; |
output [1:0] wbs7_bte_i; |
input [wbs_dat_width-1:0] wbs7_dat_o; |
input wbs7_ack_o; |
input wbs7_err_o; |
input wbs7_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs8_adr_i; |
output [wbs_dat_width-1:0] wbs8_dat_i; |
output wbs8_we_i; |
output wbs8_cyc_i; |
output wbs8_stb_i; |
output [2:0] wbs8_cti_i; |
output [1:0] wbs8_bte_i; |
input [wbs_dat_width-1:0] wbs8_dat_o; |
input wbs8_ack_o; |
input wbs8_err_o; |
input wbs8_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs9_adr_i; |
output [wbs_dat_width-1:0] wbs9_dat_i; |
output wbs9_we_i; |
output wbs9_cyc_i; |
output wbs9_stb_i; |
output [2:0] wbs9_cti_i; |
output [1:0] wbs9_bte_i; |
input [wbs_dat_width-1:0] wbs9_dat_o; |
input wbs9_ack_o; |
input wbs9_err_o; |
input wbs9_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs10_adr_i; |
output [wbs_dat_width-1:0] wbs10_dat_i; |
output wbs10_we_i; |
output wbs10_cyc_i; |
output wbs10_stb_i; |
output [2:0] wbs10_cti_i; |
output [1:0] wbs10_bte_i; |
input [wbs_dat_width-1:0] wbs10_dat_o; |
input wbs10_ack_o; |
input wbs10_err_o; |
input wbs10_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs11_adr_i; |
output [wbs_dat_width-1:0] wbs11_dat_i; |
output wbs11_we_i; |
output wbs11_cyc_i; |
output wbs11_stb_i; |
output [2:0] wbs11_cti_i; |
output [1:0] wbs11_bte_i; |
input [wbs_dat_width-1:0] wbs11_dat_o; |
input wbs11_ack_o; |
input wbs11_err_o; |
input wbs11_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs12_adr_i; |
output [wbs_dat_width-1:0] wbs12_dat_i; |
output wbs12_we_i; |
output wbs12_cyc_i; |
output wbs12_stb_i; |
output [2:0] wbs12_cti_i; |
output [1:0] wbs12_bte_i; |
input [wbs_dat_width-1:0] wbs12_dat_o; |
input wbs12_ack_o; |
input wbs12_err_o; |
input wbs12_rty_o; |
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs13_adr_i; |
output [wbs_dat_width-1:0] wbs13_dat_i; |
output wbs13_we_i; |
output wbs13_cyc_i; |
output wbs13_stb_i; |
output [2:0] wbs13_cti_i; |
output [1:0] wbs13_bte_i; |
input [wbs_dat_width-1:0] wbs13_dat_o; |
input wbs13_ack_o; |
input wbs13_err_o; |
input wbs13_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs14_adr_i; |
output [wbs_dat_width-1:0] wbs14_dat_i; |
output wbs14_we_i; |
output wbs14_cyc_i; |
output wbs14_stb_i; |
output [2:0] wbs14_cti_i; |
output [1:0] wbs14_bte_i; |
input [wbs_dat_width-1:0] wbs14_dat_o; |
input wbs14_ack_o; |
input wbs14_err_o; |
input wbs14_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs15_adr_i; |
output [wbs_dat_width-1:0] wbs15_dat_i; |
output wbs15_we_i; |
output wbs15_cyc_i; |
output wbs15_stb_i; |
output [2:0] wbs15_cti_i; |
output [1:0] wbs15_bte_i; |
input [wbs_dat_width-1:0] wbs15_dat_o; |
input wbs15_ack_o; |
input wbs15_err_o; |
input wbs15_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs16_adr_i; |
output [wbs_dat_width-1:0] wbs16_dat_i; |
output wbs16_we_i; |
output wbs16_cyc_i; |
output wbs16_stb_i; |
output [2:0] wbs16_cti_i; |
output [1:0] wbs16_bte_i; |
input [wbs_dat_width-1:0] wbs16_dat_o; |
input wbs16_ack_o; |
input wbs16_err_o; |
input wbs16_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs17_adr_i; |
output [wbs_dat_width-1:0] wbs17_dat_i; |
output wbs17_we_i; |
output wbs17_cyc_i; |
output wbs17_stb_i; |
output [2:0] wbs17_cti_i; |
output [1:0] wbs17_bte_i; |
input [wbs_dat_width-1:0] wbs17_dat_o; |
input wbs17_ack_o; |
input wbs17_err_o; |
input wbs17_rty_o; |
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs18_adr_i; |
output [wbs_dat_width-1:0] wbs18_dat_i; |
output wbs18_we_i; |
output wbs18_cyc_i; |
output wbs18_stb_i; |
output [2:0] wbs18_cti_i; |
output [1:0] wbs18_bte_i; |
input [wbs_dat_width-1:0] wbs18_dat_o; |
input wbs18_ack_o; |
input wbs18_err_o; |
input wbs18_rty_o; |
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs19_adr_i; |
output [wbs_dat_width-1:0] wbs19_dat_i; |
output wbs19_we_i; |
output wbs19_cyc_i; |
output wbs19_stb_i; |
output [2:0] wbs19_cti_i; |
output [1:0] wbs19_bte_i; |
input [wbs_dat_width-1:0] wbs19_dat_o; |
input wbs19_ack_o; |
input wbs19_err_o; |
input wbs19_rty_o; |
*/ |
|
reg watchdog_err; |
|
// Master input mux output wires |
wire [wb_adr_width-1:0] wbm_adr_o; |
wire [wbs_dat_width-1:0] wbm_dat_o; |
wire [3:0] wbm_sel_o; |
wire wbm_we_o; |
wire wbm_cyc_o; |
wire wbm_stb_o; |
wire [2:0] wbm_cti_o; |
wire [1:0] wbm_bte_o; |
|
wire [wbs_dat_width-1:0] wbm_dat_byte_i; |
wire wbm_ack_i; |
wire wbm_err_i; |
wire wbm_rty_i; |
|
|
// Master input mux (not really used, only one master on this bus) |
assign wbm_adr_o = wbm0_adr_o; |
|
// Select the right byte and put it on the data out line |
// !BIG ENDIAN! |
assign wbm_dat_o = wbm0_sel_o[3] ? wbm0_dat_o[31:24] : |
wbm0_sel_o[2] ? wbm0_dat_o[23:16] : |
wbm0_sel_o[1] ? wbm0_dat_o[15:8] : |
wbm0_dat_o[7:0]; |
|
assign wbm_we_o = wbm0_we_o; |
|
assign wbm_cyc_o = wbm0_stb_o; |
|
assign wbm_stb_o = wbm0_stb_o; |
|
// Will we really need these for byte-peripherals |
assign wbm_cti_o = wbm0_cti_o; |
|
assign wbm_bte_o = wbm0_bte_o; |
|
// Signals back to the master |
assign wbm0_dat_i = (wbm0_sel_o[3]) ? {wbm_dat_byte_i, 24'd0} : |
(wbm0_sel_o[2]) ? {8'd0, wbm_dat_byte_i, 16'd0} : |
(wbm0_sel_o[1]) ? {16'd0, wbm_dat_byte_i, 8'd0} : |
{24'd0, wbm_dat_byte_i}; |
|
assign wbm0_ack_i = wbm_ack_i; |
assign wbm0_err_i = wbm_err_i; |
assign wbm0_rty_i = wbm_rty_i; |
|
`ifdef ARBITER_BYTEBUS_WATCHDOG |
reg [`ARBITER_BYTEBUS_WATCHDOG_TIMER_WIDTH:0] watchdog_timer; |
reg wbm_stb_r; // Register strobe |
wire wbm_stb_edge; // Detect its edge |
|
always @(posedge wb_clk) |
wbm_stb_r <= wbm_stb_o; |
|
assign wbm_stb_edge = (wbm_stb_o & !wbm_stb_r); |
|
// Counter logic |
always @(posedge wb_clk) |
if (wb_rst) watchdog_timer <= 0; |
else if (wbm_ack_i) // When we see an ack, turn off timer |
watchdog_timer <= 0; |
else if (wbm_stb_edge) // New access means start timer again |
watchdog_timer <= 1; |
else if (|watchdog_timer) // Continue counting if counter > 0 |
watchdog_timer <= watchdog_timer + 1; |
|
always @(posedge wb_clk) |
watchdog_err <= (&watchdog_timer); |
|
`else // !`ifdef ARBITER_BYTEBUS_WATCHDOG |
always @(posedge wb_clk) |
watchdog_err <= 0; |
|
`endif // !`ifdef ARBITER_BYTEBUS_WATCHDOG |
|
|
// Wishbone slave mux out wires |
wire [wb_adr_width-1:0] wbs_adr_i; |
wire [wbs_dat_width-1:0] wbs_dat_i; |
wire wbs_we_i; |
wire wbs_cyc_i; |
wire wbs_stb_i; |
wire [2:0] wbs_cti_i; |
wire [1:0] wbs_bte_i; |
wire [wbs_dat_width-1:0] wbs_dat_o; |
wire wbs_ack_o; |
wire wbs_err_o; |
wire wbs_rty_o; |
|
|
// Slave select wire |
wire [wb_num_slaves-1:0] wb_slave_sel; |
|
// Slave out mux in wires |
wire [wbs_dat_width-1:0] wbs_dat_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_ack_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_err_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_rty_o_mux_i [0:wb_num_slaves-1]; |
|
// Slave selects |
assign wb_slave_sel[0] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave0_adr; |
assign wb_slave_sel[1] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave1_adr; |
assign wb_slave_sel[2] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave2_adr; |
assign wb_slave_sel[3] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave3_adr; |
assign wb_slave_sel[4] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave4_adr; |
/* |
assign wb_slave_sel[5] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave5_adr; |
assign wb_slave_sel[6] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave6_adr; |
assign wb_slave_sel[7] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave7_adr; |
assign wb_slave_sel[8] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave8_adr; |
assign wb_slave_sel[9] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave9_adr; |
assign wb_slave_sel[10] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave10_adr; |
assign wb_slave_sel[11] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave11_adr; |
assign wb_slave_sel[12] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave12_adr; |
assign wb_slave_sel[13] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave13_adr; |
assign wb_slave_sel[14] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave14_adr; |
assign wb_slave_sel[15] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave15_adr; |
assign wb_slave_sel[16] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave16_adr; |
assign wb_slave_sel[16] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave17_adr; |
assign wb_slave_sel[16] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave18_adr; |
assign wb_slave_sel[16] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave19_adr; |
*/ |
|
|
// Assign master inputs to slaves and slave inputs for MUXing back to master |
|
// Slave 0 inputs |
assign wbs0_adr_i = wbm_adr_o; |
assign wbs0_dat_i = wbm_dat_o; |
assign wbs0_cyc_i = wbm_cyc_o & wb_slave_sel[0]; |
assign wbs0_stb_i = wbm_stb_o & wb_slave_sel[0]; |
assign wbs0_we_i = wbm_we_o; |
assign wbs0_cti_i = wbm_cti_o; |
assign wbs0_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[0] = wbs0_dat_o; |
assign wbs_ack_o_mux_i[0] = wbs0_ack_o & wb_slave_sel[0]; |
assign wbs_err_o_mux_i[0] = wbs0_err_o & wb_slave_sel[0]; |
assign wbs_rty_o_mux_i[0] = wbs0_rty_o & wb_slave_sel[0]; |
|
|
// Slave 1 inputs |
assign wbs1_adr_i = wbm_adr_o; |
assign wbs1_dat_i = wbm_dat_o; |
assign wbs1_cyc_i = wbm_cyc_o & wb_slave_sel[1]; |
assign wbs1_stb_i = wbm_stb_o & wb_slave_sel[1]; |
assign wbs1_we_i = wbm_we_o; |
assign wbs1_cti_i = wbm_cti_o; |
assign wbs1_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[1] = wbs1_dat_o; |
assign wbs_ack_o_mux_i[1] = wbs1_ack_o & wb_slave_sel[1]; |
assign wbs_err_o_mux_i[1] = wbs1_err_o & wb_slave_sel[1]; |
assign wbs_rty_o_mux_i[1] = wbs1_rty_o & wb_slave_sel[1]; |
|
|
// Slave 2 inputs |
assign wbs2_adr_i = wbm_adr_o; |
assign wbs2_dat_i = wbm_dat_o; |
assign wbs2_cyc_i = wbm_cyc_o & wb_slave_sel[2]; |
assign wbs2_stb_i = wbm_stb_o & wb_slave_sel[2]; |
assign wbs2_we_i = wbm_we_o; |
assign wbs2_cti_i = wbm_cti_o; |
assign wbs2_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[2] = wbs2_dat_o; |
assign wbs_ack_o_mux_i[2] = wbs2_ack_o & wb_slave_sel[2]; |
assign wbs_err_o_mux_i[2] = wbs2_err_o & wb_slave_sel[2]; |
assign wbs_rty_o_mux_i[2] = wbs2_rty_o & wb_slave_sel[2]; |
|
|
// Slave 3 inputs |
assign wbs3_adr_i = wbm_adr_o; |
assign wbs3_dat_i = wbm_dat_o; |
assign wbs3_cyc_i = wbm_cyc_o & wb_slave_sel[3]; |
assign wbs3_stb_i = wbm_stb_o & wb_slave_sel[3]; |
assign wbs3_we_i = wbm_we_o; |
assign wbs3_cti_i = wbm_cti_o; |
assign wbs3_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[3] = wbs3_dat_o; |
assign wbs_ack_o_mux_i[3] = wbs3_ack_o & wb_slave_sel[3]; |
assign wbs_err_o_mux_i[3] = wbs3_err_o & wb_slave_sel[3]; |
assign wbs_rty_o_mux_i[3] = wbs3_rty_o & wb_slave_sel[3]; |
|
|
// Slave 4 inputs |
assign wbs4_adr_i = wbm_adr_o; |
assign wbs4_dat_i = wbm_dat_o; |
assign wbs4_cyc_i = wbm_cyc_o & wb_slave_sel[4]; |
assign wbs4_stb_i = wbm_stb_o & wb_slave_sel[4]; |
assign wbs4_we_i = wbm_we_o; |
assign wbs4_cti_i = wbm_cti_o; |
assign wbs4_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[4] = wbs4_dat_o; |
assign wbs_ack_o_mux_i[4] = wbs4_ack_o & wb_slave_sel[4]; |
assign wbs_err_o_mux_i[4] = wbs4_err_o & wb_slave_sel[4]; |
assign wbs_rty_o_mux_i[4] = wbs4_rty_o & wb_slave_sel[4]; |
|
/* |
// Slave 5 inputs |
assign wbs5_adr_i = wbm_adr_o; |
assign wbs5_dat_i = wbm_dat_o; |
assign wbs5_cyc_i = wbm_cyc_o & wb_slave_sel[5]; |
assign wbs5_stb_i = wbm_stb_o & wb_slave_sel[5]; |
assign wbs5_we_i = wbm_we_o; |
assign wbs5_cti_i = wbm_cti_o; |
assign wbs5_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[5] = wbs5_dat_o; |
assign wbs_ack_o_mux_i[5] = wbs5_ack_o & wb_slave_sel[5]; |
assign wbs_err_o_mux_i[5] = wbs5_err_o & wb_slave_sel[5]; |
assign wbs_rty_o_mux_i[5] = wbs5_rty_o & wb_slave_sel[5]; |
|
|
// Slave 6 inputs |
assign wbs6_adr_i = wbm_adr_o; |
assign wbs6_dat_i = wbm_dat_o; |
assign wbs6_cyc_i = wbm_cyc_o & wb_slave_sel[6]; |
assign wbs6_stb_i = wbm_stb_o & wb_slave_sel[6]; |
assign wbs6_we_i = wbm_we_o; |
assign wbs6_cti_i = wbm_cti_o; |
assign wbs6_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[6] = wbs6_dat_o; |
assign wbs_ack_o_mux_i[6] = wbs6_ack_o & wb_slave_sel[6]; |
assign wbs_err_o_mux_i[6] = wbs6_err_o & wb_slave_sel[6]; |
assign wbs_rty_o_mux_i[6] = wbs6_rty_o & wb_slave_sel[6]; |
|
|
// Slave 7 inputs |
assign wbs7_adr_i = wbm_adr_o; |
assign wbs7_dat_i = wbm_dat_o; |
assign wbs7_cyc_i = wbm_cyc_o & wb_slave_sel[7]; |
assign wbs7_stb_i = wbm_stb_o & wb_slave_sel[7]; |
assign wbs7_we_i = wbm_we_o; |
assign wbs7_cti_i = wbm_cti_o; |
assign wbs7_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[7] = wbs7_dat_o; |
assign wbs_ack_o_mux_i[7] = wbs7_ack_o & wb_slave_sel[7]; |
assign wbs_err_o_mux_i[7] = wbs7_err_o & wb_slave_sel[7]; |
assign wbs_rty_o_mux_i[7] = wbs7_rty_o & wb_slave_sel[7]; |
|
|
// Slave 8 inputs |
assign wbs8_adr_i = wbm_adr_o; |
assign wbs8_dat_i = wbm_dat_o; |
assign wbs8_cyc_i = wbm_cyc_o & wb_slave_sel[8]; |
assign wbs8_stb_i = wbm_stb_o & wb_slave_sel[8]; |
assign wbs8_we_i = wbm_we_o; |
assign wbs8_cti_i = wbm_cti_o; |
assign wbs8_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[8] = wbs8_dat_o; |
assign wbs_ack_o_mux_i[8] = wbs8_ack_o & wb_slave_sel[8]; |
assign wbs_err_o_mux_i[8] = wbs8_err_o & wb_slave_sel[8]; |
assign wbs_rty_o_mux_i[8] = wbs8_rty_o & wb_slave_sel[8]; |
|
|
// Slave 9 inputs |
assign wbs9_adr_i = wbm_adr_o; |
assign wbs9_dat_i = wbm_dat_o; |
assign wbs9_cyc_i = wbm_cyc_o & wb_slave_sel[9]; |
assign wbs9_stb_i = wbm_stb_o & wb_slave_sel[9]; |
assign wbs9_we_i = wbm_we_o; |
assign wbs9_cti_i = wbm_cti_o; |
assign wbs9_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[9] = wbs9_dat_o; |
assign wbs_ack_o_mux_i[9] = wbs9_ack_o & wb_slave_sel[9]; |
assign wbs_err_o_mux_i[9] = wbs9_err_o & wb_slave_sel[9]; |
assign wbs_rty_o_mux_i[9] = wbs9_rty_o & wb_slave_sel[9]; |
|
|
// Slave 10 inputs |
assign wbs10_adr_i = wbm_adr_o; |
assign wbs10_dat_i = wbm_dat_o; |
assign wbs10_cyc_i = wbm_cyc_o & wb_slave_sel[10]; |
assign wbs10_stb_i = wbm_stb_o & wb_slave_sel[10]; |
assign wbs10_we_i = wbm_we_o; |
assign wbs10_cti_i = wbm_cti_o; |
assign wbs10_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[10] = wbs10_dat_o; |
assign wbs_ack_o_mux_i[10] = wbs10_ack_o & wb_slave_sel[10]; |
assign wbs_err_o_mux_i[10] = wbs10_err_o & wb_slave_sel[10]; |
assign wbs_rty_o_mux_i[10] = wbs10_rty_o & wb_slave_sel[10]; |
|
|
// Slave 11 inputs |
assign wbs11_adr_i = wbm_adr_o; |
assign wbs11_dat_i = wbm_dat_o; |
assign wbs11_cyc_i = wbm_cyc_o & wb_slave_sel[11]; |
assign wbs11_stb_i = wbm_stb_o & wb_slave_sel[11]; |
assign wbs11_we_i = wbm_we_o; |
assign wbs11_cti_i = wbm_cti_o; |
assign wbs11_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[11] = wbs11_dat_o; |
assign wbs_ack_o_mux_i[11] = wbs11_ack_o & wb_slave_sel[11]; |
assign wbs_err_o_mux_i[11] = wbs11_err_o & wb_slave_sel[11]; |
assign wbs_rty_o_mux_i[11] = wbs11_rty_o & wb_slave_sel[11]; |
|
// Slave 12 inputs |
assign wbs12_adr_i = wbm_adr_o; |
assign wbs12_dat_i = wbm_dat_o; |
assign wbs12_cyc_i = wbm_cyc_o & wb_slave_sel[12]; |
assign wbs12_stb_i = wbm_stb_o & wb_slave_sel[12]; |
assign wbs12_we_i = wbm_we_o; |
assign wbs12_cti_i = wbm_cti_o; |
assign wbs12_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[12] = wbs12_dat_o; |
assign wbs_ack_o_mux_i[12] = wbs12_ack_o & wb_slave_sel[12]; |
assign wbs_err_o_mux_i[12] = wbs12_err_o & wb_slave_sel[12]; |
assign wbs_rty_o_mux_i[12] = wbs12_rty_o & wb_slave_sel[12]; |
|
|
// Slave 13 inputs |
assign wbs13_adr_i = wbm_adr_o; |
assign wbs13_dat_i = wbm_dat_o; |
assign wbs13_cyc_i = wbm_cyc_o & wb_slave_sel[13]; |
assign wbs13_stb_i = wbm_stb_o & wb_slave_sel[13]; |
assign wbs13_we_i = wbm_we_o; |
assign wbs13_cti_i = wbm_cti_o; |
assign wbs13_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[13] = wbs13_dat_o; |
assign wbs_ack_o_mux_i[13] = wbs13_ack_o & wb_slave_sel[13]; |
assign wbs_err_o_mux_i[13] = wbs13_err_o & wb_slave_sel[13]; |
assign wbs_rty_o_mux_i[13] = wbs13_rty_o & wb_slave_sel[13]; |
|
|
// Slave 14 inputs |
assign wbs14_adr_i = wbm_adr_o; |
assign wbs14_dat_i = wbm_dat_o; |
assign wbs14_cyc_i = wbm_cyc_o & wb_slave_sel[14]; |
assign wbs14_stb_i = wbm_stb_o & wb_slave_sel[14]; |
assign wbs14_we_i = wbm_we_o; |
assign wbs14_cti_i = wbm_cti_o; |
assign wbs14_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[14] = wbs14_dat_o; |
assign wbs_ack_o_mux_i[14] = wbs14_ack_o & wb_slave_sel[14]; |
assign wbs_err_o_mux_i[14] = wbs14_err_o & wb_slave_sel[14]; |
assign wbs_rty_o_mux_i[14] = wbs14_rty_o & wb_slave_sel[14]; |
|
|
// Slave 15 inputs |
assign wbs15_adr_i = wbm_adr_o; |
assign wbs15_dat_i = wbm_dat_o; |
assign wbs15_cyc_i = wbm_cyc_o & wb_slave_sel[15]; |
assign wbs15_stb_i = wbm_stb_o & wb_slave_sel[15]; |
assign wbs15_we_i = wbm_we_o; |
assign wbs15_cti_i = wbm_cti_o; |
assign wbs15_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[15] = wbs15_dat_o; |
assign wbs_ack_o_mux_i[15] = wbs15_ack_o & wb_slave_sel[15]; |
assign wbs_err_o_mux_i[15] = wbs15_err_o & wb_slave_sel[15]; |
assign wbs_rty_o_mux_i[15] = wbs15_rty_o & wb_slave_sel[15]; |
|
|
// Slave 16 inputs |
assign wbs16_adr_i = wbm_adr_o; |
assign wbs16_dat_i = wbm_dat_o; |
assign wbs16_cyc_i = wbm_cyc_o & wb_slave_sel[16]; |
assign wbs16_stb_i = wbm_stb_o & wb_slave_sel[16]; |
assign wbs16_we_i = wbm_we_o; |
assign wbs16_cti_i = wbm_cti_o; |
assign wbs16_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[16] = wbs16_dat_o; |
assign wbs_ack_o_mux_i[16] = wbs16_ack_o & wb_slave_sel[16]; |
assign wbs_err_o_mux_i[16] = wbs16_err_o & wb_slave_sel[16]; |
assign wbs_rty_o_mux_i[16] = wbs16_rty_o & wb_slave_sel[16]; |
|
|
// Slave 17 inputs |
assign wbs17_adr_i = wbm_adr_o; |
assign wbs17_dat_i = wbm_dat_o; |
assign wbs17_cyc_i = wbm_cyc_o & wb_slave_sel[17]; |
assign wbs17_stb_i = wbm_stb_o & wb_slave_sel[17]; |
assign wbs17_we_i = wbm_we_o; |
assign wbs17_cti_i = wbm_cti_o; |
assign wbs17_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[17] = wbs17_dat_o; |
assign wbs_ack_o_mux_i[17] = wbs17_ack_o & wb_slave_sel[17]; |
assign wbs_err_o_mux_i[17] = wbs17_err_o & wb_slave_sel[17]; |
assign wbs_rty_o_mux_i[17] = wbs17_rty_o & wb_slave_sel[17]; |
|
// Slave 18 inputs |
assign wbs18_adr_i = wbm_adr_o; |
assign wbs18_dat_i = wbm_dat_o; |
assign wbs18_cyc_i = wbm_cyc_o & wb_slave_sel[18]; |
assign wbs18_stb_i = wbm_stb_o & wb_slave_sel[18]; |
assign wbs18_we_i = wbm_we_o; |
assign wbs18_cti_i = wbm_cti_o; |
assign wbs18_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[18] = wbs18_dat_o; |
assign wbs_ack_o_mux_i[18] = wbs18_ack_o & wb_slave_sel[18]; |
assign wbs_err_o_mux_i[18] = wbs18_err_o & wb_slave_sel[18]; |
assign wbs_rty_o_mux_i[18] = wbs18_rty_o & wb_slave_sel[18]; |
|
// Slave 19 inputs |
assign wbs19_adr_i = wbm_adr_o; |
assign wbs19_dat_i = wbm_dat_o; |
assign wbs19_cyc_i = wbm_cyc_o & wb_slave_sel[19]; |
assign wbs19_stb_i = wbm_stb_o & wb_slave_sel[19]; |
assign wbs19_we_i = wbm_we_o; |
assign wbs19_cti_i = wbm_cti_o; |
assign wbs19_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[19] = wbs19_dat_o; |
assign wbs_ack_o_mux_i[19] = wbs19_ack_o & wb_slave_sel[19]; |
assign wbs_err_o_mux_i[19] = wbs19_err_o & wb_slave_sel[19]; |
assign wbs_rty_o_mux_i[19] = wbs19_rty_o & wb_slave_sel[19]; |
|
*/ |
|
|
|
// Master out mux from slave in data |
assign wbm_dat_byte_i = wb_slave_sel[0] ? wbs_dat_o_mux_i[0] : |
wb_slave_sel[1] ? wbs_dat_o_mux_i[1] : |
wb_slave_sel[2] ? wbs_dat_o_mux_i[2] : |
wb_slave_sel[3] ? wbs_dat_o_mux_i[3] : |
wb_slave_sel[4] ? wbs_dat_o_mux_i[4] : |
/* |
wb_slave_sel[5] ? wbs_dat_o_mux_i[5] : |
wb_slave_sel[6] ? wbs_dat_o_mux_i[6] : |
wb_slave_sel[7] ? wbs_dat_o_mux_i[7] : |
wb_slave_sel[8] ? wbs_dat_o_mux_i[8] : |
wb_slave_sel[9] ? wbs_dat_o_mux_i[9] : |
wb_slave_sel[10] ? wbs_dat_o_mux_i[10] : |
wb_slave_sel[11] ? wbs_dat_o_mux_i[11] : |
wb_slave_sel[12] ? wbs_dat_o_mux_i[12] : |
wb_slave_sel[13] ? wbs_dat_o_mux_i[13] : |
wb_slave_sel[14] ? wbs_dat_o_mux_i[14] : |
wb_slave_sel[15] ? wbs_dat_o_mux_i[15] : |
wb_slave_sel[16] ? wbs_dat_o_mux_i[16] : |
wb_slave_sel[17] ? wbs_dat_o_mux_i[17] : |
wb_slave_sel[18] ? wbs_dat_o_mux_i[18] : |
wb_slave_sel[19] ? wbs_dat_o_mux_i[19] : |
*/ |
wbs_dat_o_mux_i[0]; |
// Master out acks, or together |
assign wbm_ack_i = wbs_ack_o_mux_i[0] | |
wbs_ack_o_mux_i[1] | |
wbs_ack_o_mux_i[2] | |
wbs_ack_o_mux_i[3] | |
wbs_ack_o_mux_i[4] /* | |
wbs_ack_o_mux_i[5] | |
wbs_ack_o_mux_i[6] | |
wbs_ack_o_mux_i[7] | |
wbs_ack_o_mux_i[8] | |
wbs_ack_o_mux_i[9] | |
wbs_ack_o_mux_i[10] | |
wbs_ack_o_mux_i[11] | |
wbs_ack_o_mux_i[12] | |
wbs_ack_o_mux_i[13] | |
wbs_ack_o_mux_i[14] | |
wbs_ack_o_mux_i[15] | |
wbs_ack_o_mux_i[16] | |
wbs_ack_o_mux_i[17] | |
wbs_ack_o_mux_i[18] | |
wbs_ack_o_mux_i[19] |
*/ |
; |
|
|
assign wbm_err_i = wbs_err_o_mux_i[0] | |
wbs_err_o_mux_i[1] | |
wbs_err_o_mux_i[2] | |
wbs_err_o_mux_i[3] | |
wbs_err_o_mux_i[4] |/* |
wbs_err_o_mux_i[5] | |
wbs_err_o_mux_i[6] | |
wbs_err_o_mux_i[7] | |
wbs_err_o_mux_i[8] | |
wbs_err_o_mux_i[9] | |
wbs_err_o_mux_i[10] | |
wbs_err_o_mux_i[11] | |
wbs_err_o_mux_i[12] | |
wbs_err_o_mux_i[13] | |
wbs_err_o_mux_i[14] | |
wbs_err_o_mux_i[15] | |
wbs_err_o_mux_i[16] | |
wbs_err_o_mux_i[17] | |
wbs_err_o_mux_i[18] | |
wbs_err_o_mux_i[19] | |
*/ |
watchdog_err ; |
|
|
assign wbm_rty_i = wbs_rty_o_mux_i[0] | |
wbs_rty_o_mux_i[1] | |
wbs_rty_o_mux_i[2] | |
wbs_rty_o_mux_i[3] | |
wbs_rty_o_mux_i[4] /*| |
wbs_rty_o_mux_i[5] | |
wbs_rty_o_mux_i[6] | |
wbs_rty_o_mux_i[7] | |
wbs_rty_o_mux_i[8] | |
wbs_rty_o_mux_i[9] | |
wbs_rty_o_mux_i[10] | |
wbs_rty_o_mux_i[11] | |
wbs_rty_o_mux_i[12] | |
wbs_rty_o_mux_i[13] | |
wbs_rty_o_mux_i[14] | |
wbs_rty_o_mux_i[15] | |
wbs_rty_o_mux_i[16] | |
wbs_rty_o_mux_i[17] | |
wbs_rty_o_mux_i[18] | |
wbs_rty_o_mux_i[19] |
*/ |
; |
|
endmodule // arbiter_bytebus |
/verilog/arbiter/arbiter_dbus.v
0,0 → 1,1268
////////////////////////////////////////////////////////////////////// |
/// //// |
/// Wishbone arbiter, burst-compatible //// |
/// //// |
/// Simple arbiter, multi-master, multi-slave with default slave //// |
/// for chaining with peripheral arbiter //// |
/// //// |
/// Julius Baxter, julius@opencores.org //// |
/// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
`include "orpsoc-defines.v" |
// 2 Masters, a few slaves |
module arbiter_dbus |
( |
// or1200 data master |
// Wishbone Master interface |
wbm0_adr_o, |
wbm0_dat_o, |
wbm0_sel_o, |
wbm0_we_o, |
wbm0_cyc_o, |
wbm0_stb_o, |
wbm0_cti_o, |
wbm0_bte_o, |
|
wbm0_dat_i, |
wbm0_ack_i, |
wbm0_err_i, |
wbm0_rty_i, |
|
// or1200 debug master |
// Wishbone Master interface |
wbm1_adr_o, |
wbm1_dat_o, |
wbm1_sel_o, |
wbm1_we_o, |
wbm1_cyc_o, |
wbm1_stb_o, |
wbm1_cti_o, |
wbm1_bte_o, |
|
wbm1_dat_i, |
wbm1_ack_i, |
wbm1_err_i, |
wbm1_rty_i, |
|
// Slave one |
// Wishbone Slave interface |
wbs0_adr_i, |
wbs0_dat_i, |
wbs0_sel_i, |
wbs0_we_i, |
wbs0_cyc_i, |
wbs0_stb_i, |
wbs0_cti_i, |
wbs0_bte_i, |
|
wbs0_dat_o, |
wbs0_ack_o, |
wbs0_err_o, |
wbs0_rty_o, |
|
// Slave two |
// Wishbone Slave interface |
wbs1_adr_i, |
wbs1_dat_i, |
wbs1_sel_i, |
wbs1_we_i, |
wbs1_cyc_i, |
wbs1_stb_i, |
wbs1_cti_i, |
wbs1_bte_i, |
|
wbs1_dat_o, |
wbs1_ack_o, |
wbs1_err_o, |
wbs1_rty_o, |
|
|
// Slave three |
// Wishbone Slave interface |
wbs2_adr_i, |
wbs2_dat_i, |
wbs2_sel_i, |
wbs2_we_i, |
wbs2_cyc_i, |
wbs2_stb_i, |
wbs2_cti_i, |
wbs2_bte_i, |
|
wbs2_dat_o, |
wbs2_ack_o, |
wbs2_err_o, |
wbs2_rty_o, |
/* |
// Slave four |
// Wishbone Slave interface |
wbs3_adr_i, |
wbs3_dat_i, |
wbs3_sel_i, |
wbs3_we_i, |
wbs3_cyc_i, |
wbs3_stb_i, |
wbs3_cti_i, |
wbs3_bte_i, |
|
wbs3_dat_o, |
wbs3_ack_o, |
wbs3_err_o, |
wbs3_rty_o, |
|
// Slave five |
// Wishbone Slave interface |
wbs4_adr_i, |
wbs4_dat_i, |
wbs4_sel_i, |
wbs4_we_i, |
wbs4_cyc_i, |
wbs4_stb_i, |
wbs4_cti_i, |
wbs4_bte_i, |
|
wbs4_dat_o, |
wbs4_ack_o, |
wbs4_err_o, |
wbs4_rty_o, |
|
// Slave six |
// Wishbone Slave interface |
wbs5_adr_i, |
wbs5_dat_i, |
wbs5_sel_i, |
wbs5_we_i, |
wbs5_cyc_i, |
wbs5_stb_i, |
wbs5_cti_i, |
wbs5_bte_i, |
|
wbs5_dat_o, |
wbs5_ack_o, |
wbs5_err_o, |
wbs5_rty_o, |
|
// Slave seven |
// Wishbone Slave interface |
wbs6_adr_i, |
wbs6_dat_i, |
wbs6_sel_i, |
wbs6_we_i, |
wbs6_cyc_i, |
wbs6_stb_i, |
wbs6_cti_i, |
wbs6_bte_i, |
|
wbs6_dat_o, |
wbs6_ack_o, |
wbs6_err_o, |
wbs6_rty_o, |
|
// Slave eight |
// Wishbone Slave interface |
wbs7_adr_i, |
wbs7_dat_i, |
wbs7_sel_i, |
wbs7_we_i, |
wbs7_cyc_i, |
wbs7_stb_i, |
wbs7_cti_i, |
wbs7_bte_i, |
|
wbs7_dat_o, |
wbs7_ack_o, |
wbs7_err_o, |
wbs7_rty_o, |
|
// Slave nine |
// Wishbone Slave interface |
wbs8_adr_i, |
wbs8_dat_i, |
wbs8_sel_i, |
wbs8_we_i, |
wbs8_cyc_i, |
wbs8_stb_i, |
wbs8_cti_i, |
wbs8_bte_i, |
|
wbs8_dat_o, |
wbs8_ack_o, |
wbs8_err_o, |
wbs8_rty_o, |
|
// Slave ten |
// Wishbone Slave interface |
wbs9_adr_i, |
wbs9_dat_i, |
wbs9_sel_i, |
wbs9_we_i, |
wbs9_cyc_i, |
wbs9_stb_i, |
wbs9_cti_i, |
wbs9_bte_i, |
|
wbs9_dat_o, |
wbs9_ack_o, |
wbs9_err_o, |
wbs9_rty_o, |
|
// Slave eleven |
// Wishbone Slave interface |
wbs10_adr_i, |
wbs10_dat_i, |
wbs10_sel_i, |
wbs10_we_i, |
wbs10_cyc_i, |
wbs10_stb_i, |
wbs10_cti_i, |
wbs10_bte_i, |
|
wbs10_dat_o, |
wbs10_ack_o, |
wbs10_err_o, |
wbs10_rty_o, |
|
// Slave twelve |
// Wishbone Slave interface |
wbs11_adr_i, |
wbs11_dat_i, |
wbs11_sel_i, |
wbs11_we_i, |
wbs11_cyc_i, |
wbs11_stb_i, |
wbs11_cti_i, |
wbs11_bte_i, |
|
wbs11_dat_o, |
wbs11_ack_o, |
wbs11_err_o, |
wbs11_rty_o, |
|
// Slave thirteen |
// Wishbone Slave interface |
wbs12_adr_i, |
wbs12_dat_i, |
wbs12_sel_i, |
wbs12_we_i, |
wbs12_cyc_i, |
wbs12_stb_i, |
wbs12_cti_i, |
wbs12_bte_i, |
|
wbs12_dat_o, |
wbs12_ack_o, |
wbs12_err_o, |
wbs12_rty_o, |
|
// Slave fourteen |
// Wishbone Slave interface |
wbs13_adr_i, |
wbs13_dat_i, |
wbs13_sel_i, |
wbs13_we_i, |
wbs13_cyc_i, |
wbs13_stb_i, |
wbs13_cti_i, |
wbs13_bte_i, |
|
wbs13_dat_o, |
wbs13_ack_o, |
wbs13_err_o, |
wbs13_rty_o, |
|
// Slave fifteen |
// Wishbone Slave interface |
wbs14_adr_i, |
wbs14_dat_i, |
wbs14_sel_i, |
wbs14_we_i, |
wbs14_cyc_i, |
wbs14_stb_i, |
wbs14_cti_i, |
wbs14_bte_i, |
|
wbs14_dat_o, |
wbs14_ack_o, |
wbs14_err_o, |
wbs14_rty_o, |
|
// Slave sixteen |
// Wishbone Slave interface |
wbs15_adr_i, |
wbs15_dat_i, |
wbs15_sel_i, |
wbs15_we_i, |
wbs15_cyc_i, |
wbs15_stb_i, |
wbs15_cti_i, |
wbs15_bte_i, |
|
wbs15_dat_o, |
wbs15_ack_o, |
wbs15_err_o, |
wbs15_rty_o, |
|
// Slave seventeen |
// Wishbone Slave interface |
wbs16_adr_i, |
wbs16_dat_i, |
wbs16_sel_i, |
wbs16_we_i, |
wbs16_cyc_i, |
wbs16_stb_i, |
wbs16_cti_i, |
wbs16_bte_i, |
|
wbs16_dat_o, |
wbs16_ack_o, |
wbs16_err_o, |
wbs16_rty_o, |
*/ |
|
wb_clk, |
wb_rst |
); |
|
parameter wb_dat_width = 32; |
parameter wb_adr_width = 32; |
|
parameter wb_addr_match_width = 8; |
|
parameter wb_num_slaves = 2; // must also (un)comment things if changing |
|
// Slave addresses - these should be defparam'd from top level |
// Declare them as you need them |
parameter slave0_adr = 0; |
parameter slave1_adr = 0; |
parameter slave2_adr = 0; |
parameter slave3_adr = 0; |
parameter slave4_adr = 0; |
parameter slave5_adr = 0; |
parameter slave6_adr = 0; |
parameter slave7_adr = 0; |
parameter slave8_adr = 0; |
parameter slave9_adr = 0; |
parameter slave10_adr = 0; |
parameter slave11_adr = 0; |
parameter slave12_adr = 0; |
|
// Select for slave 0 |
`define WB_ARB_ADDR_MATCH_SEL_SLAVE0 wb_adr_width-1:wb_adr_width-4 |
`define WB_ARB_ADDR_MATCH_SEL wb_adr_width-1:wb_adr_width-wb_addr_match_width |
|
input wb_clk; |
input wb_rst; |
|
// WB Master one |
input [wb_adr_width-1:0] wbm0_adr_o; |
input [wb_dat_width-1:0] wbm0_dat_o; |
input [3:0] wbm0_sel_o; |
input wbm0_we_o; |
input wbm0_cyc_o; |
input wbm0_stb_o; |
input [2:0] wbm0_cti_o; |
input [1:0] wbm0_bte_o; |
output [wb_dat_width-1:0] wbm0_dat_i; |
output wbm0_ack_i; |
output wbm0_err_i; |
output wbm0_rty_i; |
|
|
input [wb_adr_width-1:0] wbm1_adr_o; |
input [wb_dat_width-1:0] wbm1_dat_o; |
input [3:0] wbm1_sel_o; |
input wbm1_we_o; |
input wbm1_cyc_o; |
input wbm1_stb_o; |
input [2:0] wbm1_cti_o; |
input [1:0] wbm1_bte_o; |
output [wb_dat_width-1:0] wbm1_dat_i; |
output wbm1_ack_i; |
output wbm1_err_i; |
output wbm1_rty_i; |
|
|
// Slave one |
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs0_adr_i; |
output [wb_dat_width-1:0] wbs0_dat_i; |
output [3:0] wbs0_sel_i; |
output wbs0_we_i; |
output wbs0_cyc_i; |
output wbs0_stb_i; |
output [2:0] wbs0_cti_i; |
output [1:0] wbs0_bte_i; |
input [wb_dat_width-1:0] wbs0_dat_o; |
input wbs0_ack_o; |
input wbs0_err_o; |
input wbs0_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs1_adr_i; |
output [wb_dat_width-1:0] wbs1_dat_i; |
output [3:0] wbs1_sel_i; |
output wbs1_we_i; |
output wbs1_cyc_i; |
output wbs1_stb_i; |
output [2:0] wbs1_cti_i; |
output [1:0] wbs1_bte_i; |
input [wb_dat_width-1:0] wbs1_dat_o; |
input wbs1_ack_o; |
input wbs1_err_o; |
input wbs1_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs2_adr_i; |
output [wb_dat_width-1:0] wbs2_dat_i; |
output [3:0] wbs2_sel_i; |
output wbs2_we_i; |
output wbs2_cyc_i; |
output wbs2_stb_i; |
output [2:0] wbs2_cti_i; |
output [1:0] wbs2_bte_i; |
input [wb_dat_width-1:0] wbs2_dat_o; |
input wbs2_ack_o; |
input wbs2_err_o; |
input wbs2_rty_o; |
/* |
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs3_adr_i; |
output [wb_dat_width-1:0] wbs3_dat_i; |
output [3:0] wbs3_sel_i; |
output wbs3_we_i; |
output wbs3_cyc_i; |
output wbs3_stb_i; |
output [2:0] wbs3_cti_i; |
output [1:0] wbs3_bte_i; |
input [wb_dat_width-1:0] wbs3_dat_o; |
input wbs3_ack_o; |
input wbs3_err_o; |
input wbs3_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs4_adr_i; |
output [wb_dat_width-1:0] wbs4_dat_i; |
output [3:0] wbs4_sel_i; |
output wbs4_we_i; |
output wbs4_cyc_i; |
output wbs4_stb_i; |
output [2:0] wbs4_cti_i; |
output [1:0] wbs4_bte_i; |
input [wb_dat_width-1:0] wbs4_dat_o; |
input wbs4_ack_o; |
input wbs4_err_o; |
input wbs4_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs5_adr_i; |
output [wb_dat_width-1:0] wbs5_dat_i; |
output [3:0] wbs5_sel_i; |
output wbs5_we_i; |
output wbs5_cyc_i; |
output wbs5_stb_i; |
output [2:0] wbs5_cti_i; |
output [1:0] wbs5_bte_i; |
input [wb_dat_width-1:0] wbs5_dat_o; |
input wbs5_ack_o; |
input wbs5_err_o; |
input wbs5_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs6_adr_i; |
output [wb_dat_width-1:0] wbs6_dat_i; |
output [3:0] wbs6_sel_i; |
output wbs6_we_i; |
output wbs6_cyc_i; |
output wbs6_stb_i; |
output [2:0] wbs6_cti_i; |
output [1:0] wbs6_bte_i; |
input [wb_dat_width-1:0] wbs6_dat_o; |
input wbs6_ack_o; |
input wbs6_err_o; |
input wbs6_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs7_adr_i; |
output [wb_dat_width-1:0] wbs7_dat_i; |
output [3:0] wbs7_sel_i; |
output wbs7_we_i; |
output wbs7_cyc_i; |
output wbs7_stb_i; |
output [2:0] wbs7_cti_i; |
output [1:0] wbs7_bte_i; |
input [wb_dat_width-1:0] wbs7_dat_o; |
input wbs7_ack_o; |
input wbs7_err_o; |
input wbs7_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs8_adr_i; |
output [wb_dat_width-1:0] wbs8_dat_i; |
output [3:0] wbs8_sel_i; |
output wbs8_we_i; |
output wbs8_cyc_i; |
output wbs8_stb_i; |
output [2:0] wbs8_cti_i; |
output [1:0] wbs8_bte_i; |
input [wb_dat_width-1:0] wbs8_dat_o; |
input wbs8_ack_o; |
input wbs8_err_o; |
input wbs8_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs9_adr_i; |
output [wb_dat_width-1:0] wbs9_dat_i; |
output [3:0] wbs9_sel_i; |
output wbs9_we_i; |
output wbs9_cyc_i; |
output wbs9_stb_i; |
output [2:0] wbs9_cti_i; |
output [1:0] wbs9_bte_i; |
input [wb_dat_width-1:0] wbs9_dat_o; |
input wbs9_ack_o; |
input wbs9_err_o; |
input wbs9_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs10_adr_i; |
output [wb_dat_width-1:0] wbs10_dat_i; |
output [3:0] wbs10_sel_i; |
output wbs10_we_i; |
output wbs10_cyc_i; |
output wbs10_stb_i; |
output [2:0] wbs10_cti_i; |
output [1:0] wbs10_bte_i; |
input [wb_dat_width-1:0] wbs10_dat_o; |
input wbs10_ack_o; |
input wbs10_err_o; |
input wbs10_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs11_adr_i; |
output [wb_dat_width-1:0] wbs11_dat_i; |
output [3:0] wbs11_sel_i; |
output wbs11_we_i; |
output wbs11_cyc_i; |
output wbs11_stb_i; |
output [2:0] wbs11_cti_i; |
output [1:0] wbs11_bte_i; |
input [wb_dat_width-1:0] wbs11_dat_o; |
input wbs11_ack_o; |
input wbs11_err_o; |
input wbs11_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs12_adr_i; |
output [wb_dat_width-1:0] wbs12_dat_i; |
output [3:0] wbs12_sel_i; |
output wbs12_we_i; |
output wbs12_cyc_i; |
output wbs12_stb_i; |
output [2:0] wbs12_cti_i; |
output [1:0] wbs12_bte_i; |
input [wb_dat_width-1:0] wbs12_dat_o; |
input wbs12_ack_o; |
input wbs12_err_o; |
input wbs12_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs13_adr_i; |
output [wb_dat_width-1:0] wbs13_dat_i; |
output [3:0] wbs13_sel_i; |
output wbs13_we_i; |
output wbs13_cyc_i; |
output wbs13_stb_i; |
output [2:0] wbs13_cti_i; |
output [1:0] wbs13_bte_i; |
input [wb_dat_width-1:0] wbs13_dat_o; |
input wbs13_ack_o; |
input wbs13_err_o; |
input wbs13_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs14_adr_i; |
output [wb_dat_width-1:0] wbs14_dat_i; |
output [3:0] wbs14_sel_i; |
output wbs14_we_i; |
output wbs14_cyc_i; |
output wbs14_stb_i; |
output [2:0] wbs14_cti_i; |
output [1:0] wbs14_bte_i; |
input [wb_dat_width-1:0] wbs14_dat_o; |
input wbs14_ack_o; |
input wbs14_err_o; |
input wbs14_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs15_adr_i; |
output [wb_dat_width-1:0] wbs15_dat_i; |
output [3:0] wbs15_sel_i; |
output wbs15_we_i; |
output wbs15_cyc_i; |
output wbs15_stb_i; |
output [2:0] wbs15_cti_i; |
output [1:0] wbs15_bte_i; |
input [wb_dat_width-1:0] wbs15_dat_o; |
input wbs15_ack_o; |
input wbs15_err_o; |
input wbs15_rty_o; |
|
|
// Wishbone Slave interface |
output [wb_adr_width-1:0] wbs16_adr_i; |
output [wb_dat_width-1:0] wbs16_dat_i; |
output [3:0] wbs16_sel_i; |
output wbs16_we_i; |
output wbs16_cyc_i; |
output wbs16_stb_i; |
output [2:0] wbs16_cti_i; |
output [1:0] wbs16_bte_i; |
input [wb_dat_width-1:0] wbs16_dat_o; |
input wbs16_ack_o; |
input wbs16_err_o; |
input wbs16_rty_o; |
|
*/ |
|
reg watchdog_err; |
|
`ifdef ARBITER_DBUS_REGISTERING |
|
|
// Registering setup: |
// Masters typically register their outputs, so do the master selection and |
// muxing before registering in the arbiter. Keep the common parts outside |
// for code brevity. |
|
// Master ins -> |MUX> -> these wires |
wire [wb_adr_width-1:0] wbm_adr_o_w; |
wire [wb_dat_width-1:0] wbm_dat_o_w; |
wire [3:0] wbm_sel_o_w; |
wire wbm_we_o_w; |
wire wbm_cyc_o_w; |
wire wbm_stb_o_w; |
wire [2:0] wbm_cti_o_w; |
wire [1:0] wbm_bte_o_w; |
// Slave ins -> |MUX> -> these wires |
wire [wb_dat_width-1:0] wbm_dat_i; |
wire wbm_ack_i; |
wire wbm_err_i; |
wire wbm_rty_i; |
|
// Registers after masters input mux |
reg [wb_adr_width-1:0] wbm_adr_o_r; |
reg [wb_dat_width-1:0] wbm_dat_o_r; |
reg [3:0] wbm_sel_o_r; |
reg wbm_we_o_r; |
reg wbm_cyc_o_r; |
reg wbm_stb_o_r; |
reg [2:0] wbm_cti_o_r; |
reg [1:0] wbm_bte_o_r; |
|
// Master input mux register wires |
wire [wb_adr_width-1:0] wbm_adr_o; |
wire [wb_dat_width-1:0] wbm_dat_o; |
wire [3:0] wbm_sel_o; |
wire wbm_we_o; |
wire wbm_cyc_o; |
wire wbm_stb_o; |
wire [2:0] wbm_cti_o; |
wire [1:0] wbm_bte_o; |
|
// Registers after slaves input mux |
reg [wb_dat_width-1:0] wbm_dat_i_r; |
reg wbm_ack_i_r; |
reg wbm_err_i_r; |
reg wbm_rty_i_r; |
|
// Master select (MUX controls) |
wire [1:0] master_sel; |
// priority to wbm1, the debug master |
assign master_sel[0] = wbm0_cyc_o & !wbm1_cyc_o; |
assign master_sel[1] = wbm1_cyc_o; |
|
|
// Master input mux, priority to debug master |
assign wbm_adr_o_w = master_sel[1] ? wbm1_adr_o : |
wbm0_adr_o; |
|
assign wbm_dat_o_w = master_sel[1] ? wbm1_dat_o : |
wbm0_dat_o; |
|
assign wbm_sel_o_w = master_sel[1] ? wbm1_sel_o : |
wbm0_sel_o; |
|
assign wbm_we_o_w = master_sel[1] ? wbm1_we_o : |
wbm0_we_o; |
|
assign wbm_cyc_o_w = master_sel[1] ? wbm1_cyc_o : |
wbm0_cyc_o; |
|
assign wbm_stb_o_w = master_sel[1] ? wbm1_stb_o : |
wbm0_stb_o; |
|
assign wbm_cti_o_w = master_sel[1] ? wbm1_cti_o : |
wbm0_cti_o; |
|
assign wbm_bte_o_w = master_sel[1] ? wbm1_bte_o : |
wbm0_bte_o; |
|
|
// Register muxed master signals |
always @(posedge wb_clk) |
begin |
wbm_adr_o_r <= wbm_adr_o_w; |
wbm_dat_o_r <= wbm_dat_o_w; |
wbm_sel_o_r <= wbm_sel_o_w; |
wbm_we_o_r <= wbm_we_o_w; |
wbm_cyc_o_r <= wbm_cyc_o_w; |
wbm_stb_o_r <= wbm_stb_o_w & !wbm_ack_i & !wbm_ack_i_r; |
wbm_cti_o_r <= wbm_cti_o_w; |
wbm_bte_o_r <= wbm_bte_o_w; |
|
wbm_dat_i_r <= wbm_dat_i; |
wbm_ack_i_r <= wbm_ack_i; |
wbm_err_i_r <= wbm_err_i; |
wbm_rty_i_r <= wbm_rty_i; |
end // always @ (posedge wb_clk) |
|
|
assign wbm_adr_o = wbm_adr_o_r; |
assign wbm_dat_o = wbm_dat_o_r; |
assign wbm_sel_o = wbm_sel_o_r; |
assign wbm_we_o = wbm_we_o_r; |
assign wbm_cyc_o = wbm_cyc_o_r; |
assign wbm_stb_o = wbm_stb_o_r; |
assign wbm_cti_o = wbm_cti_o_r; |
assign wbm_bte_o = wbm_bte_o_r; |
|
// Master input mux, priority to debug master |
assign wbm0_dat_i = wbm_dat_i_r; |
assign wbm0_ack_i = wbm_ack_i_r & master_sel[0]; |
assign wbm0_err_i = wbm_err_i_r & master_sel[0]; |
assign wbm0_rty_i = wbm_rty_i_r & master_sel[0]; |
|
assign wbm1_dat_i = wbm_dat_i_r; |
assign wbm1_ack_i = wbm_ack_i_r & master_sel[1]; |
assign wbm1_err_i = wbm_err_i_r & master_sel[1]; |
assign wbm1_rty_i = wbm_rty_i_r & master_sel[1]; |
|
`else // !`ifdef ARBITER_DBUS_REGISTERING |
|
// Master input mux output wires |
wire [wb_adr_width-1:0] wbm_adr_o; |
wire [wb_dat_width-1:0] wbm_dat_o; |
wire [3:0] wbm_sel_o; |
wire wbm_we_o; |
wire wbm_cyc_o; |
wire wbm_stb_o; |
wire [2:0] wbm_cti_o; |
wire [1:0] wbm_bte_o; |
|
// Master select |
wire [1:0] master_sel; |
// priority to wbm1, the debug master |
assign master_sel[0] = wbm0_cyc_o & !wbm1_cyc_o; |
assign master_sel[1] = wbm1_cyc_o; |
|
|
// Master input mux, priority to debug master |
assign wbm_adr_o = master_sel[1] ? wbm1_adr_o : |
wbm0_adr_o; |
|
assign wbm_dat_o = master_sel[1] ? wbm1_dat_o : |
wbm0_dat_o; |
|
assign wbm_sel_o = master_sel[1] ? wbm1_sel_o : |
wbm0_sel_o; |
|
assign wbm_we_o = master_sel[1] ? wbm1_we_o : |
wbm0_we_o; |
|
assign wbm_cyc_o = master_sel[1] ? wbm1_cyc_o : |
wbm0_cyc_o; |
|
assign wbm_stb_o = master_sel[1] ? wbm1_stb_o : |
wbm0_stb_o; |
|
assign wbm_cti_o = master_sel[1] ? wbm1_cti_o : |
wbm0_cti_o; |
|
assign wbm_bte_o = master_sel[1] ? wbm1_bte_o : |
wbm0_bte_o; |
|
|
wire [wb_dat_width-1:0] wbm_dat_i; |
wire wbm_ack_i; |
wire wbm_err_i; |
wire wbm_rty_i; |
|
|
assign wbm0_dat_i = wbm_dat_i; |
assign wbm0_ack_i = wbm_ack_i & master_sel[0]; |
assign wbm0_err_i = wbm_err_i & master_sel[0]; |
assign wbm0_rty_i = wbm_rty_i & master_sel[0]; |
|
assign wbm1_dat_i = wbm_dat_i; |
assign wbm1_ack_i = wbm_ack_i & master_sel[1]; |
assign wbm1_err_i = wbm_err_i & master_sel[1]; |
assign wbm1_rty_i = wbm_rty_i & master_sel[1]; |
|
|
|
`endif // !`ifdef ARBITER_DBUS_REGISTERING |
|
|
// Slave select wire |
wire [wb_num_slaves-1:0] wb_slave_sel; |
reg [wb_num_slaves-1:0] wb_slave_sel_r; |
|
// Register wb_slave_sel_r to break combinatorial loop when selecting default |
// slave |
always @(posedge wb_clk) |
wb_slave_sel_r <= wb_slave_sel; |
|
// Slave out mux in wires |
wire [wb_dat_width-1:0] wbs_dat_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_ack_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_err_o_mux_i [0:wb_num_slaves-1]; |
wire wbs_rty_o_mux_i [0:wb_num_slaves-1]; |
|
// |
// Slave selects |
// |
assign wb_slave_sel[0] = wbm_adr_o[31:28] == slave0_adr | wbm_adr_o[31:28] == 4'hf; // Special case, point all reads to ROM address to here |
assign wb_slave_sel[1] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave1_adr; |
|
// Auto select last slave when others are not selected |
assign wb_slave_sel[2] = !(wb_slave_sel_r[0] | wb_slave_sel_r[1]); |
|
/* |
assign wb_slave_sel[2] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave2_adr; |
assign wb_slave_sel[3] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave3_adr; |
assign wb_slave_sel[4] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave4_adr; |
assign wb_slave_sel[5] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave5_adr; |
assign wb_slave_sel[6] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave6_adr; |
assign wb_slave_sel[7] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave7_adr; |
assign wb_slave_sel[8] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave8_adr; |
assign wb_slave_sel[9] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave9_adr; |
assign wb_slave_sel[10] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave10_adr; |
assign wb_slave_sel[11] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave11_adr; |
assign wb_slave_sel[12] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave12_adr; |
assign wb_slave_sel[13] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave13_adr; |
assign wb_slave_sel[14] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave14_adr; |
assign wb_slave_sel[15] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave15_adr; |
assign wb_slave_sel[16] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == slave16_adr; |
*/ |
|
`ifdef ARBITER_DBUS_WATCHDOG |
reg [`ARBITER_DBUS_WATCHDOG_TIMER_WIDTH:0] watchdog_timer; |
reg wbm_stb_r; // Register strobe |
wire wbm_stb_edge; // Detect its edge |
|
always @(posedge wb_clk) |
wbm_stb_r <= wbm_stb_o; |
|
assign wbm_stb_edge = (wbm_stb_o & !wbm_stb_r); |
|
// Counter logic |
always @(posedge wb_clk) |
if (wb_rst) watchdog_timer <= 0; |
else if (wbm_ack_i) // When we see an ack, turn off timer |
watchdog_timer <= 0; |
else if (wbm_stb_edge) // New access means start timer again |
watchdog_timer <= 1; |
else if (|watchdog_timer) // Continue counting if counter > 0 |
watchdog_timer <= watchdog_timer + 1; |
|
always @(posedge wb_clk) |
watchdog_err <= (&watchdog_timer); |
|
|
`else // !`ifdef ARBITER_DBUS_WATCHDOG |
|
always @(posedge wb_clk) |
watchdog_err <= 0; |
|
`endif // !`ifdef ARBITER_DBUS_WATCHDOG |
|
|
|
// Slave 0 inputs |
assign wbs0_adr_i = wbm_adr_o; |
assign wbs0_dat_i = wbm_dat_o; |
assign wbs0_sel_i = wbm_sel_o; |
assign wbs0_cyc_i = wbm_cyc_o & wb_slave_sel_r[0]; |
assign wbs0_stb_i = wbm_stb_o & wb_slave_sel_r[0]; |
assign wbs0_we_i = wbm_we_o; |
assign wbs0_cti_i = wbm_cti_o; |
assign wbs0_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[0] = wbs0_dat_o; |
assign wbs_ack_o_mux_i[0] = wbs0_ack_o & wb_slave_sel_r[0]; |
assign wbs_err_o_mux_i[0] = wbs0_err_o & wb_slave_sel_r[0]; |
assign wbs_rty_o_mux_i[0] = wbs0_rty_o & wb_slave_sel_r[0]; |
|
|
// Slave 1 inputs |
assign wbs1_adr_i = wbm_adr_o; |
assign wbs1_dat_i = wbm_dat_o; |
assign wbs1_sel_i = wbm_sel_o; |
assign wbs1_cyc_i = wbm_cyc_o & wb_slave_sel_r[1]; |
assign wbs1_stb_i = wbm_stb_o & wb_slave_sel_r[1]; |
assign wbs1_we_i = wbm_we_o; |
assign wbs1_cti_i = wbm_cti_o; |
assign wbs1_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[1] = wbs1_dat_o; |
assign wbs_ack_o_mux_i[1] = wbs1_ack_o & wb_slave_sel_r[1]; |
assign wbs_err_o_mux_i[1] = wbs1_err_o & wb_slave_sel_r[1]; |
assign wbs_rty_o_mux_i[1] = wbs1_rty_o & wb_slave_sel_r[1]; |
|
|
// Slave 2 inputs |
assign wbs2_adr_i = wbm_adr_o; |
assign wbs2_dat_i = wbm_dat_o; |
assign wbs2_sel_i = wbm_sel_o; |
assign wbs2_cyc_i = wbm_cyc_o & wb_slave_sel_r[2]; |
assign wbs2_stb_i = wbm_stb_o & wb_slave_sel_r[2]; |
assign wbs2_we_i = wbm_we_o; |
assign wbs2_cti_i = wbm_cti_o; |
assign wbs2_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[2] = wbs2_dat_o; |
assign wbs_ack_o_mux_i[2] = wbs2_ack_o & wb_slave_sel_r[2]; |
assign wbs_err_o_mux_i[2] = wbs2_err_o & wb_slave_sel_r[2]; |
assign wbs_rty_o_mux_i[2] = wbs2_rty_o & wb_slave_sel_r[2]; |
/* |
|
// Slave 3 inputs |
assign wbs3_adr_i = wbm_adr_o; |
assign wbs3_dat_i = wbm_dat_o; |
assign wbs3_sel_i = wbm_sel_o; |
assign wbs3_cyc_i = wbm_cyc_o & wb_slave_sel_r[3]; |
assign wbs3_stb_i = wbm_stb_o & wb_slave_sel_r[3]; |
assign wbs3_we_i = wbm_we_o; |
assign wbs3_cti_i = wbm_cti_o; |
assign wbs3_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[3] = wbs3_dat_o; |
assign wbs_ack_o_mux_i[3] = wbs3_ack_o & wb_slave_sel_r[3]; |
assign wbs_err_o_mux_i[3] = wbs3_err_o & wb_slave_sel_r[3]; |
assign wbs_rty_o_mux_i[3] = wbs3_rty_o & wb_slave_sel_r[3]; |
|
// Slave 4 inputs |
assign wbs4_adr_i = wbm_adr_o; |
assign wbs4_dat_i = wbm_dat_o; |
assign wbs4_sel_i = wbm_sel_o; |
assign wbs4_cyc_i = wbm_cyc_o & wb_slave_sel_r[4]; |
assign wbs4_stb_i = wbm_stb_o & wb_slave_sel_r[4]; |
assign wbs4_we_i = wbm_we_o; |
assign wbs4_cti_i = wbm_cti_o; |
assign wbs4_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[4] = wbs4_dat_o; |
assign wbs_ack_o_mux_i[4] = wbs4_ack_o & wb_slave_sel_r[4]; |
assign wbs_err_o_mux_i[4] = wbs4_err_o & wb_slave_sel_r[4]; |
assign wbs_rty_o_mux_i[4] = wbs4_rty_o & wb_slave_sel_r[4]; |
|
|
// Slave 5 inputs |
assign wbs5_adr_i = wbm_adr_o; |
assign wbs5_dat_i = wbm_dat_o; |
assign wbs5_sel_i = wbm_sel_o; |
assign wbs5_cyc_i = wbm_cyc_o & wb_slave_sel_r[5]; |
assign wbs5_stb_i = wbm_stb_o & wb_slave_sel_r[5]; |
assign wbs5_we_i = wbm_we_o; |
assign wbs5_cti_i = wbm_cti_o; |
assign wbs5_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[5] = wbs5_dat_o; |
assign wbs_ack_o_mux_i[5] = wbs5_ack_o & wb_slave_sel_r[5]; |
assign wbs_err_o_mux_i[5] = wbs5_err_o & wb_slave_sel_r[5]; |
assign wbs_rty_o_mux_i[5] = wbs5_rty_o & wb_slave_sel_r[5]; |
|
|
// Slave 6 inputs |
assign wbs6_adr_i = wbm_adr_o; |
assign wbs6_dat_i = wbm_dat_o; |
assign wbs6_sel_i = wbm_sel_o; |
assign wbs6_cyc_i = wbm_cyc_o & wb_slave_sel_r[6]; |
assign wbs6_stb_i = wbm_stb_o & wb_slave_sel_r[6]; |
assign wbs6_we_i = wbm_we_o; |
assign wbs6_cti_i = wbm_cti_o; |
assign wbs6_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[6] = wbs6_dat_o; |
assign wbs_ack_o_mux_i[6] = wbs6_ack_o & wb_slave_sel_r[6]; |
assign wbs_err_o_mux_i[6] = wbs6_err_o & wb_slave_sel_r[6]; |
assign wbs_rty_o_mux_i[6] = wbs6_rty_o & wb_slave_sel_r[6]; |
|
|
// Slave 7 inputs |
assign wbs7_adr_i = wbm_adr_o; |
assign wbs7_dat_i = wbm_dat_o; |
assign wbs7_sel_i = wbm_sel_o; |
assign wbs7_cyc_i = wbm_cyc_o & wb_slave_sel_r[7]; |
assign wbs7_stb_i = wbm_stb_o & wb_slave_sel_r[7]; |
assign wbs7_we_i = wbm_we_o; |
assign wbs7_cti_i = wbm_cti_o; |
assign wbs7_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[7] = wbs7_dat_o; |
assign wbs_ack_o_mux_i[7] = wbs7_ack_o & wb_slave_sel_r[7]; |
assign wbs_err_o_mux_i[7] = wbs7_err_o & wb_slave_sel_r[7]; |
assign wbs_rty_o_mux_i[7] = wbs7_rty_o & wb_slave_sel_r[7]; |
|
|
// Slave 8 inputs |
assign wbs8_adr_i = wbm_adr_o; |
assign wbs8_dat_i = wbm_dat_o; |
assign wbs8_sel_i = wbm_sel_o; |
assign wbs8_cyc_i = wbm_cyc_o & wb_slave_sel_r[8]; |
assign wbs8_stb_i = wbm_stb_o & wb_slave_sel_r[8]; |
assign wbs8_we_i = wbm_we_o; |
assign wbs8_cti_i = wbm_cti_o; |
assign wbs8_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[8] = wbs8_dat_o; |
assign wbs_ack_o_mux_i[8] = wbs8_ack_o & wb_slave_sel_r[8]; |
assign wbs_err_o_mux_i[8] = wbs8_err_o & wb_slave_sel_r[8]; |
assign wbs_rty_o_mux_i[8] = wbs8_rty_o & wb_slave_sel_r[8]; |
|
|
// Slave 9 inputs |
assign wbs9_adr_i = wbm_adr_o; |
assign wbs9_dat_i = wbm_dat_o; |
assign wbs9_sel_i = wbm_sel_o; |
assign wbs9_cyc_i = wbm_cyc_o & wb_slave_sel_r[9]; |
assign wbs9_stb_i = wbm_stb_o & wb_slave_sel_r[9]; |
assign wbs9_we_i = wbm_we_o; |
assign wbs9_cti_i = wbm_cti_o; |
assign wbs9_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[9] = wbs9_dat_o; |
assign wbs_ack_o_mux_i[9] = wbs9_ack_o & wb_slave_sel_r[9]; |
assign wbs_err_o_mux_i[9] = wbs9_err_o & wb_slave_sel_r[9]; |
assign wbs_rty_o_mux_i[9] = wbs9_rty_o & wb_slave_sel_r[9]; |
|
|
// Slave 10 inputs |
assign wbs10_adr_i = wbm_adr_o; |
assign wbs10_dat_i = wbm_dat_o; |
assign wbs10_sel_i = wbm_sel_o; |
assign wbs10_cyc_i = wbm_cyc_o & wb_slave_sel_r[10]; |
assign wbs10_stb_i = wbm_stb_o & wb_slave_sel_r[10]; |
assign wbs10_we_i = wbm_we_o; |
assign wbs10_cti_i = wbm_cti_o; |
assign wbs10_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[10] = wbs10_dat_o; |
assign wbs_ack_o_mux_i[10] = wbs10_ack_o & wb_slave_sel_r[10]; |
assign wbs_err_o_mux_i[10] = wbs10_err_o & wb_slave_sel_r[10]; |
assign wbs_rty_o_mux_i[10] = wbs10_rty_o & wb_slave_sel_r[10]; |
|
|
// Slave 11 inputs |
assign wbs11_adr_i = wbm_adr_o; |
assign wbs11_dat_i = wbm_dat_o; |
assign wbs11_sel_i = wbm_sel_o; |
assign wbs11_cyc_i = wbm_cyc_o & wb_slave_sel_r[11]; |
assign wbs11_stb_i = wbm_stb_o & wb_slave_sel_r[11]; |
assign wbs11_we_i = wbm_we_o; |
assign wbs11_cti_i = wbm_cti_o; |
assign wbs11_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[11] = wbs11_dat_o; |
assign wbs_ack_o_mux_i[11] = wbs11_ack_o & wb_slave_sel_r[11]; |
assign wbs_err_o_mux_i[11] = wbs11_err_o & wb_slave_sel_r[11]; |
assign wbs_rty_o_mux_i[11] = wbs11_rty_o & wb_slave_sel_r[11]; |
|
|
// Slave 12 inputs |
assign wbs12_adr_i = wbm_adr_o; |
assign wbs12_dat_i = wbm_dat_o; |
assign wbs12_sel_i = wbm_sel_o; |
assign wbs12_cyc_i = wbm_cyc_o & wb_slave_sel_r[12]; |
assign wbs12_stb_i = wbm_stb_o & wb_slave_sel_r[12]; |
assign wbs12_we_i = wbm_we_o; |
assign wbs12_cti_i = wbm_cti_o; |
assign wbs12_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[12] = wbs12_dat_o; |
assign wbs_ack_o_mux_i[12] = wbs12_ack_o & wb_slave_sel_r[12]; |
assign wbs_err_o_mux_i[12] = wbs12_err_o & wb_slave_sel_r[12]; |
assign wbs_rty_o_mux_i[12] = wbs12_rty_o & wb_slave_sel_r[12]; |
|
|
// Slave 13 inputs |
assign wbs13_adr_i = wbm_adr_o; |
assign wbs13_dat_i = wbm_dat_o; |
assign wbs13_sel_i = wbm_sel_o; |
assign wbs13_cyc_i = wbm_cyc_o & wb_slave_sel_r[13]; |
assign wbs13_stb_i = wbm_stb_o & wb_slave_sel_r[13]; |
assign wbs13_we_i = wbm_we_o; |
assign wbs13_cti_i = wbm_cti_o; |
assign wbs13_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[13] = wbs13_dat_o; |
assign wbs_ack_o_mux_i[13] = wbs13_ack_o & wb_slave_sel_r[13]; |
assign wbs_err_o_mux_i[13] = wbs13_err_o & wb_slave_sel_r[13]; |
assign wbs_rty_o_mux_i[13] = wbs13_rty_o & wb_slave_sel_r[13]; |
|
|
// Slave 14 inputs |
assign wbs14_adr_i = wbm_adr_o; |
assign wbs14_dat_i = wbm_dat_o; |
assign wbs14_sel_i = wbm_sel_o; |
assign wbs14_cyc_i = wbm_cyc_o & wb_slave_sel_r[14]; |
assign wbs14_stb_i = wbm_stb_o & wb_slave_sel_r[14]; |
assign wbs14_we_i = wbm_we_o; |
assign wbs14_cti_i = wbm_cti_o; |
assign wbs14_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[14] = wbs14_dat_o; |
assign wbs_ack_o_mux_i[14] = wbs14_ack_o & wb_slave_sel_r[14]; |
assign wbs_err_o_mux_i[14] = wbs14_err_o & wb_slave_sel_r[14]; |
assign wbs_rty_o_mux_i[14] = wbs14_rty_o & wb_slave_sel_r[14]; |
|
|
// Slave 15 inputs |
assign wbs15_adr_i = wbm_adr_o; |
assign wbs15_dat_i = wbm_dat_o; |
assign wbs15_sel_i = wbm_sel_o; |
assign wbs15_cyc_i = wbm_cyc_o & wb_slave_sel_r[15]; |
assign wbs15_stb_i = wbm_stb_o & wb_slave_sel_r[15]; |
assign wbs15_we_i = wbm_we_o; |
assign wbs15_cti_i = wbm_cti_o; |
assign wbs15_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[15] = wbs15_dat_o; |
assign wbs_ack_o_mux_i[15] = wbs15_ack_o & wb_slave_sel_r[15]; |
assign wbs_err_o_mux_i[15] = wbs15_err_o & wb_slave_sel_r[15]; |
assign wbs_rty_o_mux_i[15] = wbs15_rty_o & wb_slave_sel_r[15]; |
|
|
// Slave 16 inputs |
assign wbs16_adr_i = wbm_adr_o; |
assign wbs16_dat_i = wbm_dat_o; |
assign wbs16_sel_i = wbm_sel_o; |
assign wbs16_cyc_i = wbm_cyc_o & wb_slave_sel_r[16]; |
assign wbs16_stb_i = wbm_stb_o & wb_slave_sel_r[16]; |
assign wbs16_we_i = wbm_we_o; |
assign wbs16_cti_i = wbm_cti_o; |
assign wbs16_bte_i = wbm_bte_o; |
assign wbs_dat_o_mux_i[16] = wbs16_dat_o; |
assign wbs_ack_o_mux_i[16] = wbs16_ack_o & wb_slave_sel_r[16]; |
assign wbs_err_o_mux_i[16] = wbs16_err_o & wb_slave_sel_r[16]; |
assign wbs_rty_o_mux_i[16] = wbs16_rty_o & wb_slave_sel_r[16]; |
|
*/ |
|
|
|
// Master out mux from slave in data |
assign wbm_dat_i = wb_slave_sel_r[0] ? wbs_dat_o_mux_i[0] : |
wb_slave_sel_r[1] ? wbs_dat_o_mux_i[1] : |
wb_slave_sel_r[2] ? wbs_dat_o_mux_i[2] : |
/* wb_slave_sel_r[3] ? wbs_dat_o_mux_i[3] : |
wb_slave_sel_r[4] ? wbs_dat_o_mux_i[4] : |
wb_slave_sel_r[5] ? wbs_dat_o_mux_i[5] : |
wb_slave_sel_r[6] ? wbs_dat_o_mux_i[6] : |
wb_slave_sel_r[7] ? wbs_dat_o_mux_i[7] : |
wb_slave_sel_r[8] ? wbs_dat_o_mux_i[8] : |
wb_slave_sel_r[9] ? wbs_dat_o_mux_i[9] : |
wb_slave_sel_r[10] ? wbs_dat_o_mux_i[10] : |
wb_slave_sel_r[11] ? wbs_dat_o_mux_i[11] : |
wb_slave_sel_r[12] ? wbs_dat_o_mux_i[12] : |
wb_slave_sel_r[13] ? wbs_dat_o_mux_i[13] : |
wb_slave_sel_r[14] ? wbs_dat_o_mux_i[14] : |
wb_slave_sel_r[15] ? wbs_dat_o_mux_i[15] : |
wb_slave_sel_r[16] ? wbs_dat_o_mux_i[16] : |
*/ |
wbs_dat_o_mux_i[0]; |
|
// Master out acks, or together |
assign wbm_ack_i = wbs_ack_o_mux_i[0] | |
wbs_ack_o_mux_i[1] | |
wbs_ack_o_mux_i[2] /*| |
wbs_ack_o_mux_i[3] | |
wbs_ack_o_mux_i[4] | |
wbs_ack_o_mux_i[5] | |
wbs_ack_o_mux_i[6] | |
wbs_ack_o_mux_i[7] | |
wbs_ack_o_mux_i[8] | |
wbs_ack_o_mux_i[9] | |
wbs_ack_o_mux_i[10] | |
wbs_ack_o_mux_i[11] | |
wbs_ack_o_mux_i[12] | |
wbs_ack_o_mux_i[13] | |
wbs_ack_o_mux_i[14] | |
wbs_ack_o_mux_i[15] | |
wbs_ack_o_mux_i[16] */ |
; |
|
|
assign wbm_err_i = wbs_err_o_mux_i[0] | |
wbs_err_o_mux_i[1] | |
wbs_err_o_mux_i[2] |/* |
wbs_err_o_mux_i[3] | |
wbs_err_o_mux_i[4] | |
wbs_err_o_mux_i[5] | |
wbs_err_o_mux_i[6] | |
wbs_err_o_mux_i[7] | |
wbs_err_o_mux_i[8] | |
wbs_err_o_mux_i[9] | |
wbs_err_o_mux_i[10] | |
wbs_err_o_mux_i[11] | |
wbs_err_o_mux_i[12] | |
wbs_err_o_mux_i[13] | |
wbs_err_o_mux_i[14] | |
wbs_err_o_mux_i[15] | |
wbs_err_o_mux_i[16] |*/ |
watchdog_err ; |
|
|
assign wbm_rty_i = wbs_rty_o_mux_i[0] | |
wbs_rty_o_mux_i[1] | |
wbs_rty_o_mux_i[2] /*| |
wbs_rty_o_mux_i[3] | |
wbs_rty_o_mux_i[4] | |
wbs_rty_o_mux_i[5] | |
wbs_rty_o_mux_i[6] | |
wbs_rty_o_mux_i[7] | |
wbs_rty_o_mux_i[8] | |
wbs_rty_o_mux_i[9] | |
wbs_rty_o_mux_i[10] | |
wbs_rty_o_mux_i[11] | |
wbs_rty_o_mux_i[12] | |
wbs_rty_o_mux_i[13] | |
wbs_rty_o_mux_i[14] | |
wbs_rty_o_mux_i[15] | |
wbs_rty_o_mux_i[16]*/; |
|
endmodule // arbiter_dbus |
|
/verilog/arbiter/arbiter_ibus.v
0,0 → 1,337
////////////////////////////////////////////////////////////////////// |
/// //// |
/// Wishbone arbiter, burst-compatible //// |
/// //// |
/// Simple arbiter, single master, dual slave, primarily for //// |
/// processor instruction bus, providing access to one main //// |
/// memory server and one ROM //// |
/// //// |
/// Julius Baxter, julius@opencores.org //// |
/// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
`include "orpsoc-defines.v" |
// One master, 2 slaves. |
module arbiter_ibus |
( |
// instruction bus in |
// Wishbone Master interface |
wbm_adr_o, |
wbm_dat_o, |
wbm_sel_o, |
wbm_we_o, |
wbm_cyc_o, |
wbm_stb_o, |
wbm_cti_o, |
wbm_bte_o, |
|
wbm_dat_i, |
wbm_ack_i, |
wbm_err_i, |
wbm_rty_i, |
|
|
// Slave one |
// Wishbone Slave interface |
wbs0_adr_i, |
wbs0_dat_i, |
wbs0_sel_i, |
wbs0_we_i, |
wbs0_cyc_i, |
wbs0_stb_i, |
wbs0_cti_i, |
wbs0_bte_i, |
|
wbs0_dat_o, |
wbs0_ack_o, |
wbs0_err_o, |
wbs0_rty_o, |
|
// Slave two |
// Wishbone Slave interface |
wbs1_adr_i, |
wbs1_dat_i, |
wbs1_sel_i, |
wbs1_we_i, |
wbs1_cyc_i, |
wbs1_stb_i, |
wbs1_cti_i, |
wbs1_bte_i, |
|
wbs1_dat_o, |
wbs1_ack_o, |
wbs1_err_o, |
wbs1_rty_o, |
|
wb_clk, |
wb_rst |
); |
|
|
parameter wb_dat_width = 32; |
parameter wb_adr_width = 32; |
|
parameter wb_addr_match_width = 8; |
|
parameter slave0_adr = 8'hf0; // FLASH ROM |
parameter slave1_adr = 8'h00; // Main memory (SDRAM/FPGA SRAM) |
|
`define WB_ARB_ADDR_MATCH_SEL wb_adr_width-1:wb_adr_width-wb_addr_match_width |
|
input wb_clk; |
input wb_rst; |
|
|
// WB Master |
input [wb_adr_width-1:0] wbm_adr_o; |
input [wb_dat_width-1:0] wbm_dat_o; |
input [3:0] wbm_sel_o; |
input wbm_we_o; |
input wbm_cyc_o; |
input wbm_stb_o; |
input [2:0] wbm_cti_o; |
input [1:0] wbm_bte_o; |
output [wb_dat_width-1:0] wbm_dat_i; |
output wbm_ack_i; |
output wbm_err_i; |
output wbm_rty_i; |
|
// WB Slave 0 |
output [wb_adr_width-1:0] wbs0_adr_i; |
output [wb_dat_width-1:0] wbs0_dat_i; |
output [3:0] wbs0_sel_i; |
output wbs0_we_i; |
output wbs0_cyc_i; |
output wbs0_stb_i; |
output [2:0] wbs0_cti_i; |
output [1:0] wbs0_bte_i; |
input [wb_dat_width-1:0] wbs0_dat_o; |
input wbs0_ack_o; |
input wbs0_err_o; |
input wbs0_rty_o; |
|
// WB Slave 1 |
output [wb_adr_width-1:0] wbs1_adr_i; |
output [wb_dat_width-1:0] wbs1_dat_i; |
output [3:0] wbs1_sel_i; |
output wbs1_we_i; |
output wbs1_cyc_i; |
output wbs1_stb_i; |
output [2:0] wbs1_cti_i; |
output [1:0] wbs1_bte_i; |
input [wb_dat_width-1:0] wbs1_dat_o; |
input wbs1_ack_o; |
input wbs1_err_o; |
input wbs1_rty_o; |
|
wire [1:0] slave_sel; // One bit per slave |
|
reg watchdog_err; |
|
`ifdef ARBITER_IBUS_WATCHDOG |
reg [`ARBITER_IBUS_WATCHDOG_TIMER_WIDTH:0] watchdog_timer; |
reg wbm_stb_r; // Register strobe |
wire wbm_stb_edge; // Detect its edge |
reg wbm_stb_edge_r, wbm_ack_i_r; // Reg these, better timing |
|
always @(posedge wb_clk) |
wbm_stb_r <= wbm_stb_o; |
|
assign wbm_stb_edge = (wbm_stb_o & !wbm_stb_r); |
|
always @(posedge wb_clk) |
wbm_stb_edge_r <= wbm_stb_edge; |
|
always @(posedge wb_clk) |
wbm_ack_i_r <= wbm_ack_i; |
|
|
// Counter logic |
always @(posedge wb_clk) |
if (wb_rst) watchdog_timer <= 0; |
else if (wbm_ack_i_r) // When we see an ack, turn off timer |
watchdog_timer <= 0; |
else if (wbm_stb_edge_r) // New access means start timer again |
watchdog_timer <= 1; |
else if (|watchdog_timer) // Continue counting if counter > 0 |
watchdog_timer <= watchdog_timer + 1; |
|
always @(posedge wb_clk) |
watchdog_err <= (&watchdog_timer); |
|
`else // !`ifdef ARBITER_IBUS_WATCHDOG |
|
always @(posedge wb_clk) |
watchdog_err <= 0; |
|
`endif // !`ifdef ARBITER_IBUS_WATCHDOG |
|
|
|
`ifdef ARBITER_IBUS_REGISTERING |
|
// Master input registers |
reg [wb_adr_width-1:0] wbm_adr_o_r; |
reg [wb_dat_width-1:0] wbm_dat_o_r; |
reg [3:0] wbm_sel_o_r; |
reg wbm_we_o_r; |
reg wbm_cyc_o_r; |
reg wbm_stb_o_r; |
reg [2:0] wbm_cti_o_r; |
reg [1:0] wbm_bte_o_r; |
// Slave output registers |
reg [wb_dat_width-1:0] wbs0_dat_o_r; |
reg wbs0_ack_o_r; |
reg wbs0_err_o_r; |
reg wbs0_rty_o_r; |
reg [wb_dat_width-1:0] wbs1_dat_o_r; |
reg wbs1_ack_o_r; |
reg wbs1_err_o_r; |
reg wbs1_rty_o_r; |
|
wire wbm_ack_i_pre_reg; |
|
|
|
// Register master input signals |
always @(posedge wb_clk) |
begin |
wbm_adr_o_r <= wbm_adr_o; |
wbm_dat_o_r <= wbm_dat_o; |
wbm_sel_o_r <= wbm_sel_o; |
wbm_we_o_r <= wbm_we_o; |
wbm_cyc_o_r <= wbm_cyc_o; |
wbm_stb_o_r <= wbm_stb_o & !wbm_ack_i_pre_reg & !wbm_ack_i;//classic |
wbm_cti_o_r <= wbm_cti_o; |
wbm_bte_o_r <= wbm_bte_o; |
|
// Slave signals |
wbs0_dat_o_r <= wbs0_dat_o; |
wbs0_ack_o_r <= wbs0_ack_o; |
wbs0_err_o_r <= wbs0_err_o; |
wbs0_rty_o_r <= wbs0_rty_o; |
wbs1_dat_o_r <= wbs1_dat_o; |
wbs1_ack_o_r <= wbs1_ack_o; |
wbs1_err_o_r <= wbs1_err_o; |
wbs1_rty_o_r <= wbs1_rty_o; |
|
end // always @ (posedge wb_clk) |
|
// Slave select |
assign slave_sel[0] = wbm_adr_o_r[`WB_ARB_ADDR_MATCH_SEL] == |
slave0_adr; |
|
assign slave_sel[1] = wbm_adr_o_r[`WB_ARB_ADDR_MATCH_SEL] == |
slave1_adr; |
|
// Slave out assigns |
assign wbs0_adr_i = wbm_adr_o_r; |
assign wbs0_dat_i = wbm_dat_o_r; |
assign wbs0_we_i = wbm_dat_o_r; |
assign wbs0_sel_i = wbm_sel_o_r; |
assign wbs0_cti_i = wbm_cti_o_r; |
assign wbs0_bte_i = wbm_bte_o_r; |
assign wbs0_cyc_i = wbm_cyc_o_r & slave_sel[0]; |
assign wbs0_stb_i = wbm_stb_o_r & slave_sel[0]; |
|
assign wbs1_adr_i = wbm_adr_o_r; |
assign wbs1_dat_i = wbm_dat_o_r; |
assign wbs1_we_i = wbm_dat_o_r; |
assign wbs1_sel_i = wbm_sel_o_r; |
assign wbs1_cti_i = wbm_cti_o_r; |
assign wbs1_bte_i = wbm_bte_o_r; |
assign wbs1_cyc_i = wbm_cyc_o_r & slave_sel[1]; |
assign wbs1_stb_i = wbm_stb_o_r & slave_sel[1]; |
|
// Master out assigns |
// Don't care about none selected... |
assign wbm_dat_i = slave_sel[1] ? wbs1_dat_o_r : |
wbs0_dat_o_r ; |
|
assign wbm_ack_i = (slave_sel[0] & wbs0_ack_o_r) | |
(slave_sel[1] & wbs1_ack_o_r) |
; |
|
assign wbm_err_i = (slave_sel[0] & wbs0_err_o_r) | |
(slave_sel[1] & wbs1_err_o_r) | |
watchdog_err; |
|
assign wbm_rty_i = (slave_sel[0] & wbs0_rty_o_r) | |
(slave_sel[1] & wbs1_rty_o_r); |
|
// Non-registered ack |
assign wbm_ack_i_pre_reg = (slave_sel[0] & wbs0_ack_o) | |
(slave_sel[1] & wbs1_ack_o); |
|
`else // !`ifdef ARBITER_IBUS_REGISTERING |
|
// Slave select |
assign slave_sel[0] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == |
slave0_adr; |
|
assign slave_sel[1] = wbm_adr_o[`WB_ARB_ADDR_MATCH_SEL] == |
slave1_adr; |
|
// Slave out assigns |
assign wbs0_adr_i = wbm_adr_o; |
assign wbs0_dat_i = wbm_dat_o; |
assign wbs0_we_i = wbm_we_o; |
assign wbs0_sel_i = wbm_sel_o; |
assign wbs0_cti_i = wbm_cti_o; |
assign wbs0_bte_i = wbm_bte_o; |
assign wbs0_cyc_i = wbm_cyc_o & slave_sel[0]; |
assign wbs0_stb_i = wbm_stb_o & slave_sel[0]; |
|
assign wbs1_adr_i = wbm_adr_o; |
assign wbs1_dat_i = wbm_dat_o; |
assign wbs1_we_i = wbm_we_o; |
assign wbs1_sel_i = wbm_sel_o; |
assign wbs1_cti_i = wbm_cti_o; |
assign wbs1_bte_i = wbm_bte_o; |
assign wbs1_cyc_i = wbm_cyc_o & slave_sel[1]; |
assign wbs1_stb_i = wbm_stb_o & slave_sel[1]; |
|
// Master out assigns |
// Don't care about none selected... |
assign wbm_dat_i = slave_sel[1] ? wbs1_dat_o : |
wbs0_dat_o ; |
|
assign wbm_ack_i = (slave_sel[0] & wbs0_ack_o) | |
(slave_sel[1] & wbs1_ack_o); |
|
|
assign wbm_err_i = (slave_sel[0] & wbs0_err_o) | |
(slave_sel[1] & wbs1_err_o) | |
watchdog_err; |
|
assign wbm_rty_i = (slave_sel[0] & wbs0_rty_o) | |
(slave_sel[1] & wbs1_rty_o); |
|
|
`endif |
endmodule // arbiter_ibus |
|
/verilog/gpio/gpio.v
0,0 → 1,159
/* |
* |
* Simple 24-bit wide GPIO module |
* |
* Can be made wider as needed, but must be done manually. |
* |
* First lot of bytes are the GPIO I/O regs |
* Second lot are the direction registers |
* |
* Set direction bit to '1' to output corresponding data bit. |
* |
* Register mapping: |
* |
* For 8 GPIOs we would have |
* adr 0: gpio data 7:0 |
* adr 1: gpio data 15:8 |
* adr 2: gpio data 23:16 |
* adr 3: gpio dir 7:0 |
* adr 4: gpio dir 15:8 |
* adr 5: gpio dir 23:16 |
* |
* Backend pinout file needs to be updated for any GPIO width changes. |
* |
*/ |
|
module gpio( |
wb_clk, |
wb_rst, |
|
wb_adr_i, |
wb_dat_i, |
wb_we_i, |
wb_cyc_i, |
wb_stb_i, |
wb_cti_i, |
wb_bte_i, |
|
wb_ack_o, |
wb_dat_o, |
wb_err_o, |
wb_rty_o, |
|
gpio_io); |
|
|
parameter gpio_io_width = 24; |
|
parameter gpio_dir_reset_val = 0; |
parameter gpio_o_reset_val = 0; |
|
|
parameter wb_dat_width = 8; |
parameter wb_adr_width = 3; // 8 bytes addressable |
|
input wb_clk; |
input wb_rst; |
|
input [wb_adr_width-1:0] wb_adr_i; |
input [wb_dat_width-1:0] wb_dat_i; |
input wb_we_i; |
input wb_cyc_i; |
input wb_stb_i; |
input [2:0] wb_cti_i; |
input [1:0] wb_bte_i; |
output reg [wb_dat_width-1:0] wb_dat_o; // constantly sampling gpio in bus |
output reg wb_ack_o; |
output wb_err_o; |
output wb_rty_o; |
|
inout [gpio_io_width-1:0] gpio_io; |
|
// Internal registers |
reg [gpio_io_width-1:0] gpio_dir; |
|
reg [gpio_io_width-1:0] gpio_o; |
|
wire [gpio_io_width-1:0] gpio_i; |
|
// Tristate logic for IO |
genvar i; |
generate |
for (i=0;i<gpio_io_width;i=i+1) begin: gpio_tris |
assign gpio_io[i] = (gpio_dir[i]) ? gpio_o[i] : 1'bz; |
assign gpio_i[i] = (gpio_dir[i]) ? gpio_o[i] : gpio_io[i]; |
end |
endgenerate |
|
// GPIO data out register |
always @(posedge wb_clk) |
if (wb_rst) |
gpio_o <= 0; // All set to in at reset |
else if (wb_stb_i & wb_we_i) |
begin |
if (wb_adr_i == 0) |
gpio_o[7:0] <= wb_dat_i; |
if (wb_adr_i == 1) |
gpio_o[15:8] <= wb_dat_i; |
if (wb_adr_i == 2) |
gpio_o[23:16] <= wb_dat_i; |
/* Add appropriate address detection here for wider GPIO */ |
end |
|
|
// GPIO dir register |
always @(posedge wb_clk) |
if (wb_rst) |
gpio_dir <= 0; // All set to in at reset |
else if (wb_stb_i & wb_we_i) |
begin |
if (wb_adr_i == ((gpio_io_width/8))) |
gpio_dir[7:0] <= wb_dat_i; |
if (wb_adr_i == ((gpio_io_width/8)+1)) |
gpio_dir[15:8] <= wb_dat_i; |
if (wb_adr_i == ((gpio_io_width/8)+2)) |
//gpio_dir[23:16] <= wb_dat_i; |
gpio_dir[21:16] <= wb_dat_i[5:0]; |
|
/* Add appropriate address detection here for wider GPIO */ |
|
end |
|
// Register the gpio in signal |
always @(posedge wb_clk) |
begin |
// Data regs |
if (wb_adr_i == 0) |
wb_dat_o[7:0] <= gpio_i[7:0]; |
if (wb_adr_i == 1) |
wb_dat_o[7:0] <= gpio_i[15:8]; |
if (wb_adr_i == 2) |
wb_dat_o[7:0] <= gpio_i[23:16]; |
/* Add appropriate address detection here for wider GPIO */ |
// Direction regs |
if (wb_adr_i == ((gpio_io_width/8))) |
wb_dat_o[7:0] <= gpio_dir[7:0]; |
if (wb_adr_i == ((gpio_io_width/8)+1)) |
wb_dat_o[7:0] <= gpio_dir[15:8]; |
if (wb_adr_i == ((gpio_io_width/8)+2)) |
wb_dat_o[7:0] <= gpio_dir[23:16]; |
|
/* Add appropriate address detection here for wider GPIO */ |
|
end |
|
|
// Ack generation |
always @(posedge wb_clk) |
if (wb_rst) |
wb_ack_o <= 0; |
else if (wb_ack_o) |
wb_ack_o <= 0; |
else if (wb_stb_i & !wb_ack_o) |
wb_ack_o <= 1; |
|
assign wb_err_o = 0; |
assign wb_rty_o = 0; |
|
|
endmodule // gpio |
/verilog/gpio/README
0,0 → 1,7
GPIO RTL |
|
This is a simple GPIO implementation. It is variable width, however widths of |
multiples of 8 are advised. The first width/8 bytes control are for |
reading/writing to the GPIO registers, the second set of width/8 bytes control |
the direction. |
|