Skip to content
Snippets Groups Projects
Select Git revision
  • 2d38e1217d064be122133fb61b7bc56e591bade6
  • master default protected
  • L2SS-1914-fix_job_dispatch
  • TMSS-3170
  • TMSS-3167
  • TMSS-3161
  • TMSS-3158-Front-End-Only-Allow-Changing-Again
  • TMSS-3133
  • TMSS-3319-Fix-Templates
  • test-fix-deploy
  • TMSS-3134
  • TMSS-2872
  • defer-state
  • add-custom-monitoring-points
  • TMSS-3101-Front-End-Only
  • TMSS-984-choices
  • SDC-1400-Front-End-Only
  • TMSS-3079-PII
  • TMSS-2936
  • check-for-max-244-subbands
  • TMSS-2927---Front-End-Only-PXII
  • Before-Remove-TMSS
  • LOFAR-Release-4_4_318 protected
  • LOFAR-Release-4_4_317 protected
  • LOFAR-Release-4_4_316 protected
  • LOFAR-Release-4_4_315 protected
  • LOFAR-Release-4_4_314 protected
  • LOFAR-Release-4_4_313 protected
  • LOFAR-Release-4_4_312 protected
  • LOFAR-Release-4_4_311 protected
  • LOFAR-Release-4_4_310 protected
  • LOFAR-Release-4_4_309 protected
  • LOFAR-Release-4_4_308 protected
  • LOFAR-Release-4_4_307 protected
  • LOFAR-Release-4_4_306 protected
  • LOFAR-Release-4_4_304 protected
  • LOFAR-Release-4_4_303 protected
  • LOFAR-Release-4_4_302 protected
  • LOFAR-Release-4_4_301 protected
  • LOFAR-Release-4_4_300 protected
  • LOFAR-Release-4_4_299 protected
41 results

timeline.constants.js

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    common_pkg.vhd 121.39 KiB
    -------------------------------------------------------------------------------
    --
    -- Copyright (C) 2019
    -- 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/>.
    --
    -------------------------------------------------------------------------------
    
    -- Author:
    -- . Eric Kooistra
    -- Purpose:
    -- . Collection of commonly used base funtions
    -- Interface:
    -- . [n/a]
    -- Description:
    -- . This is a package containing generic constants and functions.
    -- . More information can be found in the comments near the code.
    
    LIBRARY IEEE;
    USE IEEE.STD_LOGIC_1164.ALL;
    USE IEEE.NUMERIC_STD.ALL;
    USE IEEE.MATH_REAL.ALL;
    
    PACKAGE common_pkg IS
    
      -- CONSTANT DECLARATIONS ----------------------------------------------------
    
      -- some integers
      CONSTANT c_0                    : NATURAL := 0;
      CONSTANT c_zero                 : NATURAL := 0;
      CONSTANT c_1                    : NATURAL := 1;
      CONSTANT c_one                  : NATURAL := 1;
      CONSTANT c_2                    : NATURAL := 2;
      CONSTANT c_4                    : NATURAL := 4;
      CONSTANT c_quad                 : NATURAL := 4;
      CONSTANT c_8                    : NATURAL := 8;
      CONSTANT c_16                   : NATURAL := 16;
      CONSTANT c_32                   : NATURAL := 32;
      CONSTANT c_48                   : NATURAL := 48;
      CONSTANT c_64                   : NATURAL := 64;
      CONSTANT c_128                  : NATURAL := 128;
      CONSTANT c_256                  : NATURAL := 256;
      
      -- widths and sizes
      CONSTANT c_halfword_sz          : NATURAL := 2;
      CONSTANT c_word_sz              : NATURAL := 4;
      CONSTANT c_longword_sz          : NATURAL := 8;
      CONSTANT c_nibble_w             : NATURAL := 4;
      CONSTANT c_byte_w               : NATURAL := 8;
      CONSTANT c_octet_w              : NATURAL := 8;
      CONSTANT c_halfword_w           : NATURAL := c_byte_w*c_halfword_sz;
      CONSTANT c_word_w               : NATURAL := c_byte_w*c_word_sz;
      CONSTANT c_integer_w            : NATURAL := 32;              -- unfortunately VHDL integer type is limited to 32 bit values
      CONSTANT c_natural_w            : NATURAL := c_integer_w-1;   -- unfortunately VHDL natural type is limited to 31 bit values (0 and the positive subset of the VHDL integer type0
      CONSTANT c_longword_w           : NATURAL := c_byte_w*c_longword_sz;
      
      -- logic
      CONSTANT c_sl0                  : STD_LOGIC := '0';
      CONSTANT c_sl1                  : STD_LOGIC := '1';
      CONSTANT c_unsigned_0           : UNSIGNED(0 DOWNTO 0) := TO_UNSIGNED(0,1);
      CONSTANT c_unsigned_1           : UNSIGNED(0 DOWNTO 0) := TO_UNSIGNED(1,1);
      CONSTANT c_signed_0             : SIGNED(1 DOWNTO 0) := TO_SIGNED(0,2);
      CONSTANT c_signed_1             : SIGNED(1 DOWNTO 0) := TO_SIGNED(1,2);
      CONSTANT c_slv0                 : STD_LOGIC_VECTOR(255 DOWNTO 0) := (OTHERS=>'0');
      CONSTANT c_slv1                 : STD_LOGIC_VECTOR(255 DOWNTO 0) := (OTHERS=>'1');
      CONSTANT c_word_01              : STD_LOGIC_VECTOR(31 DOWNTO 0) := "01010101010101010101010101010101";
      CONSTANT c_word_10              : STD_LOGIC_VECTOR(31 DOWNTO 0) := "10101010101010101010101010101010";
      CONSTANT c_slv01                : STD_LOGIC_VECTOR(255 DOWNTO 0) := c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01;
      CONSTANT c_slv10                : STD_LOGIC_VECTOR(255 DOWNTO 0) := c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10;
    
      -- math
      CONSTANT c_nof_complex          : NATURAL := 2;   -- Real and imaginary part of complex number
      CONSTANT c_sign_w               : NATURAL := 1;   -- Sign bit, can be used to skip one of the double sign bits of a product
      CONSTANT c_sum_of_prod_w        : NATURAL := 1;   -- Bit growth for sum of 2 products, can be used in case complex multiply has normalized real and imag inputs instead of normalized amplitude inputs
      CONSTANT c_eps                  : REAL := 1.0e-20;  -- add small epsilon value to avoid 1/0 and log(0), 1e-20 < 1/2**64
          
      -- FF, block RAM, FIFO
      CONSTANT c_meta_delay_len       : NATURAL := 3;   -- default nof flipflops (FF) in meta stability recovery delay line (e.g. for clock domain crossing)
      CONSTANT c_meta_fifo_depth      : NATURAL := 16;  -- default use 16 word deep FIFO to cross clock domain, typically > 2*c_meta_delay_len or >~ 8 is enough
    
      CONSTANT c_bram_m9k_nof_bits    : NATURAL := 1024*9;  -- size of 1 Altera M9K block RAM in bits
      CONSTANT c_bram_m9k_max_w       : NATURAL := 36;      -- maximum width of 1 Altera M9K block RAM, so the size is then 256 words of 36 bits
      CONSTANT c_bram_m9k_fifo_depth  : NATURAL := c_bram_m9k_nof_bits/c_bram_m9k_max_w;  -- using a smaller FIFO depth than this leaves part of the RAM unused
      
      CONSTANT c_fifo_afull_margin    : NATURAL := 4;       -- default or minimal FIFO almost full margin
      
      -- DSP
      CONSTANT c_dsp_mult_w           : NATURAL := 18;   -- Width of the embedded multipliers in Stratix IV (and Arria 10 for 2 multipliers per DSP block)
      CONSTANT c_dsp_mult_18_w        : NATURAL := 18;   -- Width of the embedded multipliers in Stratix IV (and Arria 10 for 2 multipliers per DSP block)
      CONSTANT c_dsp_mult_27_w        : NATURAL := 27;   -- Width of the embedded multipliers in Arria 10
      
      -- TYPE DECLARATIONS --------------------------------------------------------
      TYPE t_boolean_arr     IS ARRAY (INTEGER RANGE <>) OF BOOLEAN;   -- INTEGER left index starts default at -2**31
      TYPE t_integer_arr     IS ARRAY (INTEGER RANGE <>) OF INTEGER;   -- INTEGER left index starts default at -2**31
      TYPE t_natural_arr     IS ARRAY (INTEGER RANGE <>) OF NATURAL;   -- INTEGER left index starts default at -2**31
      TYPE t_real_arr        IS ARRAY (INTEGER RANGE <>) OF REAL;      -- INTEGER left index starts default at -2**31
      TYPE t_nat_boolean_arr IS ARRAY (NATURAL RANGE <>) OF BOOLEAN;   -- NATURAL left index starts default at 0
      TYPE t_nat_integer_arr IS ARRAY (NATURAL RANGE <>) OF INTEGER;   -- NATURAL left index starts default at 0
      TYPE t_nat_natural_arr IS ARRAY (NATURAL RANGE <>) OF NATURAL;   -- NATURAL left index starts default at 0
      TYPE t_nat_real_arr    IS ARRAY (NATURAL RANGE <>) OF REAL;      -- NATURAL left index starts default at 0
      TYPE t_sl_arr          IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC;
      TYPE t_slv_1_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(0 DOWNTO 0);
      TYPE t_slv_2_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(1 DOWNTO 0);
      TYPE t_slv_4_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(3 DOWNTO 0);
      TYPE t_slv_8_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
      TYPE t_slv_12_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(11 DOWNTO 0);
      TYPE t_slv_16_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(15 DOWNTO 0);
      TYPE t_slv_18_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(17 DOWNTO 0);
      TYPE t_slv_24_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(23 DOWNTO 0);
      TYPE t_slv_32_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(31 DOWNTO 0);
      TYPE t_slv_44_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(43 DOWNTO 0);
      TYPE t_slv_48_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(47 DOWNTO 0);
      TYPE t_slv_64_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(63 DOWNTO 0);
      TYPE t_slv_128_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(127 DOWNTO 0);
      TYPE t_slv_256_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(255 DOWNTO 0);
      TYPE t_slv_512_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(511 DOWNTO 0);
      TYPE t_slv_1024_arr    IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(1023 DOWNTO 0);
     
      CONSTANT c_boolean_arr     : t_boolean_arr     := (TRUE, FALSE);  -- array the two possible boolean values that can be iterated over
      CONSTANT c_nat_boolean_arr : t_nat_boolean_arr := (TRUE, FALSE);  -- array the two possible boolean values that can be iterated over
     
      TYPE t_integer_matrix IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF INTEGER;
      TYPE t_boolean_matrix IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF BOOLEAN;
      TYPE t_sl_matrix      IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC;
      TYPE t_slv_8_matrix   IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
      TYPE t_slv_16_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(15 DOWNTO 0);
      TYPE t_slv_32_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(31 DOWNTO 0);
      TYPE t_slv_64_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(63 DOWNTO 0);
    
      TYPE t_natural_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_natural_arr(1 DOWNTO 0);
    
      -- STRUCTURE DECLARATIONS ---------------------------------------------------
      
      -- Clock and Reset
      --
      -- . rst   = Reset. Can be used asynchronously to take effect immediately
      --           when used before the clk'EVENT section. May also be used as
      --           synchronous reset using it as first condition in the clk'EVENT
      --           section. As synchronous reset it requires clock activity to take
      --           effect. A synchronous rst may or may not depend on clken,
      --           however typically rst should take priority over clken.
      -- . clk   = Clock. Used in clk'EVENT line via rising_edge(clk) or sometimes
      --           as falling_edge(clk).
      -- . clken = Clock Enable. Used for the whole clk'EVENT section.
      TYPE t_sys_rce IS RECORD
        rst   : STD_LOGIC;
        clk   : STD_LOGIC;
        clken : STD_LOGIC;  -- := '1';
      END RECORD;
      
      TYPE t_sys_ce IS RECORD
        clk   : STD_LOGIC;
        clken : STD_LOGIC;  -- := '1';
      END RECORD;
    
        
      -- FUNCTION DECLARATIONS ----------------------------------------------------
      
      -- All functions assume [high downto low] input ranges
      
      FUNCTION pow2(n : NATURAL) RETURN NATURAL;  -- = 2**n
      FUNCTION ceil_pow2(n : INTEGER) RETURN NATURAL;  -- = 2**n, returns 1 for n<0
    
      FUNCTION true_log2(n : NATURAL) RETURN NATURAL;  -- true_log2(n) = log2(n)
      FUNCTION ceil_log2(n : NATURAL) RETURN NATURAL;  -- ceil_log2(n) = log2(n), but force ceil_log2(1) = 1
     
      FUNCTION floor_log10(n : NATURAL) RETURN NATURAL;
    
      FUNCTION is_pow2(n : NATURAL) RETURN BOOLEAN;        -- return TRUE when n is a power of 2, so 0, 1, 2, 4, 8, 16, ...
      FUNCTION true_log_pow2(n : NATURAL) RETURN NATURAL;  -- 2**true_log2(n), return power of 2 that is >= n
      
      FUNCTION ratio( n, d : NATURAL) RETURN NATURAL;  -- return n/d when n MOD d = 0 else return 0, so ratio * d = n only when integer ratio > 0
      FUNCTION ratio2(n, m : NATURAL) RETURN NATURAL;  -- return integer ratio of n/m or m/n, whichever is the largest
     
      FUNCTION almost_equal(a, b, delta : REAL) RETURN BOOLEAN;  -- return TRUE when abs(a - b) < abs(delta), else return FALSE
      FUNCTION almost_zero(a, delta : REAL) RETURN BOOLEAN;      -- return TRUE when abs(a)     < abs(delta), else return FALSE
      
      FUNCTION ceil_div(   n, d : NATURAL)  RETURN NATURAL;   -- ceil_div    = n/d + (n MOD d)/=0
      FUNCTION ceil_value( n, d : NATURAL)  RETURN NATURAL;   -- ceil_value  = ceil_div(n, d) * d
      FUNCTION floor_value(n, d : NATURAL)  RETURN NATURAL;   -- floor_value = (n/d) * d
      FUNCTION ceil_div(   n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
      FUNCTION ceil_value( n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
      FUNCTION floor_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
      
      FUNCTION slv(n: IN STD_LOGIC)        RETURN STD_LOGIC_VECTOR;  -- standard logic to 1 element standard logic vector
      FUNCTION sl( n: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC;         -- 1 element standard logic vector to standard logic
    
      FUNCTION to_sl(  n: IN BOOLEAN)   RETURN STD_LOGIC;  -- if TRUE       then return '1'   else '0'
      FUNCTION to_bool(n: IN STD_LOGIC) RETURN BOOLEAN;    -- if '1' or 'H' then return TRUE  else FALSE
      FUNCTION to_bool(n: IN INTEGER)   RETURN BOOLEAN;    -- if  0         then return FALSE else TRUE
    
      FUNCTION to_natural_arr(n : t_integer_arr; to_zero : BOOLEAN) RETURN t_natural_arr;  -- if to_zero=TRUE then negative numbers are forced to zero, otherwise they will give a compile range error
      FUNCTION to_natural_arr(n : t_nat_natural_arr)                RETURN t_natural_arr;
      FUNCTION to_integer_arr(n : t_natural_arr)                    RETURN t_integer_arr;
      FUNCTION to_integer_arr(n : t_nat_natural_arr)                RETURN t_integer_arr;
      FUNCTION to_slv_32_arr( n : t_integer_arr)                    RETURN t_slv_32_arr;
      FUNCTION to_slv_32_arr( n : t_natural_arr)                    RETURN t_slv_32_arr;
      
      FUNCTION vector_tree(slv : STD_LOGIC_VECTOR; operation : STRING) RETURN STD_LOGIC;  -- Core operation tree function for vector "AND", "OR", "XOR"
      FUNCTION vector_and(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '1' when all slv bits are '1' else '0'
      FUNCTION vector_or( slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '0' when all slv bits are '0' else '1'
      FUNCTION vector_xor(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '1' when the slv has an odd number of '1' bits else '0'
      FUNCTION vector_one_hot(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- Returns slv when it contains one hot bit, else returns 0.
      
      FUNCTION andv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_and
      FUNCTION orv( slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_or
      FUNCTION xorv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_xor
      
      FUNCTION array_and(arr : t_nat_boolean_arr) RETURN BOOLEAN;
      FUNCTION array_or( arr : t_nat_boolean_arr) RETURN BOOLEAN;
      
      FUNCTION matrix_and(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC;  -- '1' when all matrix bits are '1' else '0'
      FUNCTION matrix_or( mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC;  -- '0' when all matrix bits are '0' else '1'
      
      FUNCTION smallest(n, m    : INTEGER)       RETURN INTEGER;
      FUNCTION smallest(n, m    : REAL)          RETURN REAL;
      FUNCTION smallest(n, m, l : INTEGER)       RETURN INTEGER;
      FUNCTION smallest(n       : t_natural_arr) RETURN NATURAL;
      FUNCTION smallest(n       : t_nat_natural_arr) RETURN NATURAL;
    
      FUNCTION largest(n, m : INTEGER)       RETURN INTEGER;
      FUNCTION largest(n, m : REAL)          RETURN REAL;
      FUNCTION largest(n    : t_natural_arr) RETURN NATURAL;
      FUNCTION largest(n    : t_nat_natural_arr) RETURN NATURAL;
      
      FUNCTION func_sum(    n : t_natural_arr)     RETURN NATURAL;      -- sum     of all elements in array
      FUNCTION func_sum(    n : t_nat_natural_arr) RETURN NATURAL;
      FUNCTION func_product(n : t_natural_arr)     RETURN NATURAL;      -- product of all elements in array
      FUNCTION func_product(n : t_nat_natural_arr) RETURN NATURAL;
      
      FUNCTION "+" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise sum
      FUNCTION "+" (L   : t_natural_arr; R : INTEGER)  RETURN t_natural_arr;  -- element wise sum
      FUNCTION "+" (L   : INTEGER; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise sum
      
      FUNCTION "-" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise subtract
      FUNCTION "-" (L, R: t_natural_arr)               RETURN t_integer_arr;  -- element wise subtract, support negative result
      FUNCTION "-" (L   : t_natural_arr; R : INTEGER)  RETURN t_natural_arr;  -- element wise subtract
      FUNCTION "-" (L   : INTEGER; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise subtract
      
      FUNCTION "*" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise product
      FUNCTION "*" (L   : t_natural_arr; R : NATURAL)  RETURN t_natural_arr;  -- element wise product
      FUNCTION "*" (L   : NATURAL; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise product
      
      FUNCTION "/" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise division
      FUNCTION "/" (L   : t_natural_arr; R : POSITIVE) RETURN t_natural_arr;  -- element wise division
      FUNCTION "/" (L   : NATURAL; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise division
      
      FUNCTION is_true(a : STD_LOGIC) RETURN BOOLEAN;
      FUNCTION is_true(a : STD_LOGIC) RETURN NATURAL;
      FUNCTION is_true(a : BOOLEAN)   RETURN STD_LOGIC;
      FUNCTION is_true(a : BOOLEAN)   RETURN NATURAL;
      FUNCTION is_true(a : INTEGER)   RETURN BOOLEAN;    -- also covers NATURAL because it is a subtype of INTEGER
      FUNCTION is_true(a : INTEGER)   RETURN STD_LOGIC;  -- also covers NATURAL because it is a subtype of INTEGER
      
      FUNCTION sel_a_b(sel,           a, b : BOOLEAN)           RETURN BOOLEAN;
      FUNCTION sel_a_b(sel,           a, b : INTEGER)           RETURN INTEGER;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : INTEGER)           RETURN INTEGER;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : REAL)              RETURN REAL;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC)         RETURN STD_LOGIC;
      FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC)         RETURN STD_LOGIC;
      FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : SIGNED)            RETURN SIGNED;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : UNSIGNED)          RETURN UNSIGNED;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_integer_arr)     RETURN t_integer_arr;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_natural_arr)     RETURN t_natural_arr;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_integer_arr) RETURN t_nat_integer_arr;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_natural_arr) RETURN t_nat_natural_arr;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STRING)            RETURN STRING;
      FUNCTION sel_a_b(sel : INTEGER; a, b : STRING)            RETURN STRING;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : TIME)              RETURN TIME;
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : SEVERITY_LEVEL)    RETURN SEVERITY_LEVEL;
      
      -- sel_n() index sel = 0, 1, 2, ... will return a, b, c, ...
      FUNCTION sel_n(sel : NATURAL; a, b, c                      : BOOLEAN) RETURN BOOLEAN;  --  3
      FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : BOOLEAN) RETURN BOOLEAN;  --  4
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : BOOLEAN) RETURN BOOLEAN;  --  5
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : BOOLEAN) RETURN BOOLEAN;  --  6
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : BOOLEAN) RETURN BOOLEAN;  --  7
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : BOOLEAN) RETURN BOOLEAN;  --  8
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : BOOLEAN) RETURN BOOLEAN;  --  9
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : BOOLEAN) RETURN BOOLEAN;  -- 10
      
      FUNCTION sel_n(sel : NATURAL; a, b, c                      : INTEGER) RETURN INTEGER;  --  3
      FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : INTEGER) RETURN INTEGER;  --  4
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : INTEGER) RETURN INTEGER;  --  5
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : INTEGER) RETURN INTEGER;  --  6
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : INTEGER) RETURN INTEGER;  --  7
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : INTEGER) RETURN INTEGER;  --  8
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : INTEGER) RETURN INTEGER;  --  9
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : INTEGER) RETURN INTEGER;  -- 10
      
      FUNCTION sel_n(sel : NATURAL; a, b                         : STRING) RETURN STRING;    --  2
      FUNCTION sel_n(sel : NATURAL; a, b, c                      : STRING) RETURN STRING;    --  3
      FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : STRING) RETURN STRING;    --  4
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : STRING) RETURN STRING;    --  5
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : STRING) RETURN STRING;    --  6
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : STRING) RETURN STRING;    --  7
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : STRING) RETURN STRING;    --  8
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : STRING) RETURN STRING;    --  9
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : STRING) RETURN STRING;    -- 10
      
      FUNCTION array_init(init : STD_LOGIC; nof              : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init a unconstrained array of size 1
      FUNCTION array_init(init :   BOOLEAN; nof              : NATURAL) RETURN t_nat_boolean_arr; -- useful to init a unconstrained array of size 1
      FUNCTION array_init(init,             nof              : NATURAL) RETURN t_natural_arr;     -- useful to init a unconstrained array of size 1
      FUNCTION array_init(init,             nof              : NATURAL) RETURN t_nat_natural_arr; -- useful to init a unconstrained array of size 1
      FUNCTION array_init(init,             nof, incr        : NATURAL) RETURN t_natural_arr;     -- useful to init an array with incrementing numbers
      FUNCTION array_init(init,             nof, incr        : NATURAL) RETURN t_nat_natural_arr;
      FUNCTION array_init(init,             nof, incr        : INTEGER) RETURN t_slv_16_arr;
      FUNCTION array_init(init,             nof, incr        : INTEGER) RETURN t_slv_32_arr;
      FUNCTION array_init(init,             nof, width       : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with repetitive content
      FUNCTION array_init(init,             nof, width, incr : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with incrementing content
      FUNCTION array_sinit(init : INTEGER;   nof, width       : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with repetitive content
      
      FUNCTION init_slv_64_matrix(nof_a, nof_b, k : INTEGER) RETURN t_slv_64_matrix;  -- initialize all elements in t_slv_64_matrix to value k
      
      -- Concatenate two or more STD_LOGIC_VECTORs into a single STD_LOGIC_VECTOR or extract one of them from a concatenated STD_LOGIC_VECTOR
      -- . Note that using func_slv_concat() without the BOOLEAN use_* is equivalent to using the 
      --   slv concatenation operator & directly. However this overloaded func_slv_concat() is
      --   still nice to have, because it shows the relation with the inverse func_slv_extract().
    
      FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a, b, c, d, e, f, g, h : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e, use_f, use_g        : BOOLEAN; a, b, c, d, e, f, g    : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e, use_f               : BOOLEAN; a, b, c, d, e, f       : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e                      : BOOLEAN; a, b, c, d, e          : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d                             : BOOLEAN; a, b, c, d             : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b, use_c                                    : BOOLEAN; a, b, c                : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(  use_a, use_b                                           : BOOLEAN; a, b                   : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c, d, e, f, g, h : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c, d, e, f, g    : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c, d, e, f       : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c, d, e          : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c, d             : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b, c                : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat(                                                                    a, b                   : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g        : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w      : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f               : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w           : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e                      : BOOLEAN; a_w, b_w, c_w, d_w, e_w                : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d                             : BOOLEAN; a_w, b_w, c_w, d_w                     : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b, use_c                                    : BOOLEAN; a_w, b_w, c_w                          : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_concat_w(use_a, use_b                                           : BOOLEAN; a_w, b_w                               : NATURAL) RETURN NATURAL;
      FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e, use_f, use_g        : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w      : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e, use_f               : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w           : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e                      : BOOLEAN; a_w, b_w, c_w, d_w, e_w                : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b, use_c, use_d                             : BOOLEAN; a_w, b_w, c_w, d_w                     : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b, use_c                                    : BOOLEAN; a_w, b_w, c_w                          : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract( use_a, use_b                                           : BOOLEAN; a_w, b_w                               : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w, d_w, e_w, f_w, g_w      : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w, d_w, e_w, f_w           : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w, d_w, e_w                : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w, d_w                     : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w, c_w                          : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION func_slv_extract(                                                                   a_w, b_w                               : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
      
      FUNCTION TO_UINT(vec : STD_LOGIC_VECTOR) RETURN NATURAL;  -- beware: NATURAL'HIGH = 2**31-1, not 2*32-1, use TO_SINT to avoid warning
      FUNCTION TO_SINT(vec : STD_LOGIC_VECTOR) RETURN INTEGER;
      
      FUNCTION TO_UVEC(dec, w : NATURAL) RETURN STD_LOGIC_VECTOR;
      FUNCTION TO_SVEC(dec, w : INTEGER) RETURN STD_LOGIC_VECTOR;
      
      FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR;  -- = TO_SVEC() with w=32 for t_slv_32_arr slv elements
      
      FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR) RETURN REAL;  -- convert unsigned slv of any length to REAL
      FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR) RETURN REAL;  -- convert signed slv of any length to REAL
      FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert unsigned fixed point slv of any length, and with resolution of 2**resolution_w, to REAL
      FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert signed fixed point slv of any length, and with resolution of 2**resolution_w, to REAL
        
    -- The RESIZE for SIGNED in IEEE.NUMERIC_STD extends the sign bit or it keeps the sign bit and LS part. This
      -- behaviour of preserving the sign bit is less suitable for DSP and not necessary in general. A more
      -- appropriate approach is to ignore the MSbit sign and just keep the LS part. For too large values this 
      -- means that the result gets wrapped, but that is fine for default behaviour, because that is also what
      -- happens for RESIZE of UNSIGNED. Therefor this is what the RESIZE_NUM for SIGNED and the RESIZE_SVEC do
      -- and better not use RESIZE for SIGNED anymore.
      FUNCTION RESIZE_NUM( u   : UNSIGNED;         w : NATURAL) RETURN UNSIGNED;          -- left extend with '0' or keep LS part (same as RESIZE for UNSIGNED)
      FUNCTION RESIZE_NUM( s   : SIGNED;           w : NATURAL) RETURN SIGNED;            -- extend sign bit or keep LS part
      FUNCTION RESIZE_UVEC(sl  : STD_LOGIC;        w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- left extend with '0' into slv
      FUNCTION RESIZE_UVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- left extend with '0' or keep LS part
      FUNCTION RESIZE_SVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- extend sign bit or keep LS part
      FUNCTION RESIZE_UINT(u   : INTEGER;          w : NATURAL) RETURN INTEGER;           -- left extend with '0' or keep LS part
      FUNCTION RESIZE_SINT(s   : INTEGER;          w : NATURAL) RETURN INTEGER;           -- extend sign bit or keep LS part
      
      FUNCTION RESIZE_UVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- = RESIZE_UVEC() with w=32 for t_slv_32_arr slv elements
      FUNCTION RESIZE_SVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- = RESIZE_SVEC() with w=32 for t_slv_32_arr slv elements
    
      FUNCTION NEGATE_SVEC(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;               -- assume negated ranges fits within -+max
      FUNCTION NEGATE_SVEC(vec : STD_LOGIC_VECTOR; w : INTEGER) RETURN STD_LOGIC_VECTOR;  -- avoid overflow by forcing -min to +max. Use w <= vec'LENGTH
      
      FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER)  RETURN STD_LOGIC_VECTOR;
      FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : UNSIGNED) RETURN STD_LOGIC_VECTOR; 
      FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER)  RETURN STD_LOGIC_VECTOR;
      FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : SIGNED)   RETURN STD_LOGIC_VECTOR; 
                                                                                                                       -- Used in common_add_sub.vhd
      FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec + r_vec, treat slv operands as signed,   slv output width is res_w
      FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec - r_vec, treat slv operands as signed,   slv output width is res_w
      FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec + r_vec, treat slv operands as unsigned, slv output width is res_w
      FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec - r_vec, treat slv operands as unsigned, slv output width is res_w
      
      FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec + r_vec, treat slv operands as signed,   slv output width is l_vec'LENGTH
      FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec - r_vec, treat slv operands as signed,   slv output width is l_vec'LENGTH
      FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec + r_vec, treat slv operands as unsigned, slv output width is l_vec'LENGTH
      FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec - r_vec, treat slv operands as unsigned, slv output width is l_vec'LENGTH
      
      FUNCTION COMPLEX_MULT_REAL(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER;  -- Calculate real part of complex multiplication: a_re*b_re - a_im*b_im 
      FUNCTION COMPLEX_MULT_IMAG(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER;  -- Calculate imag part of complex multiplication: a_im*b_re + a_re*b_im 
      
      FUNCTION SHIFT_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR;  -- < 0 shift left, > 0 shift right
      FUNCTION SHIFT_SVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR;  -- < 0 shift left, > 0 shift right
      
      FUNCTION offset_binary(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
      
      FUNCTION truncate(                vec : STD_LOGIC_VECTOR; n              : NATURAL) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec, so result has width vec'LENGTH-n
      FUNCTION truncate_and_resize_uvec(vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec and then resize to width w
      FUNCTION truncate_and_resize_svec(vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
      FUNCTION scale(                   vec : STD_LOGIC_VECTOR; n:               NATURAL) RETURN STD_LOGIC_VECTOR;  -- add n '0' LSBits to vec
      FUNCTION scale_and_resize_uvec(   vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- add n '0' LSBits to vec and then resize to width w
      FUNCTION scale_and_resize_svec(   vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
      FUNCTION truncate_or_resize_uvec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- when b=TRUE then truncate to width w, else resize to width w
      FUNCTION truncate_or_resize_svec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
      
      FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n, and clip to avoid wrap
      FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n
      FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
      FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
      FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
      FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
    
      FUNCTION u_to_s(u : NATURAL; w : NATURAL) RETURN INTEGER;   -- interpret w bit unsigned u as w bit   signed, and remove any MSbits
      FUNCTION s_to_u(s : INTEGER; w : NATURAL) RETURN NATURAL;   -- interpret w bit   signed s as w bit unsigned, and remove any MSbits
      
      FUNCTION u_wrap(u : NATURAL; w : NATURAL) RETURN NATURAL;   -- return u & 2**w-1 (bit wise and), so keep w LSbits of unsigned u, and remove MSbits
      FUNCTION s_wrap(s : INTEGER; w : NATURAL) RETURN INTEGER;   -- return s & 2**w-1 (bit wise and), so keep w LSbits of   signed s, and remove MSbits
      
      FUNCTION u_clip(u : NATURAL; max : NATURAL) RETURN NATURAL;                  -- if s < max return s, else return n
      FUNCTION s_clip(s : INTEGER; max : NATURAL; min : INTEGER) RETURN INTEGER;   -- if s <=  min return  min, else if s >= max return max, else return s
      FUNCTION s_clip(s : INTEGER; max : NATURAL               ) RETURN INTEGER;   -- if s <= -max return -max, else if s >= max return max, else return s
      
      FUNCTION hton(a : STD_LOGIC_VECTOR; w, sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, sz in symbols of width w
      FUNCTION hton(a : STD_LOGIC_VECTOR;    sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, sz in bytes
      FUNCTION hton(a : STD_LOGIC_VECTOR                 ) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, for all bytes in a
      FUNCTION ntoh(a : STD_LOGIC_VECTOR;    sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from network to host, sz in bytes, ntoh() = hton()
      FUNCTION ntoh(a : STD_LOGIC_VECTOR                 ) RETURN STD_LOGIC_VECTOR;  -- convert endianity from network to host, for all bytes in a, ntoh() = hton()
      
      FUNCTION flip(a : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;  -- bit flip a vector, map a[h:0] to [0:h]
      FUNCTION flip(a, w : NATURAL)        RETURN NATURAL;           -- bit flip a vector, map a[h:0] to [0:h], h = w-1
      FUNCTION flip(a : t_slv_32_arr)      RETURN t_slv_32_arr;
      FUNCTION flip(a : t_integer_arr)     RETURN t_integer_arr;
      FUNCTION flip(a : t_natural_arr)     RETURN t_natural_arr;
      FUNCTION flip(a : t_nat_natural_arr) RETURN t_nat_natural_arr;
      
      FUNCTION transpose(a : STD_LOGIC_VECTOR; row, col : NATURAL) RETURN STD_LOGIC_VECTOR;  -- transpose a vector, map a[i*row+j] to output index [j*col+i]
      FUNCTION transpose(a,                    row, col : NATURAL) RETURN NATURAL;           -- transpose index a = [i*row+j] to output index [j*col+i]
    
      FUNCTION split_w(input_w: NATURAL; min_out_w: NATURAL; max_out_w: NATURAL) RETURN NATURAL;
    
      FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING;
    
      FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING;
      FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL; pad_char: CHARACTER) RETURN STRING;
      FUNCTION slice_dn(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING;
    
      FUNCTION nat_arr_to_concat_slv(nat_arr: t_natural_arr; nof_elements: NATURAL) RETURN STD_LOGIC_VECTOR;
    
      ------------------------------------------------------------------------------
      -- Component specific functions
      ------------------------------------------------------------------------------
    
      -- common_fifo_*  
      PROCEDURE proc_common_fifo_asserts (CONSTANT c_fifo_name   : IN STRING;
                                          CONSTANT c_note_is_ful : IN BOOLEAN;
                                          CONSTANT c_fail_rd_emp : IN BOOLEAN;
                                          SIGNAL   wr_rst        : IN STD_LOGIC;
                                          SIGNAL   wr_clk        : IN STD_LOGIC;
                                          SIGNAL   wr_full       : IN STD_LOGIC;
                                          SIGNAL   wr_en         : IN STD_LOGIC;
                                          SIGNAL   rd_clk        : IN STD_LOGIC;
                                          SIGNAL   rd_empty      : IN STD_LOGIC;
                                          SIGNAL   rd_en         : IN STD_LOGIC);
      
      -- common_fanout_tree  
      FUNCTION func_common_fanout_tree_pipelining(c_nof_stages, c_nof_output_per_cell, c_nof_output : NATURAL;
                                                  c_cell_pipeline_factor_arr, c_cell_pipeline_arr : t_natural_arr) RETURN t_natural_arr;
      
      -- common_reorder_symbol 
      FUNCTION func_common_reorder2_is_there(I, J : NATURAL) RETURN BOOLEAN;
      FUNCTION func_common_reorder2_is_active(I, J, N : NATURAL) RETURN BOOLEAN;
      FUNCTION func_common_reorder2_get_select_index(I, J, N : NATURAL) RETURN INTEGER;
      FUNCTION func_common_reorder2_get_select(I, J, N : NATURAL; select_arr : t_natural_arr) RETURN NATURAL;
      FUNCTION func_common_reorder2_inverse_select(N : NATURAL; select_arr : t_natural_arr) RETURN t_natural_arr;
      
      -- Generate faster sample SCLK from digital DCLK for sim only
      PROCEDURE proc_common_dclk_generate_sclk(CONSTANT Pfactor : IN    POSITIVE;
                                               SIGNAL   dclk    : IN    STD_LOGIC;
                                               SIGNAL   sclk    : INOUT STD_LOGIC);
      
    END common_pkg;
    
    PACKAGE BODY common_pkg IS
    
      FUNCTION pow2(n : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN 2**n;
      END;
    
      FUNCTION ceil_pow2(n : INTEGER) RETURN NATURAL IS
      -- Also allows negative exponents and rounds up before returning the value
      BEGIN
        RETURN natural(integer(ceil(2**real(n))));
      END;
      
      FUNCTION true_log2(n : NATURAL) RETURN NATURAL IS
      -- Purpose: For calculating extra vector width of existing vector
      -- Description: Return mathematical ceil(log2(n))
      --   n    log2()
      --   0 -> -oo  --> FAILURE
      --   1 ->  0
      --   2 ->  1
      --   3 ->  2
      --   4 ->  2
      --   5 ->  3
      --   6 ->  3
      --   7 ->  3
      --   8 ->  3
      --   9 ->  4
      --   etc, up to n = NATURAL'HIGH = 2**31-1
      BEGIN
        RETURN natural(integer(ceil(log2(real(n)))));
      END;
      
      FUNCTION ceil_log2(n : NATURAL) RETURN NATURAL IS
      -- Purpose: For calculating vector width of new vector 
      -- Description:
      --   Same as true_log2() except ceil_log2(1) = 1, which is needed to support
      --   the vector width width for 1 address, to avoid NULL array for single
      --   word register address.
      --   If n = 0, return 0 so we get a NULL array when using 
      --   STD_LOGIC_VECTOR(ceil_log2(g_addr_w)-1 DOWNTO 0), instead of an error.
      BEGIN
        IF n = 0 THEN
          RETURN 0;  -- Get NULL array
        ELSIF n = 1 THEN
          RETURN 1;  -- avoid NULL array
        ELSE
          RETURN true_log2(n);
        END IF;
      END;
    
      FUNCTION floor_log10(n : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN natural(integer(floor(log10(real(n)))));
      END;
      
      FUNCTION is_pow2(n : NATURAL) RETURN BOOLEAN IS
      BEGIN
        RETURN n=2**true_log2(n);
      END;
      
      FUNCTION true_log_pow2(n : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN 2**true_log2(n);
      END;
      
      FUNCTION ratio(n, d : NATURAL) RETURN NATURAL IS
      BEGIN
        IF n MOD d = 0 THEN
          RETURN n/d;
        ELSE
          RETURN 0;
        END IF;
      END;
      
      FUNCTION ratio2(n, m : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN largest(ratio(n,m), ratio(m,n));
      END;
      
      FUNCTION almost_equal(a, b, delta : REAL) RETURN BOOLEAN IS
      BEGIN
        IF ABS(a - b) < ABS(delta) THEN
          RETURN TRUE;
        ELSE
          RETURN FALSE;
        END IF;
      END;
      
      FUNCTION almost_zero(a, delta : REAL) RETURN BOOLEAN IS
      BEGIN
        RETURN almost_equal(a, 0.0, delta);
      END;
      
      FUNCTION ceil_div(n, d : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN n/d + sel_a_b(n MOD d = 0, 0, 1);
      END;
      
      FUNCTION ceil_value(n, d : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN ceil_div(n, d) * d;
      END;
      
      FUNCTION floor_value(n, d : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN (n / d) * d;
      END;
      
      FUNCTION ceil_div(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
      BEGIN
        RETURN n/d + sel_a_b(n MOD d = 0, 0, 1);  -- "/" returns same width as n
      END;
      
      FUNCTION ceil_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
        CONSTANT w : NATURAL := n'LENGTH;
        VARIABLE p : UNSIGNED(2*w-1 DOWNTO 0);
      BEGIN
        p := ceil_div(n, d) * d;
        RETURN p(w-1 DOWNTO 0);  -- return same width as n
      END;
      
      FUNCTION floor_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
        CONSTANT w : NATURAL := n'LENGTH;
        VARIABLE p : UNSIGNED(2*w-1 DOWNTO 0);
      BEGIN
        p := (n / d) * d;
        RETURN p(w-1 DOWNTO 0);  -- return same width as n
      END;
      
      FUNCTION slv(n: IN STD_LOGIC) RETURN STD_LOGIC_VECTOR IS
        VARIABLE r : STD_LOGIC_VECTOR(0 DOWNTO 0);
      BEGIN
        r(0) := n;
        RETURN r;
      END;
      
      FUNCTION sl(n: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
        VARIABLE r : STD_LOGIC;
      BEGIN
        r := n(n'LOW);
        RETURN r;
      END;
    
    
      FUNCTION to_sl(n: IN BOOLEAN) RETURN STD_LOGIC IS
      BEGIN
        IF n = TRUE THEN
          RETURN '1';
        ELSE
          RETURN '0';
        END IF;
      END;
    
      FUNCTION to_bool(n: IN STD_LOGIC) RETURN BOOLEAN IS
      BEGIN
        RETURN n = '1' OR n = 'H';
      END;
    
      FUNCTION to_bool(n: IN INTEGER) RETURN BOOLEAN IS
      BEGIN
        RETURN NOT (n = 0);
      END;
    
    
      FUNCTION to_natural_arr(n : t_integer_arr; to_zero : BOOLEAN) RETURN t_natural_arr IS
        VARIABLE vN : t_integer_arr(n'LENGTH-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := n;
        FOR I IN vN'RANGE LOOP
          IF to_zero=FALSE THEN
            vR(I) := vN(I);
          ELSE
            vR(I) := 0;
            IF vN(I)>0 THEN
              vR(I) := vN(I);
            END IF;
          END IF;
        END LOOP;
        RETURN vR;
      END;
      
      FUNCTION to_natural_arr(n : t_nat_natural_arr) RETURN t_natural_arr IS
        VARIABLE vN : t_nat_natural_arr(n'LENGTH-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := n;
        FOR I IN vN'RANGE LOOP
          vR(I) := vN(I);
        END LOOP;
        RETURN vR;
      END;
      
      FUNCTION to_integer_arr(n : t_natural_arr) RETURN t_integer_arr IS
        VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
        VARIABLE vR : t_integer_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := n;
        FOR I IN vN'RANGE LOOP
          vR(I) := vN(I);
        END LOOP;
        RETURN vR;
      END;
      
      FUNCTION to_integer_arr(n : t_nat_natural_arr) RETURN t_integer_arr IS
        VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := to_natural_arr(n);
        RETURN to_integer_arr(vN);
      END;
      
      FUNCTION to_slv_32_arr(n : t_integer_arr) RETURN t_slv_32_arr IS
        VARIABLE vN : t_integer_arr(n'LENGTH-1 DOWNTO 0);
        VARIABLE vR : t_slv_32_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := n;
        FOR I IN vN'RANGE LOOP
          vR(I) := TO_SVEC(vN(I), 32);
        END LOOP;
        RETURN vR;
      END;
      
      FUNCTION to_slv_32_arr(n : t_natural_arr) RETURN t_slv_32_arr IS
        VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
        VARIABLE vR : t_slv_32_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := n;
        FOR I IN vN'RANGE LOOP
          vR(I) := TO_UVEC(vN(I), 32);
        END LOOP;
        RETURN vR;
      END;
      
      FUNCTION vector_tree(slv : STD_LOGIC_VECTOR; operation : STRING) RETURN STD_LOGIC IS
        -- Linear loop to determine result takes combinatorial delay that is proportional to slv'LENGTH:
        --   FOR I IN slv'RANGE LOOP
        --     v_result := v_result OPERATION slv(I);
        --   END LOOP;
        --   RETURN v_result;
        -- Instead use binary tree to determine result with smallest combinatorial delay that depends on log2(slv'LENGTH)
        CONSTANT c_slv_w      : NATURAL := slv'LENGTH;
        CONSTANT c_nof_stages : NATURAL := ceil_log2(c_slv_w);
        CONSTANT c_w          : NATURAL := 2**c_nof_stages;  -- extend the input slv to a vector with length power of 2 to ease using binary tree
        TYPE t_stage_arr IS ARRAY (-1 TO c_nof_stages-1) OF STD_LOGIC_VECTOR(c_w-1 DOWNTO 0);
        VARIABLE v_stage_arr  : t_stage_arr;
        VARIABLE v_result     : STD_LOGIC := '0';
      BEGIN
        -- default any unused, the stage results will be kept in the LSBits and the last result in bit 0
        IF    operation="AND" THEN v_stage_arr := (OTHERS=>(OTHERS=>'1'));
        ELSIF operation="OR"  THEN v_stage_arr := (OTHERS=>(OTHERS=>'0'));
        ELSIF operation="XOR" THEN v_stage_arr := (OTHERS=>(OTHERS=>'0'));
        ELSE
          ASSERT TRUE REPORT "common_pkg: Unsupported vector_tree operation" SEVERITY FAILURE;
        END IF;
        v_stage_arr(-1)(c_slv_w-1 DOWNTO 0) := slv;  -- any unused input c_w : c_slv_w bits have void default value
        FOR J IN 0 TO c_nof_stages-1 LOOP
          FOR I IN 0 TO c_w/(2**(J+1))-1 LOOP
            IF    operation="AND" THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) AND v_stage_arr(J-1)(2*I+1);
            ELSIF operation="OR"  THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) OR  v_stage_arr(J-1)(2*I+1);
            ELSIF operation="XOR" THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) XOR v_stage_arr(J-1)(2*I+1);
            END IF;
          END LOOP;
        END LOOP;
        RETURN v_stage_arr(c_nof_stages-1)(0);
      END;  
      
      FUNCTION vector_and(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "AND");
      END;
      
      FUNCTION vector_or(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "OR");
      END;
    
      FUNCTION vector_xor(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "XOR");
      END;
    
      FUNCTION vector_one_hot(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_one_hot : BOOLEAN := FALSE;
        VARIABLE v_zeros   : STD_LOGIC_VECTOR(slv'RANGE) := (OTHERS=>'0');
      BEGIN
        FOR i IN slv'RANGE LOOP
          IF slv(i) = '1' THEN
            IF NOT(v_one_hot) THEN
              -- No hot bits found so far
              v_one_hot := TRUE;
            ELSE
              -- This is the second hot bit found; return zeros.
              RETURN v_zeros;
            END IF;
          END IF;
        END LOOP;
        -- No or a single hot bit found in slv; return slv.
        RETURN slv;
      END;
      
      FUNCTION andv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "AND");
      END;
      
      FUNCTION orv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "OR");
      END;
      
      FUNCTION xorv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
      BEGIN
        RETURN vector_tree(slv, "XOR");
      END;
      
      FUNCTION array_and(arr : t_nat_boolean_arr) RETURN BOOLEAN IS
        VARIABLE v_slv : STD_LOGIC_VECTOR(arr'RANGE);
      BEGIN
        FOR I IN arr'RANGE LOOP v_slv(I) := sel_a_b(arr(I), '1', '0'); END LOOP;  -- wire map boolean arr to slv
        RETURN sel_a_b(vector_and(v_slv) = '1', TRUE, FALSE);                     -- use vector_tree to determine result
      END;
      
      FUNCTION array_or(arr : t_nat_boolean_arr) RETURN BOOLEAN IS
        VARIABLE v_slv : STD_LOGIC_VECTOR(arr'RANGE);
      BEGIN
        FOR I IN arr'RANGE LOOP v_slv(I) := sel_a_b(arr(I), '1', '0'); END LOOP;  -- wire map boolean arr to slv
        RETURN sel_a_b(vector_or(v_slv) = '1', TRUE, FALSE);                      -- use vector_tree to determine result
      END;
      
      FUNCTION matrix_and(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC IS
        VARIABLE v_mat    : t_sl_matrix(0 TO wi-1, 0 TO wj-1) := mat;  -- map to fixed range
        VARIABLE v_result : STD_LOGIC := '1';
      BEGIN
        FOR I IN 0 TO wi-1 LOOP
          FOR J IN 0 TO wj-1 LOOP
            v_result := v_result AND v_mat(I,J);
          END LOOP;
        END LOOP;
        RETURN v_result;
      END;
      
      FUNCTION matrix_or(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC IS
        VARIABLE v_mat    : t_sl_matrix(0 TO wi-1, 0 TO wj-1) := mat;  -- map to fixed range
        VARIABLE v_result : STD_LOGIC := '0';
      BEGIN
        FOR I IN 0 TO wi-1 LOOP
          FOR J IN 0 TO wj-1 LOOP
            v_result := v_result OR v_mat(I,J);
          END LOOP;
        END LOOP;
        RETURN v_result;
      END;
      
      FUNCTION smallest(n, m : INTEGER) RETURN INTEGER IS
      BEGIN
        IF n < m THEN
          RETURN n;
        ELSE
          RETURN m;
        END IF;
      END;
      
      FUNCTION smallest(n, m : REAL) RETURN REAL IS
      BEGIN
        IF n < m THEN
          RETURN n;
        ELSE
          RETURN m;
        END IF;
      END;
      
      FUNCTION smallest(n, m, l : INTEGER) RETURN INTEGER IS
        VARIABLE v : NATURAL;
      BEGIN
                      v := n;
        IF v > m THEN v := m; END IF;
        IF v > l THEN v := l; END IF;
        RETURN v;
      END;
    
      FUNCTION smallest(n : t_natural_arr) RETURN NATURAL IS
        VARIABLE m : NATURAL := 0;
      BEGIN
        FOR I IN n'RANGE LOOP
          IF n(I) < m THEN
            m := n(I);
          END IF;
        END LOOP;
        RETURN m;
      END;
      
      FUNCTION smallest(n : t_nat_natural_arr) RETURN NATURAL IS
        VARIABLE m : NATURAL := 0;
      BEGIN
        FOR I IN n'RANGE LOOP
          IF n(I) < m THEN
            m := n(I);
          END IF;
        END LOOP;
        RETURN m;
      END;
      
      FUNCTION largest(n, m : INTEGER) RETURN INTEGER IS
      BEGIN
        IF n > m THEN
          RETURN n;
        ELSE
          RETURN m;
        END IF;
      END;
      
      FUNCTION largest(n, m : REAL) RETURN REAL IS
      BEGIN
        IF n > m THEN
          RETURN n;
        ELSE
          RETURN m;
        END IF;
      END;
      
      FUNCTION largest(n : t_natural_arr) RETURN NATURAL IS
        VARIABLE m : NATURAL := 0;
      BEGIN
        FOR I IN n'RANGE LOOP
          IF n(I) > m THEN
            m := n(I);
          END IF;
        END LOOP;
        RETURN m;
      END;
      
      FUNCTION largest(n : t_nat_natural_arr) RETURN NATURAL IS
        VARIABLE m : NATURAL := 0;
      BEGIN
        FOR I IN n'RANGE LOOP
          IF n(I) > m THEN
            m := n(I);
          END IF;
        END LOOP;
        RETURN m;
      END;
      
      FUNCTION func_sum(n : t_natural_arr) RETURN NATURAL IS
        VARIABLE vS : NATURAL;
      BEGIN
        vS := 0;
        FOR I IN n'RANGE LOOP
          vS := vS + n(I);
        END LOOP;
        RETURN vS;
      END;
      
      FUNCTION func_sum(n : t_nat_natural_arr) RETURN NATURAL IS
        VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := to_natural_arr(n);
        RETURN func_sum(vN);
      END;
      
      FUNCTION func_product(n : t_natural_arr) RETURN NATURAL IS
        VARIABLE vP : NATURAL;
      BEGIN
        vP := 1;
        FOR I IN n'RANGE LOOP
          vP := vP * n(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION func_product(n : t_nat_natural_arr) RETURN NATURAL IS
        VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
      BEGIN
        vN := to_natural_arr(n);
        RETURN func_product(vN);
      END;
      
      FUNCTION "+" (L, R: t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        vR := R;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) + vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "+" (L: t_natural_arr; R : INTEGER) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) + R;
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "+" (L: INTEGER; R : t_natural_arr) RETURN t_natural_arr IS
      BEGIN
        RETURN R + L;
      END;
      
      FUNCTION "-" (L, R: t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        vR := R;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) - vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "-" (L, R: t_natural_arr) RETURN t_integer_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_integer_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        vR := R;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) - vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "-" (L: t_natural_arr; R : INTEGER) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) - R;
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "-" (L: INTEGER; R : t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := R'LENGTH;
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vR := R;
        FOR I IN vR'RANGE LOOP
          vP(I) := L - vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "*" (L, R: t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        vR := R;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) * vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "*" (L: t_natural_arr; R : NATURAL) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) * R;
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "*" (L: NATURAL; R : t_natural_arr) RETURN t_natural_arr IS
      BEGIN
        RETURN R * L;
      END;
      
      FUNCTION "/" (L, R: t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        vR := R;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) / vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "/" (L: t_natural_arr; R : POSITIVE) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := L'LENGTH;
        VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vL := L;
        FOR I IN vL'RANGE LOOP
          vP(I) := vL(I) / R;
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION "/" (L: NATURAL; R : t_natural_arr) RETURN t_natural_arr IS
        CONSTANT w  : NATURAL := R'LENGTH;
        VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
        VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
      BEGIN
        vR := R;
        FOR I IN vR'RANGE LOOP
          vP(I) := L / vR(I);
        END LOOP;
        RETURN vP;
      END;
      
      FUNCTION is_true(a : STD_LOGIC) RETURN BOOLEAN   IS BEGIN IF a='1'  THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END;
      FUNCTION is_true(a : STD_LOGIC) RETURN NATURAL   IS BEGIN IF a='1'  THEN RETURN 1;    ELSE RETURN 0;     END IF; END;
      FUNCTION is_true(a : BOOLEAN)   RETURN STD_LOGIC IS BEGIN IF a=TRUE THEN RETURN '1';  ELSE RETURN '0';   END IF; END;  
      FUNCTION is_true(a : BOOLEAN)   RETURN NATURAL   IS BEGIN IF a=TRUE THEN RETURN 1;    ELSE RETURN 0;     END IF; END;  
      FUNCTION is_true(a : INTEGER)   RETURN BOOLEAN   IS BEGIN IF a/=0   THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END;
      FUNCTION is_true(a : INTEGER)   RETURN STD_LOGIC IS BEGIN IF a/=0   THEN RETURN '1';  ELSE RETURN '0';   END IF; END;
      
      FUNCTION sel_a_b(sel, a, b : INTEGER) RETURN INTEGER IS
      BEGIN
        IF sel /= 0 THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
    
      FUNCTION sel_a_b(sel, a, b : BOOLEAN) RETURN BOOLEAN IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : INTEGER) RETURN INTEGER IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
    
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : REAL) RETURN REAL IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC) RETURN STD_LOGIC IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC) RETURN STD_LOGIC IS
      BEGIN
        IF sel /= 0 THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        IF sel /= 0 THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : SIGNED) RETURN SIGNED IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : UNSIGNED) RETURN UNSIGNED IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_integer_arr) RETURN t_integer_arr IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_natural_arr) RETURN t_natural_arr IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_integer_arr) RETURN t_nat_integer_arr IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_natural_arr) RETURN t_nat_natural_arr IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : STRING) RETURN STRING IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : INTEGER; a, b : STRING) RETURN STRING IS
      BEGIN
        IF sel /= 0 THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : TIME) RETURN TIME IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
    
      FUNCTION sel_a_b(sel : BOOLEAN; a, b : SEVERITY_LEVEL) RETURN SEVERITY_LEVEL IS
      BEGIN
        IF sel = TRUE THEN
          RETURN a;
        ELSE
          RETURN b;
        END IF;
      END;
      
      -- sel_n : boolean
      FUNCTION sel_n(sel : NATURAL; a, b, c : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h, i);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : BOOLEAN) RETURN BOOLEAN IS
        CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h, i, j);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      -- sel_n : integer
      FUNCTION sel_n(sel : NATURAL; a, b, c : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h, i);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : INTEGER) RETURN INTEGER IS
        CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h, i, j);
      BEGIN
        RETURN c_arr(sel);
      END;
      
      -- sel_n : string
      FUNCTION sel_n(sel : NATURAL; a, b                         : STRING) RETURN STRING IS BEGIN IF sel=0 THEN RETURN            a                         ; ELSE RETURN b; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c                      : STRING) RETURN STRING IS BEGIN IF sel<2 THEN RETURN sel_n(sel, a, b                     ); ELSE RETURN c; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : STRING) RETURN STRING IS BEGIN IF sel<3 THEN RETURN sel_n(sel, a, b, c                  ); ELSE RETURN d; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : STRING) RETURN STRING IS BEGIN IF sel<4 THEN RETURN sel_n(sel, a, b, c, d               ); ELSE RETURN e; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : STRING) RETURN STRING IS BEGIN IF sel<5 THEN RETURN sel_n(sel, a, b, c, d, e            ); ELSE RETURN f; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : STRING) RETURN STRING IS BEGIN IF sel<6 THEN RETURN sel_n(sel, a, b, c, d, e, f         ); ELSE RETURN g; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : STRING) RETURN STRING IS BEGIN IF sel<7 THEN RETURN sel_n(sel, a, b, c, d, e, f, g      ); ELSE RETURN h; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : STRING) RETURN STRING IS BEGIN IF sel<8 THEN RETURN sel_n(sel, a, b, c, d, e, f, g, h   ); ELSE RETURN i; END IF; END;
      FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : STRING) RETURN STRING IS BEGIN IF sel<9 THEN RETURN sel_n(sel, a, b, c, d, e, f, g, h, i); ELSE RETURN j; END IF; END;
      
      FUNCTION array_init(init : STD_LOGIC; nof : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_arr : STD_LOGIC_VECTOR(0 TO nof-1);
      BEGIN
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init : BOOLEAN; nof : NATURAL) RETURN t_nat_boolean_arr IS
        VARIABLE v_arr : t_nat_boolean_arr(0 TO nof-1);
      BEGIN
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof : NATURAL) RETURN t_natural_arr IS
        VARIABLE v_arr : t_natural_arr(0 TO nof-1);
      BEGIN
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof : NATURAL) RETURN t_nat_natural_arr IS
        VARIABLE v_arr : t_nat_natural_arr(0 TO nof-1);
      BEGIN
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof, incr : NATURAL) RETURN t_natural_arr IS
        VARIABLE v_arr : t_natural_arr(0 TO nof-1);
        VARIABLE v_i   : NATURAL;
      BEGIN
        v_i := 0;
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init + v_i * incr;
          v_i := v_i + 1;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof, incr : NATURAL) RETURN t_nat_natural_arr IS
        VARIABLE v_arr : t_nat_natural_arr(0 TO nof-1);
        VARIABLE v_i   : NATURAL;
      BEGIN
        v_i := 0;
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := init + v_i * incr;
          v_i := v_i + 1;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof, incr : INTEGER) RETURN t_slv_16_arr IS
        VARIABLE v_arr : t_slv_16_arr(0 TO nof-1);
        VARIABLE v_i   : NATURAL;
      BEGIN
        v_i := 0;
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := TO_SVEC(init + v_i * incr, 16);
          v_i := v_i + 1;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_init(init, nof, incr : INTEGER) RETURN t_slv_32_arr IS
        VARIABLE v_arr : t_slv_32_arr(0 TO nof-1);
        VARIABLE v_i   : NATURAL;
      BEGIN
        v_i := 0;
        FOR I IN v_arr'RANGE LOOP
          v_arr(I) := TO_SVEC(init + v_i * incr, 32);
          v_i := v_i + 1;
        END LOOP;
        RETURN v_arr;
      END;
    
      FUNCTION array_init(init, nof, width : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
      BEGIN
        FOR I IN 0 TO nof-1 LOOP
          v_arr(width*(I+1)-1 DOWNTO width*I) := TO_UVEC(init, width);
        END LOOP;
        RETURN v_arr;
      END;
    
      FUNCTION array_init(init, nof, width, incr : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
        VARIABLE v_i   : NATURAL;
      BEGIN
        v_i := 0;
        FOR I IN 0 TO nof-1 LOOP
          v_arr(width*(I+1)-1 DOWNTO width*I) := TO_UVEC(init + v_i * incr, width);
          v_i := v_i + 1;
        END LOOP;
        RETURN v_arr;
      END;
      
      FUNCTION array_sinit(init :INTEGER; nof, width : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
      BEGIN
        FOR I IN 0 TO nof-1 LOOP
          v_arr(width*(I+1)-1 DOWNTO width*I) := TO_SVEC(init, width);
        END LOOP;
        RETURN v_arr;
      END;
    
      FUNCTION init_slv_64_matrix(nof_a, nof_b, k : INTEGER) RETURN t_slv_64_matrix IS
        VARIABLE v_mat : t_slv_64_matrix(nof_a-1 DOWNTO 0, nof_b-1 DOWNTO 0);
      BEGIN
        FOR I IN 0 TO nof_a-1 LOOP
          FOR J IN 0 TO nof_b-1 LOOP
            v_mat(I,J) := TO_SVEC(k, 64);
          END LOOP;
        END LOOP;
        RETURN v_mat;
      END;
      
      -- Support concatenation of up to 8 slv into 1 slv
      FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a, b, c, d, e, f, g, h : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_max_w : NATURAL := a'LENGTH + b'LENGTH + c'LENGTH + d'LENGTH + e'LENGTH + f'LENGTH + g'LENGTH + h'LENGTH;
        VARIABLE v_res   : STD_LOGIC_VECTOR(c_max_w-1 DOWNTO 0) := (OTHERS=>'0');
        VARIABLE v_len   : NATURAL := 0;
      BEGIN
        IF use_a = TRUE THEN v_res(a'LENGTH-1 + v_len DOWNTO v_len) := a; v_len := v_len + a'LENGTH; END IF;
        IF use_b = TRUE THEN v_res(b'LENGTH-1 + v_len DOWNTO v_len) := b; v_len := v_len + b'LENGTH; END IF;
        IF use_c = TRUE THEN v_res(c'LENGTH-1 + v_len DOWNTO v_len) := c; v_len := v_len + c'LENGTH; END IF;
        IF use_d = TRUE THEN v_res(d'LENGTH-1 + v_len DOWNTO v_len) := d; v_len := v_len + d'LENGTH; END IF;
        IF use_e = TRUE THEN v_res(e'LENGTH-1 + v_len DOWNTO v_len) := e; v_len := v_len + e'LENGTH; END IF;
        IF use_f = TRUE THEN v_res(f'LENGTH-1 + v_len DOWNTO v_len) := f; v_len := v_len + f'LENGTH; END IF;
        IF use_g = TRUE THEN v_res(g'LENGTH-1 + v_len DOWNTO v_len) := g; v_len := v_len + g'LENGTH; END IF;
        IF use_h = TRUE THEN v_res(h'LENGTH-1 + v_len DOWNTO v_len) := h; v_len := v_len + h'LENGTH; END IF;
        RETURN v_res(v_len-1 DOWNTO 0);
      END func_slv_concat;
        
      FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a, b, c, d, e, f, g : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, use_g, FALSE, a, b, c, d, e, f, g, "0");
      END func_slv_concat;
    
      FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a, b, c, d, e, f : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, FALSE, a, b, c, d, e, f, "0", "0");
      END func_slv_concat;
      
      FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a, b, c, d, e : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, FALSE, a, b, c, d, e, "0", "0", "0");
      END func_slv_concat;
      
      FUNCTION func_slv_concat(use_a, use_b, use_c, use_d : BOOLEAN; a, b, c, d : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, FALSE, a, b, c, d, "0", "0", "0", "0");
      END func_slv_concat;
      
      FUNCTION func_slv_concat(use_a, use_b, use_c : BOOLEAN; a, b, c : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, FALSE, a, b, c, "0", "0", "0", "0", "0");
      END func_slv_concat;
      
      FUNCTION func_slv_concat(use_a, use_b : BOOLEAN; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, a, b, "0", "0", "0", "0", "0", "0");
      END func_slv_concat;
        
      FUNCTION func_slv_concat(a, b, c, d, e, f, g, h : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a, b, c, d, e, f, g, h);
      END func_slv_concat;
    
      FUNCTION func_slv_concat(a, b, c, d, e, f, g : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a, b, c, d, e, f, g);
      END func_slv_concat;
      
      FUNCTION func_slv_concat(a, b, c, d, e, f : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a, b, c, d, e, f);
      END func_slv_concat;
      
      FUNCTION func_slv_concat(a, b, c, d, e: STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, TRUE, TRUE, a, b, c, d, e);
      END func_slv_concat;
      
      FUNCTION func_slv_concat(a, b, c, d : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, TRUE, a, b, c, d);
      END func_slv_concat;
      
      FUNCTION func_slv_concat(a, b, c : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, TRUE, a, b, c);
      END func_slv_concat;
      
      FUNCTION func_slv_concat(a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_concat(TRUE, TRUE, a, b);
      END func_slv_concat;
      
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL) RETURN NATURAL IS
        VARIABLE v_len : NATURAL := 0;
      BEGIN
        IF use_a = TRUE THEN v_len := v_len + a_w; END IF;
        IF use_b = TRUE THEN v_len := v_len + b_w; END IF;
        IF use_c = TRUE THEN v_len := v_len + c_w; END IF;
        IF use_d = TRUE THEN v_len := v_len + d_w; END IF;
        IF use_e = TRUE THEN v_len := v_len + e_w; END IF;
        IF use_f = TRUE THEN v_len := v_len + f_w; END IF;
        IF use_g = TRUE THEN v_len := v_len + g_w; END IF;
        IF use_h = TRUE THEN v_len := v_len + h_w; END IF;
        RETURN v_len;
      END func_slv_concat_w;
        
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, g_w, 0);
      END func_slv_concat_w;
    
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, 0, 0);
      END func_slv_concat_w;
      
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a_w, b_w, c_w, d_w, e_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, 0, 0, 0);
      END func_slv_concat_w;
      
      FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d : BOOLEAN; a_w, b_w, c_w, d_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, 0, 0, 0, 0);
      END func_slv_concat_w;
      
      FUNCTION func_slv_concat_w(use_a, use_b, use_c : BOOLEAN; a_w, b_w, c_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, 0, 0, 0, 0, 0);
      END func_slv_concat_w;
      
      FUNCTION func_slv_concat_w(use_a, use_b : BOOLEAN; a_w, b_w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN func_slv_concat_w(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, 0, 0, 0, 0, 0, 0);
      END func_slv_concat_w;
    
      -- extract slv
      FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, use_g, use_h : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_w  : NATURAL := 0;
        VARIABLE v_lo : NATURAL := 0;
      BEGIN
        -- if the selected slv is not used in vec, then return dummy, else return the selected slv from vec
        CASE sel IS
          WHEN 0 =>
            IF use_a = TRUE THEN v_w := a_w; ELSE RETURN c_slv0(a_w-1 DOWNTO 0); END IF;
          WHEN 1 =>
            IF use_b = TRUE THEN v_w := b_w; ELSE RETURN c_slv0(b_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
          WHEN 2 =>
            IF use_c = TRUE THEN v_w := c_w; ELSE RETURN c_slv0(c_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
          WHEN 3 =>
            IF use_d = TRUE THEN v_w := d_w; ELSE RETURN c_slv0(d_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
            IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
          WHEN 4 =>
            IF use_e = TRUE THEN v_w := e_w; ELSE RETURN c_slv0(e_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
            IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
            IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
          WHEN 5 =>
            IF use_f = TRUE THEN v_w := f_w; ELSE RETURN c_slv0(f_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
            IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
            IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
            IF use_e = TRUE THEN v_lo := v_lo + e_w; END IF;
          WHEN 6 =>
            IF use_g = TRUE THEN v_w := g_w; ELSE RETURN c_slv0(g_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
            IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
            IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
            IF use_e = TRUE THEN v_lo := v_lo + e_w; END IF;
            IF use_f = TRUE THEN v_lo := v_lo + f_w; END IF;
          WHEN 7 =>
            IF use_h = TRUE THEN v_w := h_w; ELSE RETURN c_slv0(h_w-1 DOWNTO 0); END IF;
            IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
            IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
            IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
            IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
            IF use_e = TRUE THEN v_lo := v_lo + e_w; END IF;
            IF use_f = TRUE THEN v_lo := v_lo + f_w; END IF;
            IF use_g = TRUE THEN v_lo := v_lo + g_w; END IF;
          WHEN OTHERS => REPORT "Unknown common_pkg func_slv_extract argument" SEVERITY FAILURE;
        END CASE;
        RETURN vec(v_w-1 + v_lo DOWNTO v_lo);  -- extracted slv
      END func_slv_extract;
        
      FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, use_g, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, g_w, 0, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, 0, 0, vec, sel);
      END func_slv_extract;
      
      FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a_w, b_w, c_w, d_w, e_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, 0, 0, 0, vec, sel);
      END func_slv_extract;
      
      FUNCTION func_slv_extract(use_a, use_b, use_c, use_d : BOOLEAN; a_w, b_w, c_w, d_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, 0, 0, 0, 0, vec, sel);
      END func_slv_extract;
      
      FUNCTION func_slv_extract(use_a, use_b, use_c : BOOLEAN; a_w, b_w, c_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, 0, 0, 0, 0, 0, vec, sel);
      END func_slv_extract;
      
      FUNCTION func_slv_extract(use_a, use_b : BOOLEAN; a_w, b_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, 0, 0, 0, 0, 0, 0, vec, sel);
      END func_slv_extract;
        
      FUNCTION func_slv_extract(a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a_w, b_w, c_w, d_w, e_w, f_w, g_w, h_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a_w, b_w, c_w, d_w, e_w, f_w, g_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w, c_w, d_w, e_w, f_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, a_w, b_w, c_w, d_w, e_w, f_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w, c_w, d_w, e_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, TRUE, TRUE, a_w, b_w, c_w, d_w, e_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w, c_w, d_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, TRUE, a_w, b_w, c_w, d_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w, c_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, TRUE, a_w, b_w, c_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION func_slv_extract(a_w, b_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN func_slv_extract(TRUE, TRUE, a_w, b_w, vec, sel);
      END func_slv_extract;
    
      FUNCTION TO_UINT(vec : STD_LOGIC_VECTOR) RETURN NATURAL IS
      BEGIN
        RETURN TO_INTEGER(UNSIGNED(vec));
      END;
      
      FUNCTION TO_SINT(vec : STD_LOGIC_VECTOR) RETURN INTEGER IS
      BEGIN
        RETURN TO_INTEGER(SIGNED(vec));
      END;
      
      FUNCTION TO_UVEC(dec, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(TO_UNSIGNED(dec, w));
      END;
    
      FUNCTION TO_SVEC(dec, w : INTEGER) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(TO_SIGNED(dec, w));
      END;
      
      FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN TO_SVEC(dec, 32);
      END;
    
      FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR) RETURN REAL IS
        CONSTANT c_len  : NATURAL := uvec'LENGTH;
        VARIABLE v_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := uvec;
        VARIABLE v_real : REAL := 0.0;
      BEGIN
        -- Avoid using INTEGER, which is limited to 32 bit, by determining per bit whether it contributes to the REAL value
        FOR I IN 0 TO c_len-1 LOOP
          IF v_uvec(I)='1' THEN
            v_real := v_real + 2**REAL(I);
          END IF;
        END LOOP;
        RETURN v_real;
      END;
      
      FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR) RETURN REAL IS
        CONSTANT c_len  : NATURAL := svec'LENGTH + 1;  -- use +1 so the v_uvec can also fit abs() of most negative is -1 * -2**(c_len-1)
        VARIABLE v_pos  : BOOLEAN := TRUE;
        VARIABLE v_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := RESIZE_SVEC(svec, c_len);
        VARIABLE v_real : REAL := 0.0;
      BEGIN
        -- Negate svec to have positive v_uvec.
        IF SIGNED(svec) < 0 THEN
          v_pos  := FALSE;
          v_uvec := INCR_UVEC(NOT svec, 1);  -- negate the svec to make it positive
        END IF;
        -- Determine REAL value for positive
        v_real := TO_UREAL(v_uvec);
        -- Update the sign
        IF v_pos THEN
          RETURN v_real;
        ELSE
          RETURN -v_real;
        END IF;
      END;
    
      FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL IS
        -- First convert as unsigned integer:
        VARIABLE v_real : REAL := TO_UREAL(uvec);
      BEGIN
        -- Then scale to real (see TO_SREAL)
        RETURN v_real * 2.0**REAL(resolution_w);
      END;
      
      FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL IS
        -- First convert as signed integer:
        VARIABLE v_real : REAL := TO_SREAL(svec);
      BEGIN
        -- Then scale to real:
        -- . The resolution_w is the number of bits that LSbit 0 in svec(HIGH-1 DOWNTO 0) is after
        --   (when resolution_w > 0), or before (when resolution_w < 0) the fixed point.
        -- . The real value is then scaled by scaling the integer value by 2**(-1 * resolution_w):
        --   . resolution_w = 0 : scale by 2**0 = 1, so no scaling and the value is treated as an integer
        --   . resolution_w < 0 : scale up
        --   . resolution_w > 0 : scale down
        RETURN v_real * 2.0**REAL(-1 * resolution_w);
      END;
        
      
      FUNCTION RESIZE_NUM(u : UNSIGNED; w : NATURAL) RETURN UNSIGNED IS
      BEGIN
        -- left extend with '0' or keep LS part (same as RESIZE for UNSIGNED)
        RETURN RESIZE(u, w);
      END;
      
      FUNCTION RESIZE_NUM(s : SIGNED; w : NATURAL) RETURN SIGNED IS
      BEGIN
        -- extend sign bit or keep LS part
        IF w>s'LENGTH THEN
          RETURN RESIZE(s, w);                    -- extend sign bit
        ELSE
          RETURN SIGNED(RESIZE(UNSIGNED(s), w));  -- keep LSbits (= vec[w-1:0])
        END IF;
      END;
      
      FUNCTION RESIZE_UVEC(sl : STD_LOGIC; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_slv0 : STD_LOGIC_VECTOR(w-1 DOWNTO 1) := (OTHERS=>'0');
      BEGIN
        RETURN v_slv0 & sl;
      END;
      
      FUNCTION RESIZE_UVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(vec), w));
      END;
    
      FUNCTION RESIZE_SVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(vec), w));
      END;
      
      FUNCTION RESIZE_UINT(u : INTEGER; w : NATURAL) RETURN INTEGER IS
        VARIABLE v : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
      BEGIN
        v := TO_UVEC(u, c_word_w);
        RETURN TO_UINT(v(w-1 DOWNTO 0));
      END;
      
      FUNCTION RESIZE_SINT(s : INTEGER; w : NATURAL) RETURN INTEGER IS
        VARIABLE v : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
      BEGIN
        v := TO_SVEC(s, c_word_w);
        RETURN TO_SINT(v(w-1 DOWNTO 0));
      END;
      
      FUNCTION RESIZE_UVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN RESIZE_UVEC(vec, 32);
      END;
      
      FUNCTION RESIZE_SVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN RESIZE_SVEC(vec, 32);
      END;
      
      -- Negate vec, assume value range fits -+c_max, so no logic needed to check for c_min
      FUNCTION NEGATE_SVEC(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        -- use NUMERIC_STD to avoid range limitation of 32b INTEGER
        RETURN STD_LOGIC_VECTOR(-SIGNED(vec));  -- negate by multiplying by -1
      END;
    
      -- Negate vec, but avoid overflow by forcing -min to +max. Use w <= vec'LENGTH.
      FUNCTION NEGATE_SVEC(vec : STD_LOGIC_VECTOR; w : INTEGER) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_max   : INTEGER :=  2**(w-1)-1;
        CONSTANT c_min   : INTEGER := -2**(w-1);
        CONSTANT c_vec_w : NATURAL := vec'LENGTH;
        VARIABLE v_vec   : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0) := vec;  -- independent of vec'RANGE
        VARIABLE v_val   : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        v_val := v_vec(w-1 DOWNTO 0);  -- operate on width w and resize to c_vec_w for return
        -- use NUMERIC_STD to avoid range limitation of 32b INTEGER
        IF SIGNED(v_val) = c_min THEN
          RETURN STD_LOGIC_VECTOR(TO_SIGNED(c_max, c_vec_w));  -- most negative becomes most positive
        ELSE
          RETURN STD_LOGIC_VECTOR(RESIZE_NUM(-SIGNED(v_val), c_vec_w));  -- negate by multiplying by -1
        END IF;
      END;
    
      FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_dec : INTEGER;
      BEGIN
        IF dec < 0 THEN
          v_dec := -dec;
          RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) - v_dec);  -- uses function "-" (L : UNSIGNED, R : NATURAL), there is no function + with R : INTEGER argument
        ELSE
          v_dec := dec;
          RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) + v_dec);  -- uses function "+" (L : UNSIGNED, R : NATURAL)
        END IF;
      END;
    
      FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : UNSIGNED) RETURN STD_LOGIC_VECTOR IS   
      BEGIN
        RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) + dec);
      END;
      
      FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_dec : INTEGER;
      BEGIN
        RETURN STD_LOGIC_VECTOR(SIGNED(vec) + v_dec);  -- uses function "+" (L : SIGNED, R : INTEGER)
      END;
    
      FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : SIGNED) RETURN STD_LOGIC_VECTOR IS   
      BEGIN
        RETURN STD_LOGIC_VECTOR(SIGNED(vec) + dec);
      END;
      
      FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(l_vec), res_w) + SIGNED(r_vec));
      END;
      
      FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(l_vec), res_w) - SIGNED(r_vec));
      END;
      
      FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(l_vec), res_w) + UNSIGNED(r_vec));
      END;
      
      FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(l_vec), res_w) - UNSIGNED(r_vec));
      END;
      
      
      FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN ADD_SVEC(l_vec, r_vec, l_vec'LENGTH);
      END;
      
      FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN SUB_SVEC(l_vec, r_vec, l_vec'LENGTH);
      END;
      
      FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN ADD_UVEC(l_vec, r_vec, l_vec'LENGTH);
      END;
      
      FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN SUB_UVEC(l_vec, r_vec, l_vec'LENGTH);
      END;
      
      FUNCTION COMPLEX_MULT_REAL(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER IS   
      BEGIN
        RETURN (a_re*b_re - a_im*b_im); 
      END;
      
      FUNCTION COMPLEX_MULT_IMAG(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER IS
      BEGIN
        RETURN (a_im*b_re + a_re*b_im);
      END;
      
      FUNCTION SHIFT_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        IF shift < 0 THEN
          RETURN STD_LOGIC_VECTOR(SHIFT_LEFT(UNSIGNED(vec), -shift));  -- fill zeros from right
        ELSE
          RETURN STD_LOGIC_VECTOR(SHIFT_RIGHT(UNSIGNED(vec), shift));  -- fill zeros from left
        END IF;
      END;
      
      FUNCTION SHIFT_SVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        IF shift < 0 THEN
          RETURN STD_LOGIC_VECTOR(SHIFT_LEFT(SIGNED(vec), -shift));  -- same as SHIFT_LEFT for UNSIGNED
        ELSE
          RETURN STD_LOGIC_VECTOR(SHIFT_RIGHT(SIGNED(vec), shift));  -- extend sign
        END IF;
      END;
    
      --
      -- offset_binary() : maps offset binary to or from two-complement binary.
      --
      --   National ADC08DC1020     offset binary     two-complement binary
      --   + full scale =  127.5 :  11111111 = 255     127 = 01111111
      --     ...                                  
      --   +            =   +0.5 :  10000000 = 128       0 = 00000000
      --   0
      --   -            =   -0.5 :  01111111 = 127      -1 = 11111111
      --     ...                                  
      --   - full scale = -127.5 :  00000000 =   0    -128 = 10000000
      --
      -- To map between the offset binary and two complement binary involves
      -- adding 128 to the binary value or equivalently inverting the sign bit.
      -- The offset_binary() mapping can be done and undone both ways.
      -- The offset_binary() mapping to two-complement binary yields a DC offset
      -- of -0.5 Lsb.
      FUNCTION offset_binary(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_res : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;
      BEGIN
       v_res(v_res'HIGH) := NOT v_res(v_res'HIGH);  -- invert MSbit to get to from offset binary to two's complement, or vice versa
       RETURN v_res;
      END;
      
      FUNCTION truncate(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
        VARIABLE v_vec     : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0) := vec;
        VARIABLE v_res     : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
      BEGIN
       v_res := v_vec(c_vec_w-1 DOWNTO n);  -- keep MS part
       RETURN v_res;
      END;
    
      FUNCTION truncate_and_resize_uvec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
        VARIABLE v_trunc   : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
        VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        v_trunc := truncate(vec, n);       -- first keep MS part
        v_res := RESIZE_UVEC(v_trunc, w);  -- then keep LS part or left extend with '0'
        RETURN v_res;
      END;
      
      FUNCTION truncate_and_resize_svec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
        VARIABLE v_trunc   : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
        VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        v_trunc := truncate(vec, n);       -- first keep MS part
        v_res := RESIZE_SVEC(v_trunc, w);  -- then keep sign bit and LS part or left extend sign bit
        RETURN v_res;
      END;
      
      FUNCTION scale(vec : STD_LOGIC_VECTOR; n: NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_scale_w : NATURAL := c_vec_w+n;
        VARIABLE v_res     : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
      BEGIN
        v_res(c_scale_w-1 DOWNTO n) := vec;  -- scale by adding n zero bits at the right
        RETURN v_res;
      END;
      
      FUNCTION scale_and_resize_uvec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_scale_w : NATURAL := c_vec_w+n;
        VARIABLE v_scale   : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
        VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        v_scale(c_scale_w-1 DOWNTO n) := vec;  -- first scale by adding n zero bits at the right
        v_res := RESIZE_UVEC(v_scale, w);      -- then keep LS part or left extend with '0'
        RETURN v_res;
      END;
      
      FUNCTION scale_and_resize_svec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
        CONSTANT c_scale_w : NATURAL := c_vec_w+n;
        VARIABLE v_scale   : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
        VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        v_scale(c_scale_w-1 DOWNTO n) := vec;  -- first scale by adding n zero bits at the right
        v_res := RESIZE_SVEC(v_scale, w);      -- then keep LS part or left extend sign bit
        RETURN v_res;
      END;
      
      FUNCTION truncate_or_resize_uvec(vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w : NATURAL := vec'LENGTH;
        VARIABLE c_n     : INTEGER := c_vec_w-w;
        VARIABLE v_res   : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        IF b=TRUE AND c_n>0 THEN
          v_res := truncate_and_resize_uvec(vec, c_n, w);
        ELSE
          v_res := RESIZE_UVEC(vec, w);
        END IF;
        RETURN v_res;
      END;
      
      FUNCTION truncate_or_resize_svec(vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_vec_w : NATURAL := vec'LENGTH;
        VARIABLE c_n     : INTEGER := c_vec_w-w;
        VARIABLE v_res   : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
      BEGIN
        IF b=TRUE AND c_n>0 THEN
          v_res := truncate_and_resize_svec(vec, c_n, w);
        ELSE
          v_res := RESIZE_SVEC(vec, w);
        END IF;
        RETURN v_res;
      END;
      
      
      -- Functions s_round, s_round_up and u_round:
      --
      -- . The returned output width is input width - n.
      -- . If n=0 then the return value is the same as the input value so only
      --   wires (NOP, no operation).
      -- . Both have the same implementation but different c_max and c_clip values.
      -- . Round up for unsigned so +2.5 becomes 3
      -- . Round away from zero for signed so round up for positive and round down for negative, so +2.5 becomes 3 and -2.5 becomes -3.
      -- . Round away from zero is also used by round() in Matlab, Python, TCL
      -- . Rounding up implies adding 0.5 and then truncation, use clip = TRUE to
      --   clip the potential overflow due to adding 0.5 to +max.
      -- . For negative values overflow due to rounding can not occur, because c_half-1 >= 0 for n>0
      -- . If the input comes from a product and is rounded to the input width then
      --   clip can safely be FALSE, because e.g. for unsigned 4b*4b=8b->4b the
      --   maximum product is 15*15=225 <= 255-8, and for signed 4b*4b=8b->4b the
      --   maximum product is -8*-8=+64 <= 127-8, so wrapping due to rounding
      --   overflow will never occur.
    
      FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
        -- Use SIGNED to avoid NATURAL (32 bit range) overflow error
        CONSTANT c_in_w  : NATURAL := vec'LENGTH;
        CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
        CONSTANT c_one   : SIGNED(c_in_w-1 DOWNTO 0) := TO_SIGNED(1, c_in_w);
        CONSTANT c_half  : SIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                            -- = 2**(n-1)
        CONSTANT c_max   : SIGNED(c_in_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_in_w-2 DOWNTO 0)) - c_half;  -- = 2**(c_in_w-1)-1 - c_half  
        CONSTANT c_clip  : SIGNED(c_out_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_out_w-2 DOWNTO 0));         -- = 2**(c_out_w-1)-1
        VARIABLE v_in    : SIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_out   : SIGNED(c_out_w-1 DOWNTO 0);
      BEGIN
        v_in := SIGNED(vec);
        IF n > 0 THEN
          IF clip = TRUE AND v_in > c_max THEN
            v_out := c_clip;                                              -- Round clip to maximum positive to avoid wrap to negative
          ELSE
            IF vec(vec'HIGH)='0' THEN
              v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half + 0, n), c_out_w);  -- Round up for positive
            ELSE
              v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half - 1, n), c_out_w);  -- Round down for negative
            END IF;
          END IF;
        ELSE
          v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
        END IF;
        RETURN STD_LOGIC_VECTOR(v_out);
      END;
    
      FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN s_round(vec, n, FALSE);  -- no round clip
      END;
      
      -- An alternative is to always round up, also for negative numbers (i.e. s_round_up = u_round).
      FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN u_round(vec, n, clip);
      END;
      
      FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN u_round(vec, n, FALSE);  -- no round clip
      END;
      
      -- Unsigned numbers are round up (almost same as s_round, but without the else on negative vec)
      FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN ) RETURN STD_LOGIC_VECTOR IS
        -- Use UNSIGNED to avoid NATURAL (32 bit range) overflow error
        CONSTANT c_in_w  : NATURAL := vec'LENGTH;
        CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
        CONSTANT c_one   : UNSIGNED(c_in_w-1 DOWNTO 0) := TO_UNSIGNED(1, c_in_w);
        CONSTANT c_half  : UNSIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                        -- = 2**(n-1)
        CONSTANT c_max   : UNSIGNED(c_in_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_in_w-1 DOWNTO 0)) - c_half;  -- = 2**c_in_w-1 - c_half  
        CONSTANT c_clip  : UNSIGNED(c_out_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_out_w-1 DOWNTO 0));         -- = 2**c_out_w-1
        VARIABLE v_in    : UNSIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_out   : UNSIGNED(c_out_w-1 DOWNTO 0);
      BEGIN
        v_in := UNSIGNED(vec);
        IF n > 0 THEN
          IF clip = TRUE AND v_in > c_max THEN
            v_out := c_clip;                                              -- Round clip to +max to avoid wrap to 0
          ELSE
            v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half, n), c_out_w);  -- Round up
          END IF;
        ELSE
          v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
        END IF;
        RETURN STD_LOGIC_VECTOR(v_out);
      END;
    
      FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN u_round(vec, n, FALSE);  -- no round clip
      END;
    
      FUNCTION u_to_s(u : NATURAL; w : NATURAL) RETURN INTEGER IS
        VARIABLE v_u : STD_LOGIC_VECTOR(31 DOWNTO 0) := TO_UVEC(u, 32);  -- via 32 bit word to avoid NUMERIC_STD.TO_SIGNED: vector truncated warming
      BEGIN
        RETURN TO_SINT(v_u(w-1 DOWNTO 0));
      END;
          
      FUNCTION s_to_u(s : INTEGER; w : NATURAL) RETURN NATURAL IS
        VARIABLE v_s : STD_LOGIC_VECTOR(31 DOWNTO 0) := TO_SVEC(s, 32);  -- via 32 bit word to avoid NUMERIC_STD.TO_SIGNED: vector truncated warming
      BEGIN
        RETURN TO_UINT(v_s(w-1 DOWNTO 0));
      END;
    
      FUNCTION u_wrap(u : NATURAL; w : NATURAL) RETURN NATURAL IS
        VARIABLE v_u : STD_LOGIC_VECTOR(31 DOWNTO 0) := TO_UVEC(u, 32);  -- via 32 bit word to avoid NUMERIC_STD.TO_SIGNED: vector truncated warming
      BEGIN
        RETURN TO_UINT(v_u(w-1 DOWNTO 0));
      END;
      
      FUNCTION s_wrap(s : INTEGER; w : NATURAL) RETURN INTEGER IS
        VARIABLE v_s : STD_LOGIC_VECTOR(31 DOWNTO 0) := TO_SVEC(s, 32);  -- via 32 bit word to avoid NUMERIC_STD.TO_SIGNED: vector truncated warming
      BEGIN
        RETURN TO_SINT(v_s(w-1 DOWNTO 0));
      END;
      
      FUNCTION u_clip(u : NATURAL; max : NATURAL) RETURN NATURAL IS
      BEGIN
        IF u > max THEN
          RETURN max;
        ELSE
          RETURN u;
        END IF;
      END;
      
      FUNCTION s_clip(s : INTEGER; max : NATURAL; min : INTEGER) RETURN INTEGER IS
      BEGIN
        IF s < min THEN
          RETURN min;
        ELSE
          IF s > max THEN
            RETURN max;
          ELSE
            RETURN s;
          END IF;
        END IF;
      END;
      
      FUNCTION s_clip(s : INTEGER; max : NATURAL) RETURN INTEGER IS
      BEGIN
        RETURN s_clip(s, max, -max);
      END;
    
      FUNCTION hton(a : STD_LOGIC_VECTOR; w, sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_a : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;  -- map a to range [h:0]
        VARIABLE v_b : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;  -- default b = a
        VARIABLE vL  : NATURAL;
        VARIABLE vK  : NATURAL;
      BEGIN
        -- Note:
        -- . if sz = 1          then v_b = v_a
        -- . if a'LENGTH > sz*w then v_b(a'LENGTH:sz*w) = v_a(a'LENGTH:sz*w)
        FOR vL IN 0 TO sz-1 LOOP
          vK := sz-1 - vL;
          v_b((vL+1)*w-1 DOWNTO vL*w) := v_a((vK+1)*w-1 DOWNTO vK*w);
        END LOOP;
        RETURN v_b;
      END FUNCTION;
      
      FUNCTION hton(a : STD_LOGIC_VECTOR; sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN hton(a, c_byte_w, sz);  -- symbol width w = c_byte_w = 8
      END FUNCTION;
      
      FUNCTION hton(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
        CONSTANT c_sz : NATURAL := a'LENGTH/ c_byte_w;
      BEGIN
        RETURN hton(a, c_byte_w, c_sz);  -- symbol width w = c_byte_w = 8
      END FUNCTION;
      
      FUNCTION ntoh(a : STD_LOGIC_VECTOR; sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN hton(a, sz);  -- i.e. ntoh() = hton()
      END FUNCTION;
      
      FUNCTION ntoh(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
      BEGIN
        RETURN hton(a);  -- i.e. ntoh() = hton()
      END FUNCTION;
      
      FUNCTION flip(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_a : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;
        VARIABLE v_b : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
      BEGIN
        FOR I IN v_a'RANGE LOOP
          v_b(a'LENGTH-1-I) := v_a(I);
        END LOOP;
        RETURN v_b;
      END;
      
      FUNCTION flip(a, w : NATURAL) RETURN NATURAL IS
      BEGIN
        RETURN TO_UINT(flip(TO_UVEC(a, w)));
      END;
      
      FUNCTION flip(a : t_slv_32_arr) RETURN t_slv_32_arr IS
        VARIABLE v_a : t_slv_32_arr(a'LENGTH-1 DOWNTO 0) := a;
        VARIABLE v_b : t_slv_32_arr(a'LENGTH-1 DOWNTO 0);
      BEGIN
        FOR I IN v_a'RANGE LOOP
          v_b(a'LENGTH-1-I) := v_a(I);
        END LOOP;
        RETURN v_b;
      END;
      
      FUNCTION flip(a : t_integer_arr) RETURN t_integer_arr IS
        VARIABLE v_a : t_integer_arr(a'LENGTH-1 DOWNTO 0) := a;
        VARIABLE v_b : t_integer_arr(a'LENGTH-1 DOWNTO 0);
      BEGIN
        FOR I IN v_a'RANGE LOOP
          v_b(a'LENGTH-1-I) := v_a(I);
        END LOOP;
        RETURN v_b;
      END;
    
      FUNCTION flip(a : t_natural_arr) RETURN t_natural_arr IS
        VARIABLE v_a : t_natural_arr(a'LENGTH-1 DOWNTO 0) := a;
        VARIABLE v_b : t_natural_arr(a'LENGTH-1 DOWNTO 0);
      BEGIN
        FOR I IN v_a'RANGE LOOP
          v_b(a'LENGTH-1-I) := v_a(I);
        END LOOP;
        RETURN v_b;
      END;
      
      FUNCTION flip(a : t_nat_natural_arr) RETURN t_nat_natural_arr IS
        VARIABLE v_a : t_nat_natural_arr(a'LENGTH-1 DOWNTO 0) := a;
        VARIABLE v_b : t_nat_natural_arr(a'LENGTH-1 DOWNTO 0);
      BEGIN
        FOR I IN v_a'RANGE LOOP
          v_b(a'LENGTH-1-I) := v_a(I);
        END LOOP;
        RETURN v_b;
      END;
        
      FUNCTION transpose(a : STD_LOGIC_VECTOR; row, col : NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE vIn  : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
        VARIABLE vOut : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
      BEGIN
        vIn  := a;    -- map input vector to h:0 range
        vOut := vIn;  -- default leave any unused MSbits the same
        FOR J IN 0 TO row-1 LOOP
          FOR I IN 0 TO col-1 LOOP
            vOut(J*col + I) := vIn(I*row + J);  -- transpose vector, map input index [i*row+j] to output index [j*col+i]
          END LOOP;
        END LOOP;
        RETURN vOut;
      END FUNCTION;
      
      FUNCTION transpose(a, row, col : NATURAL) RETURN NATURAL IS  -- transpose index a = [i*row+j] to output index [j*col+i]
        VARIABLE vI  : NATURAL;
        VARIABLE vJ  : NATURAL;
      BEGIN
        vI := a / row;
        vJ := a MOD row;
        RETURN vJ * col + vI;
      END;
     
      FUNCTION split_w(input_w: NATURAL; min_out_w: NATURAL; max_out_w: NATURAL) RETURN NATURAL IS -- Calculate input_w in multiples as close as possible to max_out_w
        -- Examples: split_w(256, 8, 32) = 32;  split_w(16, 8, 32) = 16; split_w(72, 8, 32) = 18;    -- Input_w must be multiple of 2.
        VARIABLE r: NATURAL;
      BEGIN
        r := input_w;
        FOR i IN 1 TO ceil_log2(input_w) LOOP -- Useless to divide the number beyond this       
          IF r <= max_out_w AND r >= min_out_w THEN
            RETURN r;
          ELSIF i = ceil_log2(input_w) THEN -- last iteration
            RETURN 0; -- Indicates wrong values were used
          END IF;
          r := r / 2;
        END LOOP;
      END;
    
      FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING IS
        VARIABLE v_str : STRING(1 TO width) := (OTHERS => pad_char);
      BEGIN
        v_str(width-str'LENGTH+1 TO width) := str;
        RETURN v_str;
      END;
    
      FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING IS
      BEGIN
        RETURN str(i*width+1 TO (i+1)*width);
      END;
    
      -- If the input value is not a multiple of the desired width, the return value is padded with
      -- the passed pad value. E.g. if input='10' and desired width is 4, return value is '0010'.
      FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL; pad_char: CHARACTER) RETURN STRING IS
        VARIABLE padded_str : STRING(1 TO width) := (OTHERS=>'0');
      BEGIN
        padded_str := pad(str(i*width+1 TO (i+1)*width), width, '0');
        RETURN padded_str;
      END;
    
      FUNCTION slice_dn(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING IS
      BEGIN
        RETURN str((i+1)*width-1 DOWNTO i*width);
      END;
    
     
      FUNCTION nat_arr_to_concat_slv(nat_arr: t_natural_arr; nof_elements: NATURAL) RETURN STD_LOGIC_VECTOR IS
        VARIABLE v_concat_slv : STD_LOGIC_VECTOR(nof_elements*32-1 DOWNTO 0) := (OTHERS=>'0');
      BEGIN
        FOR i IN 0 TO nof_elements-1 LOOP
          v_concat_slv(i*32+32-1 DOWNTO i*32) :=  TO_UVEC(nat_arr(i), 32);
        END LOOP;
        RETURN v_concat_slv;
      END;
    
      
      ------------------------------------------------------------------------------
      -- common_fifo_*  
      ------------------------------------------------------------------------------
      
      PROCEDURE proc_common_fifo_asserts (CONSTANT c_fifo_name   : IN STRING;
                                          CONSTANT c_note_is_ful : IN BOOLEAN;
                                          CONSTANT c_fail_rd_emp : IN BOOLEAN;
                                          SIGNAL   wr_rst        : IN STD_LOGIC;
                                          SIGNAL   wr_clk        : IN STD_LOGIC;
                                          SIGNAL   wr_full       : IN STD_LOGIC;
                                          SIGNAL   wr_en         : IN STD_LOGIC;
                                          SIGNAL   rd_clk        : IN STD_LOGIC;
                                          SIGNAL   rd_empty      : IN STD_LOGIC;
                                          SIGNAL   rd_en         : IN STD_LOGIC) IS
      BEGIN
        -- c_fail_rd_emp : when TRUE report FAILURE when read from an empty FIFO, important when FIFO rd_val is not used
        -- c_note_is_ful : when TRUE report NOTE when FIFO goes full, to note that operation is on the limit
        -- FIFO overflow is always reported as FAILURE
    
        -- The FIFO wr_full goes high at reset to indicate that it can not be written and it goes low a few cycles after reset.
        -- Therefore only check on wr_full going high when wr_rst='0'.
        
        --synthesis translate_off
        ASSERT NOT(c_fail_rd_emp=TRUE AND rising_edge(rd_clk)  AND rd_empty='1' AND rd_en='1')  REPORT c_fifo_name & " : read from empty fifo occurred!" SEVERITY FAILURE;
        ASSERT NOT(c_note_is_ful=TRUE AND rising_edge(wr_full) AND wr_rst='0')                  REPORT c_fifo_name & " : fifo is full now"               SEVERITY NOTE;
        ASSERT NOT(                       rising_edge(wr_clk)  AND wr_full='1'  AND wr_en='1')  REPORT c_fifo_name & " : fifo overflow occurred!"        SEVERITY FAILURE;
        --synthesis translate_on
      END PROCEDURE proc_common_fifo_asserts;
      
      
      ------------------------------------------------------------------------------
      -- common_fanout_tree 
      ------------------------------------------------------------------------------
      
      FUNCTION func_common_fanout_tree_pipelining(c_nof_stages, c_nof_output_per_cell, c_nof_output : NATURAL;
                                                  c_cell_pipeline_factor_arr, c_cell_pipeline_arr : t_natural_arr) RETURN t_natural_arr IS
        CONSTANT k_cell_pipeline_factor_arr : t_natural_arr(c_nof_stages-1 DOWNTO 0) := c_cell_pipeline_factor_arr;
        CONSTANT k_cell_pipeline_arr        : t_natural_arr(c_nof_output_per_cell-1 DOWNTO 0) := c_cell_pipeline_arr;
        VARIABLE v_stage_pipeline_arr       : t_natural_arr(c_nof_output-1 DOWNTO 0) := (OTHERS=>0);
        VARIABLE v_prev_stage_pipeline_arr  : t_natural_arr(c_nof_output-1 DOWNTO 0) := (OTHERS=>0);
      BEGIN
        loop_stage : FOR j IN 0 TO c_nof_stages-1 LOOP
          v_prev_stage_pipeline_arr := v_stage_pipeline_arr;
          loop_cell : FOR i IN 0 TO c_nof_output_per_cell**j-1 LOOP
            v_stage_pipeline_arr((i+1)*c_nof_output_per_cell-1 DOWNTO i*c_nof_output_per_cell) := v_prev_stage_pipeline_arr(i) + (k_cell_pipeline_factor_arr(j) * k_cell_pipeline_arr);
          END LOOP;
        END LOOP;
        RETURN v_stage_pipeline_arr; 
      END FUNCTION func_common_fanout_tree_pipelining;
      
      
      ------------------------------------------------------------------------------
      -- common_reorder_symbol 
      ------------------------------------------------------------------------------
      
      -- Determine whether the stage I and row J index refer to any (active or redundant) 2-input reorder cell instantiation
      FUNCTION func_common_reorder2_is_there(I, J : NATURAL) RETURN BOOLEAN IS
        VARIABLE v_odd  : BOOLEAN;
        VARIABLE v_even : BOOLEAN;
      BEGIN
        v_odd  := (I MOD 2 = 1) AND (J MOD 2 = 1);  -- for odd  stage at each odd  row
        v_even := (I MOD 2 = 0) AND (J MOD 2 = 0);  -- for even stage at each even row
        RETURN v_odd OR v_even;
      END func_common_reorder2_is_there;
      
      -- Determine whether the stage I and row J index refer to an active 2-input reorder cell instantiation in a reorder network with N stages
      FUNCTION func_common_reorder2_is_active(I, J, N : NATURAL) RETURN BOOLEAN IS
        VARIABLE v_inst : BOOLEAN;
        VARIABLE v_act  : BOOLEAN;
      BEGIN
        v_inst := func_common_reorder2_is_there(I, J);
        v_act  := (I > 0) AND (I <= N) AND (J > 0) AND (J < N);
        RETURN v_inst AND v_act;
      END func_common_reorder2_is_active;
      
      -- Get the index K in the select setting array for the reorder2 cell on stage I and row J in a reorder network with N stages
      FUNCTION func_common_reorder2_get_select_index(I, J, N : NATURAL) RETURN INTEGER IS
        CONSTANT c_nof_reorder2_per_odd_stage  : NATURAL := N/2;
        CONSTANT c_nof_reorder2_per_even_stage : NATURAL := (N-1)/2;
        VARIABLE v_nof_odd_stages  : NATURAL;
        VARIABLE v_nof_even_stages : NATURAL;
        VARIABLE v_offset          : NATURAL;
        VARIABLE v_K               : INTEGER;
      BEGIN
        -- for I, J that do not refer to an reorder cell instance for -1 as dummy return value.
        -- for the redundant two port reorder cells at the border rows for -1 to indicate that the cell should pass on the input.
        v_K := -1;
        IF func_common_reorder2_is_active(I, J, N) THEN
          -- for the active two port reorder cells use the setting at index v_K from the select setting array
          v_nof_odd_stages  :=  I/2;
          v_nof_even_stages := (I-1)/2;
          v_offset          := (J-1)/2;  -- suits both odd stage and even stage
          v_K := v_nof_odd_stages * c_nof_reorder2_per_odd_stage + v_nof_even_stages * c_nof_reorder2_per_even_stage + v_offset;
        END IF;
        RETURN v_K;
      END func_common_reorder2_get_select_index;
      
      -- Get the select setting for the reorder2 cell on stage I and row J in a reorder network with N stages
      FUNCTION func_common_reorder2_get_select(I, J, N : NATURAL; select_arr : t_natural_arr) RETURN NATURAL IS
        CONSTANT c_nof_select : NATURAL := select_arr'LENGTH;
        CONSTANT c_select_arr : t_natural_arr(c_nof_select-1 DOWNTO 0) := select_arr;  -- force range downto 0
        VARIABLE v_sel        : NATURAL;
        VARIABLE v_K          : INTEGER;
      BEGIN
        v_sel := 0;
        v_K := func_common_reorder2_get_select_index(I, J, N);
        IF v_K>=0 THEN
          v_sel := c_select_arr(v_K);
        END IF;
        RETURN v_sel;
      END func_common_reorder2_get_select;
      
      -- Determine the inverse of a reorder network by using two reorder networks in series
      FUNCTION func_common_reorder2_inverse_select(N : NATURAL; select_arr : t_natural_arr) RETURN t_natural_arr IS
        CONSTANT c_nof_select      : NATURAL := select_arr'LENGTH;
        CONSTANT c_select_arr      : t_natural_arr(c_nof_select-1 DOWNTO 0) := select_arr;  -- force range downto 0
        VARIABLE v_sel             : NATURAL;
        VARIABLE v_Ki              : INTEGER;
        VARIABLE v_Ii              : NATURAL;
        VARIABLE v_inverse_arr     : t_natural_arr(2*c_nof_select-1 DOWNTO 0) := (OTHERS=>0);  -- default set identity for the reorder2 cells in both reorder instances
      BEGIN
        -- the inverse select consists of inverse_in reorder and inverse_out reorder in series
        IF N MOD 2 = 1 THEN
          -- N is odd so only need to fill in the inverse_in reorder, the inverse_out reorder remains at default pass on
          FOR I IN 1 TO N LOOP
            FOR J IN 0 TO N-1 LOOP
              -- get the DUT setting
              v_sel := func_common_reorder2_get_select(I, J, N, c_select_arr);
              -- map DUT I to inverse v_Ii stage index and determine the index for the inverse setting
              v_Ii := 1+N-I;
              v_Ki := func_common_reorder2_get_select_index(v_Ii, J, N);
              IF v_Ki>=0 THEN
                v_inverse_arr(v_Ki) := v_sel;
              END IF;
            END LOOP;
          END LOOP;
        ELSE
          -- N is even so only use stage 1 of the inverse_out reorder, the other stages remain at default pass on
          FOR K IN 0 TO N/2-1 LOOP
             v_Ki := c_nof_select + K;  -- stage 1 of the inverse_out reorder
             v_inverse_arr(v_Ki) := c_select_arr(K);
          END LOOP;
          -- N is even so leave stage 1 of the inverse_in reorder at default pass on, and do inverse the other stages
          FOR I IN 2 TO N LOOP
            FOR J IN 0 TO N-1 LOOP
              -- get the DUT setting
              v_sel := func_common_reorder2_get_select(I, J, N, c_select_arr);
              -- map DUT I to inverse v_Ii stage index and determine the index for the inverse setting
              v_Ii := 2+N-I;
              v_Ki := func_common_reorder2_get_select_index(v_Ii, J, N);
              IF v_Ki>=0 THEN
                v_inverse_arr(v_Ki) := v_sel;
              END IF;
            END LOOP;
          END LOOP;
        END IF;
        RETURN v_inverse_arr;
      END func_common_reorder2_inverse_select;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Generate faster sample SCLK from digital DCLK for sim only
      -- Description:
      --   The SCLK kan be used to serialize Pfactor >= 1 symbols per word and then 
      --   view them in a scope component that is use internally in the design.
      --   The scope component is only instantiated for simulation, to view the
      --   serialized symbols, typically with decimal radix and analogue format.
      --   The scope component will not be synthesized, because the SCLK can not
      --   be synthesized.
      --   
      --   Pfactor = 4
      --            _______         _______         _______         _______
      --   DCLK ___|       |_______|       |_______|       |_______|       |_______
      --        ___________________   _   _   _   _   _   _   _   _   _   _   _   _
      --   SCLK                    |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
      --
      --   The rising edges of SCLK occur after the rising edge of DCLK, to ensure
      --   that they all apply to the same wide data word that was clocked by the
      --   rising edge of the DCLK.
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_dclk_generate_sclk(CONSTANT Pfactor : IN    POSITIVE;
                                               SIGNAL   dclk    : IN    STD_LOGIC;
                                               SIGNAL   sclk    : INOUT STD_LOGIC) IS
        VARIABLE v_dperiod : TIME;
        VARIABLE v_speriod : TIME;
      BEGIN
        SCLK <= '1';
        -- Measure DCLK period
        WAIT UNTIL rising_edge(DCLK);
        v_dperiod := NOW;
        WAIT UNTIL rising_edge(DCLK);
        v_dperiod := NOW - v_dperiod;
        v_speriod := v_dperiod / Pfactor;
        -- Generate Pfactor SCLK periods per DCLK period
        WHILE TRUE LOOP
          -- Realign at every DCLK
          WAIT UNTIL rising_edge(DCLK);
          -- Create Pfactor SCLK periods within this DCLK period
          SCLK <= '0';
          IF Pfactor>1 THEN
            FOR I IN 0 TO 2*Pfactor-1-2 LOOP
              WAIT FOR v_speriod/2;
              SCLK <= NOT SCLK;
            END LOOP;
          END IF;
          WAIT FOR v_speriod/2;
          SCLK <= '1';
          -- Wait for next DCLK
        END LOOP;
        WAIT;
      END proc_common_dclk_generate_sclk;
      
    END common_pkg;