------------------------------------------------------------------------------- -- -- Copyright (C) 2014 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -- -- This program is free software: 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 -- MERCHANTABILITY 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. If not, see <http://www.gnu.org/licenses/>. -- ------------------------------------------------------------------------------- LIBRARY IEEE, common_lib, technology_lib; USE IEEE.STD_LOGIC_1164.ALL; USE common_lib.common_pkg.ALL; USE technology_lib.technology_pkg.ALL; PACKAGE tech_ddr_pkg IS -- Gather all DDR parameters in one record TYPE t_c_tech_ddr IS RECORD -- PHY variant within a technology name : STRING(1 TO 4); -- = "DDR3" or "DDR4" mts : NATURAL; -- = 800 access rate in mega transfers per second master : BOOLEAN; -- = TRUE TRUE = uniphy master, FALSE = uniphy slave regarding OCT and terminationcontrol for DDR3 rank : STRING(1 TO 6); -- = "SINGLE" or "DUAL " -- PHY external FPGA IO a_w : NATURAL; -- = 16 a_row_w : NATURAL; -- = 16 = a_w, row address width, via a_w lines a_col_w : NATURAL; -- = 10 <= a_w, col address width, via a_w lines ba_w : NATURAL; -- = 3 dq_w : NATURAL; -- = 64 dqs_w : NATURAL; -- = 8 = dq_w / nof_dq_per_dqs dm_w : NATURAL; -- = 8 dbi_w : NATURAL; -- = 8 bg_w : NATURAL; -- = 2 ck_w : NATURAL; -- = 2 cke_w : NATURAL; -- = 2 cs_w : NATURAL; -- = 2 = number of chip select lines cs_w_w : NATURAL; -- = 1 = true_log2(cs_w), use when the number of chip select lines is converted to a logical address odt_w : NATURAL; -- = 2 -- PHY internal FPGA IO terminationcontrol_w : NATURAL; -- = 14 internal bus in FPGA -- Controller rsl : NATURAL; -- = 4 = 2 (use both PHY clock edges) * 2 (PHY transfer at double rate), resolution rsl_w : NATURAL; -- = 2 = ceil_log2(rsl) command_queue_depth : NATURAL; -- = 8 maxburstsize : NATURAL; -- = 64 maxburstsize_w : NATURAL; -- = 7 = ceil_log2(maxburstsize+1) END RECORD; FUNCTION func_tech_sel_ddr(g_technology : NATURAL; g_ddr3, g_ddr4 : t_c_tech_ddr) RETURN t_c_tech_ddr; -- Select DDR3 or DDR4 dependent on the technology FUNCTION func_tech_sel_ddr(g_sel : BOOLEAN; a, b : t_c_tech_ddr) RETURN t_c_tech_ddr; -- Select DDR dependent on the boolean FUNCTION func_tech_ddr_dq_address_w( c_ddr : t_c_tech_ddr) RETURN NATURAL; -- return DDR address width for the DQ data at the PHY mts rate FUNCTION func_tech_ddr_ctlr_address_w(c_ddr : t_c_tech_ddr) RETURN NATURAL; -- return DDR address width for the controller data at the by rsl=4 reduced rate FUNCTION func_tech_ddr_ctlr_data_w( c_ddr : t_c_tech_ddr) RETURN NATURAL; -- return DDR data width for the controller data at the by rsl=4 reduced rate FUNCTION func_tech_ddr_module_size( c_ddr : t_c_tech_ddr) RETURN NATURAL; -- return DDR module size in GByte -- a a -- name mts master rank a row col ba dq dqs dm dbi bg ck cke cs cs_w odt term rsl rsl_w cqd burst burst_w CONSTANT c_tech_ddr3_max : t_c_tech_ddr := ("none", 800, TRUE, "DUAL ", 16, 16, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); -- maximum ranges for record field definitions CONSTANT c_tech_ddr3_sim_8k : t_c_tech_ddr := ("DDR3", 800, TRUE, "DUAL ", 10, 1, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col - rsl_w) CONSTANT c_tech_ddr3_sim_16k : t_c_tech_ddr := ("DDR3", 800, TRUE, "DUAL ", 10, 2, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col - rsl_w) CONSTANT c_tech_ddr3_sim_128k : t_c_tech_ddr := ("DDR3", 800, TRUE, "DUAL ", 10, 5, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col - rsl_w) CONSTANT c_tech_ddr3_sim_1m : t_c_tech_ddr := ("DDR3", 800, TRUE, "DUAL ", 10, 8, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col - rsl_w) CONSTANT c_tech_ddr3_4g_800m_master : t_c_tech_ddr := ("DDR3", 800, TRUE, "DUAL ", 15, 15, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); CONSTANT c_tech_ddr3_4g_800m_slave : t_c_tech_ddr := ("DDR3", 800, FALSE, "DUAL ", 15, 15, 10, 3, 64, 8, 8, 0, 0, 2, 2, 2, 1, 2, 14, 4, 2, 4, 64, 7); CONSTANT c_tech_ddr3_4g_single_rank_800m_master : t_c_tech_ddr := ("DDR3", 800, TRUE, "SINGLE", 16, 16, 10, 3, 64, 8, 8, 0, 0, 2, 1, 1, 0, 1, 14, 4, 2, 4, 64, 7); CONSTANT c_tech_ddr3_4g_single_rank_800m_slave : t_c_tech_ddr := ("DDR3", 800, FALSE, "SINGLE", 16, 16, 10, 3, 64, 8, 8, 0, 0, 2, 1, 1, 0, 1, 14, 4, 2, 4, 64, 7); CONSTANT c_tech_ddr4_max : t_c_tech_ddr := ("none", 1600, TRUE, "DUAL ", 17, 15, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- maximum ranges for record field definitions CONSTANT c_tech_ddr4_sim_4k : t_c_tech_ddr := ("DDR4", 800, TRUE, "DUAL ", 10, 1, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col + bg_w - rsl_w) CONSTANT c_tech_ddr4_sim_8k : t_c_tech_ddr := ("DDR4", 800, TRUE, "DUAL ", 10, 2, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col + bg_w - rsl_w) CONSTANT c_tech_ddr4_sim_16k : t_c_tech_ddr := ("DDR4", 800, TRUE, "DUAL ", 10, 3, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col + bg_w - rsl_w) CONSTANT c_tech_ddr4_sim_128k : t_c_tech_ddr := ("DDR4", 800, TRUE, "DUAL ", 10, 6, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col + bg_w - rsl_w) CONSTANT c_tech_ddr4_sim_1m : t_c_tech_ddr := ("DDR4", 800, TRUE, "DUAL ", 10, 9, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- use a_row to set nof ctrl addr = 2**(cs_w + ba + a_row + a_col + bg_w - rsl_w) CONSTANT c_tech_ddr4_4g_1600m : t_c_tech_ddr := ("DDR4", 1600, TRUE, "DUAL ", 17, 15, 10, 2, 72, 9, 0, 9, 2, 1, 1, 1, 0, 1, 0, 8, 3, 8, 64, 7); -- PHY in, inout and out signal records TYPE t_tech_ddr3_phy_in IS RECORD -- DDR3 Description evt : STD_LOGIC; -- event signal is Not Connected to DDR3 PHY oct_rup : STD_LOGIC; -- only master DDR3 PHY has On Chip Termination OCT inputs oct_rdn : STD_LOGIC; -- only master DDR3 PHY has On Chip Termination OCT inputs END RECORD; TYPE t_tech_ddr4_phy_in IS RECORD -- DDR4 Description evt : STD_LOGIC; -- event signal alert_n : STD_LOGIC; -- alert signal oct_rzqin : STD_LOGIC; -- PHY has On Chip Termination OCT inputs END RECORD; TYPE t_tech_ddr3_phy_io IS RECORD -- DDR3 Description dq : STD_LOGIC_VECTOR(c_tech_ddr3_max.dq_w-1 DOWNTO 0); -- data bus dqs : STD_LOGIC_VECTOR(c_tech_ddr3_max.dqs_w-1 DOWNTO 0); -- data strobe bus dqs_n : STD_LOGIC_VECTOR(c_tech_ddr3_max.dqs_w-1 DOWNTO 0); -- data strobe bus negative scl : STD_LOGIC; -- I2C clock sda : STD_LOGIC; -- I2C data END RECORD; TYPE t_tech_ddr4_phy_io IS RECORD -- DDR4 Description dq : STD_LOGIC_VECTOR(c_tech_ddr4_max.dq_w-1 DOWNTO 0); -- data bus dqs : STD_LOGIC_VECTOR(c_tech_ddr4_max.dqs_w-1 DOWNTO 0); -- data strobe bus dqs_n : STD_LOGIC_VECTOR(c_tech_ddr4_max.dqs_w-1 DOWNTO 0); -- data strobe bus negative dbi_n : STD_LOGIC_VECTOR(c_tech_ddr4_max.dbi_w-1 DOWNTO 0); -- data bus inversion END RECORD; TYPE t_tech_ddr3_phy_ou IS RECORD -- DDR3 Description a : STD_LOGIC_VECTOR(c_tech_ddr3_max.a_w-1 DOWNTO 0); -- row and column address ba : STD_LOGIC_VECTOR(c_tech_ddr3_max.ba_w-1 DOWNTO 0); -- bank address dm : STD_LOGIC_VECTOR(c_tech_ddr3_max.dm_w-1 DOWNTO 0); -- data mask bus ras_n : STD_LOGIC; -- row address strobe cas_n : STD_LOGIC; -- column address strobe we_n : STD_LOGIC; -- write enable signal reset_n : STD_LOGIC; -- reset signal ck : STD_LOGIC_VECTOR(c_tech_ddr3_max.ck_w-1 DOWNTO 0); -- clock, positive edge clock ck_n : STD_LOGIC_VECTOR(c_tech_ddr3_max.ck_w-1 DOWNTO 0); -- clock, negative edge clock cke : STD_LOGIC_VECTOR(c_tech_ddr3_max.cke_w-1 DOWNTO 0); -- clock enable cs_n : STD_LOGIC_VECTOR(c_tech_ddr3_max.cs_w-1 DOWNTO 0); -- chip select odt : STD_LOGIC_VECTOR(c_tech_ddr3_max.odt_w-1 DOWNTO 0); -- on-die termination control signal END RECORD; TYPE t_tech_ddr4_phy_ou IS RECORD -- DDR4 Description a : STD_LOGIC_VECTOR(c_tech_ddr4_max.a_w-1 DOWNTO 0); -- row and column address (note eg. a[16]=ras_n, a[15]=cas_n, a[14]=we_n) ba : STD_LOGIC_VECTOR(c_tech_ddr4_max.ba_w-1 DOWNTO 0); -- bank address bg : STD_LOGIC_VECTOR(c_tech_ddr4_max.bg_w-1 DOWNTO 0); -- bank group act_n : STD_LOGIC; -- activate signal par : STD_LOGIC; -- parity signal reset_n : STD_LOGIC; -- reset signal ck : STD_LOGIC_VECTOR(c_tech_ddr4_max.ck_w-1 DOWNTO 0); -- clock, positive edge clock ck_n : STD_LOGIC_VECTOR(c_tech_ddr4_max.ck_w-1 DOWNTO 0); -- clock, negative edge clock cke : STD_LOGIC_VECTOR(c_tech_ddr4_max.cke_w-1 DOWNTO 0); -- clock enable cs_n : STD_LOGIC_VECTOR(c_tech_ddr4_max.cs_w-1 DOWNTO 0); -- chip select odt : STD_LOGIC_VECTOR(c_tech_ddr4_max.odt_w-1 DOWNTO 0); -- on-die termination control signal END RECORD; TYPE t_tech_ddr3_phy_in_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr3_phy_in; TYPE t_tech_ddr3_phy_io_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr3_phy_io; TYPE t_tech_ddr3_phy_ou_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr3_phy_ou; TYPE t_tech_ddr4_phy_in_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr4_phy_in; TYPE t_tech_ddr4_phy_io_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr4_phy_io; TYPE t_tech_ddr4_phy_ou_arr IS ARRAY(NATURAL RANGE <>) OF t_tech_ddr4_phy_ou; TYPE t_tech_ddr3_phy_terminationcontrol IS RECORD -- DDR3 Termination control seriesterminationcontrol : STD_LOGIC_VECTOR(c_tech_ddr3_max.terminationcontrol_w-1 DOWNTO 0); -- termination control from master to slave DDR3 PHY (internal signal in FPGA) parallelterminationcontrol : STD_LOGIC_VECTOR(c_tech_ddr3_max.terminationcontrol_w-1 DOWNTO 0); -- termination control from master to slave DDR3 PHY (internal signal in FPGA) END RECORD; CONSTANT c_tech_ddr3_phy_terminationcontrol_x : t_tech_ddr3_phy_terminationcontrol := ((OTHERS=>'X'), (OTHERS=>'X')); CONSTANT c_tech_ddr3_phy_terminationcontrol_rst : t_tech_ddr3_phy_terminationcontrol := ((OTHERS=>'0'), (OTHERS=>'0')); CONSTANT c_tech_ddr3_phy_in_x : t_tech_ddr3_phy_in := ('X', 'X', 'X'); CONSTANT c_tech_ddr4_phy_in_x : t_tech_ddr4_phy_in := ('X', 'X', 'X'); CONSTANT c_tech_ddr3_phy_ou_x : t_tech_ddr3_phy_ou := ((OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), 'X', 'X', 'X', 'X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X')); CONSTANT c_tech_ddr4_phy_ou_x : t_tech_ddr4_phy_ou := ((OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), 'X', 'X', 'X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X')); END tech_ddr_pkg; PACKAGE BODY tech_ddr_pkg IS FUNCTION func_tech_sel_ddr(g_technology : NATURAL; g_ddr3, g_ddr4 : t_c_tech_ddr) RETURN t_c_tech_ddr IS BEGIN CASE g_technology IS WHEN c_tech_stratixiv => RETURN g_ddr3; WHEN c_tech_arria10 => RETURN g_ddr4; WHEN OTHERS => RETURN g_ddr3; END CASE; END; FUNCTION func_tech_sel_ddr(g_sel : BOOLEAN; a, b : t_c_tech_ddr) RETURN t_c_tech_ddr IS BEGIN IF g_sel=TRUE THEN RETURN a; ELSE RETURN b; END IF; END; FUNCTION func_tech_ddr_dq_address_w(c_ddr : t_c_tech_ddr) RETURN NATURAL IS BEGIN IF c_ddr.name="DDR3" THEN RETURN c_ddr.cs_w_w + c_ddr.ba_w + c_ddr.a_row_w + c_ddr.a_col_w; END IF; -- PHY address IF c_ddr.name="DDR4" THEN RETURN c_ddr.cs_w_w + c_ddr.ba_w + c_ddr.a_row_w + c_ddr.a_col_w + c_ddr.bg_w; END IF; -- PHY address END; FUNCTION func_tech_ddr_ctlr_address_w(c_ddr : t_c_tech_ddr) RETURN NATURAL IS CONSTANT c_dq_address_w : NATURAL := func_tech_ddr_dq_address_w(c_ddr); BEGIN RETURN c_dq_address_w-c_ddr.rsl_w; -- CTLR address END; FUNCTION func_tech_ddr_ctlr_data_w(c_ddr : t_c_tech_ddr) RETURN NATURAL IS BEGIN RETURN c_ddr.dq_w*c_ddr.rsl; -- CTLR data END; FUNCTION func_tech_ddr_module_size(c_ddr : t_c_tech_ddr) RETURN NATURAL IS CONSTANT c_dq_address_w : NATURAL := func_tech_ddr_dq_address_w(c_ddr); CONSTANT c_dq_nof_bytes : NATURAL := 8; -- both dw_q = 64 and 72 are regarded as having 8 bytes (either with 8 or 9 bits per byte) CONSTANT c_dq_nof_bytes_w : NATURAL := ceil_log2(c_dq_nof_bytes); CONSTANT c_module_nof_bytes_w : NATURAL := c_dq_address_w + c_dq_nof_bytes_w; CONSTANT c_1GB_w : NATURAL := 30; BEGIN IF c_module_nof_bytes_w < c_1GB_w THEN RETURN 0; ELSE RETURN 2**(c_module_nof_bytes_w-c_1GB_w); END IF; END; END tech_ddr_pkg;