diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 39ca669c8f184bc1e880bf341840641e720fd402..521d6753de27da8f29ca2d24d0edfb29bdd8eaa2 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -30,6 +30,7 @@ synth_files = src/vhdl/dp_pipeline_arr.vhd src/vhdl/dp_pipeline_ready.vhd src/vhdl/dp_block_resize.vhd + src/vhdl/dp_block_validate_length.vhd src/vhdl/dp_block_select.vhd src/vhdl/mms_dp_block_select.vhd src/vhdl/dp_force_data_parallel.vhd @@ -193,6 +194,7 @@ test_bench_files = tb/vhdl/dp_stream_verify.vhd tb/vhdl/tb_dp_block_select.vhd + tb/vhdl/tb_dp_block_validate_length.vhd tb/vhdl/tb_dp_block_reshape.vhd tb/vhdl/tb_dp_block_reshape_sync.vhd tb/vhdl/tb_dp_block_gen.vhd @@ -272,6 +274,7 @@ test_bench_files = tb/vhdl/tb_tb_dp_block_select.vhd + tb/vhdl/tb_tb_dp_block_validate_length.vhd tb/vhdl/tb_tb_dp_block_reshape.vhd tb/vhdl/tb_tb_dp_block_reshape_sync.vhd tb/vhdl/tb_tb_dp_block_gen.vhd @@ -337,6 +340,7 @@ regression_test_vhdl = tb/vhdl/tb_mms_dp_bsn_source_v2.vhd tb/vhdl/tb_tb_dp_block_select.vhd + tb/vhdl/tb_tb_dp_block_validate_length.vhd tb/vhdl/tb_tb_dp_block_reshape.vhd tb/vhdl/tb_tb_dp_block_reshape_sync.vhd tb/vhdl/tb_tb_dp_block_gen.vhd diff --git a/libraries/base/dp/src/vhdl/dp_block_validate_length.vhd b/libraries/base/dp/src/vhdl/dp_block_validate_length.vhd new file mode 100644 index 0000000000000000000000000000000000000000..ff4f40a6cad3f03bd41ce08cf4548e05f639e016 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_block_validate_length.vhd @@ -0,0 +1,136 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R vd Walle +-- Purpose: +-- Validate the length of a DP block. +-- Description: +-- The dp_block_validate_length.vhd checks whether the in_sosi block has the +-- expected length given by g_expected_length. The block length is defined by +-- the number of valid from sop to eop. The tasks of the +-- dp_block_validate_length.vhd are: +-- . Default all in_sosi fields are passed on to the out_sosi. +-- . If the input block length differs from g_expected_length, then the bit at +-- bit index g_err_bi in the out_sosi.err field is forced to 1, else the +-- out_sosi.err field passes on the in_sosi.err field. +-- . If the input block length > g_expected_length, then the out_sosi block +-- length is restricted to g_expected_length, by inserting an eop and +-- discarding the remaining data and eop information from the in_sosi. +-- Remarks: +-- - This component supports flow control and was designed by keeping the functional +-- state registers and the pipeline registers seperate. Therefore the function is +-- implemented using combinatorial logic and local state registers to keep its +-- state. The combinatorial function output preserves the snk_in ready latency and +-- is pipelined using dp_pipeline to ease timing closure on the output. +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.all; +USE work.dp_stream_pkg.ALL; + +ENTITY dp_block_validate_length IS + GENERIC ( + g_err_bi : NATURAL := 0; -- bit index in error field + g_expected_length : NATURAL := 255 + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + -- ST sink + snk_out : OUT t_dp_siso; + snk_in : IN t_dp_sosi; + -- ST source + src_in : IN t_dp_siso := c_dp_siso_rdy; + src_out : OUT t_dp_sosi + ); +END dp_block_validate_length; + + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.all; +USE work.dp_stream_pkg.ALL; + +ARCHITECTURE rtl OF dp_block_validate_length IS + + SIGNAL cnt_reg : NATURAL; + SIGNAL cnt : NATURAL; + SIGNAL block_sosi : t_dp_sosi; + +BEGIN + + p_clk : PROCESS(rst, clk) + BEGIN + IF rst='1' THEN + cnt_reg <= 0; + ELSIF rising_edge(clk) THEN + cnt_reg <= cnt; + END IF; + END PROCESS; + + -- Count valid per block + p_cnt : PROCESS(snk_in, cnt_reg) + BEGIN + cnt <= cnt_reg; + IF snk_in.sop='1' THEN + cnt <= 0; + ELSIF snk_in.valid='1' THEN + cnt <= cnt_reg + 1; + END IF; + END PROCESS; + + -- Resize snk_in combinatorially into block_sosi, so no impact on RL + p_block_sosi : PROCESS(snk_in, cnt) + BEGIN + -- Default keep snk_in info and data fields + block_sosi <= snk_in; + IF snk_in.valid='1' THEN + -- Set output eop, info @ eop gets lost if g_expected_length < actual block size + IF snk_in.eop = '1' XOR cnt = g_expected_length-1 THEN + block_sosi.err(g_err_bi) <= '1'; + END IF; + + IF cnt = g_expected_length-1 THEN + block_sosi.eop <= '1'; + END IF; + + IF cnt > g_expected_length-1 THEN + block_sosi <= c_dp_sosi_rst; + END IF; + END IF; + END PROCESS; + + -- Register block_sosi to easy timing closure + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => 1 -- 0 for wires, > 0 for registers, + ) + PORT MAP ( + rst => rst, + clk => clk, + -- ST sink + snk_out => snk_out, + snk_in => block_sosi, + -- ST source + src_in => src_in, + src_out => src_out + ); + +END rtl; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_validate_length.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_length.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2ddb5db41194f266fdcca2d22624f6f4e161164d --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_length.vhd @@ -0,0 +1,202 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R vd Walle +-- Purpose: +-- Test bench for dp_block_validate_length. +-- Description: +-- Verifies the output sosi of the DUT with the expected sosi. +-- Usage: +-- . as 5 +-- . run -all + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_str_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE work.tb_dp_pkg.ALL; + +ENTITY tb_dp_block_validate_length IS + GENERIC ( + g_nof_blocks_per_sync : NATURAL := 5; + g_nof_data_per_blk : NATURAL := 9; + g_expected_length : NATURAL := 3; + g_err_bi : NATURAL := 3 + ); +END tb_dp_block_validate_length; + + +ARCHITECTURE tb OF tb_dp_block_validate_length IS + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + CONSTANT c_clk_period : TIME := 5 ns; + + CONSTANT c_dut_pipeline : NATURAL := 1; + CONSTANT c_nof_sync : NATURAL := 5; + CONSTANT c_gap_size : NATURAL := 4; + CONSTANT c_exp_err : STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0) := TO_UVEC(2**g_err_bi, c_dp_stream_error_w); + + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL tb_end : STD_LOGIC := '0'; + + SIGNAL stimuli_end : STD_LOGIC; + SIGNAL stimuli_sosi : t_dp_sosi; + SIGNAL stimuli_siso : t_dp_siso; + SIGNAL stimuli_cnt_reg : NATURAL; + SIGNAL stimuli_cnt : NATURAL; + SIGNAL verify_sosi : t_dp_sosi; + SIGNAL verify_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL reference_cnt : NATURAL; + SIGNAL reference_sosi : t_dp_sosi; + SIGNAL reference_siso : t_dp_siso := c_dp_siso_rdy; + +BEGIN + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + rst <= '1', '0' AFTER c_clk_period*7; + + ------------------------------------------------------------------------------ + -- Stimuli: + ------------------------------------------------------------------------------ + + -- Generate snk_in with data frames + u_stimuli : ENTITY work.dp_stream_stimuli + GENERIC MAP ( + g_sync_period => g_nof_blocks_per_sync, + g_nof_repeat => g_nof_blocks_per_sync * c_nof_sync, + g_pkt_len => g_nof_data_per_blk, + g_pkt_gap => c_gap_size, + g_err_init => 0, + g_err_incr => 0 + ) + PORT MAP ( + rst => rst, + clk => clk, + + -- Generate stimuli + src_in => stimuli_siso, + src_out => stimuli_sosi, + + -- End of stimuli + tb_end => stimuli_end + ); + + ------------------------------------------------------------------------------ + -- DUT + ------------------------------------------------------------------------------ + u_dut : ENTITY work.dp_block_validate_length + GENERIC MAP ( + g_err_bi => g_err_bi, + g_expected_length => g_expected_length + ) + PORT MAP ( + rst => rst, + clk => clk, + -- ST sink + snk_out => stimuli_siso, + snk_in => stimuli_sosi, + -- ST source + src_in => verify_siso, + src_out => verify_sosi + ); + + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => c_dut_pipeline + ) + PORT MAP ( + rst => rst, + clk => clk, + -- ST sink + snk_out => OPEN, + snk_in => stimuli_sosi, + -- ST source + src_in => reference_siso, + src_out => reference_sosi + ); + + stimuli_cnt_reg <= stimuli_cnt WHEN rising_edge(clk); + stimuli_cnt <= 0 WHEN stimuli_sosi.sop='1' ELSE + stimuli_cnt_reg + 1 WHEN stimuli_sosi.valid='1' ELSE + stimuli_cnt_reg; + + reference_cnt <= stimuli_cnt WHEN rising_edge(clk); + + p_verify : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF reference_sosi.valid = '1' THEN + IF g_expected_length = g_nof_data_per_blk THEN -- in sosi should be identical to out sosi + ASSERT verify_sosi=reference_sosi REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + + ELSIF g_expected_length < g_nof_data_per_blk THEN -- expect an err bit to be set and the block length to be limited to g_expected_length + IF reference_cnt < g_expected_length-1 THEN + ASSERT verify_sosi=reference_sosi REPORT "Wrong block while reference_cnt < g_expected_length-1" SEVERITY ERROR; + ELSIF reference_cnt = g_expected_length-1 THEN + ASSERT verify_sosi.sync = reference_sosi.sync REPORT "Wrong sync, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.bsn = reference_sosi.bsn REPORT "Wrong bsn, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.channel = reference_sosi.channel REPORT "Wrong valid, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.data = reference_sosi.data REPORT "Wrong data, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.valid = reference_sosi.valid REPORT "Wrong valid, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.sop = reference_sosi.sop REPORT "Wrong sop, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.eop = '1' REPORT "Wrong eop, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ASSERT verify_sosi.err = c_exp_err REPORT "Wrong err, while reference_cnt = g_expected_length-1" SEVERITY ERROR; + ELSE -- reference_cnt > g_expected_length-1 + ASSERT verify_sosi.valid = '0' REPORT "Wrong, valid should be '0' when reference_cnt > g_expected_length-1" SEVERITY ERROR; + END IF; + + ELSE -- g_expected_length > g_nof_data_per_blk + -- Expected an err bit to be set at eop + IF reference_cnt = g_nof_data_per_blk-1 THEN + ASSERT verify_sosi.sync = reference_sosi.sync REPORT "Wrong sync, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.bsn = reference_sosi.bsn REPORT "Wrong bsn, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.channel = reference_sosi.channel REPORT "Wrong valid, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.data = reference_sosi.data REPORT "Wrong data, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.valid = reference_sosi.valid REPORT "Wrong valid, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.sop = reference_sosi.sop REPORT "Wrong sop, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.eop = reference_sosi.eop REPORT "Wrong eop, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ASSERT verify_sosi.err = c_exp_err REPORT "Wrong err, while reference_cnt = g_nof_data_per_blk-1" SEVERITY ERROR; + ELSE + ASSERT verify_sosi = reference_sosi REPORT "Wrong block while g_expected_length > g_nof_data_per_blk" SEVERITY ERROR; + END IF; + END IF; + END IF; + END IF; + END PROCESS; + + tb_end <= '0', stimuli_end AFTER (1 + 10*c_dut_pipeline)*c_clk_period; + +END tb; diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_length.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_length.vhd new file mode 100644 index 0000000000000000000000000000000000000000..49da01a7ea58ef184c0c7983bce1db57c5550d29 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_length.vhd @@ -0,0 +1,56 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R vd Walle +-- Purpose: +-- Verify multiple variations of tb_dp_block_validate_length +-- Usage: +-- > as 3 +-- > run -all + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_dp_block_validate_length IS +END tb_tb_dp_block_validate_length; + + +ARCHITECTURE tb OF tb_tb_dp_block_validate_length IS + + SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' + + CONSTANT c_blk_per_sync : NATURAL := 5; + CONSTANT c_data_per_blk : NATURAL := 9; + CONSTANT c_exp_length : NATURAL := 9; + CONSTANT c_err_bi : NATURAL := 3; + +BEGIN + +-- g_nof_blocks_per_sync : NATURAL := 5; +-- g_nof_data_per_blk : NATURAL := 9; +-- g_expected_length : NATURAL := 3; +-- g_err_bi : NATURAL := 3 + + u_equal : ENTITY work.tb_dp_block_validate_length GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_exp_length, c_err_bi); -- g_expected_length = g_nof_data_per_blk + u_smaller : ENTITY work.tb_dp_block_validate_length GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_exp_length - 3, c_err_bi); -- g_expected_length < g_nof_data_per_blk + u_larger : ENTITY work.tb_dp_block_validate_length GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_exp_length + 3, c_err_bi); -- g_expected_length > g_nof_data_per_blk + +END tb;