------------------------------------------------------------------------------- -- -- 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: Self checking and self-stopping tb for ddrctrl.vhd -- Usage: -- > run -a LIBRARY IEEE, common_lib, technology_lib, tech_ddr_lib, dp_lib; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; USE IEEE.MATH_REAL.ALL; USE technology_lib.technology_pkg.ALL; USE tech_ddr_lib.tech_ddr_pkg.ALL; USE dp_lib.dp_stream_pkg.ALL; 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 ( g_tech_ddr : t_c_tech_ddr := c_tech_ddr4_8g_1600m; -- type of memory g_nof_streams : POSITIVE := 12; -- number of input streams g_data_w : NATURAL := 14; -- data with of input data vectors 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_stop_percentage : NATURAL := 80; -- percentage there needs to be already written in the ddr memory when a stop gets triggered g_block_size : NATURAL := 1024 -- amount of samples that goes into one bsn ); END tb_ddrctrl; ARCHITECTURE tb OF tb_ddrctrl IS CONSTANT c_sim_model : BOOLEAN := TRUE; -- determens if this is a simulation -- Select DDR3 or DDR4 dependent on the technology and sim model CONSTANT c_mem_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, g_tech_ddr3, g_tech_ddr4); CONSTANT c_sim_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, c_tech_ddr3_sim_16k, c_tech_ddr4_sim_16k); CONSTANT c_tech_ddr : t_c_tech_ddr := func_tech_sel_ddr(c_sim_model, c_sim_ddr, c_mem_ddr); -- constants for readability CONSTANT c_ctrl_data_w : NATURAL := func_tech_ddr_ctlr_data_w(c_tech_ddr); -- 576 CONSTANT c_in_data_w : NATURAL := g_nof_streams*g_data_w; -- output data with, 168 -- constants for testbench CONSTANT c_clk_freq : NATURAL := 200; -- clock frequency in MHz CONSTANT c_clk_period : TIME := (10**6/c_clk_freq)*1 ps; -- clock priod, 5 ns CONSTANT c_mm_clk_freq : NATURAL := 100; -- mm clock frequency in MHz CONSTANT c_mm_clk_period : TIME := (10**6/c_mm_clk_freq)*1 ps; -- mm clock period, 10 ns -- constant for checking output data CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w(c_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_output_stop_adr : NATURAL := (c_max_adr+1)-((((c_max_adr+1)/64)*g_stop_percentage/100)*64); CONSTANT c_output_ds : NATURAL := 144; CONSTANT c_bim : NATURAL := (c_max_adr*c_ctrl_data_w)/(g_block_size*g_nof_streams*g_data_w); -- the amount of whole blocks that fit in memory. CONSTANT c_adr_per_b : NATURAL := ((g_block_size*g_nof_streams*g_data_w)/c_ctrl_data_w)+1; -- rounding error removes the amount of extra addresses. -- the amount of addresses used CONSTANT c_nof_adr : NATURAL := (c_bim*g_block_size*g_nof_streams*g_data_w)/c_ctrl_data_w; -- rounding error removes the amount of extra addresses. -- 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_ctrl_data_w)*c_ctrl_data_w); -- amount of overflow after one block is written to memory FUNCTION c_of_after_nof_adr_init RETURN NATURAL IS VARIABLE temp : NATURAL := 0; BEGIN FOR I IN 0 TO c_bim-1 LOOP IF temp+c_of_pb < c_ctrl_data_w THEN temp := temp+c_of_pb; ELSE temp := temp+c_of_pb-c_ctrl_data_w; END IF; END LOOP; RETURN temp; END FUNCTION c_of_after_nof_adr_init; -- the amount of overflow into the address: c_nof_adr NOT YET USED DELETE AFTER L2SDP-706 CONSTANT c_of_after_nof_adr : NATURAL := c_of_after_nof_adr_init; -- function for making total data vector FUNCTION c_total_vector_init RETURN STD_LOGIC_VECTOR IS VARIABLE temp : STD_LOGIC_VECTOR(g_data_w*g_nof_streams*c_bim*g_block_size-1 DOWNTO 0); VARIABLE conv : STD_LOGIC_VECTOR(32-1 DOWNTO 0) := (OTHERS => '0'); -- removes a warning BEGIN FOR I IN 0 TO c_bim*g_block_size-1 LOOP conv := TO_UVEC(I, 32); FOR J IN 0 TO g_nof_streams-1 LOOP temp(g_data_w*((I*g_nof_streams)+J+1)-1 DOWNTO g_data_w*((I*g_nof_streams)+j)) := conv(g_data_w-1 DOWNTO 0); END LOOP; END LOOP; RETURN temp; END FUNCTION c_total_vector_init; -- constant for running the test CONSTANT c_total_vector : STD_LOGIC_VECTOR(g_data_w*g_nof_streams*c_bim*g_block_size-1 DOWNTO 0) := c_total_vector_init; -- vector which contains all input data vectors to make it easy to fill ctr_vector SIGNAL c_total_vector_length : NATURAL := c_total_vector'length; CONSTANT c_check : NATURAL := 32; CONSTANT c_check_bottom : NATURAL := 5; CONSTANT c_ones : STD_LOGIC_VECTOR(c_check-c_check_bottom-1 DOWNTO 0) := (OTHERS => '1'); -- input signals for ddrctrl.vhd SIGNAL clk : STD_LOGIC := '1'; SIGNAL rst : STD_LOGIC := '0'; SIGNAL mm_clk : STD_LOGIC := '0'; 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 stop_in : STD_LOGIC := '0'; SIGNAL out_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_init); SIGNAL out_siso : t_dp_siso; -- testbench signal SIGNAL tb_end : STD_LOGIC := '0'; -- signal to turn the testbench off -- signals for running test SIGNAL in_data_cnt : NATURAL := 0; -- signal which contains the amount of times there has been input data for ddrctrl_repack.vhd SIGNAL test_running : STD_LOGIC := '0'; -- signal to tell wheter the testing has started SIGNAL bsn_cnt : NATURAL := g_block_size-1; -- signals for checking the output data SIGNAL output_data_cnt : NATURAL := 0; -- PHY SIGNAL phy3_io : t_tech_ddr3_phy_io; SIGNAL phy3_ou : t_tech_ddr3_phy_ou; SIGNAL phy4_io : t_tech_ddr4_phy_io; SIGNAL phy4_ou : t_tech_ddr4_phy_ou; BEGIN -- generating clock clk <= NOT clk OR tb_end AFTER c_clk_period/2; mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2; out_siso.ready <= '1'; out_siso.xon <= '1'; -- excecuting test p_test : PROCESS BEGIN -- start the test tb_end <= '0'; in_sosi_arr(0).valid <= '0'; WAIT UNTIL rising_edge(clk); -- align to rising edge WAIT FOR c_clk_period*4; rst <= '1'; mm_rst <= '1'; WAIT FOR c_clk_period*1; rst <= '0'; mm_rst <= '0'; test_running <= '1'; WAIT FOR c_clk_period*1; -- wr fifo has delay of 4 clockcylces after reset -- filling the input data vectors with the corresponding numbers run_multiple_times : FOR K in 0 TO 3 LOOP make_data : FOR J IN 0 TO c_bim*g_block_size-1 LOOP in_data_cnt <= in_data_cnt+1; fill_in_sosi_arr : FOR I IN 0 TO g_nof_streams-1 LOOP IF bsn_cnt = g_block_size-1 THEN IF I = 0 THEN bsn_cnt <= 0; END IF; in_sosi_arr(I).sop <= '1'; in_sosi_arr(I).eop <= '0'; in_sosi_arr(I).bsn <= INCR_UVEC(in_sosi_arr(I).bsn, 1); ELSE IF I = 0 THEN bsn_cnt <= bsn_cnt + 1; END IF; in_sosi_arr(I).sop <= '0'; END IF; IF bsn_cnt = g_block_size-2 THEN in_sosi_arr(I).eop <= '1'; END IF; 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); in_sosi_arr(I).valid <= '1'; END LOOP; IF K = 0 AND J = c_bim*g_block_size-1 THEN stop_in <= '1'; ELSE stop_in <= '0'; END IF; WAIT FOR c_clk_period*1; END LOOP; END LOOP; in_sosi_arr(0).valid <= '0'; test_running <= '0'; -- stopping the testbench WAIT FOR c_clk_period*g_block_size; tb_end <= '1'; ASSERT FALSE REPORT "Test: OK" SEVERITY FAILURE; END PROCESS; p_checking_output_data : PROCESS -- first do tickets L2SDP-708 and L2SDP-707 before finsishing this is worth time BEGIN WAIT UNTIL rising_edge(clk); IF out_sosi_arr(0).valid = '1' THEN FOR I IN 0 TO g_nof_streams-1 LOOP IF c_output_stop_adr+output_data_cnt <= c_max_adr THEN --ASSERT out_sosi_arr(I).data(c_in_data_w-1 DOWNTO 0) = c_total_vector(g_data_w*(I+1)+(c_output_stop_adr+output_data_cnt)*c_ctrl_data_w-1 DOWNTO g_data_w*I+(c_output_stop_adr+output_data_cnt)*c_ctrl_data_w) REPORT "wrong output data at: " & NATURAL'image(c_output_stop_adr+output_data_cnt) SEVERITY ERROR; ELSE --ASSERT out_sosi_arr(I).data(c_in_data_w-1 DOWNTO 0) = c_total_vector(g_data_w*(I+1)+(c_output_stop_adr+output_data_cnt-c_max_adr)*c_ctrl_data_w-1 DOWNTO g_data_w*I+(c_output_stop_adr+output_data_cnt-c_max_adr)*c_ctrl_data_w) REPORT "wrong output data at: " & NATURAL'image(c_output_stop_adr+output_data_cnt) SEVERITY ERROR; END IF; END LOOP; output_data_cnt <= output_data_cnt+1; END IF; WAIT FOR c_clk_period*1; END PROCESS; -- DUT u_ddrctrl : ENTITY work.ddrctrl GENERIC MAP ( g_tech_ddr => c_tech_ddr, g_sim_model => c_sim_model, g_technology => g_technology, g_nof_streams => g_nof_streams, g_data_w => g_data_w, g_stop_percentage => g_stop_percentage, g_block_size => g_block_size ) PORT MAP ( clk => clk, rst => rst, mm_clk => mm_clk, mm_rst => mm_rst, in_sosi_arr => in_sosi_arr, stop_in => stop_in, out_sosi_arr => out_sosi_arr, out_siso => out_siso, --PHY phy3_io => phy3_io, phy3_ou => phy3_ou, phy4_io => phy4_io, phy4_ou => phy4_ou ); END tb;