-
Job van Wee authoredJob van Wee authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tb_ddrctrl.vhd 13.98 KiB
-------------------------------------------------------------------------------
--
-- 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;