diff --git a/applications/lofar2/libraries/ddrctrl/hdllib.cfg b/applications/lofar2/libraries/ddrctrl/hdllib.cfg index ba8457f096cdfc6b3e1bbefff4d1fedc16d69766..53fe5f5958c0cf866e1870d4ed11367b023c7df5 100644 --- a/applications/lofar2/libraries/ddrctrl/hdllib.cfg +++ b/applications/lofar2/libraries/ddrctrl/hdllib.cfg @@ -9,6 +9,7 @@ synth_files = src/vhdl/ddrctrl_input_pack.vhd src/vhdl/ddrctrl_input_repack.vhd src/vhdl/ddrctrl_input.vhd + src/vhdl/ddrctrl_controller.vhd src/vhdl/ddrctrl.vhd test_bench_files = diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd index 8b0b96df15aafa155ad6bdc7dde31ca491df09d1..16aedd40d1b09382c4958070343051fead1af495 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd @@ -50,8 +50,9 @@ ENTITY ddrctrl IS 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_data_w : NATURAL := 14; -- data with of input data vectors + g_stop_percentage : NATURAL := 50 + ); PORT ( clk : IN STD_LOGIC := '0'; rst : IN STD_LOGIC; @@ -59,8 +60,7 @@ ENTITY ddrctrl IS mm_rst : IN STD_LOGIC := '0'; in_sosi_arr : IN t_dp_sosi_arr; -- input data wr_not_rd : IN STD_LOGIC := '0'; - out_of : OUT NATURAL; -- amount of internal overflow this output - out_adr : OUT NATURAL; + stop_in : IN STD_LOGIC := '0'; term_ctrl_out : OUT t_tech_ddr3_phy_terminationcontrol; @@ -85,40 +85,20 @@ ARCHITECTURE str OF ddrctrl IS CONSTANT c_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr ); 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_burstsize : NATURAL := 64; -- max burstsize for max troughput - CONSTANT c_bitshift_adr : NATURAL := ceil_log2(c_burstsize); - 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_zeros : STD_LOGIC_VECTOR(c_bitshift_adr-1 DOWNTO 0) := (OTHERS => '0'); -- signals for connecting the components - SIGNAL adr : NATURAL := 0; SIGNAL ctrl_clk : STD_LOGIC; SIGNAL ctrl_rst : 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 wr_sosi : t_dp_sosi := c_dp_sosi_init; SIGNAL rd_siso : t_dp_siso := c_dp_siso_rst; - SIGNAL dvr_mosi : t_mem_ctlr_mosi; BEGIN - p_burst : PROCESS(adr) - BEGIN - IF TO_UVEC(adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN - dvr_mosi.burstbegin <= '1'; - IF adr = 0 THEN - dvr_mosi.address <= TO_UVEC(c_max_adr-c_burstsize, dvr_mosi.address'length); - ELSE - dvr_mosi.address <= TO_UVEC(adr-c_burstsize, dvr_mosi.address'length); - END IF; - ELSE - dvr_mosi.burstbegin <= '0'; - END IF; - END PROCESS; - - dvr_mosi.burstsize <= TO_UVEC(c_burstsize, dvr_mosi.burstsize'length); - dvr_mosi.wr <= wr_not_rd; - dvr_mosi.rd <= NOT wr_not_rd; -- input to io_ddr u_ddrctrl_input : ENTITY work.ddrctrl_input @@ -133,8 +113,8 @@ BEGIN rst => rst, in_sosi_arr => in_sosi_arr, out_of => out_of, - out_sosi => wr_sosi, - out_adr => adr + out_sosi => out_sosi, + out_adr => out_adr ); -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick. @@ -211,4 +191,25 @@ BEGIN phy4_ou => phy4_ou ); + -- controller of ddrctrl + u_ddrctrl_controller : ENTITY work.ddrctrl_controller + GENERIC MAP( + g_tech_ddr => g_tech_ddr, + g_stop_percentage => g_stop_percentage + ) + PORT MAP( + clk => clk, + rst => rst, + + inp_of => out_of, + inp_sosi => out_sosi, + inp_adr => out_adr, + + dvr_mosi => dvr_mosi, + wr_sosi => wr_sosi, + rd_siso => rd_siso, + + stop_in => stop_in + ); + END str; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd new file mode 100644 index 0000000000000000000000000000000000000000..d11931ba0ee0126455334f2661ebd8bca1634257 --- /dev/null +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd @@ -0,0 +1,197 @@ +------------------------------------------------------------------------------- +-- +-- 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: controller for ddrctrl, decides when to write when to read or when to stop writing or reading. +-- +-- Description: +-- +-- Remark: +-- Use VHDL coding template from: +-- https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding +-- + +LIBRARY IEEE, dp_lib, common_lib, tech_ddr_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_pkg.ALL; +USE tech_ddr_lib.tech_ddr_pkg.ALL; + + +ENTITY ddrctrl_controller IS + GENERIC ( + g_tech_ddr : t_c_tech_ddr; + g_stop_percentage : NATURAL := 50 + ); + PORT ( + clk : IN STD_LOGIC; + rst : IN STD_LOGIC; + + -- ddrctrl_input + inp_of : IN NATURAL; + inp_sosi : IN t_dp_sosi; + inp_adr : IN NATURAL; + + -- io_ddr + dvr_mosi : OUT t_mem_ctlr_mosi; + wr_sosi : OUT t_dp_sosi; + rd_siso : OUT t_dp_siso; + + -- ddrctrl + stop_in : IN STD_LOGIC + ); +END ddrctrl_controller; + +ARCHITECTURE rtl OF ddrctrl_controller IS + + CONSTANT c_burstsize : NATURAL := 64; -- max burstsize for max troughput + CONSTANT c_bitshift_adr : NATURAL := ceil_log2(c_burstsize); -- bitshift to make sure there is only a burst start at a interval of c_burstsize. + 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_pof_ma : NATURAL := (c_max_adr*(100-g_stop_percentage))/100; + CONSTANT c_zeros : STD_LOGIC_VECTOR(c_bitshift_adr-1 DOWNTO 0) := (OTHERS => '0'); + + -- type for statemachine + TYPE t_state IS (RESET, WRITING, SET_STOP, STOP_WRITING, READING, STOP_READING, IDLE); + + -- record for readability + TYPE t_reg IS RECORD + -- state of program + state : t_state; + + -- signals + stop_adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + stopped : STD_LOGIC; + + -- output + dvr_mosi : t_mem_ctlr_mosi; + wr_sosi : t_dp_sosi; + rd_siso : t_dp_siso; + END RECORD; + + CONSTANT c_t_reg_init : t_reg := (RESET, TO_UVEC(c_max_adr, c_adr_w), '0', c_mem_ctlr_mosi_rst, c_dp_sosi_init, c_dp_siso_rst); + + + -- signals for readability + SIGNAL d_reg : t_reg := c_t_reg_init; + SIGNAL q_reg : t_reg := c_t_reg_init; + +BEGIN + + q_reg <= d_reg WHEN rising_edge(clk); + + -- put the input data into c_v and fill the output vector from c_v + p_state : PROCESS(q_reg, rst, inp_of, inp_sosi, inp_adr) + + VARIABLE v : t_reg := c_t_reg_init; + + BEGIN + + v := q_reg; + CASE q_reg.state IS + + + + WHEN RESET => + v := c_t_reg_init; + + + WHEN WRITING => + IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN -- if adr mod c_burstsize = 0 + v.dvr_mosi.burstbegin := '1'; + IF inp_adr = 0 THEN + v.dvr_mosi.address := TO_UVEC(c_max_adr-c_burstsize, dvr_mosi.address'length); + ELSE + v.dvr_mosi.address := TO_UVEC(inp_adr-c_burstsize, dvr_mosi.address'length); + END IF; + ELSE + v.dvr_mosi.burstbegin := '0'; + END IF; + v.dvr_mosi.burstsize := TO_UVEC(c_burstsize, dvr_mosi.burstsize'length); + v.dvr_mosi.wr := '1'; + v.dvr_mosi.rd := '0'; + v.wr_sosi := inp_sosi; + + + + WHEN SET_STOP => + --setting a stop address dependend on the g_stop_percentage + IF inp_adr+c_pof_ma >= c_max_adr THEN + v.stop_adr(c_adr_w-1 DOWNTO c_bitshift_adr) := TO_UVEC(inp_adr-c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO c_bitshift_adr); + ELSE + v.stop_adr(c_adr_w-1 DOWNTO c_bitshift_adr) := TO_UVEC(inp_adr+c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO c_bitshift_adr); + END IF; + v.stop_adr(c_bitshift_adr-1 DOWNTO 0) := c_zeros; + + -- still a write cyle + IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN -- adr mod 64 = 0 + v.dvr_mosi.burstbegin := '1'; + IF inp_adr = 0 THEN + v.dvr_mosi.address := TO_UVEC(c_max_adr-c_burstsize, dvr_mosi.address'length); + ELSE + v.dvr_mosi.address := TO_UVEC(inp_adr-c_burstsize, dvr_mosi.address'length); + END IF; + ELSE + v.dvr_mosi.burstbegin := '0'; + END IF; + v.dvr_mosi.burstsize := TO_UVEC(c_burstsize, dvr_mosi.burstsize'length); + v.dvr_mosi.wr := '1'; + v.dvr_mosi.rd := '0'; + v.wr_sosi := inp_sosi; + + + + WHEN STOP_WRITING => + v.stopped := '1'; + v.wr_sosi.valid := '0'; + v.dvr_mosi.flush := '1'; + + WHEN IDLE => + + + + WHEN OTHERS => + v := c_t_reg_init; + + + + END CASE; + + IF rst = '1' THEN + v.state := RESET; + ELSIF stop_in = '1' THEN + v.state := SET_STOP; + ELSIF v.stop_adr = TO_UVEC(inp_adr, c_adr_w) AND v.stop_adr(c_bitshift_adr-1 DOWNTO 0) = c_zeros(c_bitshift_adr-1 DOWNTO 0) AND q_reg.stopped = '0' THEN + v.state := STOP_WRITING; + ELSIF v.stopped = '1' THEN + v.state := IDLE; + ELSE + v.state := WRITING; + END IF; + d_reg <= v; + END PROCESS; + + -- fill outputs + dvr_mosi <= q_reg.dvr_mosi; + wr_sosi <= q_reg.wr_sosi; + rd_siso <= q_reg.rd_siso; + +END rtl; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd index 9416182dd0d6309b135c9ac1e7dcf06e1e5402dc..ede68f09a7bbb58774e4991fae3bed24e1a8b221 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd @@ -71,6 +71,7 @@ ARCHITECTURE rtl OF ddrctrl_input_repack IS CONSTANT c_t_reg_init : t_reg := (RESET, 0, (OTHERS => '0'), 0, 0, 0, c_dp_sosi_init); + -- signals for readability SIGNAL d_reg : t_reg := c_t_reg_init; SIGNAL q_reg : t_reg := c_t_reg_init; diff --git a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd index ebbc092b4dccc17c8ced070d319115f8adc73ad8..f38fb0f836208aaffcf1b0f292a0c747e61f2563 100644 --- a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd @@ -33,6 +33,7 @@ USE common_lib.common_mem_pkg.ALL; USE common_lib.common_pkg.ALL; USE technology_lib.technology_select_pkg.ALL; + ENTITY tb_ddrctrl IS GENERIC ( @@ -42,7 +43,8 @@ ENTITY tb_ddrctrl IS g_sim_length : NATURAL := 16500; -- close to the amount of word that gets put into the memory g_technology : NATURAL := c_tech_select_default; g_tech_ddr3 : t_c_tech_ddr := c_tech_ddr3_4g_800m_master; - g_tech_ddr4 : t_c_tech_ddr := c_tech_ddr4_4g_1600m + g_tech_ddr4 : t_c_tech_ddr := c_tech_ddr4_4g_1600m; + g_stop_percentage : NATURAL := 80 -- percentage there needs to be already written in the ddr memory when a stop gets triggered ); END tb_ddrctrl; @@ -88,6 +90,7 @@ ARCHITECTURE tb OF tb_ddrctrl IS SIGNAL mm_rst : STD_LOGIC := '0'; SIGNAL in_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_init); -- input data signal for ddrctrl_pack.vhd SIGNAL wr_not_rd : STD_LOGIC; + SIGNAL stop_in : STD_LOGIC := '0'; -- testbench signal @@ -128,16 +131,24 @@ BEGIN -- filling the input data vectors with the corresponding numbers - make_data : FOR J IN 0 TO c_sim_length-1 LOOP - in_data_cnt <= in_data_cnt+1; - fill_in_sosi_arr_rest : FOR I IN 0 TO g_nof_streams-1 LOOP - in_sosi_arr(I).data(g_data_w-1 DOWNTO 0) <= c_total_vector(g_data_w*(I+1)+J*c_in_data_w-1 DOWNTO g_data_w*I+J*c_in_data_w); + run_multiple_times : FOR K in 0 TO 4 LOOP + make_data : FOR J IN 0 TO c_sim_length-1 LOOP + in_data_cnt <= in_data_cnt+1; + fill_in_sosi_arr_0 : FOR I IN 0 TO g_nof_streams-1 LOOP + in_sosi_arr(I).data(g_data_w-1 DOWNTO 0) <= c_total_vector(g_data_w*(I+1)+J*c_in_data_w-1 DOWNTO g_data_w*I+J*c_in_data_w); + END LOOP; + WAIT FOR c_clk_period*1; END LOOP; - WAIT FOR c_clk_period*1; + IF k = 2 THEN + stop_in <= '1'; + ELSE + stop_in <= '0'; + END IF; END LOOP; test_running <= '0'; wr_not_rd <= '0'; + -- stopping the testbench WAIT FOR c_clk_period*4; tb_end <= '1'; @@ -154,7 +165,8 @@ BEGIN g_sim_model => c_sim_model, g_technology => g_technology, g_nof_streams => g_nof_streams, - g_data_w => g_data_w + g_data_w => g_data_w, + g_stop_percentage => g_stop_percentage ) PORT MAP ( clk => clk, @@ -163,8 +175,7 @@ BEGIN mm_rst => mm_rst, in_sosi_arr => in_sosi_arr, wr_not_rd => wr_not_rd, - out_of => open, - out_adr => open, + stop_in => stop_in, --PHY phy3_io => phy3_io,