URL
https://opencores.org/ocsvn/wbddr3/wbddr3/trunk
Subversion Repositories wbddr3
[/] [wbddr3/] [trunk/] [rtl/] [ddr3insert.v] - Rev 20
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: ddr3insert.v // // Project: A wishbone controlled DDR3 SDRAM memory controller. // // Purpose: Since the DDR3 RAM requires I/O resources not available // in Verilog alone, this insert (i.e. include file) is designed // to be included from a top-level block that would otherwise use the // DDR3 SDRAM. It is meant to encapsulate the I/O resource requirements // and connections required to make the DDR3 SDRAM work. // // // This file is not a module in its own right, but rather a file // included in a larger module. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2016, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program. (It's in the $(ROOT)/doc directory, run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // // EXTERNAL PINS (BOTH INPUT AND OUTPUT): // o_ddr_reset_n, o_ddr_cke, o_ddr_ck_p, o_ddr_ck_n // o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n, // io_ddr_dqs_p, io_ddr_dqs_n, // o_ddr_addr, o_ddr_ba, // io_ddr_data, o_ddr_dm, o_ddr_odt // // INPUTS: (from elsewhere in the toplevel module) // pwr_reset True for one clock at power on // i_clk 200 MHz clock used in fabric // clk_for_ddr 800 MHz clock to send to memory clk pins // mem_serial_clk 800 MHz clock to drive serdes's // mem_serial_clk_inv The inverse of the 800 MHz clock ... // // // LOCAL VARIABLES PROVIDED: // (These come from the controller) // [3:0] w_ddr_cs_n, w_ddr_ras_n, w_ddr_cas_n, w_ddr_we_n // [11:0] w_ddr_ba, divided into // { w_ddr_ba[11:9], w_ddr_ba[8:6], w_ddr[5:3], w_ddr_ba[2:0] } // [55:0] w_ddr_addr // { w_ddr_addr[55:42], w_ddr_addr[41:28], w_ddr_addr[27:14], // w_ddr_addr[13:0] } // [7:0] w_ddr_odt // On-die termination // [7:0] w_ddr_odt // On-die termination // [15:0] w_ddr_dm // Data mask, headed to memory // [127:0] wo_ddr_data // Data going to the memory // [127:0] wi_ddr_data // The data returned by the memory // // // wire w_ddr_reset_n, w_ddr_cke, w_ddr_bus_oe; wire [26:0] w_ddr_cmd_a, w_ddr_cmd_b; wire [63:0] wi_ddr_data, wo_ddr_data; wire [127:0] wide_ddr_data; // // // Wires for setting up the DDR3 memory // // // First, let's set up the clock(s) xoddrserdesb ddrclk(mem_serial_clk, i_clk, pwr_reset, 8'h66, o_ddr_ck_p, o_ddr_ck_n); wire [7:0] w_udqs_in, w_ldqs_in; xioddrserdesb ddrudqs(mem_serial_clk, mem_serial_clk_inv, i_clk, ~w_ddr_reset_n, w_ddr_cmd_a[0], (w_ddr_cmd_b[0])? 8'h66 : 8'h06, w_udqs_in, io_ddr_dqs_p[1], io_ddr_dqs_n[1]); xioddrserdesb ddrldqs(mem_serial_clk, mem_serial_clk_inv, i_clk, ~w_ddr_reset_n, w_ddr_cmd_a[0], (w_ddr_cmd_b[0])? 8'h66 : 8'h06, w_ldqs_in, io_ddr_dqs_p[0], io_ddr_dqs_n[0]); // The command wires: CS_N, RAS_N, CAS_N, and WE_N xoddrserdes ddrcsn(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[26], w_ddr_cmd_a[26], w_ddr_cmd_a[26], w_ddr_cmd_a[26], w_ddr_cmd_b[26], w_ddr_cmd_b[26], w_ddr_cmd_b[26], w_ddr_cmd_b[26] }, o_ddr_cs_n); xoddrserdes ddrrasn(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[25], w_ddr_cmd_a[25], w_ddr_cmd_a[25], w_ddr_cmd_a[25], w_ddr_cmd_b[25], w_ddr_cmd_b[25], w_ddr_cmd_b[25], w_ddr_cmd_b[25] }, o_ddr_ras_n); xoddrserdes ddrcasn(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[24], w_ddr_cmd_a[24], w_ddr_cmd_a[24], w_ddr_cmd_a[24], w_ddr_cmd_b[24], w_ddr_cmd_b[24], w_ddr_cmd_b[24], w_ddr_cmd_b[24] }, o_ddr_cas_n); xoddrserdes ddrwen(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[23], w_ddr_cmd_a[23], w_ddr_cmd_a[23], w_ddr_cmd_a[23], w_ddr_cmd_b[23], w_ddr_cmd_b[23], w_ddr_cmd_b[23], w_ddr_cmd_b[23] }, o_ddr_we_n); // Data mask wires, first the upper byte xoddrserdes ddrudm(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[4], w_ddr_cmd_a[4], w_ddr_cmd_a[2], w_ddr_cmd_a[2], w_ddr_cmd_b[4], w_ddr_cmd_b[4], w_ddr_cmd_b[2], w_ddr_cmd_b[2] }, o_ddr_dm[1]); // then the lower byte xoddrserdes ddrldm(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[3], w_ddr_cmd_a[3], w_ddr_cmd_a[1], w_ddr_cmd_a[1], w_ddr_cmd_b[3], w_ddr_cmd_b[3], w_ddr_cmd_b[1], w_ddr_cmd_b[1] }, o_ddr_dm[0]); // and the On-Die termination wire xoddrserdes ddrodt(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[0], w_ddr_cmd_a[0], w_ddr_cmd_a[0], w_ddr_cmd_a[0], w_ddr_cmd_b[0], w_ddr_cmd_b[0], w_ddr_cmd_b[0], w_ddr_cmd_b[0] }, o_ddr_odt); // // Now for the data, bank, and address wires // genvar k; generate begin // for(k=0; k<16; k=k+1) xioddrserdes ddrdata(mem_serial_clk, mem_serial_clk_inv, i_clk, ~w_ddr_reset_n, w_ddr_bus_oe, { wo_ddr_data[48+k], wo_ddr_data[48+k], wo_ddr_data[32+k], wo_ddr_data[32+k], wo_ddr_data[16+k], wo_ddr_data[16+k], wo_ddr_data[ k], wo_ddr_data[ k] }, { wide_ddr_data[112+k], wide_ddr_data[96+k], wide_ddr_data[ 80+k], wide_ddr_data[64+k], wide_ddr_data[ 48+k], wide_ddr_data[32+k], wide_ddr_data[ 16+k], wide_ddr_data[ k] }, io_ddr_data[k]); // for(k=0; k<3; k=k+1) xoddrserdes ddrbank(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k], w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k] }, o_ddr_ba[k]); // for(k=0; k<14; k=k+1) xoddrserdes ddraddr(mem_serial_clk, i_clk, ~w_ddr_reset_n, { w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k], w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k] }, o_ddr_addr[k]); // for(k=0; k<64; k=k+1) assign wi_ddr_data[k] = (w_ddr_bus_oe) ? wide_ddr_data[2*k+1] : wide_ddr_data[2*k]; end endgenerate assign o_ddr_reset_n = w_ddr_reset_n; assign o_ddr_cke = w_ddr_cke;
Go to most recent revision | Compare with Previous | Blame | View Log