From 070604c170f26dbba8ddce9e7d93b6770a826255 Mon Sep 17 00:00:00 2001
From: Reinier van der Walle <walle@astron.nl>
Date: Thu, 6 May 2021 09:56:27 +0200
Subject: [PATCH] added tb_st_xsq

---
 libraries/base/common/hdllib.cfg              |   2 +-
 .../base/common/src/vhdl/common_math_pkg.vhd  |  21 +-
 libraries/dsp/st/hdllib.cfg                   |   2 +
 libraries/dsp/st/src/vhdl/st_pkg.vhd          |  54 +++++
 libraries/dsp/st/src/vhdl/st_xsq.vhd          |  14 +-
 libraries/dsp/st/tb/vhdl/tb_st_xsq.vhd        | 225 ++++++++++++++++++
 6 files changed, 308 insertions(+), 10 deletions(-)
 create mode 100644 libraries/dsp/st/src/vhdl/st_pkg.vhd
 create mode 100644 libraries/dsp/st/tb/vhdl/tb_st_xsq.vhd

diff --git a/libraries/base/common/hdllib.cfg b/libraries/base/common/hdllib.cfg
index 75b70901a1..e95d804fc6 100644
--- a/libraries/base/common/hdllib.cfg
+++ b/libraries/base/common/hdllib.cfg
@@ -8,9 +8,9 @@ synth_files =
     $RADIOHDL_WORK/libraries/base/common/src/vhdl/common_pkg.vhd
     src/vhdl/common_str_pkg.vhd
     src/vhdl/common_mem_pkg.vhd
-    src/vhdl/common_math_pkg.vhd
     src/vhdl/common_field_pkg.vhd
     src/vhdl/common_lfsr_sequences_pkg.vhd
+    src/vhdl/common_math_pkg.vhd
     src/vhdl/common_interface_layers_pkg.vhd
     src/vhdl/common_network_layers_pkg.vhd
     src/vhdl/common_network_total_header_pkg.vhd
diff --git a/libraries/base/common/src/vhdl/common_math_pkg.vhd b/libraries/base/common/src/vhdl/common_math_pkg.vhd
index 0cbb134183..8455d30e7d 100644
--- a/libraries/base/common/src/vhdl/common_math_pkg.vhd
+++ b/libraries/base/common/src/vhdl/common_math_pkg.vhd
@@ -36,7 +36,7 @@ LIBRARY IEEE;
 USE IEEE.STD_LOGIC_1164.ALL;
 USE IEEE.MATH_REAL.ALL;
 USE work.common_pkg.ALL;
-
+USE work.common_lfsr_sequences_pkg.ALL;
 
 PACKAGE common_math_pkg IS
 
@@ -79,7 +79,10 @@ PACKAGE common_math_pkg IS
   -- To create an FFT input phasor with frequency in the middle of a channel use FREQ = ch.
   FUNCTION common_math_create_look_up_table_phasor(N, W : POSITIVE; AMPL, FREQ, PHI : REAL) RETURN t_nat_integer_arr;
   FUNCTION common_math_create_look_up_table_phasor(N, W : POSITIVE; AMPL, FREQ, PHI : REAL) RETURN t_slv_32_arr;  -- range 0 TO N-1
-  
+ 
+  FUNCTION common_math_create_random_arr(N, W : POSITIVE) RETURN t_integer_arr;
+
+ 
 END common_math_pkg;
 
 
@@ -178,6 +181,18 @@ PACKAGE BODY common_math_pkg IS
     END LOOP;
     RETURN v_exp_arr;
   END;
-  
+   
+  FUNCTION common_math_create_random_arr(N, W : POSITIVE) RETURN t_integer_arr IS
+    VARIABLE v_rand_arr : t_integer_arr(0 TO N-1);
+    VARIABLE v_random : STD_LOGIC_VECTOR(W-1 DOWNTO 0) := (OTHERS => '0');
+  BEGIN
+    FOR I IN 0 TO N-1 LOOP
+      v_random := func_common_random(v_random);
+      v_rand_arr(I) := TO_SINT(v_random);
+    END LOOP;
+    RETURN v_rand_arr;
+  END;
+
+
 END common_math_pkg;
 
diff --git a/libraries/dsp/st/hdllib.cfg b/libraries/dsp/st/hdllib.cfg
index ae82da9fbc..7203491a3b 100644
--- a/libraries/dsp/st/hdllib.cfg
+++ b/libraries/dsp/st/hdllib.cfg
@@ -5,6 +5,7 @@ hdl_lib_uses_sim =
 hdl_lib_technology = 
 
 synth_files = 
+    src/vhdl/st_pkg.vhd 
     src/vhdl/st_acc.vhd 
     src/vhdl/st_ctrl.vhd 
     src/vhdl/st_calc.vhd 
@@ -21,6 +22,7 @@ test_bench_files =
     tb/vhdl/tb_st_acc.vhd 
     tb/vhdl/tb_st_calc.vhd 
     tb/vhdl/tb_mmf_st_sst.vhd
+    tb/vhdl/tb_st_xsq.vhd
     tb/vhdl/tb_st_histogram.vhd
     tb/vhdl/tb_mms_st_histogram.vhd
     tb/vhdl/tb_tb_st_histogram.vhd
diff --git a/libraries/dsp/st/src/vhdl/st_pkg.vhd b/libraries/dsp/st/src/vhdl/st_pkg.vhd
new file mode 100644
index 0000000000..b790afd6a2
--- /dev/null
+++ b/libraries/dsp/st/src/vhdl/st_pkg.vhd
@@ -0,0 +1,54 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- 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: R. vd Walle
+-- Purpose:
+-- Functions used in st_lib 
+LIBRARY IEEE, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+
+PACKAGE st_pkg IS 
+
+  FUNCTION func_st_calculate_expected_xsq(a_re, a_im, b_re, b_im : t_integer_arr; N_crosslets, N_int : NATURAL) RETURN t_integer_arr; 
+ 
+END st_pkg;
+
+PACKAGE BODY st_pkg IS 
+
+  FUNCTION func_st_calculate_expected_xsq(a_re, a_im, b_re, b_im : t_integer_arr; N_crosslets, N_int : NATURAL) RETURN t_integer_arr IS
+    CONSTANT c_N_s : NATURAL := a_re'LENGTH/N_crosslets;
+    CONSTANT c_xsq : NATURAL := c_N_s * c_N_s;
+    CONSTANT c_N_stat : NATURAL := N_crosslets * c_xsq;
+    VARIABLE v_exp_xsq : t_integer_arr(0 TO c_nof_complex * c_N_stat-1);
+  BEGIN
+
+    FOR N IN 0 TO N_crosslets-1 LOOP
+      FOR I IN 0 TO c_N_s-1 LOOP
+        FOR J IN 0 TO c_N_s-1 LOOP
+          v_exp_xsq(c_nof_complex * (N*c_xsq + I*c_N_s+J)  ) := N_int * COMPLEX_MULT_REAL(a_re(N*c_N_s +I), a_im(N*c_N_s +I), b_re(N*c_N_s +J), b_im(N*c_N_s +J));
+          v_exp_xsq(c_nof_complex * (N*c_xsq + I*c_N_s+J)+1) := N_int * COMPLEX_MULT_IMAG(a_re(N*c_N_s +I), a_im(N*c_N_s +I), b_re(N*c_N_s +J), b_im(N*c_N_s +J));
+        END LOOP;
+      END LOOP;
+    END LOOP;
+    RETURN v_exp_xsq;
+  END;
+ 
+END st_pkg;
diff --git a/libraries/dsp/st/src/vhdl/st_xsq.vhd b/libraries/dsp/st/src/vhdl/st_xsq.vhd
index b151affbd5..91ee30fc53 100644
--- a/libraries/dsp/st/src/vhdl/st_xsq.vhd
+++ b/libraries/dsp/st/src/vhdl/st_xsq.vhd
@@ -65,8 +65,8 @@ ENTITY st_xsq IS
     in_b      : IN  t_dp_sosi;   -- Complex input data
     
     -- Memory Mapped
-    ram_st_xsq_mosi : IN  t_mem_mosi;  
-    ram_st_xsq_miso : OUT t_mem_miso
+    ram_st_xsq_mosi : IN  t_mem_mosi := c_mem_mosi_rst;  
+    ram_st_xsq_miso : OUT t_mem_miso := c_mem_miso_rst
   );
 END st_xsq;
 
@@ -79,6 +79,7 @@ ARCHITECTURE str OF st_xsq IS
   CONSTANT c_nof_word     : NATURAL := g_stat_data_sz*c_nof_statistics;
   CONSTANT c_nof_word_w   : NATURAL := ceil_log2(c_nof_word);
   CONSTANT c_stat_word_w  : NATURAL := g_stat_data_sz*c_word_w;
+  CONSTANT c_total_ram_addr_w  : NATURAL := ceil_log2(c_nof_complex) + c_nof_word_w;
   
   -- Statistics register
   CONSTANT c_mm_ram       : t_c_mem := (latency  => 1,
@@ -139,13 +140,14 @@ BEGIN
   ---------------------------------------------------------------
   -- COMBINE MEMORY MAPPED INTERFACES
   ---------------------------------------------------------------
-  -- Translate incoming MM interface [N_crosslets][S_pn A][S_pn B][N_complex] to
-  -- [N_complex][N_crosslets][S_pn A][S_pn B]
+  -- Translate incoming MM interface [N_crosslets][S_pn A][S_pn B][N_complex][word] to
+  -- [N_complex][N_crosslets][S_pn A][S_pn B][word]
   p_remap : PROCESS(ram_st_xsq_mosi)
   BEGIN
     remapped_ram_st_xsq_mosi <= ram_st_xsq_mosi;
-    remapped_ram_st_xsq_mosi.address(ceil_log2(c_nof_complex)+c_nof_word_w -1 DOWNTO c_nof_word_w) <= ram_st_xsq_mosi.address(ceil_log2(c_nof_complex)-1 DOWNTO 0);
-    remapped_ram_st_xsq_mosi.address(c_nof_word_w -1 DOWNTO 0) <= ram_st_xsq_mosi.address(ceil_log2(c_nof_complex)+c_nof_word_w -1 DOWNTO ceil_log2(c_nof_complex));
+    -- 
+    remapped_ram_st_xsq_mosi.address(c_total_ram_addr_w -1 DOWNTO c_nof_word_w) <= ram_st_xsq_mosi.address(ceil_log2(c_nof_complex)+ceil_log2(g_stat_data_sz)-1 DOWNTO ceil_log2(g_stat_data_sz));
+    remapped_ram_st_xsq_mosi.address(c_nof_word_w -1 DOWNTO 0) <= ram_st_xsq_mosi.address(c_total_ram_addr_w -1 DOWNTO ceil_log2(c_nof_complex)+ceil_log2(g_stat_data_sz)) & ram_st_xsq_mosi.address(ceil_log2(g_stat_data_sz)-1 DOWNTO 0);
   END PROCESS;
 
   -- Combine the internal array of mm interfaces for both real
diff --git a/libraries/dsp/st/tb/vhdl/tb_st_xsq.vhd b/libraries/dsp/st/tb/vhdl/tb_st_xsq.vhd
new file mode 100644
index 0000000000..29b752acce
--- /dev/null
+++ b/libraries/dsp/st/tb/vhdl/tb_st_xsq.vhd
@@ -0,0 +1,225 @@
+
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+--
+-- Purpose:  Testbench for the st_xsq unit. 
+--
+--
+-- Usage in non-auto-mode (c_modelsim_start = 0 in python):
+--   > as 5
+--   > run -all
+--   > Run python script in separate terminal: "python tc_mmf_st_xst.py --unb 0 --bn 0 --sim"
+--   > Check the results of the python script. 
+--   > Stop the simulation manually in Modelsim by pressing the stop-button.
+--   > Evalute the WAVE window. 
+
+LIBRARY IEEE, common_lib, mm_lib, diag_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_math_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_str_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE mm_lib.mm_file_unb_pkg.ALL;
+USE mm_lib.mm_file_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL; 
+USE diag_lib.diag_pkg.ALL; 
+USE dp_lib.tb_dp_pkg.ALL;
+USE work.st_pkg.ALL;
+
+ENTITY tb_st_xsq IS 
+  GENERIC(
+    g_nof_crosslets      : NATURAL := 1; 
+    g_nof_signal_inputs  : NATURAL := 2;  
+    g_in_data_w          : NATURAL := 16;
+    g_stat_data_w        : NATURAL := 32;  -- statistics accumulator width
+    g_stat_data_sz       : NATURAL := 2;   -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words
+    g_nof_sync           : NATURAL := 3;
+    g_nof_block_per_sync : NATURAL := 20;
+    g_nof_clk_per_blk    : NATURAL := 512
+  );
+END tb_st_xsq;
+
+ARCHITECTURE tb OF tb_st_xsq IS
+  
+  CONSTANT c_sim                : BOOLEAN := TRUE;
+  CONSTANT c_rl                   : NATURAL := 1;
+  CONSTANT c_block_size : NATURAL := g_nof_crosslets * g_nof_signal_inputs;
+  CONSTANT c_gap_size   : NATURAL := g_nof_clk_per_blk - c_block_size;
+  
+  CONSTANT c_xsq : NATURAL := g_nof_signal_inputs * g_nof_signal_inputs;
+  CONSTANT c_nof_statistics : NATURAL := g_nof_crosslets * c_xsq;
+
+  CONSTANT c_random_in_a_re     : t_integer_arr(0 TO c_block_size-1) := common_math_create_random_arr(c_block_size, g_in_data_w);
+  CONSTANT c_random_in_a_im     : t_integer_arr(0 TO c_block_size-1) := common_math_create_random_arr(c_block_size, g_in_data_w-1);
+  CONSTANT c_random_in_b_re     : t_integer_arr(0 TO c_block_size-1) := common_math_create_random_arr(c_block_size, g_in_data_w-2);
+  CONSTANT c_random_in_b_im     : t_integer_arr(0 TO c_block_size-1) := common_math_create_random_arr(c_block_size, g_in_data_w-3);
+
+  CONSTANT c_expected_xsq : t_integer_arr(0 TO c_nof_statistics * c_nof_complex-1) := func_st_calculate_expected_xsq(c_random_in_a_re, c_random_in_a_im, c_random_in_b_re, c_random_in_b_im, g_nof_crosslets, g_nof_block_per_sync);
+  ----------------------------------------------------------------------------
+  -- Clocks and resets
+  ----------------------------------------------------------------------------   
+  CONSTANT c_mm_clk_period      : TIME := 100 ps;
+  CONSTANT c_dp_clk_period      : TIME := 5 ns;
+  CONSTANT c_dp_pps_period      : NATURAL := 64;
+
+  SIGNAL tb_end                 : STD_LOGIC;
+  SIGNAL dp_pps                 : STD_LOGIC;
+
+  SIGNAL mm_rst                 : STD_LOGIC := '1';
+  SIGNAL mm_clk                 : STD_LOGIC := '1';
+
+  SIGNAL dp_rst                 : STD_LOGIC;
+  SIGNAL dp_clk                 : STD_LOGIC := '1';
+
+  SIGNAL st_en              : STD_LOGIC := '1';
+  SIGNAL st_siso            : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL st_sosi            : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL in_sosi_a          : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL in_sosi_b          : t_dp_sosi := c_dp_sosi_rst;
+
+  ----------------------------------------------------------------------------
+  -- MM buses
+  ----------------------------------------------------------------------------                                         
+  SIGNAL ram_st_xsq_mosi    : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL ram_st_xsq_miso    : t_mem_miso := c_mem_miso_rst;
+  SIGNAL st_xsq_out_arr     : t_slv_32_arr(0 TO c_nof_statistics * c_nof_complex * g_stat_data_sz-1) := (OTHERS => (OTHERS => '0'));
+BEGIN
+
+  ----------------------------------------------------------------------------
+  -- Clock and reset generation
+  ----------------------------------------------------------------------------
+  mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2;
+  mm_rst <= '1', '0' AFTER c_mm_clk_period*5;
+
+  dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2;
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*5;
+
+  ------------------------------------------------------------------------------
+  -- MM Stimuli
+  ------------------------------------------------------------------------------
+  p_mm_stimuli : PROCESS
+  BEGIN
+    FOR I IN 0 TO g_nof_sync -1 LOOP
+      proc_common_wait_until_lo_hi(dp_clk, st_sosi.sync);
+    END LOOP;
+    proc_common_wait_some_cycles(dp_clk, 3);
+    -- read ram
+    proc_mem_read_ram(0, c_nof_statistics * c_nof_complex * g_stat_data_sz, mm_clk, ram_st_xsq_mosi, ram_st_xsq_miso, st_xsq_out_arr);  
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- Data blocks
+  ------------------------------------------------------------------------------
+  p_st_stimuli : PROCESS
+    VARIABLE v_re  : NATURAL := 0;
+    VARIABLE v_im  : NATURAL := 0;
+  BEGIN  
+    tb_end <= '0';
+    st_sosi <= c_dp_sosi_rst;
+    proc_common_wait_until_low(dp_clk, dp_rst);
+  
+    -- Run some sync intervals with DSP counter data for the real and imag fields
+    WAIT UNTIL rising_edge(dp_clk);
+    FOR I IN 0 TO g_nof_sync-1 LOOP
+      proc_dp_gen_block_data(c_rl, FALSE, g_in_data_w, g_in_data_w, 0, v_re, v_im, c_block_size, 0, 0, '1', "0", dp_clk, st_en, st_siso, st_sosi);     -- next sync
+      st_sosi <= c_dp_sosi_rst;
+      proc_common_wait_some_cycles(dp_clk, c_gap_size);
+      FOR J IN 0 TO g_nof_block_per_sync-2 LOOP  -- provide sop and eop for block reference
+        proc_dp_gen_block_data(c_rl, FALSE, g_in_data_w, g_in_data_w, 0, v_re, v_im, c_block_size, 0, 0, '0', "0", dp_clk, st_en, st_siso, st_sosi);   -- no sync
+        st_sosi <= c_dp_sosi_rst;
+        proc_common_wait_some_cycles(dp_clk, c_gap_size);
+      END LOOP;
+    END LOOP;
+    st_sosi <= c_dp_sosi_rst;
+    proc_common_wait_some_cycles(dp_clk, 100);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  in_sosi_a.sync <= st_sosi.sync;
+  in_sosi_b.sync <= st_sosi.sync;
+  in_sosi_a.sop  <= st_sosi.sop;
+  in_sosi_b.sop  <= st_sosi.sop;
+  in_sosi_a.eop  <= st_sosi.eop;
+  in_sosi_b.eop  <= st_sosi.eop;
+  in_sosi_a.valid  <= st_sosi.valid;
+  in_sosi_b.valid  <= st_sosi.valid;
+
+  p_random_stimuli : PROCESS
+  BEGIN
+    FOR I IN 0 TO g_nof_sync * g_nof_block_per_sync-1 LOOP
+      WAIT UNTIL rising_edge(st_sosi.sop);
+      FOR J IN 0 TO c_block_size-1 LOOP
+        in_sosi_a.re <= TO_DP_DSP_DATA(c_random_in_a_re(J));
+        in_sosi_a.im <= TO_DP_DSP_DATA(c_random_in_a_im(J));
+        in_sosi_b.re <= TO_DP_DSP_DATA(c_random_in_b_re(J));
+        in_sosi_b.im <= TO_DP_DSP_DATA(c_random_in_b_im(J));
+        proc_common_wait_some_cycles(dp_clk, 1);
+      END LOOP;
+    END LOOP;
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- Verification 
+  ------------------------------------------------------------------------------
+  p_verify : PROCESS
+  BEGIN
+    proc_common_wait_until_high(mm_clk, ram_st_xsq_miso.rdval);
+    proc_common_wait_some_cycles(mm_clk, c_nof_statistics * c_nof_complex * g_stat_data_sz + 10);
+    FOR I IN 0 TO c_nof_statistics * c_nof_complex -1 LOOP
+      ASSERT TO_SINT(st_xsq_out_arr(I*2)) = c_expected_xsq(I) REPORT "WRONG XSQ DATA" SEVERITY ERROR; -- Only read low part of statistic
+    END LOOP;
+    WAIT;
+  END PROCESS;
+
+  ----------------------------------------------------------------------------
+  -- DUT: Device Under Test
+  ---------------------------------------------------------------------------- 
+  u_dut : ENTITY work.st_xsq
+  GENERIC MAP(
+    g_nof_signal_inputs  => g_nof_signal_inputs,      
+    g_nof_crosslets      => g_nof_crosslets,    
+    g_in_data_w          => g_in_data_w,     
+    g_stat_data_w        => g_stat_data_w,   
+    g_stat_data_sz       => g_stat_data_sz  
+  )
+  PORT MAP(
+    mm_rst           =>  mm_rst,
+    mm_clk           =>  mm_clk,
+    dp_rst           =>  dp_rst,
+    dp_clk           =>  dp_clk,
+    
+    -- Streaming
+    in_a             => in_sosi_a, 
+    in_b             => in_sosi_b, 
+    
+    -- Memory Mapped
+    ram_st_xsq_mosi  => ram_st_xsq_mosi,
+    ram_st_xsq_miso  => ram_st_xsq_miso
+  );
+
+END tb;
-- 
GitLab