diff --git a/libraries/technology/ddr/hdllib.cfg b/libraries/technology/ddr/hdllib.cfg index dae97d24a3842626cfb5b34752e9c6d11c16357d..0f67ecdab8960b443af579ffc1f3211dcdad7f9c 100644 --- a/libraries/technology/ddr/hdllib.cfg +++ b/libraries/technology/ddr/hdllib.cfg @@ -14,6 +14,7 @@ hdl_lib_technology = synth_files = tech_ddr_pkg.vhd + sim_ddr.vhd tech_ddr_component_pkg.vhd tech_ddr_stratixiv.vhd tech_ddr_arria10.vhd diff --git a/libraries/technology/ddr/sim_ddr.vhd b/libraries/technology/ddr/sim_ddr.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f8ec34019ba1e27c1eb3a358e471ce5bb8ee53a2 --- /dev/null +++ b/libraries/technology/ddr/sim_ddr.vhd @@ -0,0 +1,159 @@ +-------------------------------------------------------------------------------- +-- +-- 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; + diff --git a/libraries/technology/ddr/tech_ddr.vhd b/libraries/technology/ddr/tech_ddr.vhd index 03961ea0085e885f76acecd6d7d76ecc2ea39c9c..b19e6f9ad1378168ca618ff8aa1ea89d1627eac9 100644 --- a/libraries/technology/ddr/tech_ddr.vhd +++ b/libraries/technology/ddr/tech_ddr.vhd @@ -35,7 +35,7 @@ USE work.tech_ddr_pkg.ALL; ENTITY tech_ddr IS GENERIC ( - g_sim_model : BOOLEAN := FALSE; -- TRUE: use fast behavioural model, requires no external memory (uses memory array). + g_sim_model : BOOLEAN := FALSE; -- TRUE: use fast behavioural model, requires no external memory (uses memory array). g_technology : NATURAL := c_tech_select_default; g_tech_ddr : t_c_tech_ddr ); @@ -71,8 +71,8 @@ END tech_ddr; ARCHITECTURE str OF tech_ddr IS - CONSTANT c_nof_addr : NATURAL := 8192; - CONSTANT c_dat_w : NATURAL := 256; + 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; TYPE t_mem_arr IS ARRAY(0 TO c_nof_addr-1) OF STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); @@ -108,91 +108,28 @@ BEGIN END GENERATE; ----------------------------------------------------------------------------- - -- Functional simulation model - -- . Note: is it assumed that the user only performs burst reads/writes! + -- Functional simulation model of both the DDR controller and the DDR memory ----------------------------------------------------------------------------- gen_sim_model : IF g_sim_model=TRUE GENERATE - -- 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 1000 ps; - ctlr_miso.cal_ok <= '0' , '1' AFTER 1000 ps; - - -- 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 use 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 + u0 : ENTITY work.sim_ddr + GENERIC MAP ( + g_tech_ddr => g_tech_ddr + ) + PORT MAP ( + -- PLL reference clock + ref_clk => ref_clk, + ref_rst => ref_rst, - ctlr_miso.rdval <= '0'; - ctlr_miso.waitrequest_n <= '1'; + -- Controller user interface + ctlr_gen_clk => ctlr_gen_clk, + ctlr_gen_rst => ctlr_gen_rst, + ctlr_gen_clk_2x => ctlr_gen_clk_2x, + ctlr_gen_rst_2x => ctlr_gen_rst_2x, - -- 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; + ctlr_mosi => ctlr_mosi, + ctlr_miso => ctlr_miso + ); END GENERATE; - + END str;