-------------------------------------------------------------------------------- -- -- 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: Functional simulation model of both the DDR driver and the DDR memory. -- Description: -- The component also supports different types of DDR, so DDR3 and DDR4. -- Remark: -- . It is assumed that the user only performs burst reads/writes! -- . Modelsim raises warning 3391 when the DDR memory set by c_nof_addr is to big to fit in PC RAM. -- Use 'verror 3391' to display the help. This means that the computer becomes too slow due to -- page swapping to disk. Even loading the simulation becomes slow. LIBRARY IEEE, common_lib, technology_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 technology_lib.technology_select_pkg.ALL; USE work.tech_ddr_pkg.ALL; ENTITY sim_ddr 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_gen_clk_2x : OUT STD_LOGIC; ctlr_gen_rst_2x : OUT STD_LOGIC; ctlr_mosi : IN t_mem_ctlr_mosi; ctlr_miso : OUT t_mem_ctlr_miso ); END sim_ddr; ARCHITECTURE str OF sim_ddr IS -- DDR size and controller data width CONSTANT c_nof_addr : NATURAL := 2**func_tech_ddr_ctlr_address_w(g_tech_ddr); --8192; CONSTANT c_dat_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr); --256; -- DDR memory TYPE t_mem_arr IS ARRAY(0 TO c_nof_addr-1) OF STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); SIGNAL sim_clk : STD_LOGIC; SIGNAL sim_rst : STD_LOGIC; SIGNAL sim_ctlr_mosi : t_mem_ctlr_mosi; SIGNAL address : NATURAL; BEGIN -- Prevent delta delay issues by using a re-assigned clk both internally (sim_clk) and externally (ctrl_gen_clk) ctlr_gen_clk <= ref_clk; ctlr_gen_rst <= ref_rst; sim_clk <= ref_clk; sim_rst <= ref_rst; ctlr_miso.done <= '0' , '1' AFTER 1 ns; ctlr_miso.cal_ok <= '0' , '1' AFTER 1 ns; ctlr_miso.cal_fail <= '0'; -- Delay the control one cycle here so p_mem_access can update its outputs immediately p_clk : PROCESS(sim_clk) BEGIN IF rising_edge(sim_clk) THEN sim_ctlr_mosi <= ctlr_mosi; END IF; END PROCESS; p_mem_access : PROCESS(sim_clk, sim_ctlr_mosi) VARIABLE v_enable_model : BOOLEAN := FALSE; VARIABLE v_mem_arr : t_mem_arr := (OTHERS=>(OTHERS=>'0')); VARIABLE v_address : NATURAL := 0; VARIABLE v_wr_bursting : BOOLEAN := FALSE; VARIABLE v_rd_bursting : BOOLEAN := FALSE; VARIABLE v_burst_cnt : NATURAL := 0; VARIABLE v_burst_size : NATURAL := 0; BEGIN -- Don't waste simulation time when user does not access the model anyway IF v_enable_model = FALSE THEN ctlr_miso.waitrequest_n <= '1'; IF sim_ctlr_mosi.burstbegin='1' THEN v_enable_model := TRUE; END IF; END IF; IF v_enable_model = TRUE THEN IF rising_edge(sim_clk) THEN ctlr_miso.rdval <= '0'; ctlr_miso.waitrequest_n <= '1'; -- Access: burst begin IF sim_ctlr_mosi.burstbegin='1' THEN IF sim_ctlr_mosi.wr='1' THEN v_wr_bursting := TRUE; ELSIF sim_ctlr_mosi.rd='1' THEN v_rd_bursting := TRUE; END IF; v_address := TO_UINT(sim_ctlr_mosi.address); v_burst_size := TO_UINT(sim_ctlr_mosi.burstsize); v_burst_cnt := 0; END IF; IF v_wr_bursting=TRUE OR v_rd_bursting=TRUE THEN IF sim_ctlr_mosi.wr='1' THEN -- Write v_mem_arr(v_address) := sim_ctlr_mosi.wrdata(c_dat_w-1 DOWNTO 0); v_address := v_address+1; v_burst_cnt := v_burst_cnt +1; ELSIF v_rd_bursting=TRUE THEN -- Read ctlr_miso.rddata(c_dat_w-1 DOWNTO 0) <= v_mem_arr(v_address); ctlr_miso.rdval <= '1'; ctlr_miso.waitrequest_n <= '0'; v_address := v_address+1; v_burst_cnt := v_burst_cnt +1; END IF; IF v_burst_cnt = v_burst_size THEN v_wr_bursting := FALSE; v_rd_bursting := FALSE; END IF; END IF; address <= v_address; END IF; END IF; END PROCESS; END str;