Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ddr3.vhd 14.41 KiB
--------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- 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/>.
--
--------------------------------------------------------------------------------
-- Declare IP libraries to ensure default binding in simulation. The IP library clause is ignored by synthesis.
library ip_stratixiv_ddr3_uphy_4g_800_master_lib;
library ip_stratixiv_ddr3_uphy_4g_800_slave_lib;
library IEEE, common_lib, technology_lib, dp_lib, tech_ddr_lib;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
use technology_lib.technology_select_pkg.all;
use technology_lib.technology_pkg.all;
use dp_lib.dp_stream_pkg.all;
use tech_ddr_lib.tech_ddr_pkg.all;
use work.ddr3_pkg.all;
entity ddr3 is
generic(
g_phy : natural := 1; -- 0: ALTMEMPHY 1: UNIPHY_MASTER 2: UNIPHY_SLAVE
g_ddr : t_c_ddr3_phy;
g_mts : natural := 800; -- Megatransfers per second
g_wr_data_w : natural := c_ddr3_ctlr_data_w;
g_wr_use_ctrl : boolean := false; -- TRUE to allow filling the WR FIFO (by disabling flush) after an EOP
g_wr_fifo_depth : natural := 128; -- >=16 AND >c_ddr3_ctlr_maxburstsize , defined at read side of write FIFO.
g_rd_fifo_depth : natural := 256; -- >=16 AND >c_ddr3_ctlr_maxburstsize > c_ddr3_ctrl_nof_latent_reads, defined at write side of read FIFO.
g_rd_data_w : natural := c_ddr3_ctlr_data_w;
g_flush_wr_fifo : boolean := false; -- TRUE instantiates a dp_flush + controller to flush the write fifo when the driver is not ready to write
g_flush_ext_ena : boolean := false; -- TRUE enables the external flush_ena signal and discards flushing when driver is not ready. FALSE enables flushing when driver is not ready
g_flush_sop : boolean := false; -- When FALSE, flushing is stopped by valid data. When TRUE flushing is stopped by SOP
g_flush_sop_sync : boolean := false; -- When TRUE, flushing is stopped by receiving SOP and SYNC
g_flush_sop_channel : boolean := false; -- WHEN TRUE, flushing is stopped by receiving SOP and specified channel.
g_flush_sop_start_channel : natural := 0;
g_flush_nof_channels : natural := 0
);
port (
-- MM clock + reset
mm_rst : in std_logic := '0';
mm_clk : in std_logic := '0';
ctlr_ref_clk : in std_logic;
ctlr_rst : in std_logic; -- asynchronous reset input to controller
ctlr_gen_clk : out std_logic; -- Controller generated clock
ctlr_gen_rst : out std_logic;
ctlr_gen_clk_2x : out std_logic; -- Controller generated double frequency clock
ctlr_gen_rst_2x : out std_logic; -- ctlr_gen_rst synchronized to ctlr_gen_clk_2x
ctlr_init_done : out std_logic;
ctlr_rdy : out std_logic;
dvr_start_addr : in t_ddr3_addr;
dvr_end_addr : in t_ddr3_addr;
dvr_en : in std_logic;
dvr_wr_not_rd : in std_logic;
dvr_done : out std_logic;
wr_clk : in std_logic;
wr_rst : in std_logic;
-- MM register map for DDR controller status info
reg_io_ddr_mosi : in t_mem_mosi := c_mem_mosi_rst;
reg_io_ddr_miso : out t_mem_miso := c_mem_miso_rst;
flush_ena : in std_logic; -- When toggled '1' the write-fifo flusher is enabled and stops flushing when configured trigger condition is met.
wr_sosi : in t_dp_sosi;
wr_siso : out t_dp_siso;
rd_sosi : out t_dp_sosi;
rd_siso : in t_dp_siso;
rd_clk : in std_logic;
rd_rst : in std_logic;
rd_fifo_usedw : out std_logic_vector(ceil_log2(g_rd_fifo_depth * (c_ddr3_ctlr_data_w / g_rd_data_w) ) - 1 downto 0);
ser_term_ctrl_out : out std_logic_vector(13 downto 0);
par_term_ctrl_out : out std_logic_vector(13 downto 0);
ser_term_ctrl_in : in std_logic_vector(13 downto 0) := (others => '0');
par_term_ctrl_in : in std_logic_vector(13 downto 0) := (others => '0');
phy_in : in t_tech_ddr3_phy_in;
phy_io : inout t_tech_ddr3_phy_io;
phy_ou : out t_tech_ddr3_phy_ou
);
end ddr3;
architecture str of ddr3 is
constant c_wr_fifo_depth : natural := g_wr_fifo_depth * (c_ddr3_ctlr_data_w / g_wr_data_w); -- Multiply fifo depth by the fifo's rd/wr width ratio to get write side depth
constant c_latency : natural := 1;
constant c_ctlr_address_w : natural := func_tech_ddr_ctlr_address_w(c_tech_ddr3_4g_800m_master);
constant c_ctlr_data_w : natural := func_tech_ddr_ctlr_data_w(c_tech_ddr3_4g_800m_master);
signal ctlr_burst : std_logic;
signal ctlr_burst_size : std_logic_vector(c_ddr3_ctlr_maxburstsize_w - 1 downto 0);
signal ctlr_rd_req : std_logic;
signal ctlr_wr_req : std_logic;
signal ctlr_gen_rst_n : std_logic;
signal i_ctlr_gen_clk : std_logic;
signal i_ctlr_gen_rst : std_logic;
signal i_ctlr_gen_clk_2x : std_logic;
signal i_ctlr_init_done : std_logic;
signal i_ctlr_rdy : std_logic;
signal i_dvr_done : std_logic;
signal dvr_cur_addr : t_ddr3_addr;
signal dvr_flush : std_logic := '0';
signal ctlr_wr_siso : t_dp_siso := c_dp_siso_rdy; -- default xon='1'
signal ctlr_wr_sosi : t_dp_sosi;
signal flush_wr_siso : t_dp_siso;
signal flush_wr_sosi : t_dp_sosi;
signal ctlr_rd_siso : t_dp_siso;
signal ctlr_rd_sosi : t_dp_sosi;
signal wr_fifo_usedw : std_logic_vector(ceil_log2(g_wr_fifo_depth) - 1 downto 0); -- read side depth of the write FIFO
signal local_cal_success : std_logic;
signal local_cal_fail : std_logic;
constant c_mem_reg_io_ddr : t_c_mem := (c_mem_reg_rd_latency, 1, 32, 1, 'X');
signal mm_reg_io_ddr : std_logic_vector(31 downto 0);
signal term_ctrl_out : t_tech_ddr3_phy_terminationcontrol;
signal term_ctrl_in : t_tech_ddr3_phy_terminationcontrol;
signal ctlr_tech_mosi : t_mem_ctlr_mosi;
signal ctlr_tech_miso : t_mem_ctlr_miso;
begin
dvr_done <= i_dvr_done;
ctlr_gen_clk <= i_ctlr_gen_clk;
ctlr_gen_rst <= i_ctlr_gen_rst;
ctlr_gen_clk_2x <= i_ctlr_gen_clk_2x;
ctlr_rdy <= i_ctlr_rdy;
ctlr_init_done <= i_ctlr_init_done;
u_wr_fifo : entity dp_lib.dp_fifo_dc_mixed_widths
generic map (
g_wr_data_w => g_wr_data_w,
g_rd_data_w => c_ddr3_ctlr_data_w,
g_use_ctrl => g_wr_use_ctrl,
g_wr_fifo_size => c_wr_fifo_depth,
g_wr_fifo_af_margin => 4 + c_latency, -- default (4) + c_latency to compensate for latency introduced by registering wr_siso.ready
g_rd_fifo_rl => 0
)
port map (
wr_rst => wr_rst,
wr_clk => wr_clk,
rd_rst => i_ctlr_gen_rst,
rd_clk => i_ctlr_gen_clk,
snk_out => wr_siso,
snk_in => wr_sosi,
wr_usedw => OPEN,
rd_usedw => wr_fifo_usedw,
rd_emp => OPEN,
src_in => flush_wr_siso,
src_out => flush_wr_sosi
);
u_dp_flush : entity dp_lib.dp_flush -- Always instantiate the flusher as it also contains a RL adapter
generic map (
g_ready_latency => 0,
g_framed_xon => g_wr_use_ctrl, -- stop flushing when dvr_flush is low and a sop has arrived
g_framed_xoff => false -- immediately start flushing when dvr_flush goes high
)
port map (
rst => i_ctlr_gen_rst,
clk => i_ctlr_gen_clk,
snk_in => flush_wr_sosi,
snk_out => flush_wr_siso,
src_out => ctlr_wr_sosi,
src_in => ctlr_wr_siso, -- fixed streaming xon='1'
flush_en => dvr_flush -- memory mapped xon/xoff control
);
gen_flush : if g_flush_wr_fifo = true generate
u_flush_ctrl : entity work.ddr3_flush_ctrl
generic map (
g_ext_ena => g_flush_ext_ena,
g_sop => g_flush_sop,
g_sop_sync => g_flush_sop_sync,
g_sop_channel => g_flush_sop_channel,
g_sop_start_channel => g_flush_sop_start_channel,
g_nof_channels => g_flush_nof_channels
)
port map (
rst => wr_rst,
clk => wr_clk,
dvr_en => dvr_en,
dvr_wr_not_rd => dvr_wr_not_rd,
dvr_done => i_dvr_done,
wr_sosi => wr_sosi,
flush_ena => flush_ena,
dvr_flush => dvr_flush
);
end generate;
u_rd_fifo : entity dp_lib.dp_fifo_dc_mixed_widths
generic map (
g_wr_data_w => c_ddr3_ctlr_data_w,
g_rd_data_w => g_rd_data_w,
g_use_ctrl => false,
g_wr_fifo_size => g_rd_fifo_depth,
g_wr_fifo_af_margin => c_ddr3_ctrl_nof_latent_reads, -- >=4 (required by dp_fifo)
g_rd_fifo_rl => 1
)
port map (
wr_rst => i_ctlr_gen_rst,
wr_clk => i_ctlr_gen_clk,
rd_rst => rd_rst,
rd_clk => rd_clk,
snk_out => ctlr_rd_siso,
snk_in => ctlr_rd_sosi,
wr_usedw => OPEN,
rd_usedw => rd_fifo_usedw,
rd_emp => OPEN,
src_in => rd_siso,
src_out => rd_sosi
);
u_ddr3_driver : entity work.ddr3_driver
generic map (
g_wr_fifo_depth => g_wr_fifo_depth,
g_ddr => g_ddr
)
port map (
rst => i_ctlr_gen_rst,
clk => i_ctlr_gen_clk,
ctlr_rdy => i_ctlr_rdy,
ctlr_init_done => i_ctlr_init_done,
ctlr_wr_req => ctlr_wr_req,
ctlr_rd_req => ctlr_rd_req,
ctlr_burst => ctlr_burst,
ctlr_burst_size => ctlr_burst_size,
wr_val => ctlr_wr_sosi.valid,
wr_rdy => ctlr_wr_siso.ready,
rd_rdy => ctlr_rd_siso.ready,
cur_addr => dvr_cur_addr,
start_addr => dvr_start_addr,
end_addr => dvr_end_addr,
dvr_en => dvr_en,
dvr_wr_not_rd => dvr_wr_not_rd,
dvr_done => i_dvr_done,
wr_fifo_usedw => wr_fifo_usedw
);
u_reg_map : entity common_lib.common_reg_r_w_dc
generic map (
g_cross_clock_domain => true, -- : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain
g_in_new_latency => 0, -- : NATURAL := 0; -- >= 0
g_readback => false, -- : BOOLEAN := FALSE; -- must use FALSE for write/read or read only register when g_cross_clock_domain=TRUE
g_reg => c_mem_reg_io_ddr, -- : t_c_mem := c_mem_reg;
g_init_reg => (others => '0') -- : STD_LOGIC_VECTOR(c_mem_reg_init_w-1 DOWNTO 0) := (OTHERS => '0')
)
port map (
-- Clocks and reset
mm_rst => mm_rst, -- : IN STD_LOGIC; -- reset synchronous with mm_clk
mm_clk => mm_clk, -- : IN STD_LOGIC; -- memory-mapped bus clock
st_rst => i_ctlr_gen_rst, -- : IN STD_LOGIC; -- reset synchronous with st_clk
st_clk => i_ctlr_gen_clk, -- : IN STD_LOGIC; -- other clock domain clock
-- Memory Mapped Slave in mm_clk domain
sla_in => reg_io_ddr_mosi, -- : IN t_mem_mosi; -- actual ranges defined by g_reg
sla_out => reg_io_ddr_miso, -- : OUT t_mem_miso; -- actual ranges defined by g_reg
-- MM registers in st_clk domain
reg_wr_arr => OPEN, -- : OUT STD_LOGIC_VECTOR( g_reg.nof_dat-1 DOWNTO 0);
reg_rd_arr => OPEN, -- : OUT STD_LOGIC_VECTOR( g_reg.nof_dat-1 DOWNTO 0);
in_new => '1', -- : IN STD_LOGIC := '1';
in_reg => mm_reg_io_ddr, -- : IN STD_LOGIC_VECTOR(g_reg.dat_w*g_reg.nof_dat-1 DOWNTO 0);
out_reg => open -- : OUT STD_LOGIC_VECTOR(g_reg.dat_w*g_reg.nof_dat-1 DOWNTO 0)
);
mm_reg_io_ddr <= RESIZE_UVEC(local_cal_fail & local_cal_success & i_ctlr_gen_rst & flush_ena & i_ctlr_rdy & i_ctlr_init_done, 32);
ser_term_ctrl_out <= term_ctrl_out.seriesterminationcontrol;
par_term_ctrl_out <= term_ctrl_out.parallelterminationcontrol;
term_ctrl_in.seriesterminationcontrol <= ser_term_ctrl_in;
term_ctrl_in.parallelterminationcontrol <= par_term_ctrl_in;
ctlr_tech_mosi.burstbegin <= ctlr_burst;
ctlr_tech_mosi.address <= RESIZE_MEM_CTLR_ADDRESS(dvr_cur_addr.chip & dvr_cur_addr.bank & dvr_cur_addr.row(g_ddr.a_w - 1 downto 0) & dvr_cur_addr.column(g_ddr.a_col_w - 1 downto c_ddr3_ctlr_rsl_w));
ctlr_tech_mosi.wrdata <= RESIZE_MEM_CTLR_DATA(ctlr_wr_sosi.data);
ctlr_tech_mosi.rd <= ctlr_rd_req;
ctlr_tech_mosi.wr <= ctlr_wr_req;
ctlr_tech_mosi.burstsize <= RESIZE_MEM_CTLR_BURSTSIZE(ctlr_burst_size);
i_ctlr_rdy <= ctlr_tech_miso.waitrequest_n;
ctlr_rd_sosi.valid <= ctlr_tech_miso.rdval;
ctlr_rd_sosi.data <= RESIZE_DP_DATA(ctlr_tech_miso.rddata);
i_ctlr_init_done <= ctlr_tech_miso.done;
local_cal_success <= ctlr_tech_miso.cal_ok;
local_cal_fail <= ctlr_tech_miso.cal_fail;
u_tech_ddr : entity tech_ddr_lib.tech_ddr
generic map (
g_technology => c_tech_stratixiv,
g_tech_ddr => c_tech_ddr3_4g_800m_master
)
port map (
-- PLL reference clock
ref_clk => ctlr_ref_clk,
ref_rst => ctlr_rst,
-- Controller user interface
ctlr_gen_clk => i_ctlr_gen_clk,
ctlr_gen_rst => i_ctlr_gen_rst,
ctlr_gen_clk_2x => i_ctlr_gen_clk_2x,
ctlr_gen_rst_2x => ctlr_gen_rst_2x,
ctlr_mosi => ctlr_tech_mosi,
ctlr_miso => ctlr_tech_miso,
term_ctrl_out => term_ctrl_out,
term_ctrl_in => term_ctrl_in,
-- DDR3 PHY interface
phy3_in => phy_in,
phy3_io => phy_io,
phy3_ou => phy_ou
);
end str;