From 27c93f512a65eaf724ad23f5d6fcce2e4e196118 Mon Sep 17 00:00:00 2001
From: JobvanWee <wee@astron.nl>
Date: Wed, 6 Apr 2022 17:27:12 +0200
Subject: [PATCH] IT works!!

---
 .../lofar2/libraries/ddrctrl/hdllib.cfg       |   3 +
 .../libraries/ddrctrl/src/vhdl/ddrctrl.vhd    |  83 ++++++--
 .../ddrctrl/src/vhdl/ddrctrl_controller.vhd   | 184 ++++++++++++++++--
 .../ddrctrl/src/vhdl/ddrctrl_input.vhd        |   2 +-
 .../ddrctrl/src/vhdl/ddrctrl_output.vhd       | 103 ++++++++++
 .../src/vhdl/ddrctrl_output_repack.vhd        |  58 ++++++
 .../src/vhdl/ddrctrl_output_unpack.vhd        | 173 ++++++++++++++++
 .../libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd  |   2 +
 8 files changed, 573 insertions(+), 35 deletions(-)
 create mode 100644 applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output.vhd
 create mode 100644 applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_repack.vhd
 create mode 100644 applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd

diff --git a/applications/lofar2/libraries/ddrctrl/hdllib.cfg b/applications/lofar2/libraries/ddrctrl/hdllib.cfg
index dc978140ea..e399eb4af6 100644
--- a/applications/lofar2/libraries/ddrctrl/hdllib.cfg
+++ b/applications/lofar2/libraries/ddrctrl/hdllib.cfg
@@ -9,6 +9,9 @@ synth_files =
     src/vhdl/ddrctrl_input_pack.vhd
     src/vhdl/ddrctrl_input_repack.vhd
     src/vhdl/ddrctrl_input.vhd
+    src/vhdl/ddrctrl_output_unpack.vhd
+    src/vhdl/ddrctrl_output_repack.vhd
+    src/vhdl/ddrctrl_output.vhd
     src/vhdl/ddrctrl_controller.vhd
     src/vhdl/ddrctrl.vhd
 
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
index 25ce70e55c..e7de428b6c 100644
--- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd
@@ -62,6 +62,7 @@ ENTITY ddrctrl IS
     wr_not_rd         : IN  STD_LOGIC                                       := '0';
     stop_in           : IN  STD_LOGIC                                       := '0';
 
+    out_sosi_arr      : OUT t_dp_sosi_arr;
 
     term_ctrl_out     : OUT   t_tech_ddr3_phy_terminationcontrol;
     term_ctrl_in      : IN    t_tech_ddr3_phy_terminationcontrol            := c_tech_ddr3_phy_terminationcontrol_rst;
@@ -93,13 +94,24 @@ ARCHITECTURE str OF ddrctrl IS
   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    dvr_miso     : t_mem_ctlr_miso                                  := c_mem_ctlr_miso_rst;
   SIGNAL    wr_sosi      : t_dp_sosi                                        := c_dp_sosi_init;
   SIGNAL    rd_siso      : t_dp_siso                                        := c_dp_siso_rst;
+  SIGNAL    rd_sosi      : t_dp_sosi                                        := c_dp_sosi_init;
   SIGNAL    stop         : STD_LOGIC;
+  SIGNAL    rd_fifo_usedw: STD_LOGIC_VECTOR(ceil_log2(c_rd_fifo_depth*(func_tech_ddr_ctlr_data_w(g_tech_ddr)/c_io_ddr_data_w) )-1 DOWNTO 0);
+  SIGNAL    rd_ready     : STD_LOGIC;
 
+  SIGNAL    inp_ds       : NATURAL;
+  SIGNAL    inp_bsn      : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+  SIGNAL    inp_bsn_adr  : NATURAL;
+  SIGNAL    outp_ds      : NATURAL;
+  SIGNAL    outp_bsn     : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
 
 BEGIN
 
+  rd_siso.ready <= rd_ready;
+  rd_siso.xon   <= '1';
 
   -- input to io_ddr
   u_ddrctrl_input : ENTITY work.ddrctrl_input
@@ -116,7 +128,10 @@ BEGIN
     in_stop                   => stop,
     out_of                    => out_of,
     out_sosi                  => out_sosi,
-    out_adr                   => out_adr
+    out_adr                   => out_adr,
+    out_bsn_ds                => inp_ds,
+    out_bsn                   => inp_bsn,
+    out_bsn_adr               => inp_bsn_adr
   );
 
   -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick.
@@ -160,7 +175,7 @@ BEGIN
     dvr_clk                   => clk,
     dvr_rst                   => rst,
     
-    dvr_miso                  => open,
+    dvr_miso                  => dvr_miso,
     dvr_mosi                  => dvr_mosi,
     
     -- Write FIFO clock domain
@@ -175,8 +190,8 @@ BEGIN
     rd_clk                    => clk,
     rd_rst                    => rst,
     
-    rd_fifo_usedw             => open,
-    rd_sosi                   => open,
+    rd_fifo_usedw             => rd_fifo_usedw,
+    rd_sosi                   => rd_sosi,
     rd_siso                   => rd_siso,
 
     term_ctrl_out             => term_ctrl_out,
@@ -193,26 +208,62 @@ BEGIN
     phy4_ou                   => phy4_ou
   );
 
+  -- reading ddr memory
+  u_ddrctrl_output : ENTITY work.ddrctrl_output
+  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                   => rd_sosi,
+    in_ds                     => outp_ds,
+    in_bsn                    => outp_bsn,
+
+    out_sosi_arr              => out_sosi_arr,
+    out_ready                 => rd_ready
+  );
+
   -- controller of ddrctrl
   u_ddrctrl_controller : ENTITY work.ddrctrl_controller
   GENERIC MAP(
     g_tech_ddr                => g_tech_ddr,
-    g_stop_percentage         => g_stop_percentage
+    g_stop_percentage         => g_stop_percentage,
+    g_nof_streams             => g_nof_streams,
+    g_out_data_w              => g_data_w,
+    g_wr_data_w               => c_io_ddr_data_w,
+    g_rd_fifo_depth           => c_rd_fifo_depth,
+    g_rd_data_w               => c_io_ddr_data_w
   )
   PORT MAP(
-  clk                         => clk,
-  rst                         => rst,
-  
-  out_of                      => out_of,
-  out_sosi                    => out_sosi,
-  out_adr                     => out_adr,
+    clk                       => clk,
+    rst                       => rst,
+
+    -- ddrctrl_input
+    out_of                    => out_of,
+    out_sosi                  => out_sosi,
+    out_adr                   => out_adr,
+    inp_ds                    => inp_ds,
+    inp_bsn                   => inp_bsn,
+    inp_bsn_adr               => inp_bsn_adr,
+
+    -- io_ddr
+    dvr_mosi                  => dvr_mosi,
+    dvr_miso                  => dvr_miso,
+    wr_sosi                   => wr_sosi,
+    rd_fifo_usedw             => rd_fifo_usedw,
 
-  dvr_mosi                    => dvr_mosi,
-  wr_sosi                     => wr_sosi,
-  rd_siso                     => rd_siso,
+    -- ddrctrl_output
+    outp_ds                   => outp_ds,
+    outp_bsn                  => outp_bsn,
 
-  stop_in                     => stop_in,
-  stop_out                    => stop
+    -- ddrctrl_controller
+    stop_in                   => stop_in,
+    stop_out                  => stop
   );
 
 END str;
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd
index f9e9548fc7..378efd0b61 100644
--- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd
@@ -39,7 +39,12 @@ 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
+    g_stop_percentage         : NATURAL     := 50;
+    g_nof_streams             : NATURAL;
+    g_out_data_w              : NATURAL;
+    g_wr_data_w               : NATURAL;
+    g_rd_fifo_depth           : NATURAL;
+    g_rd_data_w               : NATURAL
   );
   PORT (
     clk                       : IN  STD_LOGIC;
@@ -49,13 +54,21 @@ ENTITY ddrctrl_controller IS
     out_of                    : IN NATURAL;
     out_sosi                  : IN t_dp_sosi;
     out_adr                   : IN NATURAL;
+    inp_ds                    : IN NATURAL;
+    inp_bsn                   : IN STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+    inp_bsn_adr               : IN NATURAL;
 
     -- io_ddr
     dvr_mosi                  : OUT t_mem_ctlr_mosi;
+    dvr_miso                  : IN  t_mem_ctlr_miso;
     wr_sosi                   : OUT t_dp_sosi;
-    rd_siso                   : OUT t_dp_siso;
+    rd_fifo_usedw             : IN  STD_LOGIC_VECTOR(ceil_log2(g_rd_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_rd_data_w) )-1 DOWNTO 0);
 
-    -- ddrctrl
+    -- ddrctrl_output
+    outp_ds                   : OUT NATURAL;
+    outp_bsn                  : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0)  := (OTHERS => '0');
+
+    -- ddrctrl_controller
     stop_in                   : IN  STD_LOGIC;
     stop_out                  : OUT STD_LOGIC
   );
@@ -70,25 +83,39 @@ ARCHITECTURE rtl OF ddrctrl_controller IS
   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');
 
+  -- constant for reading
+  CONSTANT  c_rd_data_w       : NATURAL                                     := g_nof_streams*g_out_data_w;                    -- 168
+  CONSTANT  c_rest            : NATURAL                                     := c_rd_data_w-(g_wr_data_w mod c_rd_data_w);     -- 96
+  CONSTANT  c_max_read_cnt    : NATURAL                                     := (c_max_adr+1)/c_burstsize;                     -- 256
+
+  -- not needed hopefully
+  --CONSTANT  c_gcd             : NATURAL                                     := GCD(c_rd_data_w, g_wr_data_w);                 -- 24
+  --CONSTANT  c_ofset_repeat    : NATURAL                                     := c_rd_data_wc/c_gcd;                            -- 7
+
   -- type for statemachine
-  TYPE t_state IS (RESET, WRITING, SET_STOP, STOP_WRITING, READING, STOP_READING, IDLE);
+  TYPE t_state IS (RESET, WRITING, SET_STOP, STOP_WRITING, START_READING, READING, STOP_READING, IDLE);
 
   -- record for readability
   TYPE t_reg IS RECORD
   -- state of program
   state                       : t_state;
 
-  -- signals
+  -- stoppping signals
   stop_adr                    : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0);
   stopped                     : STD_LOGIC;
 
+  -- reading signals
+  outp_ds                     : NATURAL;
+  outp_bsn                    : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+  read_cnt                    : NATURAL;
+  rd_burst_en                 : 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);
+  CONSTANT c_t_reg_init       : t_reg         := (RESET, TO_UVEC(c_max_adr, c_adr_w), '0', 0, (OTHERS => '0'), 0, '0', c_mem_ctlr_mosi_rst, c_dp_sosi_init);
 
 
   -- signals for readability
@@ -100,20 +127,30 @@ 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, out_of, out_sosi, out_adr)
+  p_state : PROCESS(q_reg, rst, out_of, out_sosi, out_adr, dvr_miso, rd_fifo_usedw)
 
     VARIABLE v                : t_reg         := c_t_reg_init;
 
   BEGIN
 
     v := q_reg;
-    CASE q_reg.state IS
-
-
 
+    CASE q_reg.state IS
     WHEN RESET =>
       v := c_t_reg_init;
 
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF stop_in = '1' THEN
+        v.state := SET_STOP;
+      ELSIF v.stop_adr = TO_UVEC(out_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;
+
 
     WHEN WRITING =>
       IF TO_UVEC(out_adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN                        -- if adr mod c_burstsize = 0
@@ -133,6 +170,19 @@ BEGIN
 
 
 
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF stop_in = '1' THEN
+        v.state := SET_STOP;
+      ELSIF v.stop_adr = TO_UVEC(out_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;
+
+
     WHEN SET_STOP =>
       --setting a stop address dependend on the g_stop_percentage
       IF out_adr+c_pof_ma >= c_max_adr THEN
@@ -160,13 +210,105 @@ BEGIN
 
 
 
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF stop_in = '1' THEN
+        v.state := SET_STOP;
+      ELSIF v.stop_adr = TO_UVEC(out_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;
+
+
     WHEN STOP_WRITING =>
-      v.stopped                                 := '1';
-      v.wr_sosi.valid                           := '0';
-      v.dvr_mosi.flush                          := '1';
+      v.dvr_mosi.burstbegin := '0';
+      IF dvr_miso.done = '1' THEN                         -- wait until the write burst is finished
+        v.stopped                               := '1';
+        v.wr_sosi.valid                         := '0';
+        v.dvr_mosi.flush                        := '1';
+        v.state                                 := START_READING;
+      ELSE
+        v.state := STOP_WRITING;
+      END IF;
+
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      END IF;
+
+
+    WHEN START_READING =>
+      v.rd_burst_en                             := '1';
+      v.dvr_mosi.wr                             := '0';
+      v.dvr_mosi.rd                             := '1';
+      v.outp_ds                                 :=  inp_ds;
+
+      FOR I IN 0 TO inp_bsn_adr+(c_max_adr-TO_UINT(q_reg.stop_adr)) LOOP     -- takes a while
+        IF v.outp_ds-c_rest <= 0 THEN
+          v.outp_ds := v.outp_ds+c_rd_data_w-c_rest;
+        ELSE
+          v.outp_ds := v.outp_ds-c_rest;
+        END IF;
+      END LOOP;
+
+      v.outp_bsn := TO_UVEC(TO_UINT(inp_bsn)-((inp_bsn_adr+(c_max_adr-TO_UINT(q_reg.stop_adr)))*g_wr_data_w+v.outp_ds-inp_ds)/c_rd_data_w, c_dp_stream_bsn_w); -- maths
+
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSE
+        v.state := READING;
+      END IF;
+
+
+    WHEN READING =>
+
+      IF TO_UINT(rd_fifo_usedw) = 0 AND dvr_miso.done = '1' AND q_reg.rd_burst_en = '1' THEN
+        IF TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt >= c_max_adr THEN
+          v.dvr_mosi.address(c_adr_w-1 DOWNTO 0)  := TO_UVEC((TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt)-c_max_adr, c_adr_w);
+          --assert false report "1. address: " & natural'image((TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt)-c_max_adr) severity note;
+        ELSE
+          v.dvr_mosi.address(c_adr_w-1 DOWNTO 0)  := TO_UVEC(TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt, c_adr_w);
+          --assert false report "2. address: " & natural'image((TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt)) severity note;
+        END IF;
+        v.dvr_mosi.burstbegin := '1';
+        v.read_cnt := v.read_cnt+1;
+        v.rd_burst_en := '0';
+      ELSE
+        v.dvr_mosi.burstbegin := '0';
+      END IF;
+
+      IF TO_UINT(rd_fifo_usedw) >= 1 THEN
+        v.rd_burst_en := '1';
+      END IF;
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF q_reg.read_cnt >= c_max_read_cnt THEN
+        v.state := IDLE;
+      ELSE
+        v.state := READING;
+      END IF;
+
 
     WHEN IDLE =>
-    
+
+
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF stop_in = '1' THEN
+        v.state := SET_STOP;
+      ELSIF v.stop_adr = TO_UVEC(out_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;
 
 
     WHEN OTHERS =>
@@ -174,8 +316,6 @@ BEGIN
 
 
 
-    END CASE;
-
     IF rst = '1' THEN
       v.state := RESET;
     ELSIF stop_in = '1' THEN
@@ -187,13 +327,21 @@ BEGIN
     ELSE
       v.state := WRITING;
     END IF;
+
+
+    END CASE;
+
+
+
     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;
   stop_out  <= q_reg.stopped;
+  outp_bsn  <= q_reg.outp_bsn;
+  outp_ds   <= q_reg.outp_ds;
 
 END rtl;
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd
index 88b7e492bf..e08d57fcd7 100644
--- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd
@@ -53,7 +53,7 @@ ENTITY ddrctrl_input IS
     clk               : IN  STD_LOGIC := '0';
     rst               : IN  STD_LOGIC;
     in_sosi_arr       : IN  t_dp_sosi_arr;                              -- input data
-    in_stop           : IN STD_LOGIC;
+    in_stop           : IN  STD_LOGIC;
     out_of            : OUT NATURAL;                                    -- amount of internal overflow this output
     out_sosi          : OUT t_dp_sosi;                                  -- output data
     out_adr           : OUT NATURAL;
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output.vhd
new file mode 100644
index 0000000000..cc934f3a06
--- /dev/null
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output.vhd
@@ -0,0 +1,103 @@
+-------------------------------------------------------------------------------
+--
+-- 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_output IS
+  GENERIC (
+    g_tech_ddr        : t_c_tech_ddr;                                   -- type of memory
+    g_sim_model       : BOOLEAN       := TRUE;                          -- determens if this is a simulation
+    g_in_data_w       : NATURAL       := 576;                           
+    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           : IN  t_dp_sosi := c_dp_sosi_init;              -- input data
+    in_ds             : IN  NATURAL;                                    -- amount of internal overflow this output
+    in_bsn            : IN  STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); -- bsn corresponding to the data at in_data[in_of]
+    out_sosi_arr      : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_init); -- output data
+    out_ready         : OUT STD_LOGIC
+  );
+END ddrctrl_output;
+
+
+ARCHITECTURE str OF ddrctrl_output IS
+
+  -- constant for readability
+  CONSTANT  c_out_data_w : NATURAL    := g_nof_streams*g_data_w;        -- the input data with for ddrctrl_repack 168
+
+  -- signals for connecting the components
+  SIGNAL    sosi                   : t_dp_sosi  := c_dp_sosi_init;
+
+BEGIN
+
+  -- makes one data vector out of all the data from the t_dp_sosi_arr
+  u_ddrctrl_output_unpack : ENTITY work.ddrctrl_output_unpack
+  GENERIC MAP(
+    g_tech_ddr        => g_tech_ddr,
+    g_in_data_w       => g_in_data_w,
+    g_out_data_w      => c_out_data_w
+  )
+  PORT MAP(
+    clk               => clk,
+    rst               => rst,
+    in_sosi           => in_sosi,                                       -- input data
+    in_ds             => in_ds,
+    in_bsn            => in_bsn,
+    out_sosi          => sosi,                                          -- output data
+    out_ready         => out_ready
+  );
+
+  -- resizes the input data vector so that the output data vector can be stored into the ddr memory
+  u_ddrctrl_output_repack : ENTITY work.ddrctrl_output_repack
+  GENERIC MAP(
+  g_nof_streams       => g_nof_streams,
+  g_data_w            => g_data_w
+  )
+  PORT MAP(
+    in_sosi           => sosi,
+    out_sosi_arr      => out_sosi_arr
+  );
+
+END str;
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_repack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_repack.vhd
new file mode 100644
index 0000000000..2fe5ca5162
--- /dev/null
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_repack.vhd
@@ -0,0 +1,58 @@
+-------------------------------------------------------------------------------
+--
+-- 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: Resize the input data vector so that the output data vector can be
+--  stored into the ddr memory.
+--
+-- Description:
+--  The input data gets resized and put into the output data vector.
+--
+-- Remark:
+--  Use VHDL coding template from:
+--  https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding
+--  The output vector must be larger than the input vector.
+
+LIBRARY IEEE, dp_lib, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE common_lib.common_pkg.ALL;
+
+ENTITY ddrctrl_output_repack IS
+  GENERIC (
+    g_nof_streams   : POSITIVE := 12;
+    g_data_w        : NATURAL  := 14
+  );
+  PORT (
+    in_sosi         : IN  t_dp_sosi     := c_dp_sosi_init;
+    out_sosi_arr    : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_init)
+  );
+END ddrctrl_output_repack;
+
+ARCHITECTURE rtl OF ddrctrl_output_repack IS
+
+BEGIN
+
+  -- putting the data from the stream into different streams.
+  gen_repack_data : FOR I IN 0 TO g_nof_streams-1 GENERATE
+    out_sosi_arr(I).data(g_data_w-1 DOWNTO 0)          <= in_sosi.data(g_data_w*(I+1)-1 DOWNTO g_data_w*I);
+    out_sosi_arr(I).bsn(c_dp_stream_bsn_w-1 DOWNTO 0)  <= in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0);
+  END GENERATE;
+
+END rtl;
diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd
new file mode 100644
index 0000000000..a7c644d2ac
--- /dev/null
+++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd
@@ -0,0 +1,173 @@
+-------------------------------------------------------------------------------
+--
+-- 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: Resize the input data vector so that the output data vector can be
+--  stored into the ddr memory.
+--
+-- Description:
+--  The input data gets resized and put into the output data vector.
+--
+-- Remark:
+--  Use VHDL coding template from:
+--  https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding
+--  The output vector must be larger than the input vector.
+
+LIBRARY IEEE, dp_lib, tech_ddr_lib, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE tech_ddr_lib.tech_ddr_pkg.ALL;
+USE common_lib.common_pkg.ALL;
+
+ENTITY ddrctrl_output_unpack IS
+  GENERIC (
+    g_tech_ddr      : t_c_tech_ddr;
+    g_in_data_w     : NATURAL;
+    g_out_data_w    : NATURAL
+  );
+  PORT (
+    clk             : IN  STD_LOGIC;
+    rst             : IN  STD_LOGIC;
+    in_sosi         : IN  t_dp_sosi   := c_dp_sosi_init;
+    in_ds           : IN  NATURAL;
+    in_bsn          : IN  STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+    out_sosi        : OUT t_dp_sosi   := c_dp_sosi_init;
+    out_ready       : OUT STD_LOGIC   := '0'
+  );
+END ddrctrl_output_unpack;
+
+
+ARCHITECTURE rtl OF ddrctrl_output_unpack IS
+
+  -- type for statemachine
+  TYPE t_state IS ( READING, FH_READ, SH_READ, RESET, IDLE);
+
+  -- record for readability
+  TYPE t_reg IS RECORD
+  state           : t_state;
+  a_of            : NATURAL;
+  op_data_cnt     : NATURAL;
+  out_sosi        : t_dp_sosi;
+  out_ready       : STD_LOGIC;
+  END RECORD;
+
+  CONSTANT c_t_reg_init   : t_reg     := (RESET, 0, 0, c_dp_sosi_init, '0');
+
+
+  -- 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, in_sosi, in_ds, in_bsn)
+
+    VARIABLE v            : t_reg;
+
+  BEGIN
+
+    v := q_reg;
+
+    CASE q_reg.state IS
+    WHEN READING =>
+      v.out_sosi.data(g_out_data_w-1 DOWNTO 0) := in_sosi.data((g_out_data_w*(q_reg.op_data_cnt+1))+q_reg.a_of-1 DOWNTO (g_out_data_w*q_reg.op_data_cnt)+q_reg.a_of);
+      v.out_sosi.valid := '1';
+      v.out_sosi.bsn   := ADD_UVEC(q_reg.out_sosi.bsn, "0001", c_dp_stream_bsn_w);
+      v.op_data_cnt := q_reg.op_data_cnt+1;
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF in_sosi.valid = '1' AND (g_out_data_w*(v.op_data_cnt+1))+q_reg.a_of > g_in_data_w THEN
+        v.state := FH_READ;
+      ELSIF in_sosi.valid = '1' THEN
+        v.state := READING;
+      ELSE
+        v.state := IDLE;
+      END IF;
+
+    WHEN FH_READ =>
+      v.a_of  := (g_out_data_w*(q_reg.op_data_cnt+1))+q_reg.a_of-g_in_data_w;
+      v.out_sosi.data(g_out_data_w-v.a_of-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO (g_out_data_w*q_reg.op_data_cnt)+q_reg.a_of);
+      v.out_sosi.valid   := '0';
+      v.op_data_cnt := 0;
+      v.out_ready   := '1';
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSE
+        v.state := SH_READ;
+      END IF;
+
+    WHEN SH_READ =>
+      v.out_sosi.data(g_out_data_w-1 DOWNTO g_out_data_w-q_reg.a_of) := in_sosi.data((g_out_data_w*q_reg.op_data_cnt)+q_reg.a_of-1 DOWNTO 0);
+      v.out_sosi.valid   := '1';
+      v.out_sosi.bsn   := ADD_UVEC(q_reg.out_sosi.bsn, "0001", c_dp_stream_bsn_w);
+      v.op_data_cnt := 0;
+      v.out_ready := '0';
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF in_sosi.valid = '1' AND (g_out_data_w*(v.op_data_cnt+1))+q_reg.a_of > g_in_data_w THEN
+        v.state := FH_read;
+      ELSIF in_sosi.valid = '1' THEN
+        v.state := READING;
+      ELSE
+        v.state := IDLE;
+      END IF;
+
+    WHEN RESET =>
+      v := c_t_reg_init;
+
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF in_sosi.valid = '1' AND (g_out_data_w*(q_reg.op_data_cnt+1))+q_reg.a_of > g_in_data_w THEN
+        v.state := FH_read;
+      ELSIF in_sosi.valid = '1' THEN
+        v.state := READING;
+      ELSE
+        v.state := IDLE;
+      END IF;
+
+    WHEN IDLE =>
+      v.out_ready := '1';
+      IF rst = '1' THEN
+        v.state := RESET;
+      ELSIF in_sosi.valid = '1' AND (g_out_data_w*(q_reg.op_data_cnt+1))+q_reg.a_of > g_in_data_w THEN
+        v.state := FH_read;
+      ELSIF in_sosi.valid = '1' THEN
+        v.state := READING;
+        v.a_of  := in_ds;
+      ELSE
+        v.state := IDLE;
+      END IF;
+
+    END CASE;
+
+    d_reg <= v;
+  END PROCESS;
+
+  -- fill outputs
+  out_sosi <= q_reg.out_sosi;
+  out_ready <= q_reg.out_ready;
+
+
+END rtl;
diff --git a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
index 6aef30ec40..29deea7061 100644
--- a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
+++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd
@@ -96,6 +96,7 @@ ARCHITECTURE tb OF tb_ddrctrl IS
   SIGNAL    wr_not_rd         : STD_LOGIC;
   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
@@ -201,6 +202,7 @@ BEGIN
     in_sosi_arr       => in_sosi_arr,
     wr_not_rd         => wr_not_rd,
     stop_in           => stop_in,
+    out_sosi_arr      => out_sosi_arr,
 
     --PHY
     phy3_io           => phy3_io,
-- 
GitLab