------------------------------------------------------------------------------- -- -- Copyright 2022 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- ------------------------------------------------------------------------------- -- Author: Job van Wee -- Purpose: Folding a stream of data into a mm data configuration so it can be -- stored in a DDR RAM-stick. -- -- Description: -- First the data from the sosi array gets collected into one data vector. -- After that this data vector gets resized to the right size data vector in -- order to make it storable in a DDR RAM-stick. -- After that a address gets assigned to the data so the data can be found back. -- -- Remark: -- Use VHDL coding template from: -- https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding -- The maximum value of the address is determend by g_tech_ddr. LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib, io_ddr_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; USE IEEE.MATH_REAL.ALL; USE technology_lib.technology_pkg.ALL; USE technology_lib.technology_select_pkg.ALL; USE tech_ddr_lib.tech_ddr_pkg.ALL; USE common_lib.common_pkg.ALL; USE common_lib.common_mem_pkg.ALL; USE dp_lib.dp_stream_pkg.ALL; USE io_ddr_lib.ALL; ENTITY ddrctrl IS GENERIC ( g_tech_ddr : t_c_tech_ddr; -- type of memory g_sim_model : BOOLEAN := TRUE; -- determens if this is a simulation g_technology : NATURAL := c_tech_select_default; g_nof_streams : NATURAL := 12; -- number of input streams g_data_w : NATURAL := 14; -- data with of input data vectors g_stop_percentage : NATURAL := 50; g_block_size : NATURAL := 1024 ); PORT ( clk : IN STD_LOGIC := '0'; rst : IN STD_LOGIC; ctlr_ref_clk : IN STD_LOGIC; ctlr_ref_rst : IN STD_LOGIC; mm_clk : IN STD_LOGIC := '0'; mm_rst : IN STD_LOGIC := '0'; in_sosi_arr : IN t_dp_sosi_arr; -- input data stop_in : IN STD_LOGIC := '0'; out_sosi_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); out_siso : IN t_dp_siso := c_dp_siso_rst; ddrctrl_ctrl_state: OUT STD_LOGIC_VECTOR(32-1 DOWNTO 0); term_ctrl_out : OUT t_tech_ddr3_phy_terminationcontrol; term_ctrl_in : IN t_tech_ddr3_phy_terminationcontrol := c_tech_ddr3_phy_terminationcontrol_rst; -- IO_DDR monitor data reg_io_ddr_mosi : IN t_mem_mosi := c_mem_mosi_rst; reg_io_ddr_miso : OUT t_mem_miso; -- DDR3 PHY external interface phy3_in : IN t_tech_ddr3_phy_in := c_tech_ddr3_phy_in_x; phy3_io : INOUT t_tech_ddr3_phy_io; phy3_ou : OUT t_tech_ddr3_phy_ou; -- DDR4 PHY external interface phy4_in : IN t_tech_ddr4_phy_in := c_tech_ddr4_phy_in_x; phy4_io : INOUT t_tech_ddr4_phy_io; phy4_ou : OUT t_tech_ddr4_phy_ou ); END ddrctrl; ARCHITECTURE str OF ddrctrl IS -- constant for readability CONSTANT c_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr); -- 576 CONSTANT c_wr_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K CONSTANT c_rd_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K CONSTANT c_wr_fifo_uw_w : NATURAL := ceil_log2(c_wr_fifo_depth*(func_tech_ddr_ctlr_data_w(g_tech_ddr)/c_io_ddr_data_w)); CONSTANT c_rd_fifo_uw_w : NATURAL := ceil_log2(c_rd_fifo_depth*(func_tech_ddr_ctlr_data_w(g_tech_ddr)/c_io_ddr_data_w)); CONSTANT c_burstsize : NATURAL := g_tech_ddr.maxburstsize; CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address CONSTANT c_adr_per_b : NATURAL := ((g_block_size*g_nof_streams*g_data_w)/c_io_ddr_data_w)+1; -- rounding error removes the amount of extra addresses. CONSTANT c_bim : NATURAL := NATURAL(floor(REAL(c_max_adr)/REAL(c_adr_per_b))); SIGNAL s_adr_per_b : NATURAL := c_adr_per_b; -- the amount of addresses used CONSTANT c_nof_adr : NATURAL := c_bim*c_adr_per_b; SIGNAL s_nof_adr : NATURAL := c_nof_adr; -- the amount of overflow after one block is written CONSTANT c_of_pb : NATURAL := (g_block_size*g_nof_streams*g_data_w)-(((g_block_size*g_nof_streams*g_data_w)/c_io_ddr_data_w)*c_io_ddr_data_w); -- amount of overflow after one block is written to memory CONSTANT c_aof_full_burst : NATURAL := c_nof_adr/c_burstsize; CONSTANT c_last_burstsize : NATURAL := c_nof_adr-(c_aof_full_burst*c_burstsize); SIGNAL s_last_burstsize : NATURAL := c_last_burstsize; -- signals for connecting the components SIGNAL ctrl_clk : STD_LOGIC; SIGNAL ctrl_rst : STD_LOGIC; SIGNAL rst_ddrctrl_input_ac : STD_LOGIC; SIGNAL out_of : NATURAL := 0; SIGNAL out_sosi : t_dp_sosi := c_dp_sosi_init; SIGNAL out_adr : NATURAL := 0; SIGNAL dvr_mosi : t_mem_ctlr_mosi := c_mem_ctlr_mosi_rst; SIGNAL dvr_miso : t_mem_ctlr_miso := c_mem_ctlr_miso_rst; SIGNAL wr_sosi : t_dp_sosi := c_dp_sosi_init; SIGNAL rd_siso : t_dp_siso := c_dp_siso_rst; SIGNAL rd_sosi : t_dp_sosi := c_dp_sosi_init; SIGNAL stop : STD_LOGIC; SIGNAL wr_fifo_usedw : STD_LOGIC_VECTOR(c_wr_fifo_uw_w-1 DOWNTO 0); SIGNAL rd_fifo_usedw : STD_LOGIC_VECTOR(c_rd_fifo_uw_w-1 DOWNTO 0); SIGNAL rd_ready : STD_LOGIC; SIGNAL inp_bsn_adr : NATURAL; SIGNAL bsn_co : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); SIGNAL data_stopped : STD_LOGIC; SIGNAL state_vec : STD_LOGIC_VECTOR(1 DOWNTO 0); SIGNAL ddrctrl_ctrl_state_local : STD_LOGIC_VECTOR(32-1 DOWNTO 0); BEGIN rd_siso.ready <= rd_ready; rd_siso.xon <= '1'; ddrctrl_ctrl_state(5 DOWNTO 0) <= ddrctrl_ctrl_state_local(5 DOWNTO 0); ddrctrl_ctrl_state(7 DOWNTO 6) <= state_vec(1 DOWNTO 0); ddrctrl_ctrl_state(32-1 DOWNTO 8) <= ddrctrl_ctrl_state_local(32-1 DOWNTO 8); -- input to io_ddr u_ddrctrl_input : ENTITY work.ddrctrl_input GENERIC MAP( g_tech_ddr => g_tech_ddr, g_nof_streams => g_nof_streams, g_data_w => g_data_w, g_max_adr => c_nof_adr, g_bim => c_bim, g_of_pb => c_of_pb, g_block_size => g_block_size ) PORT MAP( clk => clk, rst => rst, rst_ddrctrl_input_ac => rst_ddrctrl_input_ac, in_sosi_arr => in_sosi_arr, in_stop => stop, out_sosi => out_sosi, out_adr => out_adr, out_bsn_adr => inp_bsn_adr, out_data_stopped => data_stopped ); -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick. u_io_ddr : ENTITY io_ddr_lib.io_ddr GENERIC MAP( g_sim_model => g_sim_model, g_technology => g_technology, g_tech_ddr => g_tech_ddr, g_cross_domain_dvr_ctlr => FALSE, g_wr_data_w => c_io_ddr_data_w, g_wr_fifo_depth => c_wr_fifo_depth, g_rd_fifo_depth => c_rd_fifo_depth, g_rd_data_w => c_io_ddr_data_w, g_wr_flush_mode => "VAL", g_wr_flush_use_channel => FALSE, g_wr_flush_start_channel => 0, g_wr_flush_nof_channels => 1 ) PORT MAP( -- DDR reference clock ctlr_ref_clk => ctlr_ref_clk, ctlr_ref_rst => ctlr_ref_rst, -- DDR controller clock domain ctlr_clk_out => ctrl_clk, ctlr_rst_out => ctrl_rst, ctlr_clk_in => ctrl_clk, ctlr_rst_in => ctrl_rst, -- MM clock + reset mm_rst => mm_rst, mm_clk => mm_clk, -- MM interface reg_io_ddr_mosi => reg_io_ddr_mosi, reg_io_ddr_miso => reg_io_ddr_miso, state_vec => state_vec, -- Driver clock domain dvr_clk => clk, dvr_rst => rst, dvr_miso => dvr_miso, dvr_mosi => dvr_mosi, -- Write FIFO clock domain wr_clk => clk, wr_rst => rst, wr_fifo_usedw => wr_fifo_usedw, wr_sosi => wr_sosi, wr_siso => open, -- Read FIFO clock domain rd_clk => clk, rd_rst => rst, rd_fifo_usedw => rd_fifo_usedw, rd_sosi => rd_sosi, rd_siso => rd_siso, term_ctrl_out => term_ctrl_out, term_ctrl_in => term_ctrl_in, -- DDR3 PHY external interface phy3_in => phy3_in, phy3_io => phy3_io, phy3_ou => phy3_ou, -- DDR4 PHY external interface phy4_in => phy4_in, phy4_io => phy4_io, phy4_ou => phy4_ou ); -- reading ddr memory u_ddrctrl_output : ENTITY work.ddrctrl_output GENERIC MAP( g_technology => g_technology, g_tech_ddr => g_tech_ddr, g_sim_model => g_sim_model, g_in_data_w => c_io_ddr_data_w, g_nof_streams => g_nof_streams, g_data_w => g_data_w, g_block_size => g_block_size, g_bim => c_bim ) PORT MAP( clk => clk, rst => rst, in_sosi => rd_sosi, in_bsn => bsn_co, out_sosi_arr => out_sosi_arr, out_siso => out_siso, out_ready => rd_ready ); -- controller of ddrctrl u_ddrctrl_controller : ENTITY work.ddrctrl_controller GENERIC MAP( g_tech_ddr => g_tech_ddr, g_stop_percentage => g_stop_percentage, g_nof_streams => g_nof_streams, g_out_data_w => g_data_w, g_wr_data_w => c_io_ddr_data_w, g_rd_fifo_depth => c_rd_fifo_depth, g_rd_data_w => c_io_ddr_data_w, g_block_size => g_block_size, g_wr_fifo_uw_w => c_wr_fifo_uw_w, g_rd_fifo_uw_w => c_rd_fifo_uw_w, g_max_adr => c_nof_adr, g_burstsize => c_burstsize, g_last_burstsize => c_last_burstsize, g_adr_per_b => c_adr_per_b, g_bim => c_bim ) PORT MAP( clk => clk, rst => rst, -- ddrctrl_input inp_of => out_of, inp_sosi => out_sosi, inp_adr => out_adr, inp_bsn_adr => inp_bsn_adr, inp_data_stopped => data_stopped, rst_ddrctrl_input_ac => rst_ddrctrl_input_ac, -- io_ddr dvr_mosi => dvr_mosi, dvr_miso => dvr_miso, wr_sosi => wr_sosi, wr_fifo_usedw => wr_fifo_usedw, rd_fifo_usedw => rd_fifo_usedw, -- ddrctrl_output outp_bsn => bsn_co, -- ddrctrl_controller stop_in => stop_in, stop_out => stop, ddrctrl_ctrl_state => ddrctrl_ctrl_state_local ); END str;