Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tb_ddrctrl.vhd 11.62 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_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_stop_percentage         : NATURAL                                               := 80                                       -- percentage there needs to be already written in the ddr memory when a stop gets triggered
  );
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  c_sim_length      : NATURAL                                               := (g_sim_length*c_ctrl_data_w)/c_in_data_w; -- amount of input words that get put into the DUT
  -- 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;


  -- function for making total data vector
  FUNCTION  c_total_vector_init RETURN STD_LOGIC_VECTOR IS
    VARIABLE temp             : STD_LOGIC_VECTOR(c_in_data_w*c_sim_length-1 DOWNTO 0);
    VARIABLE conv             : STD_LOGIC_VECTOR(32-1 DOWNTO 0);                                                                  -- removes a warning
  BEGIN
    FOR I IN 0 TO c_sim_length-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(c_in_data_w*c_sim_length-1 DOWNTO 0) := c_total_vector_init;                     -- vector which contains all input data vectors to make it easy to fill ctr_vector

  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    bsn               : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0)        := (OTHERS => '0');
  SIGNAL    out_sosi_arr      : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0)               := (OTHERS => c_dp_sosi_init);

  -- 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

  -- 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;

  -- excecuting test
  p_test : PROCESS
  BEGIN

    bsn(c_check-1 DOWNTO c_check_bottom) <= c_ones(c_check-c_check_bottom-1 DOWNTO 0);

    -- start the test
    tb_end          <= '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;


    -- filling the input data vectors with the corresponding numbers
    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;
        in_sosi_arr(0).bsn(c_dp_stream_bsn_w-1 DOWNTO 0) <= bsn(c_dp_stream_bsn_w-1 DOWNTO 0);
        bsn <= INCR_UVEC(bsn, 1);
        IF K = 1 AND J = 0 THEN
          stop_in <= '1';
        ELSE
          stop_in <= '0';
        END IF;
        WAIT FOR c_clk_period*1;
      END LOOP;
    END LOOP;
    test_running      <= '0';


    -- stopping the testbench
    WAIT FOR c_clk_period*4;
    tb_end <= '1';
    ASSERT FALSE                                                                                                                          REPORT "Test: OK"                                                                                                                             SEVERITY FAILURE;
  END PROCESS;

  p_checking_output_data : PROCESS
  BEGIN
    WAIT UNTIL rising_edge(clk);
    IF out_sosi_arr(0).valid = '1' THEN
      --assert false report "checking" severity note;
      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
  )
  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,

    --PHY
    phy3_io           => phy3_io,
    phy3_ou           => phy3_ou,
    phy4_io           => phy4_io,
    phy4_ou           => phy4_ou
  );

END tb;