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

Subversion Repositories dp_pkg

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /dp_pkg/trunk
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/dp_stream_pkg.vhd
0,0 → 1,1293
--------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
--------------------------------------------------------------------------------
LIBRARY IEEE, common_pkg_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_pkg_lib.common_pkg.ALL;
 
PACKAGE dp_stream_pkg Is
 
------------------------------------------------------------------------------
-- General DP stream record defintion
------------------------------------------------------------------------------
-- Remarks:
-- * Choose smallest maximum SOSI slv lengths that fit all use cases, because unconstrained record fields slv is not allowed
-- * The large SOSI data field width of 256b has some disadvantages:
-- . about 10% extra simulation time and PC memory usage compared to 72b (measured using tb_unb_tse_board)
-- . a 256b number has 64 hex digits in the Wave window which is awkward because of the leading zeros when typically
-- only 32b are used, fortunately integer representation still works OK (except 0 which is shown as blank).
-- However the alternatives are not attractive, because they affect the implementation of the streaming
-- components that use the SOSI record. Alternatives are e.g.:
-- . define an extra long SOSI data field ldata[255:0] in addition to the existing data[71:0] field
-- . use the array of SOSI records to contain wider data, all with the same SOSI control field values
-- . define another similar SOSI record with data[255:0].
-- Therefore define data width as 256b, because the disadvantages are acceptable and the benefit is great, because all
-- streaming components can remain as they are.
-- * Added sync and bsn to SOSI to have timestamp information with the data
-- * Added re and im to SOSI to support complex data for DSP
-- * The sosi fields can be labeled in diffent groups: ctrl, info and data as shown in comment at the t_dp_sosi definition.
-- This grouping is useful for functions that operate on a t_dp_sosi signal.
-- * The info fields are valid at the sop or at the eop, but typically they hold their last active value to avoid unnessary
-- toggling and to ease viewing in the wave window.
CONSTANT c_dp_stream_bsn_w : NATURAL := 64; -- 64 is sufficient to count blocks of data for years
CONSTANT c_dp_stream_data_w : NATURAL := 768; -- 72 is sufficient for max word 8 * 9-bit. 576 supports half rate DDR4 bus data width. The current 768 is enough for wide single clock SLVs (e.g. headers)
CONSTANT c_dp_stream_dsp_data_w : NATURAL := 64; -- 64 is sufficient for DSP data, including complex power accumulates
CONSTANT c_dp_stream_empty_w : NATURAL := 16; -- 8 is sufficient for max 256 symbols per data word, still use 16 bit to be able to count c_dp_stream_data_w in bits
CONSTANT c_dp_stream_channel_w : NATURAL := 32; -- 32 is sufficient for several levels of hierarchy in mapping types of streams on to channels
CONSTANT c_dp_stream_error_w : NATURAL := 32; -- 32 is sufficient for several levels of hierarchy in mapping error numbers, e.g. 32 different one-hot encoded errors, bit [0] = 0 = OK
CONSTANT c_dp_stream_ok : NATURAL := 0; -- SOSI err field OK value
CONSTANT c_dp_stream_err : NATURAL := 1; -- SOSI err field error value /= OK
CONSTANT c_dp_stream_rl : NATURAL := 1; -- SISO default data path stream ready latency RL = 1
TYPE t_dp_siso IS RECORD -- Source In or Sink Out
ready : STD_LOGIC; -- fine cycle based flow control using ready latency RL >= 0
xon : STD_LOGIC; -- coarse typically block based flow control using xon/xoff
END RECORD;
TYPE t_dp_sosi IS RECORD -- Source Out or Sink In
sync : STD_LOGIC; -- ctrl
bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); -- info at sop (block sequence number)
data : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0); -- data
re : STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0); -- data
im : STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0); -- data
valid : STD_LOGIC; -- ctrl
sop : STD_LOGIC; -- ctrl
eop : STD_LOGIC; -- ctrl
empty : STD_LOGIC_VECTOR(c_dp_stream_empty_w-1 DOWNTO 0); -- info at eop
channel : STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0); -- info at sop
err : STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0); -- info at eop (name field 'err' to avoid the 'error' keyword)
END RECORD;
-- Initialise signal declarations with c_dp_stream_rst/rdy to ease the interpretation of slv fields with unused bits
CONSTANT c_dp_siso_rst : t_dp_siso := ('0', '0');
CONSTANT c_dp_siso_x : t_dp_siso := ('X', 'X');
CONSTANT c_dp_siso_hold : t_dp_siso := ('0', '1');
CONSTANT c_dp_siso_rdy : t_dp_siso := ('1', '1');
CONSTANT c_dp_siso_flush : t_dp_siso := ('1', '0');
CONSTANT c_dp_sosi_rst : t_dp_sosi := ('0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'));
CONSTANT c_dp_sosi_x : t_dp_sosi := ('X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), 'X', 'X', 'X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'));
-- Use integers instead of slv for monitoring purposes (integer range limited to 31 bit plus sign bit)
TYPE t_dp_sosi_integer IS RECORD
sync : STD_LOGIC;
bsn : NATURAL;
data : INTEGER;
re : INTEGER;
im : INTEGER;
valid : STD_LOGIC;
sop : STD_LOGIC;
eop : STD_LOGIC;
empty : NATURAL;
channel : NATURAL;
err : NATURAL;
END RECORD;
-- Use unsigned instead of slv for monitoring purposes beyond the integer range of t_dp_sosi_integer
TYPE t_dp_sosi_unsigned IS RECORD
sync : STD_LOGIC;
bsn : UNSIGNED(c_dp_stream_bsn_w-1 DOWNTO 0);
data : UNSIGNED(c_dp_stream_data_w-1 DOWNTO 0);
re : UNSIGNED(c_dp_stream_dsp_data_w-1 DOWNTO 0);
im : UNSIGNED(c_dp_stream_dsp_data_w-1 DOWNTO 0);
valid : STD_LOGIC;
sop : STD_LOGIC;
eop : STD_LOGIC;
empty : UNSIGNED(c_dp_stream_empty_w-1 DOWNTO 0);
channel : UNSIGNED(c_dp_stream_channel_w-1 DOWNTO 0);
err : UNSIGNED(c_dp_stream_error_w-1 DOWNTO 0);
END RECORD;
CONSTANT c_dp_sosi_unsigned_rst : t_dp_sosi_unsigned := ('0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'));
CONSTANT c_dp_sosi_unsigned_ones : t_dp_sosi_unsigned := ('1',
TO_UNSIGNED(1, c_dp_stream_bsn_w),
TO_UNSIGNED(1, c_dp_stream_data_w),
TO_UNSIGNED(1, c_dp_stream_dsp_data_w),
TO_UNSIGNED(1, c_dp_stream_dsp_data_w),
'1', '1', '1',
TO_UNSIGNED(1, c_dp_stream_empty_w),
TO_UNSIGNED(1, c_dp_stream_channel_w),
TO_UNSIGNED(1, c_dp_stream_error_w));
-- Use boolean to define whether a t_dp_siso, t_dp_sosi field is used ('1') or not ('0')
TYPE t_dp_siso_sl IS RECORD
ready : STD_LOGIC;
xon : STD_LOGIC;
END RECORD;
TYPE t_dp_sosi_sl IS RECORD
sync : STD_LOGIC;
bsn : STD_LOGIC;
data : STD_LOGIC;
re : STD_LOGIC;
im : STD_LOGIC;
valid : STD_LOGIC;
sop : STD_LOGIC;
eop : STD_LOGIC;
empty : STD_LOGIC;
channel : STD_LOGIC;
err : STD_LOGIC;
END RECORD;
CONSTANT c_dp_siso_sl_rst : t_dp_siso_sl := ('0', '0');
CONSTANT c_dp_siso_sl_ones : t_dp_siso_sl := ('1', '1');
CONSTANT c_dp_sosi_sl_rst : t_dp_sosi_sl := ('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0');
CONSTANT c_dp_sosi_sl_ones : t_dp_sosi_sl := ('1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1');
-- Multi port or multi register array for DP stream records
TYPE t_dp_siso_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_siso;
TYPE t_dp_sosi_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi;
 
TYPE t_dp_sosi_integer_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_integer;
TYPE t_dp_sosi_unsigned_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_unsigned;
 
TYPE t_dp_siso_sl_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_sl;
TYPE t_dp_sosi_sl_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_sl;
-- Multi port or multi register slv arrays for DP stream records fields
TYPE t_dp_bsn_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
TYPE t_dp_data_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0);
TYPE t_dp_dsp_data_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0);
TYPE t_dp_empty_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_empty_w-1 DOWNTO 0);
TYPE t_dp_channel_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0);
TYPE t_dp_error_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0);
-- Multi-dimemsion array types with fixed LS-dimension
TYPE t_dp_siso_2arr_1 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(0 DOWNTO 0);
TYPE t_dp_sosi_2arr_1 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(0 DOWNTO 0);
 
-- . 2 dimensional array with 2 fixed LS sosi/siso interfaces (dp_split, dp_concat)
TYPE t_dp_siso_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(1 DOWNTO 0);
TYPE t_dp_sosi_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(1 DOWNTO 0);
 
TYPE t_dp_siso_2arr_3 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(2 DOWNTO 0);
TYPE t_dp_sosi_2arr_3 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(2 DOWNTO 0);
 
TYPE t_dp_siso_2arr_4 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(3 DOWNTO 0);
TYPE t_dp_sosi_2arr_4 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(3 DOWNTO 0);
 
TYPE t_dp_siso_2arr_8 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(7 DOWNTO 0);
TYPE t_dp_sosi_2arr_8 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(7 DOWNTO 0);
 
TYPE t_dp_siso_2arr_9 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(8 DOWNTO 0);
TYPE t_dp_sosi_2arr_9 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(8 DOWNTO 0);
 
TYPE t_dp_siso_2arr_12 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(11 DOWNTO 0);
TYPE t_dp_sosi_2arr_12 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(11 DOWNTO 0);
TYPE t_dp_siso_3arr_4_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_2arr_2(3 DOWNTO 0);
TYPE t_dp_sosi_3arr_4_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_2arr_2(3 DOWNTO 0);
-- 2-dimensional streaming array type:
-- Note:
-- This t_*_mat is less useful then a t_*_2arr array of arrays, because assignments can only be done per element (i.e. not per row). However for t_*_2arr
-- the arrays dimension must be fixed, so these t_*_2arr types are application dependent and need to be defined where used.
TYPE t_dp_siso_mat IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF t_dp_siso;
TYPE t_dp_sosi_mat IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF t_dp_sosi;
 
-- Check sosi.valid against siso.ready
PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi : IN t_dp_sosi;
SIGNAL siso : IN t_dp_siso;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR);
 
-- Default RL=1
PROCEDURE proc_dp_siso_alert(SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi : IN t_dp_sosi;
SIGNAL siso : IN t_dp_siso;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR);
 
-- SOSI/SISO array version
PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi_arr : IN t_dp_sosi_arr;
SIGNAL siso_arr : IN t_dp_siso_arr;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR);
 
-- SOSI/SISO array version with RL=1
PROCEDURE proc_dp_siso_alert(SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi_arr : IN t_dp_sosi_arr;
SIGNAL siso_arr : IN t_dp_siso_arr;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR);
 
-- Resize functions to fit an integer or an SLV in the corresponding t_dp_sosi field width
-- . Use these functions to assign sosi data TO a record field
-- . Use the range selection [n-1 DOWNTO 0] to assign sosi data FROM a record field to an slv
-- . The unused sosi data field bits could remain undefined 'X', because the unused bits in the fields are not used at all.
-- Typically the sosi data are treated as unsigned in the record field, so extended with '0'. However for interpretating
-- signed data in the simulation wave window it is easier to use sign extension in the record field. Therefore TO_DP_SDATA
-- and RESIZE_DP_SDATA are defined as well.
FUNCTION TO_DP_BSN( n : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION TO_DP_DATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- use integer to support 32 bit range, so -1 = 0xFFFFFFFF = +2**32-1
FUNCTION TO_DP_SDATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- use integer to support 32 bit range and signed
FUNCTION TO_DP_UDATA( n : INTEGER) RETURN STD_LOGIC_VECTOR; -- alias of TO_DP_DATA()
FUNCTION TO_DP_DSP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR; -- for re and im fields, signed data
FUNCTION TO_DP_DSP_UDATA(n: INTEGER) RETURN STD_LOGIC_VECTOR; -- for re and im fields, unsigned data (useful to carry indices)
FUNCTION TO_DP_EMPTY( n : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION TO_DP_CHANNEL( n : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION TO_DP_ERROR( n : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION RESIZE_DP_BSN( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
FUNCTION RESIZE_DP_DATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- set unused MSBits to '0'
FUNCTION RESIZE_DP_SDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- sign extend unused MSBits
FUNCTION RESIZE_DP_XDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- set unused MSBits to 'X'
FUNCTION RESIZE_DP_DSP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- sign extend unused MSBits of re and im fields
FUNCTION RESIZE_DP_EMPTY( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
FUNCTION RESIZE_DP_CHANNEL( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
FUNCTION RESIZE_DP_ERROR( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
FUNCTION INCR_DP_DATA( vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- unsigned vec(w-1:0) + dec
FUNCTION INCR_DP_SDATA( vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- signed vec(w-1:0) + dec
FUNCTION INCR_DP_DSP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- signed vec(w-1:0) + dec
FUNCTION REPLICATE_DP_DATA( seq : STD_LOGIC_VECTOR ) RETURN STD_LOGIC_VECTOR; -- replicate seq as often as fits in c_dp_stream_data_w
FUNCTION UNREPLICATE_DP_DATA(data : STD_LOGIC_VECTOR; seq_w : NATURAL) RETURN STD_LOGIC_VECTOR; -- unreplicate data to width seq_w, return low seq_w bits and set mismatch MSbits bits to '1'
 
FUNCTION TO_DP_SOSI_UNSIGNED(sync, valid, sop, eop : STD_LOGIC; bsn, data, re, im, empty, channel, err : UNSIGNED) RETURN t_dp_sosi_unsigned;
 
-- Keep part of head data and combine part of tail data, use the other sosi from head_sosi
FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail : NATURAL) RETURN t_dp_sosi;
-- Shift and combine part of previous data and this data, use the other sosi from prev_sosi
FUNCTION func_dp_data_shift( prev_sosi, this_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_this : NATURAL) RETURN t_dp_sosi;
-- Shift part of tail data and account for input empty
FUNCTION func_dp_data_shift_last( tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail, input_empty : NATURAL) RETURN t_dp_sosi;
-- Determine resulting empty if two streams are concatenated or split
FUNCTION func_dp_empty_concat(head_empty, tail_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION func_dp_empty_split(input_empty, head_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR;
-- Multiplex the t_dp_sosi_arr based on the valid, assuming that at most one input is active valid.
FUNCTION func_dp_sosi_arr_mux(dp : t_dp_sosi_arr) RETURN t_dp_sosi;
-- Determine the combined logical value of corresponding STD_LOGIC fields in t_dp_*_arr (for all elements or only for the mask[]='1' elements)
FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_or( dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_or( dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_or( dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC;
FUNCTION func_dp_stream_arr_or( dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC;
-- Functions to set or get a STD_LOGIC field as a STD_LOGIC_VECTOR to or from an siso or an sosi array
FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_get(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC_VECTOR;
FUNCTION func_dp_stream_arr_get(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC_VECTOR;
-- Functions to select elements from two siso or two sosi arrays (sel[] = '1' selects a, sel[] = '0' selects b)
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso_arr; b : t_dp_siso) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi_arr; b : t_dp_sosi) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso; b : t_dp_siso_arr) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi; b : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso_arr) RETURN t_dp_siso_arr;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
 
-- Fix reversed buses due to connecting TO to DOWNTO range arrays.
FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_siso_arr) RETURN t_dp_siso_arr;
 
-- Functions to combinatorially hold the data fields and to set or reset the control fields in an sosi array
FUNCTION func_dp_stream_arr_combine_data_info_ctrl(dp : t_dp_sosi_arr; info, ctrl : t_dp_sosi) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_set_info( dp : t_dp_sosi_arr; info : t_dp_sosi) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_set_control( dp : t_dp_sosi_arr; ctrl : t_dp_sosi) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_arr_reset_control( dp : t_dp_sosi_arr ) RETURN t_dp_sosi_arr;
-- Reset sosi ctrl and preserve the sosi data (to avoid unnecessary data toggling and to ease data view in Wave window)
FUNCTION func_dp_stream_reset_control(dp : t_dp_sosi) RETURN t_dp_sosi;
-- Functions to combinatorially determine the maximum and minimum sosi bsn[w-1:0] value in the sosi array (for all elements or only for the mask[]='1' elements)
FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;
FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR;
-- Function to copy the BSN of one valid stream to all output streams.
FUNCTION func_dp_stream_arr_copy_valid_bsn(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr;
-- Functions to combinatorially handle channels
-- Note that the *_select and *_remove function are equivalent to dp_demux with g_combined=TRUE
FUNCTION func_dp_stream_channel_set (st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi; -- select channel nr, add the channel field
FUNCTION func_dp_stream_channel_select(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi; -- select channel nr, skip the channel field
FUNCTION func_dp_stream_channel_remove(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi; -- skip channel nr
-- Functions to combinatorially handle the error field
FUNCTION func_dp_stream_error_set(st_sosi : t_dp_sosi; n : NATURAL) RETURN t_dp_sosi; -- force err = 0, is OK
-- Functions to combinatorially handle the BSN field
FUNCTION func_dp_stream_bsn_set(st_sosi : t_dp_sosi; bsn : STD_LOGIC_VECTOR) RETURN t_dp_sosi;
-- Functions to combine sosi fields
FUNCTION func_dp_stream_combine_info_and_data(info, data : t_dp_sosi) RETURN t_dp_sosi;
-- Functions to convert sosi fields
FUNCTION func_dp_stream_slv_to_integer(slv_sosi : t_dp_sosi; w : NATURAL) RETURN t_dp_sosi_integer;
 
-- Functions to set the DATA, RE and IM field in a stream.
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi; slv : STD_LOGIC_VECTOR; str : STRING ) RETURN t_dp_sosi;
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING ) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr;
-- Concatenate the data from a SOSI array into a single SOSI stream (assumes streams are in sync)
FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi; -- Concat SOSI_ARR data into single SOSI
FUNCTION func_dp_stream_concat(src_in : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr; -- Wire single SISO to SISO_ARR
-- Deconcatenate data from SOSI into SOSI array
FUNCTION func_dp_stream_deconcat(snk_in : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr; -- Deconcat SOSI data
FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso; -- Wire SISO_ARR(0) to single SISO
END dp_stream_pkg;
 
 
PACKAGE BODY dp_stream_pkg IS
-- Check sosi.valid against siso.ready
PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi : IN t_dp_sosi;
SIGNAL siso : IN t_dp_siso;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR) IS
BEGIN
ready_reg(0) <= siso.ready;
-- Register siso.ready in c_ready_latency registers
IF rising_edge(clk) THEN
-- Check DP sink
IF sosi.valid = '1' AND ready_reg(c_ready_latency) = '0' THEN
REPORT "RL ERROR" SEVERITY FAILURE;
END IF;
ready_reg( 1 TO c_ready_latency) <= ready_reg( 0 TO c_ready_latency-1);
END IF;
END proc_dp_siso_alert;
 
-- Default RL=1
PROCEDURE proc_dp_siso_alert(SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi : IN t_dp_sosi;
SIGNAL siso : IN t_dp_siso;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR) IS
BEGIN
proc_dp_siso_alert(1, clk, sosi, siso, ready_reg);
END proc_dp_siso_alert;
 
-- SOSI/SISO array version
PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi_arr : IN t_dp_sosi_arr;
SIGNAL siso_arr : IN t_dp_siso_arr;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR) IS
BEGIN
FOR i IN 0 TO sosi_arr'LENGTH-1 LOOP
ready_reg(i*(c_ready_latency+1)) <= siso_arr(i).ready; -- SLV is used as an array: nof_streams*(0..c_ready_latency)
END LOOP;
-- Register siso.ready in c_ready_latency registers
IF rising_edge(clk) THEN
FOR i IN 0 TO sosi_arr'LENGTH-1 LOOP
-- Check DP sink
IF sosi_arr(i).valid = '1' AND ready_reg(i*(c_ready_latency+1)+1) = '0' THEN
REPORT "RL ERROR" SEVERITY FAILURE;
END IF;
ready_reg(i*(c_ready_latency+1)+1 TO i*(c_ready_latency+1)+c_ready_latency) <= ready_reg(i*(c_ready_latency+1) TO i*(c_ready_latency+1)+c_ready_latency-1);
END LOOP;
END IF;
END proc_dp_siso_alert;
 
-- SOSI/SISO array version with RL=1
PROCEDURE proc_dp_siso_alert(SIGNAL clk : IN STD_LOGIC;
SIGNAL sosi_arr : IN t_dp_sosi_arr;
SIGNAL siso_arr : IN t_dp_siso_arr;
SIGNAL ready_reg : INOUT STD_LOGIC_VECTOR) IS
BEGIN
proc_dp_siso_alert(1, clk, sosi_arr, siso_arr, ready_reg);
END proc_dp_siso_alert;
-- Resize functions to fit an integer or an SLV in the corresponding t_dp_sosi field width
FUNCTION TO_DP_BSN(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_bsn_w);
END TO_DP_BSN;
FUNCTION TO_DP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_data_w);
END TO_DP_DATA;
FUNCTION TO_DP_SDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_SVEC(TO_SVEC(n, 32), c_dp_stream_data_w);
END TO_DP_SDATA;
FUNCTION TO_DP_UDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN TO_DP_DATA(n);
END TO_DP_UDATA;
FUNCTION TO_DP_DSP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_SVEC(TO_SVEC(n, 32), c_dp_stream_dsp_data_w);
END TO_DP_DSP_DATA;
FUNCTION TO_DP_DSP_UDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_dsp_data_w);
END TO_DP_DSP_UDATA;
FUNCTION TO_DP_EMPTY(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN TO_UVEC(n, c_dp_stream_empty_w);
END TO_DP_EMPTY;
FUNCTION TO_DP_CHANNEL(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN TO_UVEC(n, c_dp_stream_channel_w);
END TO_DP_CHANNEL;
FUNCTION TO_DP_ERROR(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN TO_UVEC(n, c_dp_stream_error_w);
END TO_DP_ERROR;
FUNCTION RESIZE_DP_BSN(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(vec, c_dp_stream_bsn_w);
END RESIZE_DP_BSN;
FUNCTION RESIZE_DP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(vec, c_dp_stream_data_w);
END RESIZE_DP_DATA;
FUNCTION RESIZE_DP_SDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_SVEC(vec, c_dp_stream_data_w);
END RESIZE_DP_SDATA;
FUNCTION RESIZE_DP_XDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_vec : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0) := (OTHERS=>'X');
BEGIN
v_vec(vec'LENGTH-1 DOWNTO 0) := vec;
RETURN v_vec;
END RESIZE_DP_XDATA;
FUNCTION RESIZE_DP_DSP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_SVEC(vec, c_dp_stream_dsp_data_w);
END RESIZE_DP_DSP_DATA;
FUNCTION RESIZE_DP_EMPTY(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(vec, c_dp_stream_empty_w);
END RESIZE_DP_EMPTY;
FUNCTION RESIZE_DP_CHANNEL(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(vec, c_dp_stream_channel_w);
END RESIZE_DP_CHANNEL;
FUNCTION RESIZE_DP_ERROR(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_UVEC(vec, c_dp_stream_error_w);
END RESIZE_DP_ERROR;
FUNCTION INCR_DP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_DP_DATA(STD_LOGIC_VECTOR(UNSIGNED(vec(w-1 DOWNTO 0)) + dec));
END INCR_DP_DATA;
FUNCTION INCR_DP_SDATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_DP_SDATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec));
END INCR_DP_SDATA;
 
FUNCTION INCR_DP_DSP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
BEGIN
RETURN RESIZE_DP_DSP_DATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec));
END INCR_DP_DSP_DATA;
FUNCTION REPLICATE_DP_DATA(seq : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_seq_w : NATURAL := seq'LENGTH;
CONSTANT c_nof_replications : NATURAL := ceil_div(c_dp_stream_data_w, c_seq_w);
CONSTANT c_vec_w : NATURAL := ceil_value(c_dp_stream_data_w, c_seq_w);
VARIABLE v_vec : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
BEGIN
FOR I IN 0 TO c_nof_replications-1 LOOP
v_vec((I+1)*c_seq_w-1 DOWNTO I*c_seq_w) := seq;
END LOOP;
RETURN v_vec(c_dp_stream_data_w-1 DOWNTO 0);
END REPLICATE_DP_DATA;
FUNCTION UNREPLICATE_DP_DATA(data : STD_LOGIC_VECTOR; seq_w :NATURAL) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_data_w : NATURAL := data'LENGTH;
CONSTANT c_nof_replications : NATURAL := ceil_div(c_data_w, seq_w);
CONSTANT c_vec_w : NATURAL := ceil_value(c_data_w, seq_w);
VARIABLE v_seq : STD_LOGIC_VECTOR(seq_w-1 DOWNTO 0);
VARIABLE v_data : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
VARIABLE v_vec : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
BEGIN
v_data := RESIZE_UVEC(data, c_vec_w);
v_seq := v_data(seq_w-1 DOWNTO 0); -- low data part is the v_seq
v_vec(seq_w-1 DOWNTO 0) := v_seq; -- keep v_seq at low part of return value
IF c_nof_replications>1 THEN
FOR I IN 1 TO c_nof_replications-1 LOOP
v_vec((I+1)*seq_w-1 DOWNTO I*seq_w) := v_data((I+1)*seq_w-1 DOWNTO I*seq_w) XOR v_seq; -- set return bit to '1' for high part data bits that do not match low part v_seq
END LOOP;
END IF;
RETURN v_vec(c_data_w-1 DOWNTO 0);
END UNREPLICATE_DP_DATA;
FUNCTION TO_DP_SOSI_UNSIGNED(sync, valid, sop, eop : STD_LOGIC; bsn, data, re, im, empty, channel, err : UNSIGNED) RETURN t_dp_sosi_unsigned IS
VARIABLE v_sosi_unsigned : t_dp_sosi_unsigned;
BEGIN
v_sosi_unsigned.sync := sync;
v_sosi_unsigned.valid := valid;
v_sosi_unsigned.sop := sop;
v_sosi_unsigned.eop := eop;
v_sosi_unsigned.bsn := RESIZE(bsn, c_dp_stream_bsn_w);
v_sosi_unsigned.data := RESIZE(data, c_dp_stream_data_w);
v_sosi_unsigned.re := RESIZE(re, c_dp_stream_dsp_data_w);
v_sosi_unsigned.im := RESIZE(im, c_dp_stream_dsp_data_w);
v_sosi_unsigned.empty := RESIZE(empty, c_dp_stream_empty_w);
v_sosi_unsigned.channel := RESIZE(channel, c_dp_stream_channel_w);
v_sosi_unsigned.err := RESIZE(err, c_dp_stream_error_w);
RETURN v_sosi_unsigned;
END TO_DP_SOSI_UNSIGNED;
 
-- Keep part of head data and combine part of tail data
FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail : NATURAL) RETURN t_dp_sosi IS
VARIABLE vN : NATURAL := nof_symbols_per_data;
VARIABLE v_sosi : t_dp_sosi;
BEGIN
ASSERT nof_symbols_from_tail<vN REPORT "func_dp_data_shift_first : no symbols from head" SEVERITY FAILURE;
-- use the other sosi from head_sosi
v_sosi := head_sosi; -- I = nof_symbols_from_tail = 0
FOR I IN 1 TO vN-1 LOOP -- I > 0
IF nof_symbols_from_tail = I THEN
v_sosi.data(I*symbol_w-1 DOWNTO 0) := tail_sosi.data(vN*symbol_w-1 DOWNTO (vN-I)*symbol_w);
END IF;
END LOOP;
RETURN v_sosi;
END func_dp_data_shift_first;
-- Shift and combine part of previous data and this data,
FUNCTION func_dp_data_shift(prev_sosi, this_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_this : NATURAL) RETURN t_dp_sosi IS
VARIABLE vK : NATURAL := nof_symbols_from_this;
VARIABLE vN : NATURAL := nof_symbols_per_data;
VARIABLE v_sosi : t_dp_sosi;
BEGIN
-- use the other sosi from this_sosi if nof_symbols_from_this > 0 else use other sosi from prev_sosi
IF vK>0 THEN
v_sosi := this_sosi;
ELSE
v_sosi := prev_sosi;
END IF;
-- use sosi data from both if 0 < nof_symbols_from_this < nof_symbols_per_data (i.e. 0 < I < vN)
IF vK<nof_symbols_per_data THEN -- I = vK = nof_symbols_from_this < vN
-- Implementation using variable vK directly instead of via I in a LOOP
-- IF vK > 0 THEN
-- v_sosi.data(vN*symbol_w-1 DOWNTO vK*symbol_w) := prev_sosi.data((vN-vK)*symbol_w-1 DOWNTO 0);
-- v_sosi.data( vK*symbol_w-1 DOWNTO 0) := this_sosi.data( vN *symbol_w-1 DOWNTO (vN-vK)*symbol_w);
-- END IF;
-- Implementaion using LOOP vK rather than VARIABLE vK directly as index to help synthesis and avoid potential multiplier
v_sosi.data := prev_sosi.data; -- I = vK = nof_symbols_from_this = 0
FOR I IN 1 TO vN-1 LOOP -- I = vK = nof_symbols_from_this > 0
IF vK = I THEN
v_sosi.data(vN*symbol_w-1 DOWNTO I*symbol_w) := prev_sosi.data((vN-I)*symbol_w-1 DOWNTO 0);
v_sosi.data( I*symbol_w-1 DOWNTO 0) := this_sosi.data( vN *symbol_w-1 DOWNTO (vN-I)*symbol_w);
END IF;
END LOOP;
END IF;
RETURN v_sosi;
END func_dp_data_shift;
-- Shift part of tail data and account for input empty
FUNCTION func_dp_data_shift_last(tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail, input_empty : NATURAL) RETURN t_dp_sosi IS
VARIABLE vK : NATURAL := nof_symbols_from_tail;
VARIABLE vL : NATURAL := input_empty;
VARIABLE vN : NATURAL := nof_symbols_per_data;
VARIABLE v_sosi : t_dp_sosi;
BEGIN
ASSERT vK > 0 REPORT "func_dp_data_shift_last : no symbols from tail" SEVERITY FAILURE;
ASSERT vK+vL<=vN REPORT "func_dp_data_shift_last : impossible shift" SEVERITY FAILURE;
v_sosi := tail_sosi;
-- Implementation using variable vK directly instead of via I in a LOOP
-- IF vK > 0 THEN
-- v_sosi.data(vN*symbol_w-1 DOWNTO (vN-vK)*symbol_w) <= tail_sosi.data((vK+vL)*symbol_w-1 DOWNTO vL*symbol_w);
-- END IF;
-- Implementation using LOOP vK rather than VARIABLE vK directly as index to help synthesis and avoid potential multiplier
-- Implementation using LOOP vL rather than VARIABLE vL directly as index to help synthesis and avoid potential multiplier
FOR I IN 1 TO vN-1 LOOP
IF vK = I THEN
FOR J IN 0 TO vN-1 LOOP
IF vL = J THEN
v_sosi.data(vN*symbol_w-1 DOWNTO (vN-I)*symbol_w) := tail_sosi.data((I+J)*symbol_w-1 DOWNTO J*symbol_w);
END IF;
END LOOP;
END IF;
END LOOP;
RETURN v_sosi;
END func_dp_data_shift_last;
 
-- Determine resulting empty if two streams are concatenated
-- . both empty must use the same nof symbols per data
FUNCTION func_dp_empty_concat(head_empty, tail_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_a, v_b, v_empty : NATURAL;
BEGIN
v_a := TO_UINT(head_empty);
v_b := TO_UINT(tail_empty);
v_empty := v_a + v_b;
IF v_empty >= nof_symbols_per_data THEN
v_empty := v_empty - nof_symbols_per_data;
END IF;
RETURN TO_UVEC(v_empty, head_empty'LENGTH);
END func_dp_empty_concat;
FUNCTION func_dp_empty_split(input_empty, head_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_a, v_b, v_empty : NATURAL;
BEGIN
v_a := TO_UINT(input_empty);
v_b := TO_UINT(head_empty);
IF v_a >= v_b THEN
v_empty := v_a - v_b;
ELSE
v_empty := (nof_symbols_per_data + v_a) - v_b;
END IF;
RETURN TO_UVEC(v_empty, head_empty'LENGTH);
END func_dp_empty_split;
-- Multiplex the t_dp_sosi_arr based on the valid, assuming that at most one input is active valid.
FUNCTION func_dp_sosi_arr_mux(dp : t_dp_sosi_arr) RETURN t_dp_sosi IS
VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
BEGIN
FOR I IN dp'RANGE LOOP
IF dp(I).valid='1' THEN
v_sosi := dp(I);
EXIT;
END IF;
END LOOP;
RETURN v_sosi;
END func_dp_sosi_arr_mux;
 
-- Determine the combined logical value of corresponding STD_LOGIC fields in t_dp_*_arr (for all elements or only for the mask[]='1' elements)
FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1'); -- set default v_vec such that unmasked input have no influence on operation result
VARIABLE v_any : STD_LOGIC := '0';
BEGIN
-- map siso field to v_vec
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
v_any := '1';
IF str="READY" THEN v_vec(I) := dp(I).ready;
ELSIF str="XON" THEN v_vec(I) := dp(I).xon;
ELSE REPORT "Error in func_dp_stream_arr_and for t_dp_siso_arr";
END IF;
END IF;
END LOOP;
-- do operation on the selected record field
IF v_any='1' THEN
RETURN vector_and(v_vec); -- return AND of the masked input fields
ELSE
RETURN '0'; -- return '0' if no input was masked
END IF;
END func_dp_stream_arr_and;
FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1'); -- set default v_vec such that unmasked input have no influence on operation result
VARIABLE v_any : STD_LOGIC := '0';
BEGIN
-- map siso field to v_vec
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
v_any := '1';
IF str="VALID" THEN v_vec(I) := dp(I).valid;
ELSIF str="SOP" THEN v_vec(I) := dp(I).sop;
ELSIF str="EOP" THEN v_vec(I) := dp(I).eop;
ELSIF str="SYNC" THEN v_vec(I) := dp(I).sync;
ELSE REPORT "Error in func_dp_stream_arr_and for t_dp_sosi_arr";
END IF;
END IF;
END LOOP;
-- do operation on the selected record field
IF v_any='1' THEN
RETURN vector_and(v_vec); -- return AND of the masked input fields
ELSE
RETURN '0'; -- return '0' if no input was masked
END IF;
END func_dp_stream_arr_and;
FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_and(dp, c_mask, str);
END func_dp_stream_arr_and;
FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_and(dp, c_mask, str);
END func_dp_stream_arr_and;
FUNCTION func_dp_stream_arr_or(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'0'); -- set default v_vec such that unmasked input have no influence on operation result
VARIABLE v_any : STD_LOGIC := '0';
BEGIN
-- map siso field to v_vec
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
v_any := '1';
IF str="READY" THEN v_vec(I) := dp(I).ready;
ELSIF str="XON" THEN v_vec(I) := dp(I).xon;
ELSE REPORT "Error in func_dp_stream_arr_or for t_dp_siso_arr";
END IF;
END IF;
END LOOP;
-- do operation on the selected record field
IF v_any='1' THEN
RETURN vector_or(v_vec); -- return OR of the masked input fields
ELSE
RETURN '0'; -- return '0' if no input was masked
END IF;
END func_dp_stream_arr_or;
FUNCTION func_dp_stream_arr_or(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'0'); -- set default v_vec such that unmasked input have no influence on operation result
VARIABLE v_any : STD_LOGIC := '0';
BEGIN
-- map siso field to v_vec
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
v_any := '1';
IF str="VALID" THEN v_vec(I) := dp(I).valid;
ELSIF str="SOP" THEN v_vec(I) := dp(I).sop;
ELSIF str="EOP" THEN v_vec(I) := dp(I).eop;
ELSIF str="SYNC" THEN v_vec(I) := dp(I).sync;
ELSE REPORT "Error in func_dp_stream_arr_or for t_dp_sosi_arr";
END IF;
END IF;
END LOOP;
-- do operation on the selected record field
IF v_any='1' THEN
RETURN vector_or(v_vec); -- return OR of the masked input fields
ELSE
RETURN '0'; -- return '0' if no input was masked
END IF;
END func_dp_stream_arr_or;
FUNCTION func_dp_stream_arr_or(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_or(dp, c_mask, str);
END func_dp_stream_arr_or;
FUNCTION func_dp_stream_arr_or(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_or(dp, c_mask, str);
END func_dp_stream_arr_or;
-- Functions to set or get a STD_LOGIC field as a STD_LOGIC_VECTOR to or from an siso or an sosi array
FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_siso_arr IS
VARIABLE v_dp : t_dp_siso_arr(dp'RANGE) := dp; -- default
VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := slv; -- map to ensure same range as for dp
BEGIN
FOR I IN dp'RANGE LOOP
IF str="READY" THEN v_dp(I).ready := v_slv(I);
ELSIF str="XON" THEN v_dp(I).xon := v_slv(I);
ELSE REPORT "Error in func_dp_stream_arr_set for t_dp_siso_arr";
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_set;
FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- default
VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := slv; -- map to ensure same range as for dp
BEGIN
FOR I IN dp'RANGE LOOP
IF str="VALID" THEN v_dp(I).valid := v_slv(I);
ELSIF str="SOP" THEN v_dp(I).sop := v_slv(I);
ELSIF str="EOP" THEN v_dp(I).eop := v_slv(I);
ELSIF str="SYNC" THEN v_dp(I).sync := v_slv(I);
ELSE REPORT "Error in func_dp_stream_arr_set for t_dp_sosi_arr";
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_set;
FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_siso_arr IS
VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>sl);
BEGIN
RETURN func_dp_stream_arr_set(dp, v_slv, str);
END func_dp_stream_arr_set;
FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_sosi_arr IS
VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>sl);
BEGIN
RETURN func_dp_stream_arr_set(dp, v_slv, str);
END func_dp_stream_arr_set;
FUNCTION func_dp_stream_arr_get(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_ctrl : STD_LOGIC_VECTOR(dp'RANGE);
BEGIN
FOR I IN dp'RANGE LOOP
IF str="READY" THEN v_ctrl(I) := dp(I).ready;
ELSIF str="XON" THEN v_ctrl(I) := dp(I).xon;
ELSE REPORT "Error in func_dp_stream_arr_get for t_dp_siso_arr";
END IF;
END LOOP;
RETURN v_ctrl;
END func_dp_stream_arr_get;
FUNCTION func_dp_stream_arr_get(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_ctrl : STD_LOGIC_VECTOR(dp'RANGE);
BEGIN
FOR I IN dp'RANGE LOOP
IF str="VALID" THEN v_ctrl(I) := dp(I).valid;
ELSIF str="SOP" THEN v_ctrl(I) := dp(I).sop;
ELSIF str="EOP" THEN v_ctrl(I) := dp(I).eop;
ELSIF str="SYNC" THEN v_ctrl(I) := dp(I).sync;
ELSE REPORT "Error in func_dp_stream_arr_get for t_dp_sosi_arr";
END IF;
END LOOP;
RETURN v_ctrl;
END func_dp_stream_arr_get;
-- Functions to select elements from two siso or two sosi arrays (sel[] = '1' selects a, sel[] = '0' selects b)
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso) RETURN t_dp_siso_arr IS
VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a;
ELSE
v_dp(I) := b;
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso_arr; b : t_dp_siso) RETURN t_dp_siso_arr IS
VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a(I);
ELSE
v_dp(I) := b;
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso; b : t_dp_siso_arr) RETURN t_dp_siso_arr IS
VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a;
ELSE
v_dp(I) := b(I);
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso_arr) RETURN t_dp_siso_arr IS
VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a(I);
ELSE
v_dp(I) := b(I);
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a;
ELSE
v_dp(I) := b;
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi_arr; b : t_dp_sosi) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a(I);
ELSE
v_dp(I) := b;
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi; b : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a;
ELSE
v_dp(I) := b(I);
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
BEGIN
FOR I IN sel'RANGE LOOP
IF sel(I)='1' THEN
v_dp(I) := a(I);
ELSE
v_dp(I) := b(I);
END IF;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_select;
 
FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_siso_arr) RETURN t_dp_siso_arr IS
VARIABLE v_to_range : t_dp_siso_arr(0 TO in_arr'HIGH);
VARIABLE v_downto_range : t_dp_siso_arr(in_arr'HIGH DOWNTO 0);
BEGIN
FOR i IN in_arr'RANGE LOOP
v_to_range(i) := in_arr(in_arr'HIGH-i);
v_downto_range(i) := in_arr(in_arr'HIGH-i);
END LOOP;
IF in_arr'LEFT>in_arr'RIGHT THEN
RETURN v_downto_range;
ELSIF in_arr'LEFT<in_arr'RIGHT THEN
RETURN v_to_range;
ELSE
RETURN in_arr;
END IF;
END func_dp_stream_arr_reverse_range;
 
FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
VARIABLE v_to_range : t_dp_sosi_arr(0 TO in_arr'HIGH);
VARIABLE v_downto_range : t_dp_sosi_arr(in_arr'HIGH DOWNTO 0);
BEGIN
FOR i IN in_arr'RANGE LOOP
v_to_range(i) := in_arr(in_arr'HIGH-i);
v_downto_range(i) := in_arr(in_arr'HIGH-i);
END LOOP;
IF in_arr'LEFT>in_arr'RIGHT THEN
RETURN v_downto_range;
ELSIF in_arr'LEFT<in_arr'RIGHT THEN
RETURN v_to_range;
ELSE
RETURN in_arr;
END IF;
END func_dp_stream_arr_reverse_range;
-- Functions to combinatorially hold the data fields and to set or reset the info and control fields in an sosi array
FUNCTION func_dp_stream_arr_combine_data_info_ctrl(dp : t_dp_sosi_arr; info, ctrl : t_dp_sosi) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- hold sosi data
BEGIN
v_dp := func_dp_stream_arr_set_info( v_dp, info); -- set sosi info
v_dp := func_dp_stream_arr_set_control(v_dp, ctrl); -- set sosi ctrl
RETURN v_dp;
END func_dp_stream_arr_combine_data_info_ctrl;
FUNCTION func_dp_stream_arr_set_info(dp : t_dp_sosi_arr; info : t_dp_sosi) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- hold sosi data
BEGIN
FOR I IN dp'RANGE LOOP -- set sosi info
v_dp(I).bsn := info.bsn; -- sop
v_dp(I).channel := info.channel; -- sop
v_dp(I).empty := info.empty; -- eop
v_dp(I).err := info.err; -- eop
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_set_info;
FUNCTION func_dp_stream_arr_set_control(dp : t_dp_sosi_arr; ctrl : t_dp_sosi) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- hold sosi data
BEGIN
FOR I IN dp'RANGE LOOP -- set sosi control
v_dp(I).valid := ctrl.valid;
v_dp(I).sop := ctrl.sop;
v_dp(I).eop := ctrl.eop;
v_dp(I).sync := ctrl.sync;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_set_control;
FUNCTION func_dp_stream_arr_reset_control(dp : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- hold sosi data
BEGIN
FOR I IN dp'RANGE LOOP -- reset sosi control
v_dp(I).valid := '0';
v_dp(I).sop := '0';
v_dp(I).eop := '0';
v_dp(I).sync := '0';
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_reset_control;
FUNCTION func_dp_stream_reset_control(dp : t_dp_sosi) RETURN t_dp_sosi IS
VARIABLE v_dp : t_dp_sosi := dp; -- hold sosi data
BEGIN
-- reset sosi control
v_dp.valid := '0';
v_dp.sop := '0';
v_dp.eop := '0';
v_dp.sync := '0';
RETURN v_dp;
END func_dp_stream_reset_control;
-- Functions to combinatorially determine the maximum and minimum sosi bsn[w-1:0] value in the sosi array (for all elements or only for the mask[]='1' elements)
FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_bsn : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS=>'0'); -- init max v_bsn with minimum value
BEGIN
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
IF UNSIGNED(v_bsn) < UNSIGNED(dp(I).bsn(w-1 DOWNTO 0)) THEN
v_bsn := dp(I).bsn(w-1 DOWNTO 0);
END IF;
END IF;
END LOOP;
RETURN v_bsn;
END func_dp_stream_arr_bsn_max;
FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_bsn_max(dp, c_mask, w);
END func_dp_stream_arr_bsn_max;
FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_bsn : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS=>'1'); -- init min v_bsn with maximum value
BEGIN
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
IF UNSIGNED(v_bsn) > UNSIGNED(dp(I).bsn(w-1 DOWNTO 0)) THEN
v_bsn := dp(I).bsn(w-1 DOWNTO 0);
END IF;
END IF;
END LOOP;
RETURN v_bsn;
END func_dp_stream_arr_bsn_min;
FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
BEGIN
RETURN func_dp_stream_arr_bsn_min(dp, c_mask, w);
END func_dp_stream_arr_bsn_min;
 
-- Function to copy the BSN number of one valid stream to all other streams.
FUNCTION func_dp_stream_arr_copy_valid_bsn(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr IS
VARIABLE v_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'0');
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp; -- hold sosi data
BEGIN
FOR I IN dp'RANGE LOOP
IF mask(I)='1' THEN
v_bsn := dp(I).bsn;
END IF;
END LOOP;
FOR I IN dp'RANGE LOOP
v_dp(I).bsn := v_bsn;
END LOOP;
RETURN v_dp;
END func_dp_stream_arr_copy_valid_bsn;
-- Functions to combinatorially handle channels
FUNCTION func_dp_stream_channel_set(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := st_sosi;
BEGIN
v_rec.channel := TO_UVEC(ch, c_dp_stream_channel_w);
RETURN v_rec;
END func_dp_stream_channel_set;
FUNCTION func_dp_stream_channel_select(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := st_sosi;
BEGIN
IF UNSIGNED(st_sosi.channel)/=ch THEN
v_rec.valid := '0';
v_rec.sop := '0';
v_rec.eop := '0';
END IF;
RETURN v_rec;
END func_dp_stream_channel_select;
FUNCTION func_dp_stream_channel_remove(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := st_sosi;
BEGIN
IF UNSIGNED(st_sosi.channel)=ch THEN
v_rec.valid := '0';
v_rec.sop := '0';
v_rec.eop := '0';
END IF;
RETURN v_rec;
END func_dp_stream_channel_remove;
FUNCTION func_dp_stream_error_set(st_sosi : t_dp_sosi; n : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := st_sosi;
BEGIN
v_rec.err := TO_UVEC(n, c_dp_stream_error_w);
RETURN v_rec;
END func_dp_stream_error_set;
FUNCTION func_dp_stream_bsn_set(st_sosi : t_dp_sosi; bsn : STD_LOGIC_VECTOR) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := st_sosi;
BEGIN
v_rec.bsn := RESIZE_DP_BSN(bsn);
RETURN v_rec;
END func_dp_stream_bsn_set;
FUNCTION func_dp_stream_combine_info_and_data(info, data : t_dp_sosi) RETURN t_dp_sosi IS
VARIABLE v_rec : t_dp_sosi := data; -- Sosi data fields
BEGIN
-- Combine sosi data with the sosi info fields
v_rec.sync := info.sync AND data.sop; -- force sync only active at data.sop
v_rec.bsn := info.bsn;
v_rec.channel := info.channel;
v_rec.empty := info.empty;
v_rec.err := info.err;
RETURN v_rec;
END func_dp_stream_combine_info_and_data;
FUNCTION func_dp_stream_slv_to_integer(slv_sosi : t_dp_sosi; w : NATURAL) RETURN t_dp_sosi_integer IS
VARIABLE v_rec : t_dp_sosi_integer;
BEGIN
v_rec.sync := slv_sosi.sync;
v_rec.bsn := TO_UINT(slv_sosi.bsn(30 DOWNTO 0)); -- NATURAL'width = 31 bit
v_rec.data := TO_SINT(slv_sosi.data(w-1 DOWNTO 0));
v_rec.re := TO_SINT(slv_sosi.re(w-1 DOWNTO 0));
v_rec.im := TO_SINT(slv_sosi.im(w-1 DOWNTO 0));
v_rec.valid := slv_sosi.valid;
v_rec.sop := slv_sosi.sop;
v_rec.eop := slv_sosi.eop;
v_rec.empty := TO_UINT(slv_sosi.empty);
v_rec.channel := TO_UINT(slv_sosi.channel);
v_rec.err := TO_UINT(slv_sosi.err);
RETURN v_rec;
END func_dp_stream_slv_to_integer;
 
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi IS
VARIABLE v_dp : t_dp_sosi := dp;
BEGIN
IF str="DATA" THEN v_dp.data := RESIZE_DP_DATA(slv);
ELSIF str="DSP" THEN v_dp.re := RESIZE_DP_DSP_DATA(slv);
v_dp.im := RESIZE_DP_DSP_DATA(slv);
ELSIF str="RE" THEN v_dp.re := RESIZE_DP_DSP_DATA(slv);
ELSIF str="IM" THEN v_dp.im := RESIZE_DP_DSP_DATA(slv);
ELSIF str="ALL" THEN v_dp.data := RESIZE_DP_DATA(slv);
v_dp.re := RESIZE_DP_DSP_DATA(slv);
v_dp.im := RESIZE_DP_DSP_DATA(slv);
ELSE REPORT "Error in func_dp_stream_set_data for t_dp_sosi";
END IF;
RETURN v_dp;
END;
 
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;
BEGIN
FOR I IN dp'RANGE LOOP
v_dp(I) := func_dp_stream_set_data(dp(I), slv, str);
END LOOP;
RETURN v_dp;
END;
 
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr IS
VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;
BEGIN
FOR I IN dp'RANGE LOOP
IF mask(I)='0' THEN
v_dp(I) := func_dp_stream_set_data(dp(I), slv, str);
END IF;
END LOOP;
RETURN v_dp;
END;
 
-- Concatenate the data (and complex fields) from a SOSI array into a single SOSI stream (assumes streams are in sync)
FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_src_out : t_dp_sosi := snk_in_arr(0);
VARIABLE v_compl_data_w : NATURAL := data_w/2;
BEGIN
FOR i IN snk_in_arr'RANGE LOOP
v_src_out.data((i+1)* data_w-1 DOWNTO i* data_w) := snk_in_arr(i).data( data_w-1 DOWNTO 0);
v_src_out.re( (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).re(v_compl_data_w-1 DOWNTO 0);
v_src_out.im( (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).im(v_compl_data_w-1 DOWNTO 0);
END LOOP;
RETURN v_src_out;
END;
 
FUNCTION func_dp_stream_concat(src_in : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr IS -- Wire single SISO to SISO_ARR
VARIABLE v_snk_out_arr : t_dp_siso_arr(nof_streams-1 DOWNTO 0);
BEGIN
FOR i IN v_snk_out_arr'RANGE LOOP
v_snk_out_arr(i) := src_in;
END LOOP;
RETURN v_snk_out_arr;
END;
 
-- Deconcatenate data from SOSI into SOSI array
FUNCTION func_dp_stream_deconcat(snk_in : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr IS
VARIABLE v_src_out_arr : t_dp_sosi_arr(nof_streams-1 DOWNTO 0);
VARIABLE v_compl_data_w : NATURAL := data_w/2;
BEGIN
FOR i IN v_src_out_arr'RANGE LOOP
v_src_out_arr(i) := snk_in;
v_src_out_arr(i).data := (OTHERS=>'0');
v_src_out_arr(i).re := (OTHERS=>'0');
v_src_out_arr(i).im := (OTHERS=>'0');
v_src_out_arr(i).data( data_w-1 DOWNTO 0) := snk_in.data((i+1)* data_w-1 DOWNTO i* data_w);
v_src_out_arr(i).re( v_compl_data_w-1 DOWNTO 0) := snk_in.re ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
v_src_out_arr(i).im( v_compl_data_w-1 DOWNTO 0) := snk_in.im ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
END LOOP;
RETURN v_src_out_arr;
END;
 
FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso IS -- Wire SISO_ARR(0) to single SISO
BEGIN
RETURN src_out_arr(0);
END;
 
END dp_stream_pkg;
 
/dp_stream_stimuli.vhd
0,0 → 1,185
-------------------------------------------------------------------------------
--
-- Copyright (C) 2015
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
 
-- Purpose:
-- . The dp_stream_stimuli generates as stream of packets with counter data.
-- Description:
--
-- Remark:
-- . The stimuli empty = 0 because the data in proc_dp_gen_block_data() is
-- generated with one symbol per data (because symbol_w = data_w).
--
-- Usage:
-- . See tb_dp_example_no_dut for usage example
--
 
LIBRARY IEEE, common_pkg_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_pkg_lib.common_pkg.ALL;
USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
USE common_pkg_lib.tb_common_pkg.ALL;
USE work.dp_stream_pkg.ALL;
USE work.tb_dp_pkg.ALL;
 
 
ENTITY dp_stream_stimuli IS
GENERIC (
g_instance_nr : NATURAL := 0;
-- flow control
g_random_w : NATURAL := 15; -- use different random width for stimuli and for verify to have different random sequences
g_pulse_active : NATURAL := 1;
g_pulse_period : NATURAL := 2;
g_flow_control : t_dp_flow_control_enum := e_active; -- always active, random or pulse flow control
-- initializations
g_sync_period : NATURAL := 10;
g_sync_offset : NATURAL := 0;
g_data_init : NATURAL := 0; -- choose some easy to recognize and unique value, data will increment at every valid
g_bsn_init : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := TO_DP_BSN(0); -- X"0877665544332211", bsn will increment at every sop
g_err_init : NATURAL := 247; -- choose some easy to recognize and unique value
g_err_incr : NATURAL := 1; -- when 0 keep fixed at init value, when 1 increment at every sop
g_channel_init : NATURAL := 5; -- choose some easy to recognize and unique value
g_channel_incr : NATURAL := 1; -- when 0 keep fixed at init value, when 1 increment at every sop
-- specific
g_in_dat_w : NATURAL := 32;
g_nof_repeat : NATURAL := 5;
g_pkt_len : NATURAL := 16;
g_pkt_gap : NATURAL := 4
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Generate stimuli
src_in : IN t_dp_siso := c_dp_siso_rdy;
src_out : OUT t_dp_sosi;
 
-- End of stimuli
last_snk_in : OUT t_dp_sosi; -- expected verify_snk_in after end of stimuli
last_snk_in_evt : OUT STD_LOGIC; -- trigger verify to verify the last_snk_in
tb_end : OUT STD_LOGIC -- signal end of tb as far as this dp_stream_stimuli is concerned
);
END dp_stream_stimuli;
 
 
ARCHITECTURE str OF dp_stream_stimuli IS
SIGNAL random : STD_LOGIC_VECTOR(g_random_w-1 DOWNTO 0) := TO_UVEC(g_instance_nr, g_random_w); -- use different initialization to have different random sequences per stream
SIGNAL pulse : STD_LOGIC;
SIGNAL pulse_en : STD_LOGIC := '1';
SIGNAL stimuli_en : STD_LOGIC := '1';
SIGNAL src_out_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
SIGNAL i_src_out : t_dp_sosi;
BEGIN
 
src_out <= i_src_out;
------------------------------------------------------------------------------
-- STREAM CONTROL
------------------------------------------------------------------------------
random <= func_common_random(random) WHEN rising_edge(clk);
proc_common_gen_duty_pulse(g_pulse_active, g_pulse_period, '1', rst, clk, pulse_en, pulse);
 
stimuli_en <= '1' WHEN g_flow_control=e_active ELSE
random(random'HIGH) WHEN g_flow_control=e_random ELSE
pulse WHEN g_flow_control=e_pulse;
------------------------------------------------------------------------------
-- DATA GENERATION
------------------------------------------------------------------------------
-- Generate data path input data
p_stimuli_st : PROCESS
VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
VARIABLE v_last : t_dp_sosi := c_dp_sosi_rst;
BEGIN
-- Initialisations
last_snk_in <= c_dp_sosi_rst;
last_snk_in_evt <= '0';
tb_end <= '0';
-- Adjust initial sosi field values by -1 to compensate for auto increment
v_sosi.bsn := INCR_UVEC(g_bsn_init, -1);
v_sosi.channel := INCR_UVEC(TO_DP_CHANNEL(g_channel_init), -g_channel_incr);
v_sosi.data := INCR_UVEC(TO_DP_DATA(g_data_init), -g_pkt_len);
v_sosi.err := INCR_UVEC(TO_DP_ERROR(g_err_init), -g_err_incr);
i_src_out <= c_dp_sosi_rst;
proc_common_wait_until_low(clk, rst);
proc_common_wait_some_cycles(clk, 5);
 
-- Generate g_nof_repeat packets
FOR I IN 0 TO g_nof_repeat-1 LOOP
-- Auto increment v_sosi field values for this packet
v_sosi.bsn := INCR_UVEC(v_sosi.bsn, 1);
v_sosi.sync := sel_a_b((UNSIGNED(v_sosi.bsn) MOD g_sync_period) = g_sync_offset, '1', '0'); -- insert sync starting at BSN=g_sync_offset and with period g_sync_period
v_sosi.channel := INCR_UVEC(v_sosi.channel, g_channel_incr);
v_sosi.data := INCR_UVEC(v_sosi.data, g_pkt_len);
v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_in_dat_w-1 DOWNTO 0)); -- wrap when >= 2**g_in_dat_w
v_sosi.err := INCR_UVEC(v_sosi.err, g_err_incr);
-- Send packet
proc_dp_gen_block_data(g_in_dat_w, TO_UINT(v_sosi.data), g_pkt_len, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, clk, stimuli_en, src_in, i_src_out);
-- Insert optional gap between the packets
proc_common_wait_some_cycles(clk, g_pkt_gap);
-- Update v_last.sync
IF v_sosi.sync='1' THEN v_last.sync := '1'; END IF;
END LOOP;
 
-- Update v_last control
IF g_nof_repeat>0 THEN
v_last.sop := '1';
v_last.eop := '1';
v_last.valid := '1';
END IF;
-- Determine and keep last expected sosi field values after end of stimuli
-- . e_qual
v_last.bsn := STD_LOGIC_VECTOR( UNSIGNED(g_bsn_init) + g_nof_repeat-1);
v_last.channel := TO_DP_CHANNEL(g_channel_init + (g_nof_repeat-1)*g_channel_incr);
v_last.err := TO_DP_ERROR(g_err_init + (g_nof_repeat-1)*g_err_incr);
-- . account for g_pkt_len
v_last.data := INCR_UVEC(v_sosi.data, g_pkt_len-1);
v_last.data := RESIZE_DP_DATA(v_last.data(g_in_dat_w-1 DOWNTO 0)); -- wrap when >= 2**g_in_dat_w
last_snk_in <= v_last;
-- Signal end of stimuli
proc_common_wait_some_cycles(clk, 100); -- latency from stimuli to verify depends on the flow control, so wait sufficiently long for last packet to have passed through
proc_common_gen_pulse(clk, last_snk_in_evt);
proc_common_wait_some_cycles(clk, 50);
tb_end <= '1';
WAIT;
END PROCESS;
------------------------------------------------------------------------------
-- Auxiliary
------------------------------------------------------------------------------
-- Map to slv to ease monitoring in wave window
src_out_data <= i_src_out.data(g_in_dat_w-1 DOWNTO 0);
END str;
/dp_stream_verify.vhd
0,0 → 1,200
-------------------------------------------------------------------------------
--
-- Copyright (C) 2015
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
 
-- Purpose:
-- . The dp_stream_verify verifies the stream of packets with counter data that
-- are generated by dp_stimuli_st.
-- Description:
-- The component can verify a stream:
-- . The sosi control fields are verified conform the bus specifications
-- eg. considering the RL, no missing eop, etc.
-- . The sosi data fields are verified based on their previous value under
-- the assumption that they contain incrementing data. Whether a field
-- is checked depends on verify_snk_in_enable.
--
-- The component also checks whether the stream is active at all. A
-- pulse in verify_expected_snk_in_evt triggers the verification of the
-- corresponding field in snk_in using the expected_snk_in as reference.
--
-- Usage:
-- . See tb_dp_example_no_dut for usage example
--
 
LIBRARY IEEE, common_pkg_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_pkg_lib.common_pkg.ALL;
USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
USE common_pkg_lib.tb_common_pkg.ALL;
USE work.dp_stream_pkg.ALL;
USE work.tb_dp_pkg.ALL;
 
 
ENTITY dp_stream_verify IS
GENERIC (
g_instance_nr : NATURAL := 0;
-- flow control
g_random_w : NATURAL := 14; -- use different random width for stimuli and for verify to have different random sequences
g_pulse_active : NATURAL := 1;
g_pulse_period : NATURAL := 2;
g_flow_control : t_dp_flow_control_enum := e_active; -- always active, random or pulse flow control
-- initializations
g_sync_period : NATURAL := 10;
g_sync_offset : NATURAL := 7;
g_snk_in_cnt_max : t_dp_sosi_unsigned := c_dp_sosi_unsigned_rst; -- default 0 is no wrap
g_snk_in_cnt_gap : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1
-- specific
g_in_dat_w : NATURAL := 32;
g_pkt_len : NATURAL := 16
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Verify data
snk_out : OUT t_dp_siso;
snk_in : IN t_dp_sosi;
 
-- During stimuli
verify_snk_in_enable : IN t_dp_sosi_sl; -- enable to verify that the snk_in fields are incrementing
-- End of stimuli
expected_snk_in : IN t_dp_sosi; -- expected snk_in at verify_expected_snk_in_evt
verify_expected_snk_in_evt : IN t_dp_sosi_sl -- trigger to verify the expected_snk_in
);
END dp_stream_verify;
 
 
ARCHITECTURE tb OF dp_stream_verify IS
 
CONSTANT c_rl : NATURAL := 1;
CONSTANT c_no_dut : BOOLEAN:= TRUE;
SIGNAL random : STD_LOGIC_VECTOR(g_random_w-1 DOWNTO 0) := TO_UVEC(g_instance_nr, g_random_w); -- use different initialization to have different random sequences per stream
SIGNAL pulse : STD_LOGIC;
SIGNAL pulse_en : STD_LOGIC := '1';
SIGNAL i_snk_out : t_dp_siso := c_dp_siso_rdy;
SIGNAL prev_snk_out : t_dp_siso;
SIGNAL hold_snk_in_data : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0); -- used to hold valid data for verify at verify_expected_snk_in_evt
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
SIGNAL prev_snk_in : t_dp_sosi;
SIGNAL hold_snk_in_sop : STD_LOGIC := '0';
SIGNAL detected_snk_in_ctrl : t_dp_sosi_sl := c_dp_sosi_sl_rst;
SIGNAL verify_snk_in_increment : t_dp_sosi_sl := c_dp_sosi_sl_rst;
SIGNAL verify_snk_in_ctrl : t_dp_sosi_sl := c_dp_sosi_sl_rst;
 
SIGNAL exp_size : NATURAL;
SIGNAL cnt_size : NATURAL;
BEGIN
 
snk_out <= i_snk_out;
 
------------------------------------------------------------------------------
-- STREAM CONTROL
------------------------------------------------------------------------------
random <= func_common_random(random) WHEN rising_edge(clk);
proc_common_gen_duty_pulse(g_pulse_active, g_pulse_period, '1', rst, clk, pulse_en, pulse);
 
i_snk_out.ready <= '1' WHEN g_flow_control=e_active ELSE
random(random'HIGH) WHEN g_flow_control=e_random ELSE
pulse WHEN g_flow_control=e_pulse;
------------------------------------------------------------------------------
-- DATA VERIFICATION
------------------------------------------------------------------------------
-- Detect first sync, sop, eop, valid
detected_snk_in_ctrl.sync <= '1' WHEN snk_in.sync='1' AND rising_edge(clk);
detected_snk_in_ctrl.valid <= '1' WHEN snk_in.valid='1' AND rising_edge(clk);
detected_snk_in_ctrl.sop <= '1' WHEN snk_in.sop='1' AND rising_edge(clk);
detected_snk_in_ctrl.eop <= '1' WHEN snk_in.eop='1' AND rising_edge(clk);
-- Verify that the stimuli have been applied at all so at least one active sosi sync, sop, eop, valid field has been detected
proc_dp_verify_value("snk_in.sync", clk, verify_expected_snk_in_evt.sync, expected_snk_in.sync, detected_snk_in_ctrl.sync);
proc_dp_verify_value("snk_in.sop", clk, verify_expected_snk_in_evt.sop, expected_snk_in.sop, detected_snk_in_ctrl.sop);
proc_dp_verify_value("snk_in.eop", clk, verify_expected_snk_in_evt.eop, expected_snk_in.eop, detected_snk_in_ctrl.eop);
proc_dp_verify_value("snk_in.valid", clk, verify_expected_snk_in_evt.valid, expected_snk_in.valid, detected_snk_in_ctrl.valid);
-- Verify that the last sosi data, bsn, channel and err fields are correct
proc_dp_verify_value("snk_in.data", e_equal, clk, verify_expected_snk_in_evt.data, expected_snk_in.data, hold_snk_in_data);
proc_dp_verify_value("snk_in.bsn", e_equal, clk, verify_expected_snk_in_evt.bsn, expected_snk_in.bsn, snk_in.bsn);
proc_dp_verify_value("snk_in.channel", e_equal, clk, verify_expected_snk_in_evt.channel, expected_snk_in.channel, snk_in.channel);
proc_dp_verify_value("snk_in.err", e_equal, clk, verify_expected_snk_in_evt.err, expected_snk_in.err, snk_in.err);
-- Verify that the output is incrementing data, like the input stimuli
p_verify_snk_in_increment : PROCESS(verify_snk_in_enable, detected_snk_in_ctrl)
BEGIN
verify_snk_in_increment <= verify_snk_in_enable;
verify_snk_in_increment.data <= verify_snk_in_enable.data AND detected_snk_in_ctrl.valid;
verify_snk_in_increment.re <= verify_snk_in_enable.re AND detected_snk_in_ctrl.valid;
verify_snk_in_increment.im <= verify_snk_in_enable.im AND detected_snk_in_ctrl.valid;
verify_snk_in_increment.bsn <= verify_snk_in_enable.bsn AND detected_snk_in_ctrl.sop;
verify_snk_in_increment.channel <= verify_snk_in_enable.channel AND detected_snk_in_ctrl.sop;
verify_snk_in_increment.empty <= verify_snk_in_enable.empty AND detected_snk_in_ctrl.eop;
verify_snk_in_increment.err <= verify_snk_in_enable.err AND detected_snk_in_ctrl.eop;
END PROCESS;
proc_dp_verify_data("snk_in.data", c_rl, g_snk_in_cnt_max.data, g_snk_in_cnt_gap.data, clk, verify_snk_in_increment.data, i_snk_out.ready, snk_in.valid, snk_in.data, prev_snk_in.data);
proc_dp_verify_data("snk_in.re", c_rl, g_snk_in_cnt_max.re, g_snk_in_cnt_gap.re, clk, verify_snk_in_increment.re, i_snk_out.ready, snk_in.valid, snk_in.re, prev_snk_in.re);
proc_dp_verify_data("snk_in.im", c_rl, g_snk_in_cnt_max.im, g_snk_in_cnt_gap.im, clk, verify_snk_in_increment.im, i_snk_out.ready, snk_in.valid, snk_in.im, prev_snk_in.im);
proc_dp_verify_data("snk_in.bsn", c_rl, g_snk_in_cnt_max.bsn, g_snk_in_cnt_gap.bsn, clk, verify_snk_in_increment.bsn, i_snk_out.ready, snk_in.sop, snk_in.bsn, prev_snk_in.bsn);
proc_dp_verify_data("snk_in.channel", c_rl, g_snk_in_cnt_max.channel, g_snk_in_cnt_gap.channel, clk, verify_snk_in_increment.channel, i_snk_out.ready, snk_in.sop, snk_in.channel, prev_snk_in.channel);
proc_dp_verify_data("snk_in.empty", c_rl, g_snk_in_cnt_max.empty, g_snk_in_cnt_gap.empty, clk, verify_snk_in_increment.empty, i_snk_out.ready, snk_in.eop, snk_in.empty, prev_snk_in.empty);
proc_dp_verify_data("snk_in.err", c_rl, g_snk_in_cnt_max.err, g_snk_in_cnt_gap.err, clk, verify_snk_in_increment.err, i_snk_out.ready, snk_in.eop, snk_in.err, prev_snk_in.err);
-- Verify that the snk_in control fields are correct
p_verify_snk_in_ctrl: PROCESS(snk_in, verify_snk_in_enable)
BEGIN
verify_snk_in_ctrl.sync <= snk_in.sync AND verify_snk_in_enable.valid AND verify_snk_in_enable.sync;
verify_snk_in_ctrl.sop <= snk_in.sop AND verify_snk_in_enable.valid AND verify_snk_in_enable.sop AND verify_snk_in_enable.eop;
verify_snk_in_ctrl.eop <= snk_in.eop AND verify_snk_in_enable.valid AND verify_snk_in_enable.sop AND verify_snk_in_enable.eop;
verify_snk_in_ctrl.valid <= snk_in.valid AND verify_snk_in_enable.valid;
END PROCESS;
-- Verify that the output sync occurs when expected
proc_dp_verify_sync(g_sync_period, g_sync_offset, clk, detected_snk_in_ctrl.sop, verify_snk_in_ctrl.sync, verify_snk_in_ctrl.sop, snk_in.bsn);
-- Verify output packet ctrl
proc_dp_verify_sop_and_eop(clk, verify_snk_in_ctrl.valid, verify_snk_in_ctrl.sop, verify_snk_in_ctrl.eop, hold_snk_in_sop);
-- Verify output packet block size
exp_size <= g_pkt_len;
proc_dp_verify_block_size(exp_size, clk, verify_snk_in_ctrl.valid, verify_snk_in_ctrl.sop, verify_snk_in_ctrl.eop, cnt_size);
 
-- Verify output ready latency
proc_dp_verify_valid(clk, detected_snk_in_ctrl.valid, i_snk_out.ready, prev_snk_out.ready, verify_snk_in_ctrl.valid);
------------------------------------------------------------------------------
-- Auxiliary
------------------------------------------------------------------------------
-- Map to slv to ease monitoring in wave window
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
hold_snk_in_data <= snk_in.data WHEN snk_in.valid='1';
END tb;
/hdllib.cfg
0,0 → 1,20
hdl_lib_name = dp_pkg
hdl_library_clause_name = dp_pkg_lib
hdl_lib_uses_synth = common_pkg
hdl_lib_uses_sim =
hdl_lib_technology =
 
synth_files =
dp_stream_pkg.vhd
tb_dp_pkg.vhd
dp_stream_stimuli.vhd
dp_stream_verify.vhd
test_bench_files =
 
regression_test_vhdl =
[modelsim_project_file]
 
 
[quartus_project_file]
/tb_dp_pkg.vhd
0,0 → 1,2413
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- 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/>.
--
-------------------------------------------------------------------------------
 
LIBRARY IEEE, common_pkg_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_pkg_lib.common_pkg.ALL;
USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
USE common_pkg_lib.tb_common_pkg.ALL;
USE work.dp_stream_pkg.ALL;
 
 
PACKAGE tb_dp_pkg IS
 
------------------------------------------------------------------------------
-- Purpose:
--
-- Test bench package for applying stimuli to a streaming data path. The
-- input is counter data, the output is verified and an error is reported
-- if a counter value is missing or duplicate.
--
-- Description:
--
-- The test is divided into intervals marked by sync to start a new subtest
-- named by state. New subtests can be added by adding an extra sync interval
-- and state name to this package. In each subtest the streaming interface
-- DUT can be verified for different situations by manipulating:
-- . cnt_en : cnt_en not always active when in_ready is asserted
-- . out_ready : out_ready not always active
--
-- Remarks:
-- . See e.g. tb_dp_pipeline.vhd for how to use the procedures.
-- . To run all stimuli in Modelsim do:
-- > as 10
-- > run 400 us
------------------------------------------------------------------------------
 
CONSTANT clk_period : TIME := 10 ns; -- 100 MHz
CONSTANT c_dp_sync_interval : NATURAL := 3000;
CONSTANT c_dp_test_interval : NATURAL := 100;
CONSTANT c_dp_nof_toggle : NATURAL := 40;
CONSTANT c_dp_nof_both : NATURAL := 50;
 
-- The test bench uses other field widths than the standard t_dp_sosi record field widths, the assumptions are:
-- . c_dp_data_w < c_dp_stream_data_w
-- . c_dp_data_w > c_dp_stream_empty_w
-- . c_dp_data_w > c_dp_stream_channel_w
-- . c_dp_data_w > c_dp_stream_error_w
CONSTANT c_dp_data_w : NATURAL := c_word_w; -- =32, choose wide enough to avoid out_data wrap around issue for p_verify
CONSTANT c_dp_bsn_w : NATURAL := c_dp_data_w; -- c_dp_stream_bsn_w;
CONSTANT c_dp_empty_w : NATURAL := c_dp_stream_empty_w;
CONSTANT c_dp_channel_w : NATURAL := c_dp_stream_channel_w;
CONSTANT c_dp_channel_user_w : NATURAL := c_dp_stream_channel_w/2; -- support some bits for mux input user streams channel widths
CONSTANT c_dp_channel_mux_w : NATURAL :=(c_dp_stream_channel_w+1)/2; -- support rest bits for the nof input ports of a mux
CONSTANT c_dp_error_w : NATURAL := c_dp_stream_error_w;
 
TYPE t_dp_data_arr IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
-- The state name tells what kind of test is done in the sync interval
TYPE t_dp_state_enum IS (
s_idle,
s_both_active,
s_pull_down_out_ready,
s_pull_down_cnt_en,
s_toggle_out_ready,
s_toggle_cnt_en,
s_toggle_both,
s_pulse_cnt_en,
s_chirp_out_ready,
s_random,
s_done
);
 
TYPE t_dp_value_enum IS (
e_equal,
e_at_least
);
-- always active, random or pulse flow control
TYPE t_dp_flow_control_enum IS (
e_active,
e_random,
e_pulse
);
TYPE t_dp_flow_control_enum_arr IS ARRAY (NATURAL RANGE <>) OF t_dp_flow_control_enum;
CONSTANT c_dp_flow_control_enum_arr : t_dp_flow_control_enum_arr := (e_active, e_random, e_pulse); -- array all possible values that can be iterated over
------------------------------------------------------------------------------
-- Stream source functions
------------------------------------------------------------------------------
-- Block data generator with feedforward throttle control
-- !!! old style: sync before sop
-- !!! used by tb_dp_packetizing, do not use for new DP components
PROCEDURE proc_dp_gen_block_data(CONSTANT c_nof_block_per_sync : IN NATURAL;
CONSTANT c_block_size : IN NATURAL;
CONSTANT c_gap_size : IN NATURAL;
CONSTANT c_throttle_num : IN NATURAL;
CONSTANT c_throttle_den : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync_nr : INOUT NATURAL;
SIGNAL block_nr : INOUT NATURAL;
SIGNAL cnt_sync : OUT STD_LOGIC;
SIGNAL cnt_val : OUT STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR);
-- Block data generator with ready flow control and symbols counter
PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_use_data : IN BOOLEAN; -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X'
CONSTANT c_data_w : IN NATURAL; -- data width for the data, re and im fields
CONSTANT c_symbol_w : IN NATURAL; -- c_data_w/c_symbol_w must be an integer
CONSTANT c_symbol_init : IN NATURAL; -- init counter for symbols in data field
CONSTANT c_symbol_re_init : IN NATURAL; -- init counter for symbols in re field
CONSTANT c_symbol_im_init : IN NATURAL; -- init counter for symbols in im field
CONSTANT c_nof_symbols : IN NATURAL; -- nof symbols per frame for the data, re and im fields
CONSTANT c_channel : IN NATURAL; -- channel field
CONSTANT c_error : IN NATURAL; -- error field
CONSTANT c_sync : IN STD_LOGIC; -- when '1' issue sync pulse during this block
CONSTANT c_bsn : IN STD_LOGIC_VECTOR; -- bsn field
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi);
PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w : IN NATURAL; -- data width for the data field
CONSTANT c_symbol_init : IN NATURAL; -- init counter for the data in the data field
CONSTANT c_nof_symbols : IN NATURAL; -- nof symbols per frame for the data fields
CONSTANT c_channel : IN NATURAL; -- channel field
CONSTANT c_error : IN NATURAL; -- error field
CONSTANT c_sync : IN STD_LOGIC; -- when '1' issue sync pulse during this block
CONSTANT c_bsn : IN STD_LOGIC_VECTOR; -- bsn field
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi);
-- Handle stream ready signal, only support RL=0 or 1.
PROCEDURE proc_dp_stream_ready_latency(CONSTANT c_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL ready : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '1' then active output when ready
CONSTANT c_sync : IN STD_LOGIC;
CONSTANT c_valid : IN STD_LOGIC;
CONSTANT c_sop : IN STD_LOGIC;
CONSTANT c_eop : IN STD_LOGIC;
SIGNAL out_sync : OUT STD_LOGIC;
SIGNAL out_valid : OUT STD_LOGIC;
SIGNAL out_sop : OUT STD_LOGIC;
SIGNAL out_eop : OUT STD_LOGIC);
-- Initialize the data per symbol
FUNCTION func_dp_data_init(c_data_w, c_symbol_w, init : NATURAL) RETURN STD_LOGIC_VECTOR;
-- Increment the data per symbol
FUNCTION func_dp_data_incr(c_data_w, c_symbol_w : NATURAL; data : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
-- Generate a counter data with valid
PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_data_init : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi);
 
-- As above but with counter max
PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_data_init : IN NATURAL;
CONSTANT c_data_max : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi);
-- Generate a frame with symbols counter
PROCEDURE proc_dp_gen_frame(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_symbol_w : IN NATURAL; -- c_data_w/c_symbol_w must be an integer
CONSTANT c_symbol_init : IN NATURAL;
CONSTANT c_nof_symbols : IN NATURAL;
CONSTANT c_bsn : IN NATURAL;
CONSTANT c_sync : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi);
 
-- Input data counter
PROCEDURE proc_dp_cnt_dat(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR);
 
PROCEDURE proc_dp_cnt_dat(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
SIGNAL cnt_val : INOUT STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR);
-- Transmit data
PROCEDURE proc_dp_tx_data(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL cnt_val : IN STD_LOGIC;
SIGNAL cnt_dat : IN STD_LOGIC_VECTOR;
SIGNAL tx_data : INOUT t_dp_data_arr;
SIGNAL tx_val : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data : OUT STD_LOGIC_VECTOR;
SIGNAL out_val : OUT STD_LOGIC);
-- Transmit data control (use for sop, eop)
PROCEDURE proc_dp_tx_ctrl(CONSTANT c_offset : IN NATURAL;
CONSTANT c_period : IN NATURAL;
SIGNAL data : IN STD_LOGIC_VECTOR;
SIGNAL valid : IN STD_LOGIC;
SIGNAL ctrl : OUT STD_LOGIC);
-- Define sync interval
PROCEDURE proc_dp_sync_interval(SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : OUT STD_LOGIC);
 
-- Stimuli for cnt_en
PROCEDURE proc_dp_count_en(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL lfsr : INOUT STD_LOGIC_VECTOR;
SIGNAL state : OUT t_dp_state_enum;
SIGNAL done : OUT STD_LOGIC;
SIGNAL tb_end : OUT STD_LOGIC;
SIGNAL cnt_en : OUT STD_LOGIC);
 
------------------------------------------------------------------------------
-- Stream sink functions
------------------------------------------------------------------------------
-- Stimuli for out_ready
PROCEDURE proc_dp_out_ready(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL lfsr : INOUT STD_LOGIC_VECTOR;
SIGNAL out_ready : OUT STD_LOGIC);
-- DUT output verify enable
PROCEDURE proc_dp_verify_en(CONSTANT c_delay : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC);
PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN BOOLEAN;
SIGNAL clk : IN STD_LOGIC;
SIGNAL valid : IN STD_LOGIC;
SIGNAL sop : IN STD_LOGIC;
SIGNAL eop : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC);
-- Run and verify for some cycles
PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk : IN NATURAL;
CONSTANT nof_verify_clk : IN NATURAL;
CONSTANT nof_post_clk : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC);
-- Verify the expected value
PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
CONSTANT mode : IN t_dp_value_enum;
SIGNAL clk : IN STD_LOGIC;
SIGNAL en : IN STD_LOGIC;
SIGNAL exp : IN STD_LOGIC_VECTOR;
SIGNAL res : IN STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum;
SIGNAL clk : IN STD_LOGIC;
SIGNAL en : IN STD_LOGIC;
SIGNAL exp : IN STD_LOGIC_VECTOR;
SIGNAL res : IN STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL en : IN STD_LOGIC;
SIGNAL exp : IN STD_LOGIC;
SIGNAL res : IN STD_LOGIC);
-- Verify output global and local BSN
-- . incrementing or replicated global BSN
-- . incrementing local BSN that starts at 1
PROCEDURE proc_dp_verify_bsn(CONSTANT c_use_local_bsn : IN BOOLEAN; -- use local BSN or only use global BSN
CONSTANT c_global_bsn_increment : IN POSITIVE; -- increment per global BSN
CONSTANT c_nof_replicated_global_bsn : IN POSITIVE; -- number of replicated global BSN
CONSTANT c_block_per_sync : IN POSITIVE; -- of sop/eop blocks per sync interval
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_sync : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_bsn : IN STD_LOGIC_VECTOR;
SIGNAL verify_en : INOUT STD_LOGIC; -- initialize '0', becomes '1' when bsn verification starts
SIGNAL cnt_replicated_global_bsn : INOUT NATURAL;
SIGNAL prev_out_bsn_global : INOUT STD_LOGIC_VECTOR;
SIGNAL prev_out_bsn_local : INOUT STD_LOGIC_VECTOR);
-- Verify incrementing data
-- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0
-- . default increment by +1, but also allow an increment by +c_out_data_gap
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_out_data_max : IN UNSIGNED;
CONSTANT c_out_data_gap : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify the DUT incrementing output data that wraps in range 0 ... c_out_data_max
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_out_data_max : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify the DUT incrementing output data, fixed increment +1
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC; -- by using sop or eop proc_dp_verify_data() can also be used to verify other SOSI fields like bsn, error, channel, empty
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify incrementing data with RL > 0 or no flow control, support wrap at maximum and increment gap
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN UNSIGNED;
CONSTANT c_out_data_gap : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN NATURAL;
CONSTANT c_out_data_gap : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify incrementing data with RL > 0 or no flow control, fixed increment +1
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify the DUT output symbols
PROCEDURE proc_dp_verify_symbols(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_symbol_w : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL out_empty : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR);
-- Verify the DUT output data with empty
PROCEDURE proc_dp_verify_data_empty(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_last_word : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL out_eop_1 : INOUT STD_LOGIC;
SIGNAL out_eop_2 : INOUT STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL out_data_1 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data_2 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data_3 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_empty : IN STD_LOGIC_VECTOR;
SIGNAL out_empty_1 : INOUT STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_other_sosi(CONSTANT c_str : IN STRING;
CONSTANT c_exp_data : IN STD_LOGIC_VECTOR;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL res_data : IN STD_LOGIC_VECTOR);
PROCEDURE proc_dp_verify_valid(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL prev_out_ready : INOUT STD_LOGIC_VECTOR;
SIGNAL out_val : IN STD_LOGIC);
PROCEDURE proc_dp_verify_valid(SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL prev_out_ready : INOUT STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC);
-- Verify the DUT output sync
PROCEDURE proc_dp_verify_sync(CONSTANT c_sync_period : IN NATURAL;
CONSTANT c_sync_offset : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL sop : IN STD_LOGIC;
SIGNAL bsn : IN STD_LOGIC_VECTOR);
-- Verify the DUT output sop and eop
PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_verify_valid : IN BOOLEAN;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC);
PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC);
PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC);
PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL alt_size : IN NATURAL; -- alternative size (eg. use exp_size'last_value)
SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL);
PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL);
PROCEDURE proc_dp_verify_block_size(SIGNAL alt_size : IN NATURAL; -- alternative size (eg. use exp_size'last_value)
SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL);
PROCEDURE proc_dp_verify_block_size(SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL);
-- Verify the DUT output invalid between frames
PROCEDURE proc_dp_verify_gap_invalid(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_val : IN STD_LOGIC;
SIGNAL in_sop : IN STD_LOGIC;
SIGNAL in_eop : IN STD_LOGIC;
SIGNAL out_gap : INOUT STD_LOGIC); -- declare initial gap signal = '1'
-- Verify the DUT output control (use for sop, eop)
PROCEDURE proc_dp_verify_ctrl(CONSTANT c_offset : IN NATURAL;
CONSTANT c_period : IN NATURAL;
CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL data : IN STD_LOGIC_VECTOR;
SIGNAL valid : IN STD_LOGIC;
SIGNAL ctrl : IN STD_LOGIC);
-- Wait for stream valid
PROCEDURE proc_dp_stream_valid(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC);
-- Wait for stream valid AND sop
PROCEDURE proc_dp_stream_valid_sop(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC;
SIGNAL in_sop : IN STD_LOGIC);
-- Wait for stream valid AND eop
PROCEDURE proc_dp_stream_valid_eop(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC;
SIGNAL in_eop : IN STD_LOGIC);
END tb_dp_pkg;
 
 
PACKAGE BODY tb_dp_pkg IS
 
------------------------------------------------------------------------------
-- PROCEDURE: Block data generator with feedforward throttle control
------------------------------------------------------------------------------
PROCEDURE proc_dp_gen_block_data(CONSTANT c_nof_block_per_sync : IN NATURAL;
CONSTANT c_block_size : IN NATURAL;
CONSTANT c_gap_size : IN NATURAL;
CONSTANT c_throttle_num : IN NATURAL;
CONSTANT c_throttle_den : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync_nr : INOUT NATURAL;
SIGNAL block_nr : INOUT NATURAL;
SIGNAL cnt_sync : OUT STD_LOGIC;
SIGNAL cnt_val : OUT STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR) IS
CONSTANT c_start_delay : NATURAL := 10;
VARIABLE v_throttle : NATURAL;
BEGIN
sync_nr <= 0;
block_nr <= 0;
cnt_sync <= '0';
cnt_val <= '0';
cnt_dat <= (cnt_dat'RANGE=>'1'); -- -1, so first valid cnt_dat starts at 0
-- allow some clock cycles before start after rst release
WAIT UNTIL rst='0';
FOR I IN 0 TO c_start_delay-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- output first sync
cnt_sync <= '1';
WAIT UNTIL rising_edge(clk);
cnt_sync <= '0';
FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
WHILE TRUE LOOP
-- output block
IF c_throttle_num >= c_throttle_den THEN
-- no need to throttle, so cnt_val active during whole data block
FOR I IN 0 TO c_block_size-1 LOOP
cnt_val <= '1';
cnt_dat <= INCR_UVEC(cnt_dat, 1);
WAIT UNTIL rising_edge(clk);
END LOOP;
ELSE
-- throttle cnt_val, so c_throttle_num active cnt_val cycles per c_throttle_den cycles
FOR I IN 0 TO c_block_size/c_throttle_num-1 LOOP
FOR J IN 0 TO c_throttle_num-1 LOOP
cnt_val <= '1';
cnt_dat <= INCR_UVEC(cnt_dat, 1);
WAIT UNTIL rising_edge(clk);
END LOOP;
FOR J IN 0 TO c_throttle_den-c_throttle_num-1 LOOP
cnt_val <= '0';
WAIT UNTIL rising_edge(clk);
END LOOP;
END LOOP;
END IF;
cnt_val <= '0';
-- output sync for next block at first sample of gap
IF block_nr>0 AND ((block_nr + 1) MOD c_nof_block_per_sync)=0 THEN
cnt_sync <= '1';
sync_nr <= sync_nr+1;
END IF;
WAIT UNTIL rising_edge(clk);
-- output rest of the gap
cnt_sync <= '0';
FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- next block
block_nr <= block_nr+1;
END LOOP;
END proc_dp_gen_block_data;
------------------------------------------------------------------------------
-- PROCEDURE: Block data generator with ready flow control and symbols counter
-- . dependent on in_en and src_in.ready
-- . optional sync pulse at end of frame
------------------------------------------------------------------------------
PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_use_data : IN BOOLEAN; -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X'
CONSTANT c_data_w : IN NATURAL; -- data width for the data, re and im fields
CONSTANT c_symbol_w : IN NATURAL; -- c_data_w/c_symbol_w must be an integer
CONSTANT c_symbol_init : IN NATURAL; -- init counter for symbols in data field
CONSTANT c_symbol_re_init : IN NATURAL; -- init counter for symbols in re field
CONSTANT c_symbol_im_init : IN NATURAL; -- init counter for symbols in im field
CONSTANT c_nof_symbols : IN NATURAL; -- nof symbols per frame for the data, re and im fields
CONSTANT c_channel : IN NATURAL; -- channel field
CONSTANT c_error : IN NATURAL; -- error field
CONSTANT c_sync : IN STD_LOGIC; -- when '1' issue sync pulse during this block
CONSTANT c_bsn : IN STD_LOGIC_VECTOR; -- bsn field
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi) IS
CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
CONSTANT c_div : NATURAL := c_nof_symbols / c_nof_symbols_per_data;
CONSTANT c_mod : NATURAL := c_nof_symbols MOD c_nof_symbols_per_data;
CONSTANT c_empty : NATURAL := sel_a_b(c_mod, c_nof_symbols_per_data - c_mod, 0);
CONSTANT c_nof_data : NATURAL := sel_a_b(c_mod, 1, 0) + c_div;
VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_init);
VARIABLE v_re : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_re_init);
VARIABLE v_im : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_im_init);
BEGIN
src_out <= c_dp_sosi_rst;
IF src_in.xon='1' THEN
-- Generate this block
src_out.bsn <= RESIZE_DP_BSN(c_bsn);
src_out.empty <= TO_DP_EMPTY(c_empty);
src_out.channel <= TO_DP_CHANNEL(c_channel);
src_out.err <= TO_DP_ERROR(c_error);
IF c_use_data=TRUE THEN src_out.data <= RESIZE_DP_DATA(v_data); END IF;
IF c_use_data=FALSE THEN src_out.re <= RESIZE_DP_DSP_DATA(v_re); END IF;
IF c_use_data=FALSE THEN src_out.im <= RESIZE_DP_DSP_DATA(v_im); END IF;
IF c_nof_data>1 THEN
-- . sop
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
-- . valid
FOR I IN 1 TO c_nof_data-2 LOOP
v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
v_re := func_dp_data_incr(c_data_w, c_symbol_w, v_re);
v_im := func_dp_data_incr(c_data_w, c_symbol_w, v_im);
IF c_use_data=TRUE THEN src_out.data <= RESIZE_DP_DATA(v_data); END IF;
IF c_use_data=FALSE THEN src_out.re <= RESIZE_DP_DSP_DATA(v_re); END IF;
IF c_use_data=FALSE THEN src_out.im <= RESIZE_DP_DSP_DATA(v_im); END IF;
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
END LOOP;
-- . eop
v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
v_re := func_dp_data_incr(c_data_w, c_symbol_w, v_re);
v_im := func_dp_data_incr(c_data_w, c_symbol_w, v_im);
IF c_use_data=TRUE THEN src_out.data <= RESIZE_DP_DATA(v_data); END IF;
IF c_use_data=FALSE THEN src_out.re <= RESIZE_DP_DSP_DATA(v_re); END IF;
IF c_use_data=FALSE THEN src_out.im <= RESIZE_DP_DSP_DATA(v_im); END IF;
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
ELSE
-- . sop and eop, frame has only one word
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
END IF;
ELSE
-- Skip this block
proc_common_wait_some_cycles(clk, c_nof_data);
END IF;
END proc_dp_gen_block_data;
PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w : IN NATURAL; -- data width for the data field
CONSTANT c_symbol_init : IN NATURAL; -- init counter for the data in the data field
CONSTANT c_nof_symbols : IN NATURAL; -- nof symbols per frame for the data fields
CONSTANT c_channel : IN NATURAL; -- channel field
CONSTANT c_error : IN NATURAL; -- error field
CONSTANT c_sync : IN STD_LOGIC; -- when '1' issue sync pulse during this block
CONSTANT c_bsn : IN STD_LOGIC_VECTOR; -- bsn field
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi) IS
BEGIN
proc_dp_gen_block_data(1, TRUE, c_data_w, c_data_w, c_symbol_init, 0, 0, c_nof_symbols, c_channel, c_error, c_sync, c_bsn, clk, in_en, src_in, src_out);
END proc_dp_gen_block_data;
------------------------------------------------------------------------------
-- PROCEDURE: Handle stream ready signal
-- . output active when src_in is ready and in_en='1'
-- . only support RL=0 or 1, support for RL>1 requires keeping previous ready information in a STD_LOGIC_VECTOR(RL-1 DOWNTO 0).
------------------------------------------------------------------------------
PROCEDURE proc_dp_stream_ready_latency(CONSTANT c_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL ready : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
CONSTANT c_sync : IN STD_LOGIC;
CONSTANT c_valid : IN STD_LOGIC;
CONSTANT c_sop : IN STD_LOGIC;
CONSTANT c_eop : IN STD_LOGIC;
SIGNAL out_sync : OUT STD_LOGIC;
SIGNAL out_valid : OUT STD_LOGIC;
SIGNAL out_sop : OUT STD_LOGIC;
SIGNAL out_eop : OUT STD_LOGIC) IS
BEGIN
-- Default no output
out_sync <= '0';
out_valid <= '0';
out_sop <= '0';
out_eop <= '0';
-- Skip cycles until in_en='1'
WHILE in_en='0' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
-- Active output when ready
-- . RL = 0
IF c_latency=0 THEN
-- show the available output until acknowledge
out_sync <= c_sync;
out_valid <= c_valid;
out_sop <= c_sop;
out_eop <= c_eop;
WAIT UNTIL rising_edge(clk);
WHILE ready /= '1' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
-- ready has acknowledged the valid output
END IF;
-- . RL = 1
IF c_latency=1 THEN
-- no valid output until request
WHILE ready /= '1' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
-- ready has requested this valid output
out_sync <= c_sync;
out_valid <= c_valid;
out_sop <= c_sop;
out_eop <= c_eop;
WAIT UNTIL rising_edge(clk);
END IF;
-- Return with no active output
out_sync <= '0';
out_valid <= '0';
out_sop <= '0';
out_eop <= '0';
END proc_dp_stream_ready_latency;
 
------------------------------------------------------------------------------
-- FUNCTION: Initialize the data per symbol
-- . use big endian
-- . if c_data_w=32, c_symbol_w=8, init=3 then return 0x03040506
------------------------------------------------------------------------------
FUNCTION func_dp_data_init(c_data_w, c_symbol_w, init : NATURAL) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
VARIABLE v_sym : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
BEGIN
v_data := (OTHERS=>'0');
v_sym := TO_UVEC(init, c_symbol_w);
FOR I IN c_nof_symbols_per_data-1 DOWNTO 0 LOOP
v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_sym;
v_sym := INCR_UVEC(v_sym, 1);
END LOOP;
RETURN v_data;
END func_dp_data_init;
------------------------------------------------------------------------------
-- FUNCTION: Increment the data per symbol
-- . use big endian
-- . if c_data_w=32, c_symbol_w=8 then 0x00010203 returns 0x04050607
-- . the actual data'LENGTH must be >= c_data_w, unused bits become 0
-- . c_data_w/c_symbol_w must be an integer
------------------------------------------------------------------------------
FUNCTION func_dp_data_incr(c_data_w, c_symbol_w : NATURAL; data : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
VARIABLE v_data : STD_LOGIC_VECTOR(data'LENGTH-1 DOWNTO 0);
VARIABLE v_sym : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
BEGIN
v_data := (OTHERS=>'0');
v_sym := data(c_symbol_w-1 DOWNTO 0);
FOR I IN c_nof_symbols_per_data-1 DOWNTO 0 LOOP
v_sym := INCR_UVEC(v_sym, 1);
v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_sym;
END LOOP;
RETURN v_data;
END func_dp_data_incr;
------------------------------------------------------------------------------
-- PROCEDURE: Generate counter data with valid
-- . Output counter data dependent on in_en and src_in.ready
------------------------------------------------------------------------------
PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_data_init : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi) IS
VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_UVEC(c_data_init, c_data_w);
BEGIN
src_out <= c_dp_sosi_rst;
src_out.data <= RESIZE_DP_DATA(v_data);
IF rst='0' THEN
WAIT UNTIL rising_edge(clk);
WHILE TRUE LOOP
src_out.data <= RESIZE_DP_DATA(v_data);
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
v_data := INCR_UVEC(v_data, 1);
END LOOP;
END IF;
END proc_dp_gen_data;
 
 
------------------------------------------------------------------------------
-- PROCEDURE: Generate counter data with valid
-- . Output counter data dependent on in_en and src_in.ready
-- . with maximum count value
------------------------------------------------------------------------------
PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_data_init : IN NATURAL;
CONSTANT c_data_max : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi) IS
VARIABLE v_cnt : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_UVEC(c_data_init, c_data_w);
BEGIN
src_out <= c_dp_sosi_rst;
src_out.data <= RESIZE_DP_DATA(v_cnt);
IF rst='0' THEN
WAIT UNTIL rising_edge(clk);
WHILE TRUE LOOP
src_out.data <= RESIZE_DP_DATA(v_cnt);
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
IF TO_UINT(v_cnt)=c_data_max THEN
v_cnt := TO_UVEC(c_data_init, c_data_w);
ELSE
v_cnt := INCR_UVEC(v_cnt, 1);
END IF;
END LOOP;
END IF;
END proc_dp_gen_data;
------------------------------------------------------------------------------
-- PROCEDURE: Generate a frame with symbols counter
-- . dependent on in_en and src_in.ready
------------------------------------------------------------------------------
PROCEDURE proc_dp_gen_frame(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency()
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_symbol_w : IN NATURAL; -- c_data_w/c_symbol_w must be an integer
CONSTANT c_symbol_init : IN NATURAL;
CONSTANT c_nof_symbols : IN NATURAL;
CONSTANT c_bsn : IN NATURAL;
CONSTANT c_sync : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready
SIGNAL src_in : IN t_dp_siso;
SIGNAL src_out : OUT t_dp_sosi) IS
CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
CONSTANT c_div : NATURAL := c_nof_symbols / c_nof_symbols_per_data;
CONSTANT c_mod : NATURAL := c_nof_symbols MOD c_nof_symbols_per_data;
CONSTANT c_empty : NATURAL := sel_a_b(c_mod, c_nof_symbols_per_data - c_mod, 0);
CONSTANT c_nof_data : NATURAL := sel_a_b(c_mod, 1, 0) + c_div;
VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_init);
BEGIN
src_out <= c_dp_sosi_rst;
src_out.bsn <= TO_DP_BSN(c_bsn);
src_out.empty <= TO_DP_EMPTY(c_empty);
src_out.data <= RESIZE_DP_DATA(v_data);
IF c_nof_data>1 THEN
-- . sop
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
-- . valid
FOR I IN 1 TO c_nof_data-2 LOOP
v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
src_out.data <= RESIZE_DP_DATA(v_data);
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
END LOOP;
-- . eop
v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
src_out.data <= RESIZE_DP_DATA(v_data);
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
ELSE
-- . sop and eop, frame has only one word
proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
END IF;
src_out.sync <= '0';
src_out.valid <= '0';
src_out.sop <= '0';
src_out.eop <= '0';
END proc_dp_gen_frame;
------------------------------------------------------------------------------
-- PROCEDURE: Input data counter
------------------------------------------------------------------------------
PROCEDURE proc_dp_cnt_dat(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR) IS
BEGIN
IF rst='1' THEN
cnt_dat <= (cnt_dat'RANGE=>'0');
ELSIF rising_edge(clk) THEN
IF in_en='1' THEN
cnt_dat <= STD_LOGIC_VECTOR(UNSIGNED(cnt_dat)+1);
END IF;
END IF;
END proc_dp_cnt_dat;
PROCEDURE proc_dp_cnt_dat(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL in_en : IN STD_LOGIC;
SIGNAL cnt_val : INOUT STD_LOGIC;
SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR) IS
BEGIN
IF rst='1' THEN
cnt_val <= '0';
cnt_dat <= (cnt_dat'RANGE=>'0');
ELSIF rising_edge(clk) THEN
cnt_val <= '0';
IF in_en='1' THEN
cnt_val <= '1';
cnt_dat <= STD_LOGIC_VECTOR(UNSIGNED(cnt_dat)+1);
END IF;
END IF;
END proc_dp_cnt_dat;
------------------------------------------------------------------------------
-- PROCEDURE: Transmit data
------------------------------------------------------------------------------
PROCEDURE proc_dp_tx_data(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL cnt_val : IN STD_LOGIC;
SIGNAL cnt_dat : IN STD_LOGIC_VECTOR;
SIGNAL tx_data : INOUT t_dp_data_arr;
SIGNAL tx_val : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data : OUT STD_LOGIC_VECTOR;
SIGNAL out_val : OUT STD_LOGIC) IS
CONSTANT c_void : NATURAL := sel_a_b(c_ready_latency, 1, 0); -- used to avoid empty range VHDL warnings when c_ready_latency=0
BEGIN
-- TX data array for output ready latency [c_ready_latency], index [0] for zero latency combinatorial
tx_data(0) <= cnt_dat;
tx_val( 0) <= cnt_val;
IF rst='1' THEN
tx_data(1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>(OTHERS=>'0'));
tx_val( 1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>'0');
ELSIF rising_edge(clk) THEN
tx_data(1 TO c_ready_latency+c_void) <= tx_data(0 TO c_ready_latency+c_void-1);
tx_val( 1 TO c_ready_latency+c_void) <= tx_val( 0 TO c_ready_latency+c_void-1);
END IF;
out_data <= tx_data(c_ready_latency);
out_val <= tx_val(c_ready_latency);
END proc_dp_tx_data;
------------------------------------------------------------------------------
-- PROCEDURE: Transmit data control (use for sop, eop)
------------------------------------------------------------------------------
PROCEDURE proc_dp_tx_ctrl(CONSTANT c_offset : IN NATURAL;
CONSTANT c_period : IN NATURAL;
SIGNAL data : IN STD_LOGIC_VECTOR;
SIGNAL valid : IN STD_LOGIC;
SIGNAL ctrl : OUT STD_LOGIC) IS
VARIABLE v_data : INTEGER;
BEGIN
v_data := TO_UINT(data);
ctrl <= '0';
IF valid='1' AND ((v_data-c_offset) MOD c_period)=0 THEN
ctrl <= '1';
END IF;
END proc_dp_tx_ctrl;
------------------------------------------------------------------------------
-- PROCEDURE: Define test sync interval
------------------------------------------------------------------------------
PROCEDURE proc_dp_sync_interval(SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : OUT STD_LOGIC) IS
BEGIN
sync <= '0';
FOR I IN 1 TO c_dp_sync_interval-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
sync <= '1';
WAIT UNTIL rising_edge(clk);
END proc_dp_sync_interval;
 
------------------------------------------------------------------------------
-- PROCEDURE: Stimuli for cnt_en
------------------------------------------------------------------------------
PROCEDURE proc_dp_count_en(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL lfsr : INOUT STD_LOGIC_VECTOR;
SIGNAL state : OUT t_dp_state_enum;
SIGNAL done : OUT STD_LOGIC;
SIGNAL tb_end : OUT STD_LOGIC;
SIGNAL cnt_en : OUT STD_LOGIC) IS
BEGIN
-- The counter operates at zero latency
state <= s_idle;
done <= '0';
tb_end <= '0';
cnt_en <= '0';
WAIT UNTIL rst='0';
WAIT UNTIL rising_edge(clk);
-- The cnt_val may be asserted for every active in_ready, but als support
-- cnt_val not asserted for every asserted in_ready.
 
----------------------------------------------------------------------------
-- Interval 1
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_both_active;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 2
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_pull_down_out_ready;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 3
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_pull_down_cnt_en;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 3 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 4 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 5 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 6 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 7 cycle
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 4
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_toggle_out_ready;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 5
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_toggle_cnt_en;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-1 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-2 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 2-1 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2-2 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-3 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 3-1 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 2-3 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 3-2 toggle
cnt_en <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
cnt_en <= '1';
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Interval 6
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_toggle_both;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
FOR I IN 1 TO c_dp_nof_both LOOP
cnt_en <= '0';
FOR J IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
cnt_en <= '1';
FOR J IN I TO c_dp_nof_both LOOP WAIT UNTIL rising_edge(clk); END LOOP;
END LOOP;
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 7
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_pulse_cnt_en;
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
FOR I IN 1 TO 15 LOOP
FOR J IN 1 TO 15 LOOP
cnt_en <= '0';
FOR K IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
cnt_en <= '1';
WAIT UNTIL rising_edge(clk);
END LOOP;
FOR J IN 1 TO 20 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
END LOOP;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Interval 8
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_chirp_out_ready;
cnt_en <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Interval 9
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_random;
cnt_en <= '1';
FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP
lfsr <= func_common_random(lfsr);
cnt_en <= lfsr(lfsr'HIGH);
WAIT UNTIL rising_edge(clk);
END LOOP;
----------------------------------------------------------------------------
-- Done
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
state <= s_done;
WAIT UNTIL rising_edge(clk);
cnt_en <= '0';
-- pulse done
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
done <= '1';
WAIT UNTIL rising_edge(clk);
done <= '0';
----------------------------------------------------------------------------
-- Testbench end
----------------------------------------------------------------------------
-- set tb_end
WAIT UNTIL sync='1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
tb_end <= '1';
WAIT;
END proc_dp_count_en;
 
 
------------------------------------------------------------------------------
-- PROCEDURE: Stimuli for out_ready
------------------------------------------------------------------------------
PROCEDURE proc_dp_out_ready(SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL lfsr : INOUT STD_LOGIC_VECTOR;
SIGNAL out_ready : OUT STD_LOGIC) IS
BEGIN
out_ready <= '0';
WAIT UNTIL rst='0';
WAIT UNTIL rising_edge(clk);
 
----------------------------------------------------------------------------
-- Interval 1 : Assert both cnt_en and out_ready
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 2 : Make out_ready low for 1 or more cycles
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 3 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 4 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 5 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 6 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 7 cycle
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Interval 3
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 4 : Toggle out_ready for 1 or more cycles
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-1 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-2 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2-1 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2-2 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 1-3 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
-- . 3-1 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 2-3 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . 3-2 toggle
out_ready <= '0';
FOR I IN 1 TO c_dp_nof_toggle LOOP
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
out_ready <= '1';
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 5
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 6
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
FOR I IN 1 TO c_dp_nof_both LOOP
out_ready <= '0';
FOR J IN I TO c_dp_nof_both LOOP WAIT UNTIL rising_edge(clk); END LOOP;
out_ready <= '1';
FOR J IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
END LOOP;
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 7
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
----------------------------------------------------------------------------
-- Interval 8 : Chirp out_ready
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
 
-- . slow toggle
out_ready <= '0';
FOR I IN 0 TO c_dp_nof_toggle LOOP
out_ready <= '0';
FOR J IN 0 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
out_ready <= '1';
FOR J IN 0 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
END LOOP;
out_ready <= '1';
FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Interval 9 : Random
----------------------------------------------------------------------------
WAIT UNTIL sync='1';
out_ready <= '1';
FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP
lfsr <= func_common_random(lfsr);
out_ready <= lfsr(lfsr'HIGH);
WAIT UNTIL rising_edge(clk);
END LOOP;
----------------------------------------------------------------------------
-- Done
----------------------------------------------------------------------------
WAIT;
END proc_dp_out_ready;
 
------------------------------------------------------------------------------
-- PROCEDURE: DUT output verify enable
------------------------------------------------------------------------------
-- Fixed delay until verify_en active
PROCEDURE proc_dp_verify_en(CONSTANT c_delay : IN NATURAL;
SIGNAL rst : IN STD_LOGIC;
SIGNAL clk : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC) IS
BEGIN
verify_en <= '0';
WAIT UNTIL rst='0';
WAIT UNTIL rising_edge(clk);
WAIT UNTIL sync='1';
-- Use c_delay delay before enabling the p_verify.
FOR I IN 0 TO c_delay LOOP WAIT UNTIL rising_edge(clk); END LOOP;
verify_en <= '1';
WAIT;
END proc_dp_verify_en;
-- Dynamicly depend on first valid data to make verify_en active
PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN BOOLEAN;
SIGNAL clk : IN STD_LOGIC;
SIGNAL valid : IN STD_LOGIC;
SIGNAL sop : IN STD_LOGIC;
SIGNAL eop : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC) IS
BEGIN
IF rising_edge(clk) THEN
IF c_continuous=TRUE THEN
-- Verify across frames (so enable data verify after the first data has been output)
IF valid='1' THEN
verify_en <= '1';
END IF;
ELSE
-- Verify only per frame (so re-enable data verify after the every sop)
IF eop='1' THEN
verify_en <= '0';
ELSIF sop='1' THEN
verify_en <= '1';
END IF;
END IF;
END IF;
END proc_dp_verify_en;
-- Run and verify for some cycles
PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk : IN NATURAL;
CONSTANT nof_verify_clk : IN NATURAL;
CONSTANT nof_post_clk : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : OUT STD_LOGIC) IS
BEGIN
proc_common_wait_some_cycles(clk, nof_pre_clk);
verify_en <= '1';
proc_common_wait_some_cycles(clk, nof_verify_clk);
verify_en <= '0';
proc_common_wait_some_cycles(clk, nof_post_clk);
END proc_dp_verify_run_some_cycles;
 
------------------------------------------------------------------------------
-- PROCEDURE: Verify the expected value
------------------------------------------------------------------------------
-- e.g. to check that a test has ran at all
PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
CONSTANT mode : IN t_dp_value_enum;
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 = e_equal AND UNSIGNED(res) /= UNSIGNED(exp) THEN
REPORT "DP : Wrong " & c_str & " result value" SEVERITY ERROR;
END IF;
IF mode = e_at_least AND UNSIGNED(res) < UNSIGNED(exp) THEN
REPORT "DP : Wrong " & c_str & " result value too small" SEVERITY ERROR;
END IF;
END IF;
END IF;
END proc_dp_verify_value;
 
PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum;
SIGNAL clk : IN STD_LOGIC;
SIGNAL en : IN STD_LOGIC;
SIGNAL exp : IN STD_LOGIC_VECTOR;
SIGNAL res : IN STD_LOGIC_VECTOR) IS
BEGIN
proc_dp_verify_value("", mode, clk, en, exp, res);
END proc_dp_verify_value;
PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL en : IN STD_LOGIC;
SIGNAL exp : IN STD_LOGIC;
SIGNAL res : IN STD_LOGIC) IS
BEGIN
IF rising_edge(clk) THEN
IF en='1' THEN
IF res /= exp THEN
REPORT "DP : Wrong " & c_str & " result value" SEVERITY ERROR;
END IF;
END IF;
END IF;
END proc_dp_verify_value;
------------------------------------------------------------------------------
-- PROCEDURE: Verify output global and local BSN
------------------------------------------------------------------------------
-- Verify BSN:
-- . incrementing or replicated global BSN
-- . incrementing local BSN that starts at 1
--
-- _ _ _ _
-- sync __| |____________| |____________| |____________| |____________
-- _ _ _ _ _ _ _ _ _ _ _ _
-- sop __| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__ c_block_per_sync = 3
--
-- c_use_local_bsn = FALSE:
-- c_nof_replicated_global_bsn = 1
-- bsn 3 4 5 6 7 8 9 10 11 12 13 14 c_global_bsn_increment = 1
-- bsn 3 5 7 9 11 13 15 17 19 21 22 23 c_global_bsn_increment = 2
--
-- c_use_local_bsn = TRUE:
--
-- global bsn 3 4 5 6 c_global_bsn_increment = 1, c_nof_replicated_global_bsn = 1
-- global bsn 3 6 9 12 c_global_bsn_increment = 3, c_nof_replicated_global_bsn = 1
-- global bsn 3 3 9 9 c_global_bsn_increment = 6, c_nof_replicated_global_bsn = 2
-- local bsn - 1 2 - 1 2 - 1 2 - 1 2 range 1:c_block_per_sync-1
--
-- The verify_en should initially be set to '0' and gets enabled when
-- sufficient BSN history is available to do the verification.
--
PROCEDURE proc_dp_verify_bsn(CONSTANT c_use_local_bsn : IN BOOLEAN; -- use local BSN or only use global BSN
CONSTANT c_global_bsn_increment : IN POSITIVE; -- increment per global BSN
CONSTANT c_nof_replicated_global_bsn : IN POSITIVE; -- number of replicated global BSN
CONSTANT c_block_per_sync : IN POSITIVE; -- of sop/eop blocks per sync interval
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_sync : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_bsn : IN STD_LOGIC_VECTOR;
SIGNAL verify_en : INOUT STD_LOGIC; -- initialize '0', becomes '1' when bsn verification starts
SIGNAL cnt_replicated_global_bsn : INOUT NATURAL;
SIGNAL prev_out_bsn_global : INOUT STD_LOGIC_VECTOR;
SIGNAL prev_out_bsn_local : INOUT STD_LOGIC_VECTOR) IS
BEGIN
IF rising_edge(clk) THEN
-- out_sop must be active, because only then out_bsn will differ from the previous out_bsn
IF out_sop='1' THEN
IF c_use_local_bsn=FALSE THEN
------------------------------------------------------------------
-- Only use global BSN
------------------------------------------------------------------
prev_out_bsn_global <= out_bsn;
-- verify
IF out_sync='1' THEN
verify_en <= '1';
END IF;
IF verify_en='1' THEN
ASSERT UNSIGNED(out_bsn) = UNSIGNED(prev_out_bsn_global)+c_global_bsn_increment REPORT "DP : Wrong BSN increment" SEVERITY ERROR;
END IF;
ELSE
------------------------------------------------------------------
-- Use global and local BSN
------------------------------------------------------------------
IF out_sync='1' THEN
prev_out_bsn_global <= out_bsn;
IF UNSIGNED(out_bsn) /= UNSIGNED(prev_out_bsn_global) THEN
verify_en <= '1'; -- wait until after last replicated global bsn
cnt_replicated_global_bsn <= 0;
ELSE
cnt_replicated_global_bsn <= cnt_replicated_global_bsn + 1;
END IF;
prev_out_bsn_local <= TO_UVEC(0, prev_out_bsn_global'LENGTH);
ELSE
prev_out_bsn_local <= out_bsn;
END IF;
-- verify
IF verify_en='1' THEN
IF out_sync='1' THEN
IF UNSIGNED(out_bsn) /= UNSIGNED(prev_out_bsn_global) THEN
ASSERT cnt_replicated_global_bsn=c_nof_replicated_global_bsn-1 REPORT "DP : Wrong number of replicated global BSN" SEVERITY ERROR;
ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_global)+c_global_bsn_increment REPORT "DP : Wrong global BSN increment" SEVERITY ERROR;
ELSE
ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_global) REPORT "DP : Wrong replicated global BSN" SEVERITY ERROR;
END IF;
ASSERT UNSIGNED(prev_out_bsn_local)=c_block_per_sync-1 REPORT "DP : Wrong last local BSN in sync interval" SEVERITY ERROR;
ELSE
ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_local)+1 REPORT "DP : Wrong local BSN increment" SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_bsn;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output data
------------------------------------------------------------------------------
-- Verify incrementing data
-- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0
-- . default increment by 1, but also allow an increment by c_out_data_gap
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_out_data_max : IN UNSIGNED;
CONSTANT c_out_data_gap : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC; -- only needed when c_ready_latency = 0
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
BEGIN
IF rising_edge(clk) THEN
-- out_val must be active, because only the out_data will it differ from the previous out_data
IF out_val='1' THEN
-- for ready_latency > 0 out_val indicates new data
-- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
IF c_out_data_max=0 THEN
prev_out_data <= out_data; -- no wrap detection
ELSIF UNSIGNED(out_data)<c_out_data_max THEN
prev_out_data <= out_data; -- no wrap
ELSE
prev_out_data <= TO_SVEC(-1, prev_out_data'LENGTH); -- do wrap
END IF;
IF verify_en='1' THEN
IF UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+1 AND -- check increment +1
UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+c_out_data_gap AND -- increment +c_out_data_gap
UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+c_out_data_gap-c_out_data_max THEN -- increment +c_out_data_gap wrapped
REPORT "DP : Wrong out_data " & c_str & " count" SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_data;
-- Verify incrementing data that wraps in range 0 ... c_out_data_max
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_out_data_max : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
BEGIN
proc_dp_verify_data(c_str, c_ready_latency, c_out_data_max, TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
-- Verify incrementing data
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
BEGIN
proc_dp_verify_data(c_str, c_ready_latency, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
-- Verify incrementing data with RL > 0 or no flow control
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN UNSIGNED;
CONSTANT c_out_data_gap : IN UNSIGNED;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
BEGIN
-- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
proc_dp_verify_data(c_str, 1, c_out_data_max, c_out_data_gap, clk, verify_en, out_val, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN NATURAL;
CONSTANT c_out_data_gap : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
CONSTANT c_data_w : NATURAL := out_data'LENGTH;
BEGIN
proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(c_out_data_gap, c_data_w), clk, verify_en, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
CONSTANT c_out_data_max : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
CONSTANT c_data_w : NATURAL := out_data'LENGTH;
BEGIN
proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(1, 1), clk, verify_en, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
BEGIN
-- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
proc_dp_verify_data(c_str, 1, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_val, out_val, out_data, prev_out_data);
END proc_dp_verify_data;
------------------------------------------------------------------------------
-- PROCEDURE: Verify incrementing symbols in data
-- . for c_data_w = c_symbol_w proc_dp_verify_symbols() = proc_dp_verify_data()
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_symbols(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_data_w : IN NATURAL;
CONSTANT c_symbol_w : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL out_empty : IN STD_LOGIC_VECTOR;
SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR) IS
CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w; -- must be an integer
CONSTANT c_empty_w : NATURAL := ceil_log2(c_nof_symbols_per_data);
VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
VARIABLE v_symbol : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
VARIABLE v_empty : NATURAL;
BEGIN
IF rising_edge(clk) THEN
-- out_val must be active, because only the out_data will it differ from the previous out_data
IF out_val='1' THEN
-- for ready_latency > 0 out_val indicates new data
-- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
prev_out_data <= out_data;
IF verify_en='1' THEN
v_data := prev_out_data(c_data_w-1 DOWNTO 0);
FOR I IN 0 TO c_nof_symbols_per_data-1 LOOP
v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := INCR_UVEC(v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w), c_nof_symbols_per_data); -- increment each symbol
END LOOP;
IF out_eop='0' THEN
IF UNSIGNED(out_data) /= UNSIGNED(v_data) THEN
REPORT "DP : Wrong out_data symbols count" SEVERITY ERROR;
END IF;
ELSE
v_empty := TO_UINT(out_empty(c_empty_w-1 DOWNTO 0));
IF UNSIGNED(out_data(c_data_w-1 DOWNTO v_empty*c_symbol_w)) /= UNSIGNED(v_data(c_data_w-1 DOWNTO v_empty*c_symbol_w)) THEN
REPORT "DP : Wrong out_data symbols count at eop" SEVERITY ERROR;
END IF;
IF v_empty>0 THEN
-- adjust prev_out_data for potentially undefined empty symbols in out_data
v_symbol := v_data((v_empty+1)*c_symbol_w-1 DOWNTO v_empty*c_symbol_w); -- last valid symbol
FOR I IN 0 TO c_nof_symbols_per_data-1 LOOP
v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_symbol; -- put the last valid symbol at the end of the v_data
v_symbol := INCR_UVEC(v_symbol, -1); -- decrement each symbol towards the beginning of v_data
END LOOP;
prev_out_data <= v_data;
END IF;
END IF;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_symbols;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output data with empty
-- . account for stream empty
-- . support last word replace (e.g. by a CRC instead of the count, or use
-- c_last_word=out_data for no replace)
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_data_empty(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_last_word : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL out_eop_1 : INOUT STD_LOGIC;
SIGNAL out_eop_2 : INOUT STD_LOGIC;
SIGNAL out_data : IN STD_LOGIC_VECTOR;
SIGNAL out_data_1 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data_2 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_data_3 : INOUT STD_LOGIC_VECTOR;
SIGNAL out_empty : IN STD_LOGIC_VECTOR;
SIGNAL out_empty_1 : INOUT STD_LOGIC_VECTOR) IS
VARIABLE v_last_word : STD_LOGIC_VECTOR(out_data'RANGE);
VARIABLE v_ref_data : STD_LOGIC_VECTOR(out_data'RANGE);
VARIABLE v_empty_data : STD_LOGIC_VECTOR(out_data'RANGE);
BEGIN
IF rising_edge(clk) THEN
-- out_val must be active, because only then out_data will differ from the previous out_data
IF out_val='1' THEN
-- for ready_latency > 0 out_val indicates new data
-- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
-- default expected data
out_data_1 <= out_data;
out_data_2 <= out_data_1;
out_data_3 <= out_data_2;
out_empty_1 <= out_empty;
out_eop_1 <= out_eop;
out_eop_2 <= out_eop_1;
IF verify_en='1' THEN
-- assume sufficient valid cycles between eop and sop, so no need to check for out_sop with regard to eop empty
IF out_eop='0' AND out_eop_1='0' AND out_eop_2='0'THEN
-- verify out_data from eop-n to eop-2 and from eop+1 to eop+n, n>2
v_ref_data := INCR_UVEC(out_data_2, 1);
IF UNSIGNED(out_data_1) /= UNSIGNED(v_ref_data) THEN
REPORT "DP : Wrong out_data count" SEVERITY ERROR;
END IF;
ELSE
-- the empty and crc replace affect data at eop_1 and eop, so need to check data from eop-2 to eop-1 to eop to eop+1
v_last_word := TO_UVEC(c_last_word, out_data'LENGTH);
IF out_eop='1' THEN
-- verify out_data at eop
CASE TO_INTEGER(UNSIGNED(out_empty)) IS
WHEN 0 => v_empty_data := v_last_word;
WHEN 1 => v_empty_data := v_last_word(3*c_byte_w-1 DOWNTO 0) & c_slv0(1*c_byte_w-1 DOWNTO 0);
WHEN 2 => v_empty_data := v_last_word(2*c_byte_w-1 DOWNTO 0) & c_slv0(2*c_byte_w-1 DOWNTO 0);
WHEN 3 => v_empty_data := v_last_word(1*c_byte_w-1 DOWNTO 0) & c_slv0(3*c_byte_w-1 DOWNTO 0);
WHEN OTHERS => NULL;
END CASE;
IF UNSIGNED(out_data) /= UNSIGNED(v_empty_data) THEN
REPORT "DP : Wrong out_data count at eop" SEVERITY ERROR;
END IF;
ELSIF out_eop_1='1' THEN
-- verify out_data from eop-2 to eop-1
v_ref_data := INCR_UVEC(out_data_3, 1);
CASE TO_INTEGER(UNSIGNED(out_empty_1)) IS
WHEN 0 => v_empty_data := v_ref_data;
WHEN 1 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 1*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 3*c_byte_w);
WHEN 2 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 2*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 2*c_byte_w);
WHEN 3 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 3*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 1*c_byte_w);
WHEN OTHERS => NULL;
END CASE;
IF UNSIGNED(out_data_2) /= UNSIGNED(v_empty_data) THEN
REPORT "DP : Wrong out_data count at eop-1" SEVERITY ERROR;
END IF;
-- verify out_data from eop-2 to eop+1
v_ref_data := INCR_UVEC(out_data_3, 3);
IF UNSIGNED(out_data) /= UNSIGNED(v_ref_data) THEN
REPORT "DP : Wrong out_data count at eop+1" SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_data_empty;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output other SOSI data
-- . Suited to verify the empty, error, channel fields assuming that these
-- are treated in the same way in parallel to the SOSI data.
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_other_sosi(CONSTANT c_str : IN STRING;
CONSTANT c_exp_data : IN STD_LOGIC_VECTOR; -- use constant to support assignment via FUNCTION return value
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL res_data : IN STD_LOGIC_VECTOR) IS
BEGIN
IF rising_edge(clk) THEN
IF verify_en='1' THEN
IF c_str="bsn" THEN
IF UNSIGNED(c_exp_data(c_dp_bsn_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_bsn_w-1 DOWNTO 0)) THEN
REPORT "DP : Wrong sosi.bsn value" SEVERITY ERROR;
END IF;
ELSIF c_str="empty" THEN
IF UNSIGNED(c_exp_data(c_dp_empty_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_empty_w-1 DOWNTO 0)) THEN
REPORT "DP : Wrong sosi.empty value" SEVERITY ERROR;
END IF;
ELSIF c_str="channel" THEN
IF UNSIGNED(c_exp_data(c_dp_channel_user_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_channel_user_w-1 DOWNTO 0)) THEN
REPORT "DP : Wrong sosi.channel value" SEVERITY ERROR;
END IF;
ELSIF c_str="error" THEN
IF UNSIGNED(c_exp_data(c_dp_error_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_error_w-1 DOWNTO 0)) THEN
REPORT "DP : Wrong sosi.error value" SEVERITY ERROR;
END IF;
ELSE
REPORT "proc_dp_verify_other_sosi : Unknown sosi." & c_str & "field" SEVERITY FAILURE;
END IF;
END IF;
END IF;
END proc_dp_verify_other_sosi;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output valid
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_valid(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL prev_out_ready : INOUT STD_LOGIC_VECTOR;
SIGNAL out_val : IN STD_LOGIC) IS
BEGIN
IF rising_edge(clk) THEN
-- for ready_latency > 0 out_val may only be asserted after out_ready
-- for ready_latency = 0 out_val may always be asserted
prev_out_ready <= (prev_out_ready'RANGE=>'0');
IF c_ready_latency/=0 THEN
IF c_ready_latency=1 THEN
prev_out_ready(0) <= out_ready;
ELSE
prev_out_ready <= out_ready & prev_out_ready(0 TO c_ready_latency-1);
END IF;
IF verify_en='1' AND out_val='1' THEN
IF prev_out_ready(c_ready_latency-1)/='1' THEN
REPORT "DP : Wrong ready latency between out_ready and out_val" SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_valid;
PROCEDURE proc_dp_verify_valid(SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL prev_out_ready : INOUT STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC) IS
BEGIN
-- Can not reuse:
-- proc_dp_verify_valid(1, clk, verify_en, out_ready, prev_out_ready, out_val);
-- because prev_out_ready needs to map from STD_LOGIC to STD_LOGIC_VECTOR. Therefore copy paste code for RL=1:
IF rising_edge(clk) THEN
-- for ready_latency = 1 out_val may only be asserted after out_ready
prev_out_ready <= out_ready;
IF verify_en='1' AND out_val='1' THEN
IF prev_out_ready/='1' THEN
REPORT "DP : Wrong ready latency between out_ready and out_val" SEVERITY ERROR;
END IF;
END IF;
END IF;
END proc_dp_verify_valid;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output sync
-- . sync is defined such that it can only be active at sop
-- . assume that the sync occures priodically at bsn MOD c_sync_period = c_sync_offset
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_sync(CONSTANT c_sync_period : IN NATURAL; -- BSN sync period
CONSTANT c_sync_offset : IN NATURAL; -- BSN sync offset
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL sync : IN STD_LOGIC;
SIGNAL sop : IN STD_LOGIC;
SIGNAL bsn : IN STD_LOGIC_VECTOR) IS
CONSTANT c_bsn_w : NATURAL := sel_a_b(bsn'LENGTH>31, 31, bsn'LENGTH); -- use maximally 31 bit of BSN slv to allow calculations with integers
VARIABLE v_expected_sync : BOOLEAN;
BEGIN
IF rising_edge(clk) THEN
IF verify_en='1' THEN
v_expected_sync := (TO_UINT(bsn(c_bsn_w-1 DOWNTO 0))-c_sync_offset) MOD c_sync_period = 0;
-- Check for unexpected sync
IF sync='1' THEN
ASSERT v_expected_sync = TRUE
REPORT "Error: Unexpected sync at BSN" SEVERITY ERROR;
ASSERT sop = '1'
REPORT "Error: Unexpected sync at inactive sop" SEVERITY ERROR;
END IF;
-- Check for missing sync
IF sop='1' AND v_expected_sync=TRUE THEN
ASSERT sync = '1'
REPORT "Error: Missing sync" SEVERITY ERROR;
END IF;
END IF;
END IF;
END proc_dp_verify_sync;
 
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output sop and eop
------------------------------------------------------------------------------
-- sop and eop in pairs, valid during packet and invalid between packets
PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL;
CONSTANT c_verify_valid : IN BOOLEAN;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC) IS
BEGIN
IF rising_edge(clk) THEN
IF out_val='0' THEN
IF out_sop='1' THEN REPORT "DP : Wrong active sop during invalid" SEVERITY ERROR; END IF;
IF out_eop='1' THEN REPORT "DP : Wrong active eop during invalid" SEVERITY ERROR; END IF;
ELSE
-- for ready_latency > 0 out_val indicates new data
-- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
IF out_sop='1' THEN
hold_sop <= '1';
IF hold_sop='1' THEN
REPORT "DP : Unexpected sop without eop" SEVERITY ERROR;
END IF;
END IF;
IF out_eop='1' THEN
hold_sop <= '0';
IF hold_sop='0' AND out_sop='0' THEN
REPORT "DP : Unexpected eop without sop" SEVERITY ERROR;
END IF;
END IF;
-- out_val='1'
IF c_verify_valid=TRUE AND out_sop='0' AND hold_sop='0' THEN
REPORT "DP : Unexpected valid in gap between eop and sop" SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_sop_and_eop;
PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC) IS
BEGIN
proc_dp_verify_sop_and_eop(c_ready_latency, TRUE, clk, out_ready, out_val, out_sop, out_eop, hold_sop);
END proc_dp_verify_sop_and_eop;
PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL hold_sop : INOUT STD_LOGIC) IS
BEGIN
-- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
proc_dp_verify_sop_and_eop(1, TRUE, clk, out_val, out_val, out_sop, out_eop, hold_sop);
END proc_dp_verify_sop_and_eop;
PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL alt_size : IN NATURAL; -- alternative size
SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL) IS
BEGIN
IF rising_edge(clk) THEN
IF out_val='1' THEN
-- for ready_latency > 0 out_val indicates new data
-- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
IF out_sop='1' THEN
cnt_size <= 1;
ELSIF out_eop='1' THEN
cnt_size <= 0;
IF cnt_size/=alt_size-1 AND cnt_size/=exp_size-1 THEN
REPORT "DP : Unexpected block size" SEVERITY ERROR;
END IF;
ELSE
cnt_size <= cnt_size+1;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_block_size;
PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL;
SIGNAL exp_size : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_ready : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL) IS
BEGIN
proc_dp_verify_block_size(c_ready_latency, exp_size, exp_size, clk, out_ready, out_val, out_sop, out_eop, cnt_size);
END proc_dp_verify_block_size;
PROCEDURE proc_dp_verify_block_size(SIGNAL alt_size : IN NATURAL; -- alternative size
SIGNAL exp_size : IN NATURAL; -- expected size
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL) IS
BEGIN
-- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
proc_dp_verify_block_size(1, alt_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size);
END proc_dp_verify_block_size;
PROCEDURE proc_dp_verify_block_size(SIGNAL exp_size : IN NATURAL;
SIGNAL clk : IN STD_LOGIC;
SIGNAL out_val : IN STD_LOGIC;
SIGNAL out_sop : IN STD_LOGIC;
SIGNAL out_eop : IN STD_LOGIC;
SIGNAL cnt_size : INOUT NATURAL) IS
BEGIN
-- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
proc_dp_verify_block_size(1, exp_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size);
END proc_dp_verify_block_size;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output invalid between frames
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_gap_invalid(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_val : IN STD_LOGIC;
SIGNAL in_sop : IN STD_LOGIC;
SIGNAL in_eop : IN STD_LOGIC;
SIGNAL out_gap : INOUT STD_LOGIC) IS
BEGIN
IF rising_edge(clk) THEN
IF in_eop='1' THEN
out_gap <= '1';
ELSIF in_sop='1' THEN
out_gap <= '0';
ELSIF in_val='1' AND out_gap='1' THEN
REPORT "DP : Wrong valid in gap between eop and sop" SEVERITY ERROR;
END IF;
END IF;
END proc_dp_verify_gap_invalid;
------------------------------------------------------------------------------
-- PROCEDURE: Verify the DUT output control (use for sop, eop)
------------------------------------------------------------------------------
PROCEDURE proc_dp_verify_ctrl(CONSTANT c_offset : IN NATURAL;
CONSTANT c_period : IN NATURAL;
CONSTANT c_str : IN STRING;
SIGNAL clk : IN STD_LOGIC;
SIGNAL verify_en : IN STD_LOGIC;
SIGNAL data : IN STD_LOGIC_VECTOR;
SIGNAL valid : IN STD_LOGIC;
SIGNAL ctrl : IN STD_LOGIC) IS
VARIABLE v_data : INTEGER;
BEGIN
IF rising_edge(clk) THEN
IF verify_en='1' THEN
v_data := TO_UINT(data);
IF ((v_data-c_offset) MOD c_period)=0 THEN
IF valid='1' AND ctrl/='1' THEN
REPORT "DP : Wrong data control, missing " & c_str SEVERITY ERROR;
END IF;
ELSE
IF ctrl='1' THEN
REPORT "DP : Wrong data control, unexpected " & c_str SEVERITY ERROR;
END IF;
END IF;
END IF;
END IF;
END proc_dp_verify_ctrl;
------------------------------------------------------------------------------
-- PROCEDURE: Wait for stream valid
------------------------------------------------------------------------------
PROCEDURE proc_dp_stream_valid(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC) IS
BEGIN
WAIT UNTIL rising_edge(clk);
WHILE in_valid /= '1' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
END proc_dp_stream_valid;
------------------------------------------------------------------------------
-- PROCEDURE: Wait for stream valid AND sop
------------------------------------------------------------------------------
PROCEDURE proc_dp_stream_valid_sop(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC;
SIGNAL in_sop : IN STD_LOGIC) IS
BEGIN
WAIT UNTIL rising_edge(clk);
WHILE in_valid /= '1' AND in_sop /= '1' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
END proc_dp_stream_valid_sop;
 
------------------------------------------------------------------------------
-- PROCEDURE: Wait for stream valid AND eop
------------------------------------------------------------------------------
PROCEDURE proc_dp_stream_valid_eop(SIGNAL clk : IN STD_LOGIC;
SIGNAL in_valid : IN STD_LOGIC;
SIGNAL in_eop : IN STD_LOGIC) IS
BEGIN
WAIT UNTIL rising_edge(clk);
WHILE in_valid /= '1' AND in_eop /= '1' LOOP
WAIT UNTIL rising_edge(clk);
END LOOP;
END proc_dp_stream_valid_eop;
END tb_dp_pkg;

powered by: WebSVN 2.1.0

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