diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
index 9577a0ca48378e3eede404c1f93486941a0fa9e2..0a2afbc86ec912364931c6450d836d1ce316dfb3 100644
--- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
@@ -57,8 +57,13 @@ ENTITY ddrctrl IS
   PORT (
     clk               : IN  STD_LOGIC := '0';
     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
+    wr_not_rd         : IN  STD_LOGIC := '0';
     out_of            : OUT NATURAL;                                    -- amount of internal overflow this output
+    out_adr           : OUT NATURAL;
+
 
     term_ctrl_out     : OUT   t_tech_ddr3_phy_terminationcontrol;
     term_ctrl_in      : IN    t_tech_ddr3_phy_terminationcontrol := c_tech_ddr3_phy_terminationcontrol_rst;
@@ -83,12 +88,11 @@ ARCHITECTURE str OF ddrctrl IS
   CONSTANT  c_io_ddr_data_w  : NATURAL    := func_tech_ddr_ctlr_data_w( g_tech_ddr );
 
   -- signals for connecting the components
-  SIGNAL    data         : STD_LOGIC_VECTOR(c_out_data_w-1 DOWNTO 0);
   SIGNAL    sosi         : t_dp_sosi  := c_dp_sosi_init;
   SIGNAL    adr          : NATURAL    := 0;
   SIGNAL    a_of         : NATURAL    := 0;
-  SIGNAL    ctrl_clk     : STD_LOGIC  := '0';
-  SIGNAL    ctrl_rst     : STD_LOGIC  := '0';
+  SIGNAL    ctrl_clk     : STD_LOGIC;
+  SIGNAL    ctrl_rst     : STD_LOGIC;
   SIGNAL    wr_sosi      : t_dp_sosi  := c_dp_sosi_init;
   SIGNAL    wr_siso      : t_dp_siso;
   SIGNAL    rd_siso      : t_dp_siso;
@@ -96,51 +100,25 @@ ARCHITECTURE str OF ddrctrl IS
 
 BEGIN
 
-  dvr_mosi.address <= TO_UVEC(adr, dvr_mosi.address'length);
-
-  -- makes one data vector out of all the data from the t_dp_sosi_arr
-  u_pack : ENTITY work.ddrctrl_pack
-  GENERIC MAP(
-
-    g_nof_streams     => g_nof_streams,                                 -- number of input streams
-    g_data_w          => g_data_w                                       -- data with of input data vectors
-
-  )
-  PORT MAP(
-
-    in_sosi_arr       => in_sosi_arr,                                   -- input data
-    out_data          => data                                           -- output data
-
-  );
-
-  -- resizes the input data vector so that the output data vector can be stored into the ddr memory
-  u_repack : ENTITY work.ddrctrl_repack
+  dvr_mosi.address    <= TO_UVEC(adr, dvr_mosi.address'length);
+  dvr_mosi.burstbegin <= wr_sosi.valid;
+  dvr_mosi.wr         <= wr_not_rd;
+  dvr_mosi.rd         <= NOT wr_not_rd;
+  -- input to io_ddr
+  u_ddrctrl_input : ENTITY work.ddrctrl_input
   GENERIC MAP(
-    g_tech_ddr        => g_tech_ddr,                                    -- type of memory
-    g_in_data_w       => c_out_data_w                                   -- the input data with
-  )
-  PORT MAP(
-    clk               => clk,
-    rst               => rst,
-    in_data           => data,                                          -- input data
-    out_of            => a_of,                                          -- amount of internal overflow
-    out_sosi          => sosi                                           -- output data
-  );
-
-  -- creates address by counting input valids
-  u_address_counter : ENTITY work.ddrctrl_address_counter
-  GENERIC MAP(
-    g_tech_ddr        => g_tech_ddr,                                    -- type of memory
-    g_sim_model       => g_sim_model                                    -- determens if this is a simulation
+    g_tech_ddr                => g_tech_ddr,
+    g_sim_model               => g_sim_model,
+    g_nof_streams             => g_nof_streams,
+    g_data_w                  => g_data_w
   )
   PORT MAP(
-    clk               => clk,
-    rst               => rst,
-    in_sosi           => sosi,                                          -- input data
-    in_of             => a_of,
-    out_sosi          => wr_sosi,                                       -- output data
-    out_of            => out_of,
-    out_adr           => adr
+    clk                       => clk,
+    rst                       => rst,
+    in_sosi_arr               => in_sosi_arr,
+    out_of                    => out_of,
+    out_sosi                  => wr_sosi,
+    out_adr                   => out_adr
   );
 
   -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick.
@@ -173,8 +151,8 @@ BEGIN
     ctlr_rst_in               => ctrl_rst,
     
     -- MM clock + reset
-    mm_rst                    => rst,                                           
-    mm_clk                    => clk, 
+    mm_rst                    => mm_rst,                                           
+    mm_clk                    => mm_clk, 
     
     -- MM interface
     reg_io_ddr_mosi           => open,
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..3f46046f2ea2459685d898534382d876d5458843
--- /dev/null
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd
@@ -0,0 +1,121 @@
+-------------------------------------------------------------------------------
+--
+-- 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;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE technology_lib.technology_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;
+
+
+ENTITY ddrctrl_input IS
+  GENERIC (
+    g_tech_ddr        : t_c_tech_ddr;                                   -- type of memory
+    g_sim_model       : BOOLEAN       := TRUE;                          -- determens if this is a simulation
+    g_nof_streams     : NATURAL       := 12;                            -- number of input streams
+    g_data_w          : NATURAL       := 14                             -- data with of input data vectors
+  );
+  PORT (
+    clk               : IN  STD_LOGIC := '0';
+    rst               : IN  STD_LOGIC;
+    in_sosi_arr       : IN  t_dp_sosi_arr;                              -- input data
+    out_of            : OUT NATURAL;                                    -- amount of internal overflow this output
+    out_sosi          : OUT t_dp_sosi;                                  -- output data
+    out_adr           : OUT NATURAL
+  );
+END ddrctrl_input;
+
+
+ARCHITECTURE str OF ddrctrl_input IS
+
+  -- constant for readability
+  CONSTANT  c_out_data_w : NATURAL    := g_nof_streams*g_data_w;        -- the input data with for ddrctrl_repack
+
+
+  -- signals for connecting the components
+  SIGNAL    data         : STD_LOGIC_VECTOR(c_out_data_w-1 DOWNTO 0);
+  SIGNAL    sosi         : t_dp_sosi  := c_dp_sosi_init;
+  SIGNAL    a_of           : NATURAL    := 0;
+
+BEGIN
+
+  -- makes one data vector out of all the data from the t_dp_sosi_arr
+  u_pack : ENTITY work.ddrctrl_pack
+  GENERIC MAP(
+
+    g_nof_streams     => g_nof_streams,                                 -- number of input streams
+    g_data_w          => g_data_w                                       -- data with of input data vectors
+
+  )
+  PORT MAP(
+
+    in_sosi_arr       => in_sosi_arr,                                   -- input data
+    out_data          => data                                           -- output data
+
+  );
+
+  -- resizes the input data vector so that the output data vector can be stored into the ddr memory
+  u_repack : ENTITY work.ddrctrl_repack
+  GENERIC MAP(
+    g_tech_ddr        => g_tech_ddr,                                    -- type of memory
+    g_in_data_w       => c_out_data_w                                   -- the input data with
+  )
+  PORT MAP(
+    clk               => clk,
+    rst               => rst,
+    in_data           => data,                                          -- input data
+    out_of            => a_of,                                          -- amount of internal overflow
+    out_sosi          => sosi                                           -- output data
+  );
+
+  -- creates address by counting input valids
+  u_address_counter : ENTITY work.ddrctrl_address_counter
+  GENERIC MAP(
+    g_tech_ddr        => g_tech_ddr,                                    -- type of memory
+    g_sim_model       => g_sim_model                                    -- determens if this is a simulation
+  )
+  PORT MAP(
+    clk               => clk,
+    rst               => rst,
+    in_sosi           => sosi,                                          -- input data
+    in_of             => a_of,
+    out_sosi          => out_sosi,                                      -- output data
+    out_of            => out_of,
+    out_adr           => out_adr
+  );
+
+END str;
diff --git a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
index ff2f25739c6e171f8d4739cbab2604826d7f58a9..9bd01e39ea8cbf727db27d456a615d9ae2feffa3 100644
--- a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
+++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
@@ -31,6 +31,7 @@ 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 (
@@ -39,10 +40,10 @@ ENTITY tb_ddrctrl IS
     g_sim_model               : BOOLEAN                                               := TRUE;                                    -- determens if this is a simulation
     g_nof_streams             : POSITIVE                                              := 12;                                      -- number of input streams
     g_data_w                  : NATURAL                                               := 14;                                      -- data with of input data vectors
-    g_sim_length              : NATURAL                                               := 52
+    g_sim_length              : NATURAL                                               := 1052;
     g_technology              : NATURAL                                               := c_tech_select_default;
-    g_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
-    g_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
+    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
   );
 END tb_ddrctrl;
 
@@ -51,7 +52,17 @@ ARCHITECTURE tb OF tb_ddrctrl IS
   -- 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;
+  CONSTANT  c_mm_clk_period   : TIME                                                  := (10**6 / c_mm_clk_freq) * 1 ps;
 
+  -- 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(g_sim_model, c_sim_ddr, c_mem_ddr);
+
+  CONSTANT c_wr_fifo_depth            : NATURAL := 16;  -- defined at DDR side of the FIFO 
+  CONSTANT c_rd_fifo_depth            : NATURAL := 256;  -- defined at DDR side of the FIFO 
+  
   -- constants for readability
   CONSTANT  c_in_data_w       : NATURAL                                               := g_nof_streams * g_data_w;                -- output data with, 168
   CONSTANT  c_out_data_w      : NATURAL                                               := func_tech_ddr_ctlr_data_w( g_tech_ddr ); -- output data vector with, 576
@@ -75,13 +86,16 @@ ARCHITECTURE tb OF tb_ddrctrl IS
   -- 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    q_rst             : STD_LOGIC                                             := '0';
   SIGNAL    q_q_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;
 
   -- output singals from ddrctrl.vhd
   SIGNAL    out_of            : NATURAL                                               := 0;                                       -- output signal from ddrctrl_repack to determen how high the overflow is
-  SIGNAL    out_mosi          : t_mem_ctlr_mosi                                       := c_mem_ctlr_mosi_rst;                     -- output signal from ddrctrl_pack.vhd
+  SIGNAL    out_adr           : NATURAL                                               := 0;
 
   -- testbench signal
   SIGNAL    tb_end            : STD_LOGIC                                             := '0';                                     -- signal to turn the testbench off
@@ -96,10 +110,17 @@ ARCHITECTURE tb OF tb_ddrctrl IS
   SIGNAL    lag_due_reset     : NATURAL                                               := 0;                                       -- signal to hold the address lag after a rest
   SIGNAL    q_lag_due_reset   : NATURAL                                               := 0;                                       -- signal to hold the address lag after a rest with a delay of 1 clockcycle
 
+  -- 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
@@ -110,9 +131,12 @@ BEGIN
     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';
+    wr_not_rd    <= '1';
 
     -- filling the input data vectors with the corresponding numbers
     make_data : FOR J IN 0 TO g_sim_length-1 LOOP
@@ -123,14 +147,15 @@ BEGIN
       WAIT FOR c_clk_period*1;
     END LOOP;
     test_running      <= '0';
+    wr_not_rd         <= '0';
 
     -- testing reset
-    FOR I IN 0 TO g_sim_length-1 LOOP
-      rst <= '1';
-      WAIT FOR c_clk_period*1;
-      rst <= '0';
-      WAIT FOR c_clk_period*((((c_out_data_w/c_in_data_w)+1)*c_adr_size)+4);
-    END LOOP;
+--    FOR I IN 0 TO g_sim_length-1 LOOP
+--      rst <= '1';
+--      WAIT FOR c_clk_period*1;
+--      rst <= '0';
+--      WAIT FOR c_clk_period*((((c_out_data_w/c_in_data_w)+1)*c_adr_size)+4);
+--    END LOOP;
 
 
     -- stopping the testbench
@@ -139,75 +164,49 @@ BEGIN
     ASSERT FALSE                                                                                                                          REPORT "Test: OK"                                                                                                                             SEVERITY FAILURE;
   END PROCESS;
 
-  -- generating compare data for out_mosi
-  p_out_mosi : PROCESS
-  BEGIN
-    WAIT UNTIL rising_edge(clk);
-    if rising_edge(clk) THEN
-      q_q_rst           <= q_rst;
-      q_lag_due_reset   <= lag_due_reset;
-      q_rst             <= rst;
-    END IF;
-    IF q_rst = '1' THEN
-      IF lag_due_reset + TO_UINT(out_mosi.address) >= c_adr_size THEN
-        lag_due_reset <= lag_due_reset+TO_UINT(out_mosi.address)-c_adr_size;
-      ELSE
-        lag_due_reset <= lag_due_reset+TO_UINT(out_mosi.address);
-      END IF;
-    END IF;
-  END PROCESS;
-
-  -- verifying if the address is correct by keeping track of the address
-  p_verify_address : PROCESS
-  BEGIN
-    FOR I IN 0 TO c_adr_size-1 LOOP
-      IF I >= q_lag_due_reset THEN
-        ASSERT I-q_lag_due_reset   = TO_UINT(out_mosi.address)                                                                            REPORT "Wrong address, 1, I = " & NATURAL'image(I-q_lag_due_reset) & ", address = " & NATURAL'image(TO_UINT(out_mosi.address))                SEVERITY ERROR;
-      ELSE
-        ASSERT (I-q_lag_due_reset)+c_adr_size = TO_UINT(out_mosi.address)                                                                 REPORT "Wrong address, 2, I = " & NATURAL'image((I-q_lag_due_reset)+c_adr_size) & ", address = " & NATURAL'image(TO_UINT(out_mosi.address))   SEVERITY ERROR;
-      END IF;
-      WAIT UNTIL out_mosi.wr = '1';
-      IF q_q_rst = '1' THEN
-        WAIT UNTIL out_mosi.wr = '1';
-      END IF;
-    END LOOP;
-  END PROCESS;
-
-  -- verification by checking if the input vectors are correctly put into the output vector and the amount of overflow is as expected
-  p_verify : PROCESS
 
-  VARIABLE  ctr_of            : NATURAL                                                := 0;
-  VARIABLE  out_data_cnt      : NATURAL                                                := 0;
-
-  BEGIN
-  WAIT UNTIL rising_edge(clk);
-  IF q_q_test_running = '1' AND out_mosi.wr = '1' THEN
-    out_data_cnt      := out_data_cnt+1;
-    IF out_data_cnt mod 2 = 0 THEN
-      ctr_of := c_in_data_w*(q_q_in_data_cnt)-c_out_data_w*out_data_cnt;
-      ASSERT ctr_of                               = out_of                                                                                REPORT "The amount of overflow does not match, ctr_of = " & NATURAL'image(ctr_of) & ", out_of = " & NATURAL'image(out_of)                     SEVERITY ERROR;
-    END IF;
-    ASSERT out_mosi.wrdata(c_out_data_w-1 DOWNTO 0) = c_total_vector(c_out_data_w*out_data_cnt-1 DOWNTO c_out_data_w*(out_data_cnt-1))    REPORT "Data does not match, out_data_cnt = " & NATURAL'image(out_data_cnt)                                                                   SEVERITY ERROR;
-  END IF;
-  END PROCESS;
 
 
   -- DUT
   u_ddrctrl : ENTITY work.ddrctrl
   GENERIC MAP (
-    g_tech_ddr        => g_tech_ddr,
+    g_tech_ddr        => c_tech_ddr,
     g_sim_model       => g_sim_model,
     g_technology      => g_technology,
     g_nof_streams     => g_nof_streams,
     g_data_w          => g_data_w,
-    g_wr_fifo_depth   => g_wr_fifo_depth,
-    g_rd_fifo_depth   => g_rd_fifo_depth
+    g_wr_fifo_depth   => c_wr_fifo_depth,
+    g_rd_fifo_depth   => c_rd_fifo_depth
   )
   PORT MAP (
     clk               => clk,
     rst               => rst,
+    mm_clk            => mm_clk,
+    mm_rst            => mm_rst,
     in_sosi_arr       => in_sosi_arr,
+    wr_not_rd         => wr_not_rd,
     out_of            => out_of,
+    out_adr           => out_adr,
+
+    --PHY
+    phy3_io           => phy3_io,
+    phy3_ou           => phy3_ou,
+    phy4_io           => phy4_io,
+    phy4_ou           => phy4_ou
+  );
+
+  u_tech_ddr_memory_model : ENTITY tech_ddr_lib.tech_ddr_memory_model
+  GENERIC MAP (
+    g_tech_ddr        => c_tech_ddr
+  )
+  PORT MAP (
+    -- DDR3 PHY interface
+    mem3_in           => phy3_ou,
+    mem3_io           => phy3_io,
+    
+    -- DDR4 PHY interface
+    mem4_in           => phy4_ou,
+    mem4_io           => phy4_io
   );
 
 END tb;
diff --git a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl_input.vhd b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl_input.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..5d6da7aa7c2eb069fa8d4c62e66ba1dfa195f722
--- /dev/null
+++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl_input.vhd
@@ -0,0 +1,211 @@
+-------------------------------------------------------------------------------
+--
+-- 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_input.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;
+
+ENTITY tb_ddrctrl_input IS
+  GENERIC (
+
+    g_tech_ddr                : t_c_tech_ddr                                          := c_tech_ddr4_8g_1600m;                    -- type of memory
+    g_sim_model               : BOOLEAN                                               := TRUE;                                    -- determens if this is a simulation
+    g_nof_streams             : POSITIVE                                              := 12;                                      -- number of input streams
+    g_data_w                  : NATURAL                                               := 14;                                      -- data with of input data vectors
+    g_sim_length              : NATURAL                                               := 52
+
+  );
+END tb_ddrctrl_input;
+
+ARCHITECTURE tb OF tb_ddrctrl_input IS
+
+  -- 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
+
+  -- constants for readability
+  CONSTANT  c_in_data_w       : NATURAL                                               := g_nof_streams * g_data_w;                -- output data with, 168
+  CONSTANT  c_out_data_w      : NATURAL                                               := func_tech_ddr_ctlr_data_w( g_tech_ddr ); -- output data vector with, 576
+  CONSTANT  c_adr_w           : NATURAL                                               := 4;                                       -- address with in simulation
+  CONSTANT  c_adr_size        : NATURAL                                               := 2**c_adr_w;                              -- address size in simulation
+
+  -- 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*g_sim_length-1 DOWNTO 0);
+  BEGIN
+    FOR I IN 0 TO g_sim_length*g_nof_streams-1 LOOP
+      temp(g_data_w*(I+1)-1 DOWNTO g_data_w*I) := TO_UVEC(I, g_data_w);
+    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*g_sim_length-1 DOWNTO 0) := c_total_vector_init;                     -- vector which contains all input data vectors to make it easy to fill ctr_vector
+
+
+  -- input signals for ddrctrl_input.vhd
+  SIGNAL    clk               : STD_LOGIC                                             := '1';
+  SIGNAL    rst               : STD_LOGIC                                             := '0';
+  SIGNAL    q_rst             : STD_LOGIC                                             := '0';
+  SIGNAL    q_q_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 
+
+  -- output singals from ddrctrl_input.vhd
+  SIGNAL    out_of            : NATURAL                                               := 0;                                       -- output signal from ddrctrl_repack to determen how high the overflow is
+  SIGNAL    out_sosi          : t_dp_sosi                                             := c_dp_sosi_init;                     -- output signal from ddrctrl_pack.vhd
+  SIGNAL    out_adr           : NATURAL                                               := 0;
+
+  -- 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    q_in_data_cnt     : NATURAL                                               := 0;                                       -- signal which contains the amount of times there has been input data for ddrctrl_repack.vhd with a delay of 1 clockcycle
+  SIGNAL    q_q_in_data_cnt   : NATURAL                                               := 0;                                       -- signal which contains the amount of times there has been input data for ddrctrl_repack.vhd with a delay of 2 clockcycles
+  SIGNAL    test_running      : STD_LOGIC                                             := '0';                                     -- signal to tell wheter the testing has started
+  SIGNAL    q_test_running    : STD_LOGIC                                             := '0';                                     -- signal to tell wheter the testing has started with a delay of 1 clockcycle
+  SIGNAL    q_q_test_running  : STD_LOGIC                                             := '0';                                     -- signal to tell wheter the testing has started with a delay of 2 clockcycles
+  SIGNAL    lag_due_reset     : NATURAL                                               := 0;                                       -- signal to hold the address lag after a rest
+  SIGNAL    q_lag_due_reset   : NATURAL                                               := 0;                                       -- signal to hold the address lag after a rest with a delay of 1 clockcycle
+
+BEGIN
+
+  -- generating clock
+  clk               <= NOT clk OR tb_end AFTER c_clk_period/2;
+
+  -- excecuting test
+  p_test : PROCESS
+  BEGIN
+
+    -- start the test
+    tb_end          <= '0';
+    WAIT UNTIL rising_edge(clk);                                                                                                  -- align to rising edge
+    WAIT FOR c_clk_period*4;
+    rst <= '1';
+    WAIT FOR c_clk_period*1;
+    rst <= '0';
+    test_running <= '1';
+
+    -- filling the input data vectors with the corresponding numbers
+    make_data : FOR J IN 0 TO g_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);
+      END LOOP;
+      WAIT FOR c_clk_period*1;
+    END LOOP;
+    test_running      <= '0';
+
+    -- testing reset
+    FOR I IN 0 TO g_sim_length-1 LOOP
+      rst <= '1';
+      WAIT FOR c_clk_period*1;
+      rst <= '0';
+      WAIT FOR c_clk_period*((((c_out_data_w/c_in_data_w)+1)*c_adr_size)+4);
+    END LOOP;
+
+
+    -- stopping the testbench
+    WAIT FOR c_clk_period*4;
+    tb_end <= '1';
+    ASSERT FALSE                                                                                                                          REPORT "Test: OK"                                                                                                                             SEVERITY FAILURE;
+  END PROCESS;
+
+  -- generating compare data for out_sosi
+  p_out_sosi : PROCESS
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    if rising_edge(clk) THEN
+      q_q_rst           <= q_rst;
+      q_lag_due_reset   <= lag_due_reset;
+      q_rst             <= rst;
+    END IF;
+    IF q_rst = '1' THEN
+      IF lag_due_reset + out_adr >= c_adr_size THEN
+        lag_due_reset <= lag_due_reset+out_adr-c_adr_size;
+      ELSE
+        lag_due_reset <= lag_due_reset+out_adr;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -- verifying if the address is correct by keeping track of the address
+  p_verify_address : PROCESS
+  BEGIN
+    FOR I IN 0 TO c_adr_size-1 LOOP
+      IF I >= q_lag_due_reset THEN
+        ASSERT I-q_lag_due_reset   = out_adr                                                                            REPORT "Wrong address, 1, I = " & NATURAL'image(I-q_lag_due_reset) & ", address = " & NATURAL'image(out_adr)                SEVERITY ERROR;
+      ELSE
+        ASSERT (I-q_lag_due_reset)+c_adr_size = out_adr                                                                 REPORT "Wrong address, 2, I = " & NATURAL'image((I-q_lag_due_reset)+c_adr_size) & ", address = " & NATURAL'image(out_adr)   SEVERITY ERROR;
+      END IF;
+      WAIT UNTIL out_sosi.valid = '1';
+      IF q_q_rst = '1' THEN
+        WAIT UNTIL out_sosi.valid = '1';
+      END IF;
+    END LOOP;
+  END PROCESS;
+
+  -- verification by checking if the input vectors are correctly put into the output vector and the amount of overflow is as expected
+  p_verify : PROCESS
+
+  VARIABLE  ctr_of            : NATURAL                                                := 0;
+  VARIABLE  out_data_cnt      : NATURAL                                                := 0;
+
+  BEGIN
+  WAIT UNTIL rising_edge(clk);
+  IF q_q_test_running = '1' AND out_sosi.valid = '1' THEN
+    out_data_cnt      := out_data_cnt+1;
+    IF out_data_cnt mod 2 = 0 THEN
+      ctr_of := c_in_data_w*(q_q_in_data_cnt)-c_out_data_w*out_data_cnt;
+      ASSERT ctr_of                               = out_of                                                                                REPORT "The amount of overflow does not match, ctr_of = " & NATURAL'image(ctr_of) & ", out_of = " & NATURAL'image(out_of)                     SEVERITY ERROR;
+    END IF;
+    ASSERT out_sosi.data(c_out_data_w-1 DOWNTO 0) = c_total_vector(c_out_data_w*out_data_cnt-1 DOWNTO c_out_data_w*(out_data_cnt-1))      REPORT "Data does not match, out_data_cnt = " & NATURAL'image(out_data_cnt)                                                                   SEVERITY ERROR;
+  END IF;
+  END PROCESS;
+
+
+  -- DUT
+  u_ddrctrl_input : ENTITY work.ddrctrl_input
+  GENERIC MAP (
+    g_tech_ddr        => g_tech_ddr,
+    g_sim_model       => g_sim_model,
+    g_nof_streams     => g_nof_streams,
+    g_data_w          => g_data_w
+  )
+  PORT MAP (
+    clk               => clk,
+    rst               => rst,
+    in_sosi_arr       => in_sosi_arr,
+    out_of            => out_of,
+    out_sosi          => out_sosi,
+    out_adr           => out_adr
+  );
+
+END tb;