Select Git revision
tech_ddr_arria10.vhd
-
Pieter Donker authoredPieter Donker authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tech_ddr_arria10.vhd 10.50 KiB
--------------------------------------------------------------------------------
--
-- Copyright (C) 2015
-- 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/>.
--
--------------------------------------------------------------------------------
-- Purpose: DDR4 memory access component for Arria10.
-- Description:
-- Remarks:
-- . The local_init_done goes high some time after power up. It could have been
-- AND-ed with ctlr_miso.waitrequest_n. However the timing closure for
-- ctlr_miso.waitrequest_n can be critical, so therefore it is better not
-- to combinatorially load it with the AND local_init_done. Instead a
-- ctlr_miso.done field was added and used to pass on local_init_done. In fact
-- for normal operation it is sufficient to only wait for
-- ctlr_miso.waitrequest_n. The ctlr_miso.init_done is then only used for
-- DDR interface monitoring purposes.
-- Declare IP libraries to ensure default binding in simulation. The IP library clause is ignored by synthesis.
library ip_arria10_ddr4_4g_1600_altera_emif_150;
library ip_arria10_ddr4_4g_2000_altera_emif_150;
library IEEE, technology_lib, common_lib;
use IEEE.std_logic_1164.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
use technology_lib.technology_pkg.all;
use work.tech_ddr_pkg.all;
use work.tech_ddr_component_pkg.all;
entity tech_ddr_arria10 is
generic (
g_tech_ddr : t_c_tech_ddr
);
port (
-- PLL reference clock
ref_clk : in std_logic;
ref_rst : in std_logic;
-- Controller user interface
ctlr_gen_clk : out std_logic;
ctlr_gen_rst : out std_logic;
ctlr_mosi : in t_mem_ctlr_mosi;
ctlr_miso : out t_mem_ctlr_miso;
-- PHY interface
phy_in : in t_tech_ddr4_phy_in;
phy_io : inout t_tech_ddr4_phy_io;
phy_ou : out t_tech_ddr4_phy_ou
);
end tech_ddr_arria10;
architecture str of tech_ddr_arria10 is
constant c_gigabytes : integer := func_tech_ddr_module_gigabytes(g_tech_ddr);
constant c_ctlr_address_w : natural := 26; -- func_tech_ddr_ctlr_address_w(g_tech_ddr);
constant c_ctlr_data_w : natural := 576; -- func_tech_ddr_ctlr_data_w( g_tech_ddr);
signal i_ctlr_gen_clk : std_logic;
signal ref_rst_n : std_logic;
signal ctlr_gen_rst_n : std_logic := '0';
signal local_cal_success : std_logic;
signal local_cal_fail : std_logic;
begin
ctlr_gen_clk <= i_ctlr_gen_clk;
ref_rst_n <= not ref_rst;
ctlr_gen_rst <= not ctlr_gen_rst_n;
gen_ip_arria10_ddr4_4g_2000 : if g_tech_ddr.name = "DDR4" and c_gigabytes = 4 and g_tech_ddr.mts = 2000 generate
phy_ou.cs_n(1) <= '1';
phy_ou.cke(1) <= '0';
phy_ou.odt(1) <= '0';
u_ip_arria10_ddr4_4g_2000 : ip_arria10_ddr4_4g_2000
port map (
amm_ready_0 => ctlr_miso.waitrequest_n, -- ctrl_amm_avalon_slave_0.waitrequest_n
amm_read_0 => ctlr_mosi.rd, -- .read
amm_write_0 => ctlr_mosi.wr, -- .write
amm_address_0 => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0), -- .address
amm_readdata_0 => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0), -- .readdata
amm_writedata_0 => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0), -- .writedata
amm_burstcount_0 => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0), -- .burstcount
amm_byteenable_0 => (others => '1'), -- .byteenable
amm_readdatavalid_0 => ctlr_miso.rdval, -- .readdatavalid
emif_usr_clk => i_ctlr_gen_clk, -- emif_usr_clk_clock_source.clk
emif_usr_reset_n => ctlr_gen_rst_n, -- emif_usr_reset_reset_source.reset_n
global_reset_n => ref_rst_n, -- global_reset_reset_sink.reset_n
mem_ck => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0), -- mem_conduit_end.mem_ck
mem_ck_n => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0), -- .mem_ck_n
mem_a => phy_ou.a(g_tech_ddr.a_w - 1 downto 0), -- .mem_a
sl(mem_act_n) => phy_ou.act_n, -- .mem_act_n
mem_ba => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0), -- .mem_ba
mem_bg => phy_ou.bg(g_tech_ddr.bg_w - 1 downto 0), -- .mem_bg
mem_cke => phy_ou.cke(g_tech_ddr.cke_w - 1 downto 0), -- .mem_cke
mem_cs_n => phy_ou.cs_n(g_tech_ddr.cs_w - 1 downto 0), -- .mem_cs_n
mem_odt => phy_ou.odt(g_tech_ddr.odt_w - 1 downto 0), -- .mem_odt
sl(mem_reset_n) => phy_ou.reset_n, -- .mem_reset_n
sl(mem_par) => phy_ou.par, -- .mem_par
mem_alert_n => slv(phy_in.alert_n), -- .mem_alert_n
mem_dqs => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0), -- .mem_dqs
mem_dqs_n => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0), -- .mem_dqs_n
mem_dq => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0), -- .mem_dq
mem_dbi_n => phy_io.dbi_n(g_tech_ddr.dbi_w - 1 downto 0), -- .mem_dbi_n
oct_rzqin => phy_in.oct_rzqin, -- oct_conduit_end.oct_rzqin
pll_ref_clk => ref_clk, -- pll_ref_clk_clock_sink.clk
local_cal_success => local_cal_success, -- status_conduit_end.local_cal_success
local_cal_fail => local_cal_fail -- .local_cal_fail
);
-- Signals in DDR3 that are not available with DDR4:
--
--avl_burstbegin => ctlr_mosi.burstbegin, -- .beginbursttransfer
-- beginbursttransfer is obselete for new Avalon designs, because the slave can count valid data itself to know when a new burst starts
--
--local_init_done => ctlr_miso.done, -- status.local_init_done
-- local_init_done = ctlr_init_done originally and mapped to ctlr_miso.done for the DDR3 IP. For the DDR4 IP the local_cal_success and
-- NOT local_cal_fail seem to serve as local_init_done
ctlr_miso.done <= local_cal_success and not local_cal_fail when rising_edge(i_ctlr_gen_clk);
ctlr_miso.cal_ok <= local_cal_success;
ctlr_miso.cal_fail <= local_cal_fail;
end generate;
gen_ip_arria10_ddr4_4g_1600 : if g_tech_ddr.name = "DDR4" and c_gigabytes = 4 and g_tech_ddr.mts = 1600 generate
phy_ou.cs_n(1) <= '1';
phy_ou.cke(1) <= '0';
phy_ou.odt(1) <= '0';
u_ip_arria10_ddr4_4g_1600 : ip_arria10_ddr4_4g_1600
port map (
amm_ready_0 => ctlr_miso.waitrequest_n, -- ctrl_amm_avalon_slave_0.waitrequest_n
amm_read_0 => ctlr_mosi.rd, -- .read
amm_write_0 => ctlr_mosi.wr, -- .write
amm_address_0 => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0), -- .address
amm_readdata_0 => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0), -- .readdata
amm_writedata_0 => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0), -- .writedata
amm_burstcount_0 => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0), -- .burstcount
amm_byteenable_0 => (others => '1'), -- .byteenable
amm_readdatavalid_0 => ctlr_miso.rdval, -- .readdatavalid
emif_usr_clk => i_ctlr_gen_clk, -- emif_usr_clk_clock_source.clk
emif_usr_reset_n => ctlr_gen_rst_n, -- emif_usr_reset_reset_source.reset_n
global_reset_n => ref_rst_n, -- global_reset_reset_sink.reset_n
mem_ck => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0), -- mem_conduit_end.mem_ck
mem_ck_n => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0), -- .mem_ck_n
mem_a => phy_ou.a(g_tech_ddr.a_w - 1 downto 0), -- .mem_a
sl(mem_act_n) => phy_ou.act_n, -- .mem_act_n
mem_ba => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0), -- .mem_ba
mem_bg => phy_ou.bg(g_tech_ddr.bg_w - 1 downto 0), -- .mem_bg
mem_cke => phy_ou.cke(g_tech_ddr.cke_w - 1 downto 0), -- .mem_cke
mem_cs_n => phy_ou.cs_n(g_tech_ddr.cs_w - 1 downto 0), -- .mem_cs_n
mem_odt => phy_ou.odt(g_tech_ddr.odt_w - 1 downto 0), -- .mem_odt
sl(mem_reset_n) => phy_ou.reset_n, -- .mem_reset_n
sl(mem_par) => phy_ou.par, -- .mem_par
mem_alert_n => slv(phy_in.alert_n), -- .mem_alert_n
mem_dqs => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0), -- .mem_dqs
mem_dqs_n => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0), -- .mem_dqs_n
mem_dq => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0), -- .mem_dq
mem_dbi_n => phy_io.dbi_n(g_tech_ddr.dbi_w - 1 downto 0), -- .mem_dbi_n
oct_rzqin => phy_in.oct_rzqin, -- oct_conduit_end.oct_rzqin
pll_ref_clk => ref_clk, -- pll_ref_clk_clock_sink.clk
local_cal_success => local_cal_success, -- status_conduit_end.local_cal_success
local_cal_fail => local_cal_fail -- .local_cal_fail
);
-- Signals in DDR3 that are not available with DDR4:
--
--avl_burstbegin => ctlr_mosi.burstbegin, -- .beginbursttransfer
-- beginbursttransfer is obselete for new Avalon designs, because the slave can count valid data itself to know when a new burst starts
--
--local_init_done => ctlr_miso.done, -- status.local_init_done
-- local_init_done = ctlr_init_done originally and mapped to ctlr_miso.done for the DDR3 IP. For the DDR4 IP the local_cal_success and
-- NOT local_cal_fail seem to serve as local_init_done
ctlr_miso.done <= local_cal_success and not local_cal_fail when rising_edge(i_ctlr_gen_clk);
ctlr_miso.cal_ok <= local_cal_success;
ctlr_miso.cal_fail <= local_cal_fail;
end generate;
end str;