Skip to content
Snippets Groups Projects
Select Git revision
  • d81f992807bb509fc7754a0daebbca19a2f873ee
  • master default protected
  • L2SDP-LIFT
  • L2SDP-1113
  • HPR-158
5 results

tb_common_pkg.vhd

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    tb_common_pkg.vhd 67.76 KiB
    -------------------------------------------------------------------------------
    --
    -- Copyright (C) 2019
    -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
    -- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.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 for simulations
    -- Interface:
    -- . [n/a]
    -- Description:
    -- . 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 std.textio.ALL;             -- for boolean, integer file IO
    USE IEEE.std_logic_textio.ALL;  -- for std_logic, std_logic_vector file IO
    USE work.common_pkg.ALL;  
    
    
    PACKAGE tb_common_pkg IS
    
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  NATURAL);
                                                    
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  REAL);
                                                    
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk_in       : IN  STD_LOGIC;
                                             SIGNAL clk_out      : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  NATURAL);
          
      PROCEDURE proc_common_wait_some_pulses(SIGNAL clk          : IN  STD_LOGIC;
                                             SIGNAL pulse        : IN  STD_LOGIC;
                                                    c_nof_pulses : IN  NATURAL);
                                                    
      PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  STD_LOGIC);
                                                    
      PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  INTEGER);
                                                    
      PROCEDURE proc_common_wait_until_evt(CONSTANT c_timeout : IN  NATURAL;
                                           SIGNAL   clk       : IN  STD_LOGIC;
                                           SIGNAL   level     : IN  STD_LOGIC);
                                            
      PROCEDURE proc_common_wait_until_high(CONSTANT c_timeout : IN  NATURAL;
                                            SIGNAL   clk       : IN  STD_LOGIC;
                                            SIGNAL   level     : IN  STD_LOGIC);
                                            
      PROCEDURE proc_common_wait_until_high(SIGNAL clk    : IN  STD_LOGIC;
                                            SIGNAL level  : IN  STD_LOGIC);
                                                    
      PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN  NATURAL;
                                           SIGNAL   clk       : IN  STD_LOGIC;
                                           SIGNAL   level     : IN  STD_LOGIC);
                                           
      PROCEDURE proc_common_wait_until_low(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  STD_LOGIC);
                                             
      PROCEDURE proc_common_wait_until_hi_lo(CONSTANT c_timeout : IN  NATURAL;
                                             SIGNAL   clk       : IN  STD_LOGIC;
                                             SIGNAL   level     : IN  STD_LOGIC);
                                             
      PROCEDURE proc_common_wait_until_hi_lo(SIGNAL clk    : IN  STD_LOGIC;
                                             SIGNAL level  : IN  STD_LOGIC);
                                             
      PROCEDURE proc_common_wait_until_lo_hi(CONSTANT c_timeout : IN  NATURAL;
                                             SIGNAL   clk       : IN  STD_LOGIC;
                                             SIGNAL   level     : IN  STD_LOGIC);
                                             
      PROCEDURE proc_common_wait_until_lo_hi(SIGNAL clk    : IN  STD_LOGIC;
                                             SIGNAL level  : IN  STD_LOGIC);
                                             
      PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
                                             SIGNAL clk       : IN  STD_LOGIC;
                                             SIGNAL level     : IN  INTEGER);
                                             
      PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
                                             SIGNAL clk       : IN  STD_LOGIC;
                                             SIGNAL level     : IN  STD_LOGIC_VECTOR);
                                             
      PROCEDURE proc_common_wait_until_value(CONSTANT c_timeout : IN  NATURAL;
                                             CONSTANT c_value   : IN  INTEGER;
                                             SIGNAL clk         : IN  STD_LOGIC;
                                             SIGNAL level       : IN  STD_LOGIC_VECTOR);
    
      -- Wait until absolute simulation time NOW = c_time
      PROCEDURE proc_common_wait_until_time(SIGNAL clk      : IN  STD_LOGIC;
                                            CONSTANT c_time : IN  TIME);
                                           
      -- Exit simulation on timeout failure                                         
      PROCEDURE proc_common_timeout_failure(CONSTANT c_timeout : IN TIME;
                                            SIGNAL tb_end      : IN STD_LOGIC);
    
                                           
      -- Stop simulation using severity FAILURE when g_tb_end=TRUE, else for use in multi tb report as severity NOTE
      PROCEDURE proc_common_stop_simulation(SIGNAL tb_end : IN STD_LOGIC);
    
      PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
                                            CONSTANT g_latency : IN NATURAL;   -- latency between tb_done and tb_)end
                                            SIGNAL clk         : IN STD_LOGIC;
                                            SIGNAL tb_done     : IN STD_LOGIC;
                                            SIGNAL tb_end      : OUT STD_LOGIC);
    
      PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
                                            SIGNAL clk         : IN STD_LOGIC;
                                            SIGNAL tb_done     : IN STD_LOGIC;
                                            SIGNAL tb_end      : OUT STD_LOGIC);
                                           
      -- Handle stream ready signal, only support ready latency c_rl = 0 or 1.
      PROCEDURE proc_common_ready_latency(CONSTANT c_rl      : IN  NATURAL;
                                          SIGNAL   clk       : IN  STD_LOGIC;
                                          SIGNAL   enable    : IN  STD_LOGIC;  -- when '1' then active output when ready
                                          SIGNAL   ready     : IN  STD_LOGIC;
                                          SIGNAL   out_valid : OUT STD_LOGIC);
                                          
                                      
      -- Generate a single active, inactive pulse
      PROCEDURE proc_common_gen_pulse(CONSTANT c_active : IN  NATURAL;    -- pulse active for nof clk
                                      CONSTANT c_period : IN  NATURAL;    -- pulse period for nof clk
                                      CONSTANT c_level  : IN  STD_LOGIC;  -- pulse level when active
                                      SIGNAL   clk      : IN  STD_LOGIC;
                                      SIGNAL   pulse    : OUT STD_LOGIC);
                                      
      -- Pulse forever after rst was released
      PROCEDURE proc_common_gen_pulse(CONSTANT c_active : IN  NATURAL;    -- pulse active for nof clk
                                      CONSTANT c_period : IN  NATURAL;    -- pulse period for nof clk
                                      CONSTANT c_level  : IN  STD_LOGIC;  -- pulse level when active
                                      SIGNAL   rst      : IN  STD_LOGIC;
                                      SIGNAL   clk      : IN  STD_LOGIC;
                                      SIGNAL   pulse    : OUT STD_LOGIC);
                                           
      -- Generate a single '1', '0' pulse
      PROCEDURE proc_common_gen_pulse(SIGNAL clk   : IN  STD_LOGIC;
                                      SIGNAL pulse : OUT STD_LOGIC);
                                      
      -- Generate a periodic pulse with arbitrary duty cycle
      PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_delay     : IN  NATURAL;    -- delay pulse for nof_clk after enable
                                           CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
                                           CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
                                           CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
                                           SIGNAL   rst         : IN  STD_LOGIC;
                                           SIGNAL   clk         : IN  STD_LOGIC;
                                           SIGNAL   enable      : IN  STD_LOGIC;  -- once enabled, the pulse remains enabled
                                           SIGNAL   pulse       : OUT STD_LOGIC);
                                           
      PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
                                           CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
                                           CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
                                           SIGNAL   rst         : IN  STD_LOGIC;
                                           SIGNAL   clk         : IN  STD_LOGIC;
                                           SIGNAL   enable      : IN  STD_LOGIC;  -- once enabled, the pulse remains enabled
                                           SIGNAL   pulse       : OUT STD_LOGIC);
                                           
      -- Generate counter data with valid and arbitrary increment or fixed increment=1
      PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
                                     CONSTANT c_init      : IN  INTEGER;
                                     CONSTANT c_incr      : IN  INTEGER;
                                     SIGNAL   rst         : IN  STD_LOGIC;
                                     SIGNAL   clk         : IN  STD_LOGIC;
                                     SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
                                     SIGNAL   ready       : IN  STD_LOGIC;
                                     SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
                                     SIGNAL   out_valid   : OUT STD_LOGIC);
                                     
      PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
                                     CONSTANT c_init      : IN  INTEGER;
                                     SIGNAL   rst         : IN  STD_LOGIC;
                                     SIGNAL   clk         : IN  STD_LOGIC;
                                     SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
                                     SIGNAL   ready       : IN  STD_LOGIC;
                                     SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
                                     SIGNAL   out_valid   : OUT STD_LOGIC);
                                     
      -- Generate frame control
      PROCEDURE proc_common_sop(SIGNAL clk     : IN  STD_LOGIC;
                                SIGNAL in_val  : OUT STD_LOGIC;
                                SIGNAL in_sop  : OUT STD_LOGIC);
                                
      PROCEDURE proc_common_eop(SIGNAL clk     : IN  STD_LOGIC;
                                SIGNAL in_val  : OUT STD_LOGIC;
                                SIGNAL in_eop  : OUT STD_LOGIC);
                                
      PROCEDURE proc_common_val(CONSTANT c_val_len : IN NATURAL;
                                SIGNAL   clk       : IN  STD_LOGIC;
                                SIGNAL   in_val    : OUT STD_LOGIC);
                                
      PROCEDURE proc_common_val_duty(CONSTANT c_hi_len  : IN NATURAL;
                                     CONSTANT c_lo_len  : IN NATURAL;
                                     SIGNAL   clk       : IN  STD_LOGIC;
                                     SIGNAL   in_val    : OUT STD_LOGIC);
                                     
      PROCEDURE proc_common_eop_flush(CONSTANT c_flush_len : IN NATURAL;
                                      SIGNAL   clk         : IN  STD_LOGIC;
                                      SIGNAL   in_val      : OUT STD_LOGIC;
                                      SIGNAL   in_eop      : OUT STD_LOGIC);
                                           
      -- Verify the DUT output incrementing data, only support ready latency c_rl = 0 or 1.
      PROCEDURE proc_common_verify_data(CONSTANT c_rl            : IN    NATURAL;
                                        SIGNAL   clk             : IN    STD_LOGIC;
                                        SIGNAL   verify_en       : IN    STD_LOGIC;
                                        SIGNAL   ready           : IN    STD_LOGIC;
                                        SIGNAL   out_valid       : IN    STD_LOGIC;
                                        SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
                                        SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
                                        
      -- Verify the DUT output valid for ready latency, only support ready latency c_rl = 0 or 1.
      PROCEDURE proc_common_verify_valid(CONSTANT c_rl        : IN    NATURAL;
                                         SIGNAL   clk         : IN    STD_LOGIC;
                                         SIGNAL   verify_en   : IN    STD_LOGIC;
                                         SIGNAL   ready       : IN    STD_LOGIC;
                                         SIGNAL   prev_ready  : INOUT STD_LOGIC;
                                         SIGNAL   out_valid   : IN    STD_LOGIC);
                                         
      -- Verify the DUT input to output latency for SL ctrl signals
      PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "valid", "sop", "eop"
                                           CONSTANT c_latency     : IN    NATURAL;
                                           SIGNAL   clk           : IN    STD_LOGIC;
                                           SIGNAL   verify_en     : IN    STD_LOGIC;
                                           SIGNAL   in_ctrl       : IN    STD_LOGIC;
                                           SIGNAL   pipe_ctrl_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:c_latency]
                                           SIGNAL   out_ctrl      : IN    STD_LOGIC);
                                           
      -- Verify the DUT input to output latency for SLV data signals
      PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "data"
                                           CONSTANT c_latency     : IN    NATURAL;
                                           SIGNAL   clk           : IN    STD_LOGIC;
                                           SIGNAL   verify_en     : IN    STD_LOGIC;
                                           SIGNAL   in_data       : IN    STD_LOGIC_VECTOR;
                                           SIGNAL   pipe_data_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:(1 + c_latency)*c_data_w-1]
                                           SIGNAL   out_data      : IN    STD_LOGIC_VECTOR);
                                           
      -- Verify the expected value, e.g. to check that a test has ran at all
      PROCEDURE proc_common_verify_value(CONSTANT mode : IN NATURAL;
                                         SIGNAL   clk  : IN STD_LOGIC;
                                         SIGNAL   en   : IN STD_LOGIC;
                                         SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
                                         SIGNAL   res  : IN STD_LOGIC_VECTOR);
      -- open, read line, close file
      PROCEDURE proc_common_open_file(file_status  : INOUT FILE_OPEN_STATUS;
                                      FILE in_file : TEXT; 
                                      file_name    : IN STRING;
                                      file_mode    : IN FILE_OPEN_KIND);
      
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_value_0 : OUT INTEGER);
      
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_value_0 : OUT INTEGER;
                                          read_value_1 : OUT INTEGER);
      
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          value_array  : OUT t_integer_arr;
                                          nof_reads    : IN  INTEGER);
                                      
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_slv     : OUT STD_LOGIC_VECTOR);
                                      
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;                  
                                          res_string   : OUT STRING);
      
      PROCEDURE proc_common_close_file(file_status  : INOUT FILE_OPEN_STATUS;
                                       FILE in_file : TEXT);
    
      -- read entire file
      PROCEDURE proc_common_read_integer_file(file_name              : IN  STRING;
                                              nof_header_lines       : NATURAL;
                                              nof_row                : NATURAL;
                                              nof_col                : NATURAL;
                                              SIGNAL return_array    : OUT t_integer_arr);
                                      
      PROCEDURE proc_common_read_mif_file(file_name           : IN  STRING;
                                          SIGNAL return_array : OUT t_integer_arr);
      
      -- Complex multiply function with conjugate option for input b
      FUNCTION func_complex_multiply(in_ar, in_ai, in_br, in_bi : STD_LOGIC_VECTOR; conjugate_b : BOOLEAN; str : STRING; g_out_dat_w : NATURAL) RETURN STD_LOGIC_VECTOR;
      
      FUNCTION func_decstring_to_integer(in_string: STRING) RETURN INTEGER;     
      
      FUNCTION func_hexstring_to_integer(in_string: STRING) RETURN INTEGER;     
      
      FUNCTION func_find_char_in_string(in_string: STRING; find_char: CHARACTER) RETURN INTEGER;
      
      FUNCTION func_find_string_in_string(in_string: STRING; find_string: STRING) RETURN BOOLEAN;
      
    END tb_common_pkg;
    
    
    PACKAGE BODY tb_common_pkg IS
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Wait some clock cycles
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  NATURAL) IS
      BEGIN
        FOR I IN 0 TO c_nof_cycles-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
      END proc_common_wait_some_cycles;
      
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  REAL) IS
      BEGIN
        proc_common_wait_some_cycles(clk, NATURAL(c_nof_cycles));
      END proc_common_wait_some_cycles;
      
      PROCEDURE proc_common_wait_some_cycles(SIGNAL clk_in       : IN  STD_LOGIC;
                                             SIGNAL clk_out      : IN  STD_LOGIC;
                                                    c_nof_cycles : IN  NATURAL) IS
      BEGIN
        proc_common_wait_some_cycles(clk_in, c_nof_cycles);
        proc_common_wait_some_cycles(clk_out, c_nof_cycles);
      END proc_common_wait_some_cycles;
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Wait some pulses
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_wait_some_pulses(SIGNAL clk          : IN  STD_LOGIC;
                                             SIGNAL pulse        : IN  STD_LOGIC;
                                                    c_nof_pulses : IN  NATURAL) IS
      BEGIN
        FOR I IN 0 TO c_nof_pulses-1 LOOP
          proc_common_wait_until_hi_lo(clk, pulse);
        END LOOP;
      END proc_common_wait_some_pulses;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Wait until the level input event
      -- PROCEDURE: Wait until the level input is high
      -- PROCEDURE: Wait until the level input is low
      -- PROCEDURE: Wait until the       input is equal to c_value
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  STD_LOGIC) IS
        VARIABLE v_level : STD_LOGIC := level;
      BEGIN
        WAIT UNTIL rising_edge(clk);
        WHILE v_level=level LOOP
          v_level := level;
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END proc_common_wait_until_evt;
      
      PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  INTEGER) IS
        VARIABLE v_level : INTEGER := level;
      BEGIN
        WAIT UNTIL rising_edge(clk);
        WHILE v_level=level LOOP
          v_level := level;
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END proc_common_wait_until_evt;
      
      PROCEDURE proc_common_wait_until_evt(CONSTANT c_timeout : IN  NATURAL;
                                           SIGNAL   clk       : IN  STD_LOGIC;
                                           SIGNAL   level     : IN  STD_LOGIC) IS
        VARIABLE v_level : STD_LOGIC := level;
        VARIABLE v_I     : NATURAL := 0;
      BEGIN
        WAIT UNTIL rising_edge(clk);
        WHILE v_level=level LOOP
          v_level := level;
          WAIT UNTIL rising_edge(clk);
          v_I := v_I + 1;
          IF v_I>=c_timeout-1 THEN
            REPORT "COMMON : level evt timeout" SEVERITY ERROR;
            EXIT;
          END IF;
        END LOOP;
      END proc_common_wait_until_evt;
      
      PROCEDURE proc_common_wait_until_high(SIGNAL clk    : IN  STD_LOGIC;
                                            SIGNAL level  : IN  STD_LOGIC) IS
      BEGIN
        IF level/='1' THEN
          WAIT UNTIL rising_edge(clk) AND level='1';
        END IF;
      END proc_common_wait_until_high;
      
      PROCEDURE proc_common_wait_until_high(CONSTANT c_timeout : IN  NATURAL;
                                            SIGNAL   clk       : IN  STD_LOGIC;
                                            SIGNAL   level     : IN  STD_LOGIC) IS
      BEGIN
        FOR I IN 0 TO c_timeout-1 LOOP
          IF level='1' THEN
            EXIT;
          ELSE
            IF I=c_timeout-1 THEN
              REPORT "COMMON : level high timeout" SEVERITY ERROR;
            END IF;
            WAIT UNTIL rising_edge(clk);
          END IF;
        END LOOP;
      END proc_common_wait_until_high;
      
      PROCEDURE proc_common_wait_until_low(SIGNAL clk    : IN  STD_LOGIC;
                                           SIGNAL level  : IN  STD_LOGIC) IS
      BEGIN
        IF level/='0' THEN
          WAIT UNTIL rising_edge(clk) AND level='0';
        END IF;
      END proc_common_wait_until_low;
      
      PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN  NATURAL;
                                           SIGNAL   clk       : IN  STD_LOGIC;
                                           SIGNAL   level     : IN  STD_LOGIC) IS
      BEGIN
        FOR I IN 0 TO c_timeout-1 LOOP
          IF level='0' THEN
            EXIT;
          ELSE
            IF I=c_timeout-1 THEN
              REPORT "COMMON : level low timeout" SEVERITY ERROR;
            END IF;
            WAIT UNTIL rising_edge(clk);
          END IF;
        END LOOP;
      END proc_common_wait_until_low;
      
      PROCEDURE proc_common_wait_until_hi_lo(SIGNAL clk    : IN  STD_LOGIC;
                                             SIGNAL level  : IN  STD_LOGIC) IS
      BEGIN
        IF level/='1' THEN
          proc_common_wait_until_high(clk, level);
        END IF;
        proc_common_wait_until_low(clk, level);
      END proc_common_wait_until_hi_lo;
      
      PROCEDURE proc_common_wait_until_hi_lo(CONSTANT c_timeout : IN  NATURAL;
                                             SIGNAL   clk       : IN  STD_LOGIC;
                                             SIGNAL   level     : IN  STD_LOGIC) IS
      BEGIN
        IF level/='1' THEN
          proc_common_wait_until_high(c_timeout, clk, level);
        END IF;
        proc_common_wait_until_low(c_timeout, clk, level);
      END proc_common_wait_until_hi_lo;
      
      PROCEDURE proc_common_wait_until_lo_hi(SIGNAL clk    : IN  STD_LOGIC;
                                             SIGNAL level  : IN  STD_LOGIC) IS
      BEGIN
        IF level/='0' THEN
          proc_common_wait_until_low(clk, level);
        END IF;
        proc_common_wait_until_high(clk, level);
      END proc_common_wait_until_lo_hi;
      
      PROCEDURE proc_common_wait_until_lo_hi(CONSTANT c_timeout : IN  NATURAL;
                                             SIGNAL   clk       : IN  STD_LOGIC;
                                             SIGNAL   level     : IN  STD_LOGIC) IS
      BEGIN
        IF level/='0' THEN
          proc_common_wait_until_low(c_timeout, clk, level);
        END IF;
        proc_common_wait_until_high(c_timeout, clk, level);
      END proc_common_wait_until_lo_hi;
      
      PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
                                             SIGNAL clk       : IN  STD_LOGIC;
                                             SIGNAL level     : IN  INTEGER) IS
      BEGIN
        WHILE level/=c_value LOOP
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END proc_common_wait_until_value;
      
      PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
                                             SIGNAL clk       : IN  STD_LOGIC;
                                             SIGNAL level     : IN  STD_LOGIC_VECTOR) IS
      BEGIN
        WHILE SIGNED(level)/=c_value LOOP
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END proc_common_wait_until_value;
      
      PROCEDURE proc_common_wait_until_value(CONSTANT c_timeout : IN  NATURAL;
                                             CONSTANT c_value   : IN  INTEGER;
                                             SIGNAL clk         : IN  STD_LOGIC;
                                             SIGNAL level       : IN  STD_LOGIC_VECTOR) IS
      BEGIN
        FOR I IN 0 TO c_timeout-1 LOOP
          IF SIGNED(level)=c_value THEN
            EXIT;
          ELSE
            IF I=c_timeout-1 THEN
              REPORT "COMMON : level value timeout" SEVERITY ERROR;
            END IF;
            WAIT UNTIL rising_edge(clk);
          END IF;
        END LOOP;
      END proc_common_wait_until_value;
      
      PROCEDURE proc_common_wait_until_time(SIGNAL clk      : IN  STD_LOGIC;
                                            CONSTANT c_time : IN  TIME) IS
      BEGIN
        WHILE NOW < c_time LOOP
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END PROCEDURE;                                        
     
      PROCEDURE proc_common_timeout_failure(CONSTANT c_timeout : IN TIME;
                                            SIGNAL tb_end      : IN STD_LOGIC) IS
      BEGIN
        WHILE tb_end='0' LOOP
          ASSERT NOW < c_timeout REPORT "Test bench timeout." SEVERITY FAILURE;
          WAIT FOR 1 us;
        END LOOP;
      END PROCEDURE;
    
      PROCEDURE proc_common_stop_simulation(SIGNAL tb_end : IN STD_LOGIC) IS
      BEGIN
        WAIT UNTIL tb_end='1';
        -- For modelsim_regression_test_vhdl.py:
        -- The tb_end will stop the test verification bases on error or failure. The wait is necessary to
        -- stop the simulation using failure, without causing the test to fail.
        WAIT FOR 1 ns;
        REPORT "Tb simulation finished." SEVERITY FAILURE;
        WAIT;
      END PROCEDURE;
      
      PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
                                            CONSTANT g_latency : IN NATURAL;
                                            SIGNAL clk         : IN STD_LOGIC;
                                            SIGNAL tb_done     : IN STD_LOGIC;
                                            SIGNAL tb_end      : OUT STD_LOGIC) IS
      BEGIN
        -- Wait until simulation indicates done
        proc_common_wait_until_high(clk, tb_done);
        
        -- Wait some more cycles
        proc_common_wait_some_cycles(clk, g_latency);
        
        -- Stop the simulation or only report NOTE
        tb_end <= '1';
        -- For modelsim_regression_test_vhdl.py:
        -- The tb_end will stop the test verification bases on error or failure. The wait is necessary to
        -- stop the simulation using failure, without causing the test to fail.
        WAIT FOR 1 ns;
        IF g_tb_end=FALSE THEN
          REPORT "Tb Simulation finished." SEVERITY NOTE;
        ELSE
          REPORT "Tb Simulation finished." SEVERITY FAILURE;
        END IF;
        WAIT;
      END PROCEDURE;
    
      PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
                                            SIGNAL clk         : IN STD_LOGIC;
                                            SIGNAL tb_done     : IN STD_LOGIC;
                                            SIGNAL tb_end      : OUT STD_LOGIC) IS
      BEGIN
        proc_common_stop_simulation(g_tb_end, 0, clk, tb_done, tb_end);
      END PROCEDURE;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Handle stream ready signal for data valid
      -- . output active when ready='1' and enable='1'
      -- . only support ready latency c_rl = 0 or 1
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_ready_latency(CONSTANT c_rl      : IN  NATURAL;
                                          SIGNAL   clk       : IN  STD_LOGIC;
                                          SIGNAL   enable    : IN  STD_LOGIC;
                                          SIGNAL   ready     : IN  STD_LOGIC;
                                          SIGNAL   out_valid : OUT STD_LOGIC) IS
      BEGIN
        -- skip ready cycles until enable='1'
        out_valid <= '0';
        WHILE enable='0' LOOP
          IF c_rl=0 THEN
            WAIT UNTIL rising_edge(clk);
            WHILE ready /= '1' LOOP
              WAIT UNTIL rising_edge(clk);
            END LOOP;
          END IF;
          IF c_rl=1 THEN
            WHILE ready /= '1' LOOP
              WAIT UNTIL rising_edge(clk);
            END LOOP;
            WAIT UNTIL rising_edge(clk);
          END IF;
        END LOOP;
        -- active output when ready
        IF c_rl=0 THEN
          out_valid <= '1';
          WAIT UNTIL rising_edge(clk);
          WHILE ready /= '1' LOOP
            WAIT UNTIL rising_edge(clk);
          END LOOP;
        END IF;
        IF c_rl=1 THEN
          WHILE ready /= '1' LOOP
            out_valid <= '0';
            WAIT UNTIL rising_edge(clk);
          END LOOP;
          out_valid <= '1';
          WAIT UNTIL rising_edge(clk);
        END IF;
      END proc_common_ready_latency;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Generate a single active, inactive pulse
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_gen_pulse(CONSTANT c_active  : IN  NATURAL;    -- pulse active for nof clk
                                      CONSTANT c_period  : IN  NATURAL;    -- pulse period for nof clk
                                      CONSTANT c_level   : IN  STD_LOGIC;  -- pulse level when active
                                      SIGNAL   clk       : IN  STD_LOGIC;
                                      SIGNAL   pulse     : OUT STD_LOGIC) IS
        VARIABLE v_cnt : NATURAL RANGE 0 TO c_period := 0;
      BEGIN
        WHILE v_cnt<c_period LOOP
          IF v_cnt<c_active THEN
            pulse <= c_level;
          ELSE
            pulse <= NOT c_level;    
          END IF;
          v_cnt := v_cnt+1;
          WAIT UNTIL rising_edge(clk);
        END LOOP;
      END proc_common_gen_pulse;
      
      -- Pulse forever after rst was released
      PROCEDURE proc_common_gen_pulse(CONSTANT c_active  : IN  NATURAL;    -- pulse active for nof clk
                                      CONSTANT c_period  : IN  NATURAL;    -- pulse period for nof clk
                                      CONSTANT c_level   : IN  STD_LOGIC;  -- pulse level when active
                                      SIGNAL   rst       : IN  STD_LOGIC;
                                      SIGNAL   clk       : IN  STD_LOGIC;
                                      SIGNAL   pulse     : OUT STD_LOGIC) IS
        VARIABLE v_cnt : NATURAL RANGE 0 TO c_period := 0;
      BEGIN
        pulse <= NOT c_level;
        IF rst='0' THEN
          WAIT UNTIL rising_edge(clk);
          WHILE TRUE LOOP
            proc_common_gen_pulse(c_active, c_period, c_level, clk, pulse);
          END LOOP;
        END IF;
      END proc_common_gen_pulse;
      
      -- pulse '1', '0'
      PROCEDURE proc_common_gen_pulse(SIGNAL clk   : IN  STD_LOGIC;
                                      SIGNAL pulse : OUT STD_LOGIC) IS
      BEGIN
        proc_common_gen_pulse(1, 2, '1', clk, pulse);
      END proc_common_gen_pulse;
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Generate a periodic pulse with arbitrary duty cycle
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_delay     : IN  NATURAL;    -- delay pulse for nof_clk after enable
                                           CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
                                           CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
                                           CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
                                           SIGNAL   rst         : IN  STD_LOGIC;
                                           SIGNAL   clk         : IN  STD_LOGIC;
                                           SIGNAL   enable      : IN  STD_LOGIC;
                                           SIGNAL   pulse       : OUT STD_LOGIC) IS
        VARIABLE v_cnt : NATURAL RANGE 0 TO c_period-1 := 0;
      BEGIN
        pulse <= NOT c_level;
        IF rst='0' THEN
          proc_common_wait_until_high(clk, enable);    -- if enabled then continue immediately else wait here
          proc_common_wait_some_cycles(clk, c_delay);  -- apply initial c_delay. Once enabled, the pulse remains enabled
          WHILE TRUE LOOP
            WAIT UNTIL rising_edge(clk);
            IF v_cnt<c_active THEN
              pulse <= c_level;
            ELSE
              pulse <= NOT c_level;    
            END IF;
            IF v_cnt<c_period-1 THEN
              v_cnt := v_cnt+1;
            ELSE
              v_cnt := 0;
            END IF;
          END LOOP;
        END IF;
      END proc_common_gen_duty_pulse;
      
      PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
                                           CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
                                           CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
                                           SIGNAL   rst         : IN  STD_LOGIC;
                                           SIGNAL   clk         : IN  STD_LOGIC;
                                           SIGNAL   enable      : IN  STD_LOGIC;
                                           SIGNAL   pulse       : OUT STD_LOGIC) IS
      BEGIN
        proc_common_gen_duty_pulse(0, c_active, c_period, c_level, rst, clk, enable, pulse);
      END proc_common_gen_duty_pulse;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Generate counter data with valid
      -- . Output counter data dependent on enable and ready
      ------------------------------------------------------------------------------
      -- arbitrary c_incr
      PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
                                     CONSTANT c_init      : IN  INTEGER;
                                     CONSTANT c_incr      : IN  INTEGER;
                                     SIGNAL   rst         : IN  STD_LOGIC;
                                     SIGNAL   clk         : IN  STD_LOGIC;
                                     SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
                                     SIGNAL   ready       : IN  STD_LOGIC;
                                     SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
                                     SIGNAL   out_valid   : OUT STD_LOGIC) IS
        CONSTANT c_data_w  : NATURAL := out_data'LENGTH;
        VARIABLE v_data    : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_SVEC(c_init, c_data_w);
      BEGIN
        out_valid <= '0';
        out_data  <= v_data;
        IF rst='0' THEN
          WAIT UNTIL rising_edge(clk);
          WHILE TRUE LOOP
            out_data <= v_data;
            proc_common_ready_latency(c_rl, clk, enable, ready, out_valid);
            v_data := INCR_UVEC(v_data, c_incr);
          END LOOP;
        END IF;
      END proc_common_gen_data;
      
      -- c_incr = 1
      PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
                                     CONSTANT c_init      : IN  INTEGER;
                                     SIGNAL   rst         : IN  STD_LOGIC;
                                     SIGNAL   clk         : IN  STD_LOGIC;
                                     SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
                                     SIGNAL   ready       : IN  STD_LOGIC;
                                     SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
                                     SIGNAL   out_valid   : OUT STD_LOGIC) IS
      BEGIN
        proc_common_gen_data(c_rl, c_init, 1, rst, clk, enable, ready, out_data, out_valid);
      END proc_common_gen_data;
      
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Generate frame control
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_sop(SIGNAL clk     : IN  STD_LOGIC;
                                SIGNAL in_val  : OUT STD_LOGIC;
                                SIGNAL in_sop  : OUT STD_LOGIC) IS
      BEGIN
        in_val <= '1';
        in_sop <= '1';
        proc_common_wait_some_cycles(clk, 1);
        in_sop <= '0';
      END proc_common_sop;
        
      PROCEDURE proc_common_eop(SIGNAL clk     : IN  STD_LOGIC;
                                SIGNAL in_val  : OUT STD_LOGIC;
                                SIGNAL in_eop  : OUT STD_LOGIC) IS
      BEGIN
        in_val <= '1';
        in_eop <= '1';
        proc_common_wait_some_cycles(clk, 1);
        in_val <= '0';
        in_eop <= '0';
      END proc_common_eop;
      
      PROCEDURE proc_common_val(CONSTANT c_val_len : IN NATURAL;
                                SIGNAL   clk       : IN  STD_LOGIC;
                                SIGNAL   in_val    : OUT STD_LOGIC) IS
      BEGIN
        in_val <= '1';
        proc_common_wait_some_cycles(clk, c_val_len);
        in_val <= '0';
      END proc_common_val;
      
      PROCEDURE proc_common_val_duty(CONSTANT c_hi_len  : IN NATURAL;
                                     CONSTANT c_lo_len  : IN NATURAL;
                                     SIGNAL   clk       : IN  STD_LOGIC;
                                     SIGNAL   in_val    : OUT STD_LOGIC) IS
      BEGIN
        in_val <= '1';
        proc_common_wait_some_cycles(clk, c_hi_len);
        in_val <= '0';
        proc_common_wait_some_cycles(clk, c_lo_len);
      END proc_common_val_duty;
      
      PROCEDURE proc_common_eop_flush(CONSTANT c_flush_len : IN NATURAL;
                                      SIGNAL   clk         : IN  STD_LOGIC;
                                      SIGNAL   in_val      : OUT STD_LOGIC;
                                      SIGNAL   in_eop      : OUT STD_LOGIC) IS
      BEGIN
        -- . eop
        proc_common_eop(clk, in_val, in_eop);
        -- . flush after in_eop to empty the shift register
        proc_common_wait_some_cycles(clk, c_flush_len);
      END proc_common_eop_flush;
      
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Verify incrementing data
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_verify_data(CONSTANT c_rl            : IN    NATURAL;
                                        SIGNAL   clk             : IN    STD_LOGIC;
                                        SIGNAL   verify_en       : IN    STD_LOGIC;
                                        SIGNAL   ready           : IN    STD_LOGIC;
                                        SIGNAL   out_valid       : IN    STD_LOGIC;
                                        SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
                                        SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
        VARIABLE v_exp_data : STD_LOGIC_VECTOR(out_data'RANGE);
      BEGIN
        IF rising_edge(clk) THEN
          -- out_valid must be active, because only the out_data will it differ from the previous out_data
          IF out_valid='1' THEN
            -- for ready_latency = 1 out_valid indicates new data
            -- for ready_latency = 0 out_valid only indicates new data when it is confirmed by ready
            IF c_rl=1 OR (c_rl=0 AND ready='1') THEN
              prev_out_data <= out_data;
              v_exp_data := INCR_UVEC(prev_out_data, 1);  -- increment first then compare to also support increment wrap around
              IF verify_en='1' AND UNSIGNED(out_data) /= UNSIGNED(v_exp_data) THEN
                REPORT "COMMON : Wrong out_data count" SEVERITY ERROR;
              END IF;
            END IF;
          END IF;
        END IF;
      END proc_common_verify_data;
      
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Verify the DUT output valid
      -- . only support ready latency c_rl = 0 or 1
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_verify_valid(CONSTANT c_rl        : IN    NATURAL;
                                         SIGNAL   clk         : IN    STD_LOGIC;
                                         SIGNAL   verify_en   : IN    STD_LOGIC;
                                         SIGNAL   ready       : IN    STD_LOGIC;
                                         SIGNAL   prev_ready  : INOUT STD_LOGIC;
                                         SIGNAL   out_valid   : IN    STD_LOGIC) IS
      BEGIN
        IF rising_edge(clk) THEN
          -- for ready latency c_rl = 1 out_valid may only be asserted after ready
          -- for ready latency c_rl = 0 out_valid may always be asserted
          prev_ready <= '0';
          IF c_rl=1 THEN
            prev_ready <= ready;
            IF verify_en='1' AND out_valid='1' THEN
              IF prev_ready/='1' THEN
                REPORT "COMMON : Wrong ready latency between ready and out_valid" SEVERITY ERROR;
              END IF;
            END IF;
          END IF;
        END IF;
      END proc_common_verify_valid;
      
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Verify the DUT input to output latency
      ------------------------------------------------------------------------------
      -- for SL ctrl
      PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "valid", "sop", "eop"
                                           CONSTANT c_latency     : IN    NATURAL;
                                           SIGNAL   clk           : IN    STD_LOGIC;
                                           SIGNAL   verify_en     : IN    STD_LOGIC;
                                           SIGNAL   in_ctrl       : IN    STD_LOGIC;
                                           SIGNAL   pipe_ctrl_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:c_latency]
                                           SIGNAL   out_ctrl      : IN    STD_LOGIC) IS
      BEGIN
        IF rising_edge(clk) THEN
          pipe_ctrl_vec <= in_ctrl & pipe_ctrl_vec(0 TO c_latency-1);  -- note: pipe_ctrl_vec(c_latency) is a dummy place holder to avoid [0:-1] range
          IF verify_en='1' THEN
            IF c_latency=0 THEN
              IF in_ctrl/=out_ctrl THEN
                REPORT "COMMON : Wrong zero latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
              END IF;
            ELSE
              IF pipe_ctrl_vec(c_latency-1)/=out_ctrl THEN
                REPORT "COMMON : Wrong latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
              END IF;
            END IF;
          END IF;
        END IF;
      END proc_common_verify_latency;
      
      
      -- for SLV data
      PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "data"
                                           CONSTANT c_latency     : IN    NATURAL;
                                           SIGNAL   clk           : IN    STD_LOGIC;
                                           SIGNAL   verify_en     : IN    STD_LOGIC;
                                           SIGNAL   in_data       : IN    STD_LOGIC_VECTOR;
                                           SIGNAL   pipe_data_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:(1 + c_latency)*c_data_w-1]
                                           SIGNAL   out_data      : IN    STD_LOGIC_VECTOR) IS
        CONSTANT c_data_w     : NATURAL := in_data'LENGTH;
        CONSTANT c_data_vec_w : NATURAL := pipe_data_vec'LENGTH;  -- = (1 + c_latency) * c_data_w
      BEGIN
        IF rising_edge(clk) THEN
          pipe_data_vec <= in_data & pipe_data_vec(0 TO c_data_vec_w-c_data_w-1);  -- note: pipe_data_vec(c_latency) is a dummy place holder to avoid [0:-1] range
          IF verify_en='1' THEN
            IF c_latency=0 THEN
              IF UNSIGNED(in_data)/=UNSIGNED(out_data) THEN
                REPORT "COMMON : Wrong zero latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
              END IF;
            ELSE
              IF UNSIGNED(pipe_data_vec(c_data_vec_w-c_data_w-c_data_w TO c_data_vec_w-c_data_w-1))/=UNSIGNED(out_data) THEN
                REPORT "COMMON : Wrong latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
              END IF;
            END IF;
          END IF;
        END IF;
      END proc_common_verify_latency;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Verify the expected value
      -- . e.g. to check that a test has ran at all
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_verify_value(CONSTANT mode : IN NATURAL;
                                         SIGNAL   clk  : IN STD_LOGIC;
                                         SIGNAL   en   : IN STD_LOGIC;
                                         SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
                                         SIGNAL   res  : IN STD_LOGIC_VECTOR) IS
      BEGIN
        IF rising_edge(clk) THEN
          IF en='1' THEN
            IF mode = 0 AND UNSIGNED(res) /= UNSIGNED(exp) THEN
              REPORT "COMMON : Wrong result value" SEVERITY ERROR;             -- == (equal)
            END IF;
            IF mode = 1 AND UNSIGNED(res) < UNSIGNED(exp) THEN
              REPORT "COMMON : Wrong result value too small" SEVERITY ERROR;   -- >= (at least)
            END IF;
          END IF;
        END IF;
      END proc_common_verify_value;
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Opens a file for access and reports fail or success of opening. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_open_file( file_status  : INOUT FILE_OPEN_STATUS;
                                       FILE in_file : TEXT; 
                                       file_name    : IN    STRING;
                                       file_mode    : IN    FILE_OPEN_KIND) IS
      BEGIN
        IF file_status=OPEN_OK THEN
          file_close(in_file);
        END IF;
        file_open (file_status, in_file, file_name, file_mode);
        IF file_status=OPEN_OK THEN
          REPORT "COMMON : File opened " SEVERITY NOTE;
        ELSE
          REPORT "COMMON : Unable to open file " SEVERITY FAILURE;
        END IF;
      END proc_common_open_file;
    
     ------------------------------------------------------------------------------
      -- PROCEDURE: Reads an integer from a file. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_value_0 : OUT INTEGER) IS
         VARIABLE v_line : LINE;    
         VARIABLE v_good : BOOLEAN; 
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File is not opened " SEVERITY FAILURE;
        ELSE
          IF ENDFILE(in_file) THEN
            REPORT "COMMON : end of file " SEVERITY NOTE;
          ELSE
            READLINE(in_file, v_line);
            READ(v_line, read_value_0, v_good);         
            IF v_good = FALSE THEN 
              REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
            END IF;
          END IF;
        END IF;
      END proc_common_readline_file;
     
      ------------------------------------------------------------------------------
      -- PROCEDURE: Reads two integers from two columns in a file. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_value_0 : OUT INTEGER;  
                                          read_value_1 : OUT INTEGER) IS 
         VARIABLE v_line : LINE;    
         VARIABLE v_good : BOOLEAN; 
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File is not opened " SEVERITY FAILURE;
        ELSE
          IF ENDFILE(in_file) THEN
            REPORT "COMMON : end of file " SEVERITY NOTE;
          ELSE
            READLINE(in_file, v_line);
            READ(v_line, read_value_0, v_good);         
            IF v_good = FALSE THEN 
              REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
            END IF;
            READ(v_line, read_value_1, v_good);         
            IF v_good = FALSE THEN 
              REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
            END IF;
          END IF;
        END IF;
      END proc_common_readline_file;
    
    ------------------------------------------------------------------------------
      -- PROCEDURE: Reads an array of integer from a file. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          value_array  : OUT t_integer_arr;  
                                          nof_reads    : IN  INTEGER) IS 
         VARIABLE v_line : LINE;    
         VARIABLE v_good : BOOLEAN; 
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File is not opened " SEVERITY FAILURE;
        ELSE
          IF ENDFILE(in_file) THEN
            REPORT "COMMON : end of file " SEVERITY NOTE;
          ELSE
            READLINE(in_file, v_line);
            FOR I IN 0 TO nof_reads - 1 LOOP 
              READ(v_line, value_array(I), v_good);         
              IF v_good = FALSE THEN 
                REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
              END IF;
            END LOOP;
          END IF;
        END IF;
      END proc_common_readline_file;
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Reads an std_logic_vector from a file
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;
                                          read_slv     : OUT STD_LOGIC_VECTOR) IS
         VARIABLE v_line : LINE;    
         VARIABLE v_good : BOOLEAN; 
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File is not opened " SEVERITY FAILURE;
        ELSE
          IF ENDFILE(in_file) THEN
            REPORT "COMMON : end of file " SEVERITY NOTE;
          ELSE
            READLINE(in_file, v_line);
            READ(v_line, read_slv, v_good);         
            IF v_good = FALSE THEN 
              REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
            END IF;
          END IF;
        END IF;
      END proc_common_readline_file;
     
      ------------------------------------------------------------------------------
      -- PROCEDURE: Reads a string of any length from a file pointer. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
                                          FILE in_file : TEXT;                  
                                          res_string   : OUT STRING) IS
        VARIABLE v_line    : LINE;
        VARIABLE v_char    : CHARACTER;
        VARIABLE is_string : BOOLEAN;
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File is not opened " SEVERITY FAILURE;
        ELSE
          IF ENDFILE(in_file) THEN
            REPORT "COMMON : end of file " SEVERITY NOTE;
          ELSE
            readline(in_file, v_line);
            -- clear the contents of the result string
            FOR I IN res_string'RANGE LOOP
                res_string(I) := ' ';
            END LOOP;   
            -- read all characters of the line, up to the length  
            -- of the results string
            FOR I IN res_string'RANGE LOOP
               read(v_line, v_char, is_string);
               IF NOT is_string THEN -- found end of line
                  EXIT;
               END IF;   
               res_string(I) := v_char;
            END LOOP; 
          END IF;
        END IF;
      END proc_common_readline_file;
      
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Closes a file. 
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_close_file(file_status  : INOUT FILE_OPEN_STATUS;
                                       FILE in_file : TEXT) IS
      BEGIN
        IF file_status/=OPEN_OK THEN
          REPORT "COMMON : File was not opened " SEVERITY WARNING;
        END IF;
        FILE_CLOSE(in_file);
        REPORT "COMMON : File closed " SEVERITY NOTE;
      END proc_common_close_file;     
      
      ------------------------------------------------------------------------------
      -- PROCEDURE: Reads the integer data from nof_rows with nof_col values per
      --            row from a file and returns it row by row in an array of
      --            integers.
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_read_integer_file(file_name              : IN  STRING;
                                              nof_header_lines       : NATURAL;
                                              nof_row                : NATURAL;
                                              nof_col                : NATURAL;
                                              SIGNAL return_array    : OUT t_integer_arr) IS
        VARIABLE v_file_status : FILE_OPEN_STATUS;                                  
        FILE     v_in_file     : TEXT;  
        VARIABLE v_input_line  : LINE;   
        VARIABLE v_string      : STRING(1 TO 80);
        VARIABLE v_row_arr     : t_integer_arr(0 TO nof_col-1);
      BEGIN
        IF file_name/="UNUSED" AND file_name/="unused" THEN
          -- Open the file for reading
          proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); 
          -- Read and skip the header
          FOR J IN 0 TO nof_header_lines-1  LOOP
            proc_common_readline_file(v_file_status, v_in_file, v_string); 
          END LOOP;
          FOR J IN 0 TO nof_row-1  LOOP
            proc_common_readline_file(v_file_status, v_in_file, v_row_arr, nof_col);
            FOR I IN 0 TO nof_col-1 LOOP
              return_array(J*nof_col + I) <= v_row_arr(I);  -- use loop to be independent of t_integer_arr downto or to range
            END LOOP;
            IF ENDFILE(v_in_file) THEN
              IF J/=nof_row-1 THEN
                REPORT "COMMON : Unexpected end of file" SEVERITY FAILURE;
              END IF;
              EXIT;
            END IF;
          END LOOP;
          -- Close the file 
          proc_common_close_file(v_file_status, v_in_file);
        ELSE
          return_array <= (return_array'RANGE=>0);
        END IF;
      END proc_common_read_integer_file;
    
      ------------------------------------------------------------------------------
      -- PROCEDURE: Reads the data column from a .mif file and returns it in an 
      --            array of integers
      ------------------------------------------------------------------------------
      PROCEDURE proc_common_read_mif_file(        file_name    : IN  STRING;
                                           SIGNAL return_array : OUT t_integer_arr) IS
        VARIABLE v_file_status : FILE_OPEN_STATUS;                                  
        FILE     v_in_file     : TEXT;  
        VARIABLE v_input_line  : LINE;   
        VARIABLE v_string      : STRING(1 TO 80); 
        VARIABLE v_mem_width   : NATURAL := 0;        
        VARIABLE v_mem_depth   : NATURAL := 0; 
        VARIABLE v_up_bound    : NATURAL := 0; 
        VARIABLE v_low_bound   : NATURAL := 0; 
        VARIABLE v_end_header  : BOOLEAN := FALSE;
        VARIABLE v_char        : CHARACTER;
      BEGIN
        -- Open the .mif file for reading
        proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); 
        -- Read the header.
        WHILE NOT v_end_header LOOP
          proc_common_readline_file(v_file_status, v_in_file, v_string); 
          IF(func_find_string_in_string(v_string, "WIDTH=")) THEN                              -- check for "WIDTH=" 
            v_up_bound  := func_find_char_in_string(v_string, ';');
            v_low_bound := func_find_char_in_string(v_string, '=');
            v_mem_width := func_decstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1)); 
          ELSIF(func_find_string_in_string(v_string, "DEPTH=")) THEN                           -- check for "DEPTH=" 
            v_up_bound  := func_find_char_in_string(v_string, ';');
            v_low_bound := func_find_char_in_string(v_string, '=');                      
            v_mem_depth := func_decstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1)); 
          ELSIF(func_find_string_in_string(v_string, "CONTENT BEGIN")) THEN                  
            v_end_header := TRUE; 
          END IF;  
        END LOOP;
        -- Read the data           
        FOR I IN 0 TO v_mem_depth-1  LOOP
          proc_common_readline_file(v_file_status, v_in_file, v_string);                 -- Read the next line from the file. 
          v_low_bound     := func_find_char_in_string(v_string, ':');   -- Find the left position of the string that contains the data field
          v_up_bound      := func_find_char_in_string(v_string, ';');   -- Find the right position of the string that contains the data field           
          return_array(I) <= func_hexstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1));
        END LOOP; 
        -- Close the file 
        proc_common_close_file(v_file_status, v_in_file);             
      END proc_common_read_mif_file;
    
      ------------------------------------------------------------------------------
      -- FUNCTION: Complex multiply with conjugate option for input b
      ------------------------------------------------------------------------------
      FUNCTION func_complex_multiply(in_ar, in_ai, in_br, in_bi : STD_LOGIC_VECTOR; conjugate_b : BOOLEAN; str : STRING; g_out_dat_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
        -- Function: Signed complex multiply
        --   p = a * b       when g_conjugate_b = FALSE
        --     = (ar + j ai) * (br + j bi)
        --     =  ar*br - ai*bi + j ( ar*bi + ai*br)
        --
        --   p = a * conj(b) when g_conjugate_b = TRUE
        --     = (ar + j ai) * (br - j bi)
        --     =  ar*br + ai*bi + j (-ar*bi + ai*br)
        -- From mti_numeric_std.vhd follows:
        -- . SIGNED * --> output width = 2 * input width
        -- . SIGNED + --> output width = largest(input width)
        CONSTANT c_in_w      : NATURAL := in_ar'LENGTH;  -- all input have same width
        CONSTANT c_res_w     : NATURAL := 2*c_in_w+1;    -- *2 for multiply, +1 for sum of two products
        VARIABLE v_ar        : SIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_ai        : SIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_br        : SIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_bi        : SIGNED(c_in_w-1 DOWNTO 0);
        VARIABLE v_result_re : SIGNED(c_res_w-1 DOWNTO 0);
        VARIABLE v_result_im : SIGNED(c_res_w-1 DOWNTO 0);
      BEGIN
        -- Calculate expected result
        v_ar := RESIZE_NUM(SIGNED(in_ar), c_in_w);
        v_ai := RESIZE_NUM(SIGNED(in_ai), c_in_w);
        v_br := RESIZE_NUM(SIGNED(in_br), c_in_w);
        v_bi := RESIZE_NUM(SIGNED(in_bi), c_in_w);
        IF conjugate_b=FALSE THEN
          v_result_re := RESIZE_NUM(v_ar*v_br, c_res_w) - v_ai*v_bi;
          v_result_im := RESIZE_NUM(v_ar*v_bi, c_res_w) + v_ai*v_br;
        ELSE
          v_result_re := RESIZE_NUM(v_ar*v_br, c_res_w) + v_ai*v_bi;
          v_result_im := RESIZE_NUM(v_ai*v_br, c_res_w) - v_ar*v_bi;
        END IF;
        -- Note that for the product needs as many bits as the sum of the input widths. However the
        -- sign bit is then only needed for the case that both inputs have the largest negative
        -- values, only then the MSBits will be "01". For all other inputs the MSbits will always
        -- be "00" for positive numbers or "11" for negative numbers. MSbits "10" can not occur.
        -- For largest negative inputs the complex multiply result becomes:
        --
        --   3b inputs                --> 6b products     --> c_res_w = 7b
        --     -4 *   -4 +   -4 *   -4 =     +16 +     +16 =      +64       -- most negative valued inputs
        --   b100 * b100 + b100 * b100 = b010000 + b010000 = b0100000
        --
        --   --> if g_out_dat_w = 6b then
        --       a) IEEE unsigned resizing skips   the MSbits so b0100000 = +64 becomes b_100000 = -64
        --       b) IEEE signed resizing preserves the MSbit  so b0100000 = +64 becomes b0_00000 = 0
        --       c) detect MSbits = "01" to clip max positive to get                    _b011111 = +63
        -- Option a) seems to map best on the FPGA hardware multiplier IP.
        IF str="RE" THEN
          RETURN STD_LOGIC_VECTOR(RESIZE_NUM(v_result_re, g_out_dat_w));  -- conform option a)
        ELSE
          RETURN STD_LOGIC_VECTOR(RESIZE_NUM(v_result_im, g_out_dat_w));  -- conform option a)
        END IF;
      END;  
      
      ------------------------------------------------------------------------------
      -- FUNCTION: Converts the decimal value represented in a string to an integer value. 
      ------------------------------------------------------------------------------
      FUNCTION func_decstring_to_integer(in_string: STRING) RETURN INTEGER IS
        CONSTANT c_nof_digits : NATURAL := in_string'LENGTH;   -- Define the length of the string
        VARIABLE v_char       : CHARACTER;
        VARIABLE v_weight     : INTEGER := 1; 
        VARIABLE v_return_int : INTEGER := 0;
      BEGIN
        -- Walk through the string character by character. 
        FOR I IN c_nof_digits-1 DOWNTO 0 LOOP         
          v_char := in_string(I+in_string'LOW);
          CASE v_char IS
             WHEN '0' => v_return_int := v_return_int + 0*v_weight;
             WHEN '1' => v_return_int := v_return_int + 1*v_weight;
             WHEN '2' => v_return_int := v_return_int + 2*v_weight;
             WHEN '3' => v_return_int := v_return_int + 3*v_weight;
             WHEN '4' => v_return_int := v_return_int + 4*v_weight;
             WHEN '5' => v_return_int := v_return_int + 5*v_weight;
             WHEN '6' => v_return_int := v_return_int + 6*v_weight;
             WHEN '7' => v_return_int := v_return_int + 7*v_weight;
             WHEN '8' => v_return_int := v_return_int + 8*v_weight;
             WHEN '9' => v_return_int := v_return_int + 9*v_weight;
             WHEN OTHERS => NULL;
          END CASE; 
          IF (v_char /= ' ') THEN      -- Only increment the weight when the character is NOT a spacebar. 
            v_weight := v_weight*10;   -- Addapt the weight for the next decimal digit.
          END IF;
        END LOOP;
        RETURN(v_return_int);
      END FUNCTION func_decstring_to_integer;  
    
      ------------------------------------------------------------------------------
      -- FUNCTION: Converts the hexadecimal value represented in a string to an integer value. 
      ------------------------------------------------------------------------------
      FUNCTION func_hexstring_to_integer(in_string: STRING) RETURN INTEGER IS
        CONSTANT c_nof_digits : NATURAL := in_string'LENGTH;  -- Define the length of the string
        VARIABLE v_char       : CHARACTER;
        VARIABLE v_weight     : INTEGER := 1; 
        VARIABLE v_return_int : INTEGER := 0;
      BEGIN     
        -- Walk through the string character by character. 
        FOR I IN c_nof_digits-1 DOWNTO 0 LOOP
          v_char := in_string(I+in_string'LOW);
          CASE v_char IS
             WHEN '0' => v_return_int := v_return_int + 0*v_weight;
             WHEN '1' => v_return_int := v_return_int + 1*v_weight;
             WHEN '2' => v_return_int := v_return_int + 2*v_weight;
             WHEN '3' => v_return_int := v_return_int + 3*v_weight;
             WHEN '4' => v_return_int := v_return_int + 4*v_weight;
             WHEN '5' => v_return_int := v_return_int + 5*v_weight;
             WHEN '6' => v_return_int := v_return_int + 6*v_weight;
             WHEN '7' => v_return_int := v_return_int + 7*v_weight;
             WHEN '8' => v_return_int := v_return_int + 8*v_weight;
             WHEN '9' => v_return_int := v_return_int + 9*v_weight;
             WHEN 'A' | 'a' => v_return_int := v_return_int + 10*v_weight;
             WHEN 'B' | 'b' => v_return_int := v_return_int + 11*v_weight;
             WHEN 'C' | 'c' => v_return_int := v_return_int + 12*v_weight;
             WHEN 'D' | 'd' => v_return_int := v_return_int + 13*v_weight;
             WHEN 'E' | 'e' => v_return_int := v_return_int + 14*v_weight;
             WHEN 'F' | 'f' => v_return_int := v_return_int + 15*v_weight;
             WHEN OTHERS => NULL;
          END CASE; 
          IF (v_char /= ' ') THEN     -- Only increment the weight when the character is NOT a spacebar. 
            v_weight := v_weight*16;  -- Addapt the weight for the next hexadecimal digit.                   
          END IF; 
        END LOOP;
        RETURN(v_return_int);
      END FUNCTION func_hexstring_to_integer;  
    
      ------------------------------------------------------------------------------
      -- FUNCTION: Finds the first instance of a given character in a string 
      --           and returns its position. 
      ------------------------------------------------------------------------------
      FUNCTION func_find_char_in_string(in_string: STRING; find_char: CHARACTER) RETURN INTEGER IS
        VARIABLE v_char_position : INTEGER := 0;
      BEGIN
        FOR I IN 1 TO in_string'LENGTH LOOP
          IF(in_string(I) = find_char) THEN
            v_char_position := I;
          END IF;
        END LOOP;  
        RETURN(v_char_position); 
      END FUNCTION func_find_char_in_string;
      
      ------------------------------------------------------------------------------
      -- FUNCTION: Checks if a string(find_string) is part of a larger string(in_string).
      --           The result is returned as a BOOLEAN. 
      ------------------------------------------------------------------------------
      FUNCTION func_find_string_in_string(in_string: STRING; find_string: STRING) RETURN BOOLEAN IS
        CONSTANT c_in_length     : NATURAL := in_string'LENGTH;   -- Define the length of the string to search in
        CONSTANT c_find_length   : NATURAL := find_string'LENGTH; -- Define the length of the string to be find
        VARIABLE v_found_it      : BOOLEAN := FALSE;
      BEGIN
        FOR I IN 1 TO c_in_length-c_find_length LOOP
          IF(in_string(I TO (I+c_find_length-1)) = find_string) THEN
            v_found_it := TRUE;
          END IF;
        END LOOP;  
        RETURN(v_found_it); 
      END FUNCTION func_find_string_in_string;
    
    END tb_common_pkg;