OpenCores
URL https://opencores.org/ocsvn/common_pkg/common_pkg/trunk

Subversion Repositories common_pkg

[/] [common_pkg/] [trunk/] [tb_common_pkg.vhd] - Rev 16

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
--
-- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
-- 
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
-- 
--     http://www.apache.org/licenses/LICENSE-2.0
-- 
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
 
-- Author:
-- . 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;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.