diff --git a/libraries/base/common/src/vhdl/common_counter.vhd b/libraries/base/common/src/vhdl/common_counter.vhd index 4a3dd59d1da1b92a0722d2e6523a57e95ed58881..d4826da0ff55f29abdd3b937430ab18051055fcf 100644 --- a/libraries/base/common/src/vhdl/common_counter.vhd +++ b/libraries/base/common/src/vhdl/common_counter.vhd @@ -22,6 +22,7 @@ -- Purpose : Counter with extra options -- Description: -- - default wrap at 2**g_width or special wrap at fixed g_max or dynamically via cnt_max +-- - count can be clipped instead of wrapped by setting g_clip to True. -- - default increment +1 or other g_step_size -- - external clr -- - external load with g_init or dynamically via load @@ -42,7 +43,8 @@ ENTITY common_counter IS g_init : INTEGER := 0; g_width : NATURAL := 32; g_max : NATURAL := 0; -- default 0 to disable the g_max setting. - g_step_size : INTEGER := 1 -- counting in steps of g_step_size, can be + or - + g_step_size : INTEGER := 1; -- counting in steps of g_step_size, can be + or - + g_clip : BOOLEAN := FALSE -- when True, counter will clip at g_max, if g_max = 0 and g_step_size > 0, the counter clips at 2**g_width -1. ); PORT ( rst : IN STD_LOGIC := '0'; -- either use asynchronous rst or synchronous cnt_clr @@ -51,7 +53,8 @@ ENTITY common_counter IS cnt_clr : IN STD_LOGIC := '0'; -- synchronous cnt_clr is only interpreted when clken is active cnt_ld : IN STD_LOGIC := '0'; -- cnt_ld loads the output count with the input load value, independent of cnt_en cnt_en : IN STD_LOGIC := '1'; - cnt_max : IN STD_LOGIC_VECTOR(g_width-1 DOWNTO 0) := TO_UVEC(sel_a_b(ceil_log2(g_max+1)>g_width, 0, g_max), g_width); -- see remarks + cnt_max : IN STD_LOGIC_VECTOR(g_width-1 DOWNTO 0) := sel_a_b( g_step_size > 0 AND g_max = 0, array_init('1', g_width), + sel_a_b( ceil_log2(g_max+1) > g_width, array_init('1', g_width), TO_UVEC(g_max, g_width) )); -- see remarks load : IN STD_LOGIC_VECTOR(g_width-1 DOWNTO 0) := TO_SVEC(g_init, g_width); count : OUT STD_LOGIC_VECTOR(g_width-1 DOWNTO 0) ); @@ -60,7 +63,6 @@ END common_counter; ARCHITECTURE rtl OF common_counter IS - CONSTANT zeros : STD_LOGIC_VECTOR(count'RANGE) := (OTHERS => '0'); -- used to check if cnt_max is zero SIGNAL reg_count : STD_LOGIC_VECTOR(count'RANGE) := TO_SVEC(g_init, g_width); -- in case rst is not used SIGNAL nxt_count : STD_LOGIC_VECTOR(count'RANGE) := TO_SVEC(g_init, g_width); -- to avoid Warning: NUMERIC_STD.">=": metavalue detected, returning FALSE, when using unsigned() SIGNAL comb_count : STD_LOGIC_VECTOR(count'RANGE) := TO_SVEC(g_init, g_width); -- to avoid Warning: NUMERIC_STD.">=": metavalue detected, returning FALSE, when using unsigned() @@ -87,10 +89,14 @@ BEGIN p_count : PROCESS(reg_count, cnt_clr, cnt_en, cnt_ld, load, cnt_max) BEGIN nxt_count <= reg_count; - IF cnt_clr='1' OR (reg_count=cnt_max AND cnt_max /= zeros) THEN + IF cnt_clr='1' THEN nxt_count <= (OTHERS => '0'); ELSIF cnt_ld='1' THEN nxt_count <= load; + ELSIF reg_count=cnt_max THEN + IF NOT g_clip THEN + nxt_count <= (OTHERS => '0'); + END IF; ELSIF cnt_en='1' THEN nxt_count <= INCR_UVEC(reg_count, g_step_size); END IF; diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 521d6753de27da8f29ca2d24d0edfb29bdd8eaa2..df7d5faad304285832f2a0ebc5dd69219470430f 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -31,6 +31,7 @@ synth_files = src/vhdl/dp_pipeline_ready.vhd src/vhdl/dp_block_resize.vhd src/vhdl/dp_block_validate_length.vhd + src/vhdl/dp_block_validate_bsn_at_sync.vhd src/vhdl/dp_block_select.vhd src/vhdl/mms_dp_block_select.vhd src/vhdl/dp_force_data_parallel.vhd @@ -61,6 +62,7 @@ synth_files = src/vhdl/dp_fifo_from_mm_reg.vhd src/vhdl/dp_fifo_monitor.vhd src/vhdl/dp_fifo_monitor_arr.vhd + src/vhdl/dp_block_validate_err.vhd src/vhdl/mms_dp_fifo_to_mm.vhd src/vhdl/mms_dp_fifo_from_mm.vhd src/vhdl/mms_dp_fifo_fill.vhd @@ -195,6 +197,8 @@ test_bench_files = tb/vhdl/tb_dp_block_select.vhd tb/vhdl/tb_dp_block_validate_length.vhd + tb/vhdl/tb_dp_block_validate_err.vhd + tb/vhdl/tb_dp_block_validate_bsn_at_sync.vhd tb/vhdl/tb_dp_block_reshape.vhd tb/vhdl/tb_dp_block_reshape_sync.vhd tb/vhdl/tb_dp_block_gen.vhd @@ -275,6 +279,8 @@ 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_validate_err.vhd + tb/vhdl/tb_tb_dp_block_validate_bsn_at_sync.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 @@ -341,6 +347,8 @@ regression_test_vhdl = tb/vhdl/tb_tb_dp_block_select.vhd tb/vhdl/tb_tb_dp_block_validate_length.vhd + tb/vhdl/tb_tb_dp_block_validate_err.vhd + tb/vhdl/tb_tb_dp_block_validate_bsn_at_sync.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_bsn_at_sync.vhd b/libraries/base/dp/src/vhdl/dp_block_validate_bsn_at_sync.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b71ce78bc5cdfcf2bbfbee099bbde6ea961265e9 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_block_validate_bsn_at_sync.vhd @@ -0,0 +1,229 @@ +------------------------------------------------------------------------------- +-- +-- 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: +-- The dp_block_validate_bsn_at_sync.vhd checks whether the remote block +-- sequence number (BSN) at the start of an in_sosi.sync interval is equal to +-- the local BSN at start of the local bs_sosi.sync interval. +-- Description: +-- The dp_block_validate_bsn_at_sync.vhd holds the local BSN that it gets at +-- each bs_sosi.sync and uses that when it receives the remote BSN at the +-- in_sosi.sync. The dp_validate_bsn_at_sync.vhd compares the entire +-- g_bsn_w bit BSN. If the remote BSN at in_sosi.sync and the local BSN at +-- bs_sosi.sync are: +-- . Not equal, then discard all subsequent in_sosi blocks until the next +-- in_sosi .sync +-- . Equal, then pass on all subsequent in_sosi blocks until the next +-- in_sosi.sync +-- Only packets with channel = g_check_channel are checked. Other packets are +-- just passed on. +-- The dp_block_validate_bsn_at_sync.vhd maintains a total number of +-- in_sosi.sync counter and a number of discarded sync intervals counter, that +-- can be read via the MM interface. +-- Remarks: +-- . g_check_channel is needed for designs like the ring. The +-- dp_block_validate_bsn_at_sync.vhd only has to check the remote packets +-- from its neighbour ring node that is at one hop distance. The packets +-- that have traveled one hop have in_sosi.channel = g_check_channel = 1. +-- The packets at other channels from more distant PN are just passed on. +-- These packets have already been checked by the +-- dp_block_validate_bsn_at_sync.vhd on other PN. In this way it is +-- suffiicent to have one instance of dp_block_validate_bsn_at_sync.vhd per +-- PN. +------------------------------------------------------------------------------- +-- REGMAP +------------------------------------------------------------------------------- +-- wi Bits R/W Name Default +-- ===================================================================== +-- 0 [31..0] RO nof_sync_discarded 0x0 +-- 1 [31..0] RO nof_sync 0x0 +-- 2 [31..0] RW clear 0x0 read or write to clear counters +-- ===================================================================== +------------------------------------------------------------------------------- +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.all; +USE IEEE.numeric_std.all; +USE work.dp_stream_pkg.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +ENTITY dp_block_validate_bsn_at_sync IS + GENERIC ( + g_check_channel : NATURAL := 0; + g_bsn_w : NATURAL := c_dp_stream_bsn_w + ); + PORT ( + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + -- ST sink + in_sosi : IN t_dp_sosi; + bs_sosi : IN t_dp_sosi; + -- ST source + out_sosi : OUT t_dp_sosi; + + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + reg_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_miso : OUT t_mem_miso := c_mem_miso_rst + ); +END dp_block_validate_bsn_at_sync; + +ARCHITECTURE rtl OF dp_block_validate_bsn_at_sync IS + + CONSTANT c_nof_regs : NATURAL := 3; + CONSTANT c_clear_adr : NATURAL := c_nof_regs-1; + -- Define the actual size of the MM slave register + CONSTANT c_mm_reg : t_c_mem := (latency => 1, + adr_w => ceil_log2(c_nof_regs), + dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers + nof_dat => c_nof_regs, -- total counter + discarded counter + init_sl => '0'); + + -- Registers in st_clk domain + SIGNAL count_reg : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); + + SIGNAL mm_cnt_clr : STD_LOGIC; + SIGNAL cnt_clr : STD_LOGIC; + SIGNAL cnt_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL cnt_sync_en : STD_LOGIC; + SIGNAL cnt_discarded : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL cnt_discarded_en : STD_LOGIC; + + SIGNAL out_valid : STD_LOGIC; + SIGNAL bsn_ok : STD_LOGIC; + SIGNAL bsn_ok_reg : STD_LOGIC; + SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL bsn_at_sync_reg : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + + SIGNAL block_sosi : t_dp_sosi; + +BEGIN + + mm_cnt_clr <= (reg_mosi.rd OR reg_mosi.wr) WHEN TO_UINT(reg_mosi.address(c_mm_reg.adr_w-1 DOWNTO 0)) = c_clear_adr ELSE '0' ; + u_common_spulse : ENTITY common_lib.common_spulse + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_pulse => mm_cnt_clr, + out_rst => dp_rst, + out_clk => dp_clk, + out_pulse => cnt_clr + ); + + -- discarded counter + cnt_discarded_en <= '1' WHEN in_sosi.sync = '1' AND bsn_ok = '0' ELSE '0'; + u_discarded_counter : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_word_w, + g_clip => TRUE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + cnt_clr => cnt_clr, + cnt_en => cnt_discarded_en, + count => cnt_discarded + ); + + -- sync counter + u_blk_counter : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_word_w, + g_clip => TRUE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + cnt_clr => cnt_clr, + cnt_en => in_sosi.sync, + count => cnt_sync + ); + + -- Register mapping + count_reg( c_word_w - 1 DOWNTO 0 ) <= cnt_discarded; + count_reg(2*c_word_w - 1 DOWNTO c_word_w ) <= cnt_sync; + + u_reg : ENTITY common_lib.common_reg_r_w_dc + GENERIC MAP ( + g_cross_clock_domain => TRUE, + g_readback => FALSE, + g_reg => c_mm_reg + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => dp_rst, + st_clk => dp_clk, + + -- Memory Mapped Slave in mm_clk domain + sla_in => reg_mosi, + sla_out => reg_miso, + + -- MM registers in st_clk domain + reg_wr_arr => OPEN, + reg_rd_arr => OPEN, + in_reg => count_reg, -- read only + out_reg => OPEN -- no write + ); + + bsn_at_sync <= bs_sosi.bsn WHEN bs_sosi.sync = '1' ELSE bsn_at_sync_reg; + bsn_ok <= bsn_ok_reg WHEN in_sosi.sync = '0' ELSE '1' WHEN in_sosi.bsn = bsn_at_sync ELSE '0'; + out_valid <= bsn_ok WHEN TO_UINT(in_sosi.channel) = g_check_channel ELSE '1'; + + p_dp_clk : PROCESS(dp_rst, dp_clk) + BEGIN + IF dp_rst='1' THEN + bsn_ok_reg <= '1'; + bsn_at_sync_reg <= (OTHERS => '0'); + ELSIF rising_edge(dp_clk) THEN + bsn_ok_reg <= bsn_ok; + bsn_at_sync_reg <= bsn_at_sync; + END IF; + END PROCESS; + + p_sosi : PROCESS(in_sosi, out_valid) + BEGIN + block_sosi <= in_sosi; + block_sosi.valid <= in_sosi.valid AND out_valid; + block_sosi.sop <= in_sosi.sop AND out_valid; + block_sosi.eop <= in_sosi.eop AND out_valid; + block_sosi.sync <= in_sosi.sync AND out_valid; + END PROCESS; + + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => 1 -- 0 for wires, > 0 for registers, + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + -- ST sink + snk_in => block_sosi, + -- ST source + src_out => out_sosi + ); + +END rtl; diff --git a/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd b/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd new file mode 100644 index 0000000000000000000000000000000000000000..8ec87e33d5e660fcffebb90920322adf73704d99 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd @@ -0,0 +1,314 @@ +------------------------------------------------------------------------------- +-- +-- 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 error field of a DP block. +-- Description: +-- . The dp_block_validate_err.vhd checks the in_sosi.err field at the end of a +-- block. Therefore the block needs to be stored, before it can be validated. +-- The stored block is then either forwarded when the in_sosi.err = 0, or else +-- it is discarded. +-- . The dp_block_validate_err.vhd has to maintain the a total number of in_sosi +-- blocks counter and a number of discarded blocks counter per bit in the +-- in_sosi.err field. The counters can be read via the MM interface. +-- Remarks: +-- . Note that a block can have more than one bit set in the err field. This can +-- result in multiple counters increasing per block. Therefore, it should not be +-- assumed that the sum of the err counters is the total amount of discarded +-- blocks. +-- . Note that dp_fifo_fill_eop cannot handle continues stream of blocks without +-- a gap between blocks the dp_fifo_fill_eop needs 1 cycle to process a block. +-- Streaming without gaps may cause the fifo to overflow. Bursts of blocks +-- can be handled by increasing g_fifo_size. +------------------------------------------------------------------------------- +-- REGMAP +------------------------------------------------------------------------------- +-- wi Bits R/W Name Default +-- ==================================================================================== +-- 0 [31..0] RO err_count_index_0 0x0 +-- 1 [31..0] RO err_count_index_1 0x0 +-- . . . . . +-- . . . . . +-- . . . . . +-- g_nof_err_counts-1 [31..0] RO err_count_index_[g_nof_err_counts-1] 0x0 +-- g_nof_err_counts [31..0] RO total_discarded_blocks 0x0 +-- g_nof_err_counts+1 [31..0] RO total_block_count 0x0 +-- g_nof_err_counts+2 [31..0] RW clear 0x0 read or write to clear counters +-- ==================================================================================== +------------------------------------------------------------------------------- +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.all; +USE IEEE.numeric_std.all; +USE work.dp_stream_pkg.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +ENTITY dp_block_validate_err IS + GENERIC ( + g_cnt_w : NATURAL := c_word_w; -- max is c_word_w due to mm word width + g_max_block_size : POSITIVE := 250; + g_min_block_size : POSITIVE := 1; + g_nof_err_counts : NATURAL := 8; + -- fifo generics + g_fifo_size : POSITIVE := 256; + g_data_w : NATURAL := 16; + g_bsn_w : NATURAL := 1; + g_empty_w : NATURAL := 1; + g_channel_w : NATURAL := 1; + g_use_bsn : BOOLEAN := FALSE; + g_use_empty : BOOLEAN := FALSE; + g_use_channel : BOOLEAN := FALSE; + g_use_sync : BOOLEAN := FALSE; + g_use_complex : BOOLEAN := FALSE + ); + PORT ( + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + -- ST sink + snk_out : OUT t_dp_siso := c_dp_siso_rdy; + snk_in : IN t_dp_sosi; + -- ST source + src_in : IN t_dp_siso := c_dp_siso_rdy; + src_out : OUT t_dp_sosi; + + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + reg_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_miso : OUT t_mem_miso := c_mem_miso_rst + ); +END dp_block_validate_err; + +ARCHITECTURE rtl OF dp_block_validate_err IS + + CONSTANT c_max_cnt : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT c_nof_err_ok : NATURAL := ceil_div(g_max_block_size, g_min_block_size); + CONSTANT c_nof_regs : NATURAL := g_nof_err_counts + 3; + CONSTANT c_clear_adr : NATURAL := c_nof_regs-1; + + TYPE t_cnt_err_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + + -- Define the actual size of the MM slave register + CONSTANT c_mm_reg : t_c_mem := (latency => 1, + adr_w => ceil_log2(c_nof_regs), + dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers + nof_dat => c_nof_regs, + init_sl => '0'); + + -- Registers in st_clk domain + SIGNAL count_reg : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); + + SIGNAL mm_cnt_clr : STD_LOGIC; + SIGNAL cnt_clr : STD_LOGIC; + SIGNAL cnt_blk : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + SIGNAL cnt_discarded : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + SIGNAL cnt_discarded_en : STD_LOGIC; + SIGNAL cnt_err : t_cnt_err_arr(g_nof_err_counts-1 DOWNTO 0); + SIGNAL cnt_err_en : STD_LOGIC_VECTOR(g_nof_err_counts-1 DOWNTO 0); + + SIGNAL err_ok : STD_LOGIC; + SIGNAL err_ok_reg : STD_LOGIC; + SIGNAL fifo_err_ok : STD_LOGIC; + SIGNAL fifo_err_ok_val : STD_LOGIC; + SIGNAL out_valid : STD_LOGIC; + SIGNAL out_valid_reg : STD_LOGIC; + + SIGNAL block_sosi : t_dp_sosi; + SIGNAL block_siso : t_dp_siso; + SIGNAL block_sosi_piped : t_dp_sosi; + +BEGIN + + mm_cnt_clr <= (reg_mosi.rd OR reg_mosi.wr) WHEN TO_UINT(reg_mosi.address(c_mm_reg.adr_w-1 DOWNTO 0)) = c_clear_adr ELSE '0' ; + u_common_spulse : ENTITY common_lib.common_spulse + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_pulse => mm_cnt_clr, + out_rst => dp_rst, + out_clk => dp_clk, + out_pulse => cnt_clr + ); + + -- block counter + u_blk_counter : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => g_cnt_w, + g_clip => TRUE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + cnt_clr => cnt_clr, + cnt_en => snk_in.eop, + count => cnt_blk + ); + + -- discarded block counter + cnt_discarded_en <= snk_in.eop WHEN TO_UINT(snk_in.err(g_nof_err_counts-1 DOWNTO 0)) > 0 ELSE '0'; + u_discarded_counter : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => g_cnt_w, + g_clip => TRUE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + cnt_clr => cnt_clr, + cnt_en => cnt_discarded_en, + count => cnt_discarded + ); + + -- error counters + gen_err_counters : FOR I IN 0 TO g_nof_err_counts-1 GENERATE + cnt_err_en(I) <= snk_in.eop AND snk_in.err(I); + u_blk_counter : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => g_cnt_w, + g_clip => TRUE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + cnt_clr => cnt_clr, + cnt_en => cnt_err_en(I), + count => cnt_err(I) + ); + END GENERATE; + + -- Register mapping + gen_reg : FOR I IN 0 TO g_nof_err_counts-1 GENERATE + count_reg((I + 1) * c_word_w - 1 DOWNTO I * c_word_w) <= RESIZE_UVEC(cnt_err(I), c_word_w); + END GENERATE; + count_reg((g_nof_err_counts+1) * c_word_w - 1 DOWNTO g_nof_err_counts * c_word_w ) <= RESIZE_UVEC(cnt_discarded, c_word_w); + count_reg((g_nof_err_counts+2) * c_word_w - 1 DOWNTO (g_nof_err_counts+1) * c_word_w ) <= RESIZE_UVEC(cnt_blk, c_word_w); + + u_reg : ENTITY common_lib.common_reg_r_w_dc + GENERIC MAP ( + g_cross_clock_domain => TRUE, + g_readback => FALSE, + g_reg => c_mm_reg + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => dp_rst, + st_clk => dp_clk, + + -- Memory Mapped Slave in mm_clk domain + sla_in => reg_mosi, + sla_out => reg_miso, + + -- MM registers in st_clk domain + reg_wr_arr => OPEN, + reg_rd_arr => OPEN, + in_reg => count_reg, -- read only + out_reg => OPEN -- no write + ); + + u_fifo_fill_eop : ENTITY work.dp_fifo_fill_eop + GENERIC MAP ( + g_data_w => g_data_w, + g_bsn_w => g_bsn_w, + g_empty_w => g_empty_w, + g_channel_w => g_channel_w, + g_use_bsn => g_use_bsn, + g_use_empty => g_use_empty, + g_use_channel => g_use_channel, + g_use_sync => g_use_sync, + g_use_complex => g_use_complex, + g_fifo_fill => g_max_block_size, + g_fifo_size => g_fifo_size + ) + PORT MAP ( + wr_rst => dp_rst, + wr_clk => dp_clk, + rd_rst => dp_rst, + rd_clk => dp_clk, + + -- ST sink + snk_out => snk_out, + snk_in => snk_in, + -- ST source + src_in => block_siso, + src_out => block_sosi + ); + + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => 1 -- 0 for wires, > 0 for registers, + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + -- ST sink + snk_out => block_siso, + snk_in => block_sosi, + -- ST source + src_in => src_in, + src_out => block_sosi_piped + ); + + p_dp_clk : PROCESS(dp_rst, dp_clk) + BEGIN + IF dp_rst='1' THEN + err_ok_reg <= '0'; + out_valid_reg <= '0'; + ELSIF rising_edge(dp_clk) THEN + err_ok_reg <= err_ok; + out_valid_reg <= out_valid; + END IF; + END PROCESS; + + err_ok <= NOT vector_or(snk_in.err(g_nof_err_counts-1 DOWNTO 0)) WHEN snk_in.eop = '1' ELSE err_ok_reg; + + u_fifo_err_ok : ENTITY common_lib.common_fifo_sc + GENERIC MAP ( + g_dat_w => 1, + g_nof_words => c_nof_err_ok + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + wr_dat(0) => err_ok, + wr_req => snk_in.eop, + rd_req => block_sosi.sop, + rd_dat(0) => fifo_err_ok, + rd_val => fifo_err_ok_val + ); + + out_valid <= fifo_err_ok WHEN fifo_err_ok_val = '1' ELSE out_valid_reg; + + p_src_out : PROCESS(block_sosi_piped, out_valid) + BEGIN + src_out <= block_sosi_piped; + src_out.valid <= block_sosi_piped.valid AND out_valid; + src_out.sop <= block_sosi_piped.sop AND out_valid; + src_out.eop <= block_sosi_piped.eop AND out_valid; + src_out.sync <= block_sosi_piped.sync AND out_valid; + END PROCESS; + +END rtl; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_validate_bsn_at_sync.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_bsn_at_sync.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9483cfab0d228c49774aaaadea4e3ee978b62d30 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_bsn_at_sync.vhd @@ -0,0 +1,235 @@ +------------------------------------------------------------------------------- +-- +-- 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_bsn_at_sync. +-- Description: +-- Verifies the output sosi of the DUT with the expected sosi. +-- The TB also reads the register values via MM and verifies them against the +-- expected values. +-- 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_mem_pkg.ALL; +USE common_lib.tb_common_mem_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_bsn_at_sync IS + GENERIC ( + g_nof_blocks_per_sync : NATURAL := 5; + g_nof_data_per_blk : NATURAL := 6; + g_bsn_init : NATURAL := 7; -- >= g_nof_blocks_per_sync for discarded sync, < g_nof_blocks_per_sync for no discarded sync, + g_check_channel : NATURAL := 8 -- channel to check, the channel field is a counter value. + ); +END tb_dp_block_validate_bsn_at_sync; + + +ARCHITECTURE tb OF tb_dp_block_validate_bsn_at_sync IS + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + CONSTANT c_dp_clk_period : TIME := 5 ns; + CONSTANT c_mm_clk_period : TIME := 10 ns; + + CONSTANT c_dut_pipeline : NATURAL := 1; + CONSTANT c_gap_size : NATURAL := 4; + CONSTANT c_nof_sync : NATURAL := 5; + CONSTANT c_nof_blk : NATURAL := g_nof_blocks_per_sync * c_nof_sync; + + SIGNAL dp_clk : STD_LOGIC := '1'; + SIGNAL mm_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 := c_dp_siso_rdy; + SIGNAL bs_sosi : t_dp_sosi; + SIGNAL bs_siso : t_dp_siso := c_dp_siso_rdy; + 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_cnt_reg : NATURAL; + SIGNAL reference_sosi : t_dp_sosi; + SIGNAL reference_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL reg_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_miso : t_mem_miso := c_mem_miso_rst; +BEGIN + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2; + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + rst <= '1', '0' AFTER c_dp_clk_period*7; + + ------------------------------------------------------------------------------ + -- Stimuli: + ------------------------------------------------------------------------------ + + -- Generate in_sosi with data frames + u_stimuli_in : ENTITY work.dp_stream_stimuli + GENERIC MAP ( + g_sync_period => g_nof_blocks_per_sync, + g_nof_repeat => c_nof_blk, + g_pkt_len => g_nof_data_per_blk, + g_pkt_gap => c_gap_size, + g_channel_init=> 0, + g_bsn_init => TO_DP_BSN(0) + ) + PORT MAP ( + rst => rst, + clk => dp_clk, + + -- Generate stimuli + src_in => stimuli_siso, + src_out => stimuli_sosi, + + -- End of stimuli + tb_end => stimuli_end + ); + + -- Generate bs_sosi with data frames + u_stimuli_bs : ENTITY work.dp_stream_stimuli + GENERIC MAP ( + g_sync_period => g_nof_blocks_per_sync, + g_nof_repeat => c_nof_blk, + g_pkt_len => g_nof_data_per_blk, + g_pkt_gap => c_gap_size, + g_channel_init=> 0, + g_bsn_init => TO_DP_BSN(g_bsn_init) + ) + PORT MAP ( + rst => rst, + clk => dp_clk, + + -- Generate stimuli + src_in => bs_siso, + src_out => bs_sosi, + + -- End of stimuli + tb_end => OPEN + ); + ------------------------------------------------------------------------------ + -- DUT + ------------------------------------------------------------------------------ + u_dut : ENTITY work.dp_block_validate_bsn_at_sync + GENERIC MAP ( + g_check_channel => g_check_channel + ) + PORT MAP ( + dp_rst => rst, + dp_clk => dp_clk, + + mm_rst => rst, + mm_clk => mm_clk, + -- ST sink + in_sosi => stimuli_sosi, + bs_sosi => bs_sosi, + -- ST source + out_sosi => verify_sosi, + + reg_mosi => reg_mosi, + reg_miso => reg_miso + ); + + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => c_dut_pipeline + ) + PORT MAP ( + rst => rst, + clk => dp_clk, + -- ST sink + snk_out => OPEN, + snk_in => stimuli_sosi, + -- ST source + src_in => reference_siso, + src_out => reference_sosi + ); + + reference_cnt_reg <= reference_cnt WHEN rising_edge(dp_clk); + reference_cnt <= reference_cnt_reg + 1 WHEN reference_sosi.sync='1' ELSE reference_cnt_reg; + + p_verify : PROCESS(dp_clk) + VARIABLE v_valid_blk : BOOLEAN := TRUE; + BEGIN + IF rising_edge(dp_clk) THEN + IF reference_sosi.sop = '1' THEN + IF g_bsn_init >= g_nof_blocks_per_sync AND TO_UINT(reference_sosi.channel) = g_check_channel THEN + v_valid_blk := FALSE; + ELSE + v_valid_blk := TRUE; + END IF; + END IF; + + IF v_valid_blk THEN -- we expect a block + ASSERT verify_sosi = reference_sosi REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ELSE -- we expect no block + ASSERT verify_sosi.valid = '0' REPORT "Wrong, valid is not '0' which is unexpected." SEVERITY ERROR; + ASSERT verify_sosi.sop = '0' REPORT "Wrong, sop is not '0' which is unexpected." SEVERITY ERROR; + ASSERT verify_sosi.eop = '0' REPORT "Wrong, eop is not '0' which is unexpected." SEVERITY ERROR; + END IF; + END IF; + END PROCESS; + + p_verify_mm : PROCESS + BEGIN + proc_common_wait_until_lo_hi(dp_clk, stimuli_end); + proc_common_wait_some_cycles(dp_clk, c_dut_pipeline + 1); + proc_common_wait_some_cycles(mm_clk, 1); + proc_mem_mm_bus_rd(1, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT c_nof_sync = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong total sync count" SEVERITY ERROR; + + proc_mem_mm_bus_rd(0, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + IF g_bsn_init = g_nof_blocks_per_sync THEN -- should have c_nof_sync discarded sync + ASSERT c_nof_sync = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong discarded sync count" SEVERITY ERROR; + ELSIF g_bsn_init > g_nof_blocks_per_sync THEN -- should have c_nof_sync -1 discarded sync + ASSERT c_nof_sync-1 = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong discarded sync count" SEVERITY ERROR; + ELSE -- 0 discarded sync + ASSERT 0 = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong discarded sync count" SEVERITY ERROR; + END IF; + proc_common_wait_some_cycles(dp_clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + +END tb; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9b0c20e901e1475494ae2798e9c98d159599e05e --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd @@ -0,0 +1,248 @@ +------------------------------------------------------------------------------- +-- +-- 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_err. +-- Description: +-- Verifies the output sosi of the DUT with the expected sosi. +-- The TB also reads the register values via MM and verifies them against the +-- expected values. +-- 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_mem_pkg.ALL; +USE common_lib.tb_common_mem_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_err IS + GENERIC ( + g_nof_blocks_per_sync : NATURAL := 5; + g_nof_data_per_blk : NATURAL := 9; + g_max_block_size : NATURAL := 9; + g_nof_err_counts : NATURAL := 8; + g_gap_size : NATURAL := 4; + g_cnt_w : NATURAL := 3 + ); +END tb_dp_block_validate_err; + + +ARCHITECTURE tb OF tb_dp_block_validate_err IS + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + CONSTANT c_dp_clk_period : TIME := 5 ns; + CONSTANT c_mm_clk_period : TIME := 10 ns; + + CONSTANT c_dut_pipeline : NATURAL := g_nof_data_per_blk + 3; + CONSTANT c_nof_sync : NATURAL := 5; + CONSTANT c_nof_blk : NATURAL := g_nof_blocks_per_sync * c_nof_sync; + CONSTANT c_nof_discarded : NATURAL := c_nof_blk - ceil_div(c_nof_blk, 2**g_nof_err_counts); + CONSTANT c_max_cnt : NATURAL := 2**g_cnt_w -1; + + CONSTANT c_mm_addr_dp_blk_cnt : NATURAL := g_nof_err_counts+1; + CONSTANT c_mm_addr_dp_discarded_cnt : NATURAL := g_nof_err_counts; + CONSTANT c_exp_blk_cnt : NATURAL := sel_a_b(c_nof_blk < c_max_cnt, c_nof_blk, c_max_cnt); + CONSTANT c_exp_discarded_cnt : NATURAL := sel_a_b(c_nof_discarded < c_max_cnt, c_nof_discarded, c_max_cnt); + + SIGNAL dp_clk : STD_LOGIC := '1'; + SIGNAL mm_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_cnt_reg : NATURAL; + SIGNAL reference_sosi : t_dp_sosi; + SIGNAL reference_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL reg_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_miso : t_mem_miso := c_mem_miso_rst; +BEGIN + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2; + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + rst <= '1', '0' AFTER c_dp_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 => g_gap_size, + g_err_init => 0, + g_err_incr => 1 + ) + PORT MAP ( + rst => rst, + clk => dp_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_err + GENERIC MAP ( + g_cnt_w => g_cnt_w, + g_max_block_size => g_max_block_size, + g_nof_err_counts => g_nof_err_counts, + g_data_w => c_word_w, + g_bsn_w => c_dp_stream_bsn_w, + g_empty_w => c_dp_stream_empty_w, + g_channel_w => c_dp_stream_channel_w, + g_use_bsn => TRUE, + g_use_empty => TRUE, + g_use_channel => TRUE, + g_use_sync => TRUE + ) + PORT MAP ( + dp_rst => rst, + dp_clk => dp_clk, + + mm_rst => rst, + mm_clk => mm_clk, + -- ST sink + snk_out => stimuli_siso, + snk_in => stimuli_sosi, + -- ST source + src_in => verify_siso, + src_out => verify_sosi, + + reg_mosi => reg_mosi, + reg_miso => reg_miso + ); + + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => c_dut_pipeline + ) + PORT MAP ( + rst => rst, + clk => dp_clk, + -- ST sink + snk_out => OPEN, + snk_in => stimuli_sosi, + -- ST source + src_in => reference_siso, + src_out => reference_sosi + ); + + reference_cnt_reg <= reference_cnt WHEN rising_edge(dp_clk); + reference_cnt <= 0 WHEN reference_sosi.eop='1' AND ((reference_cnt_reg+1) MOD 2**g_nof_err_counts) = 0 ELSE + reference_cnt_reg + 1 WHEN reference_sosi.eop='1' ELSE + reference_cnt_reg; + + p_verify : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + IF reference_cnt_reg = 0 THEN -- no errors so we expect a block + ASSERT verify_sosi.valid = reference_sosi.valid REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.sop = reference_sosi.sop REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.eop = reference_sosi.eop REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.data = reference_sosi.data REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.channel = reference_sosi.channel REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.bsn = reference_sosi.bsn REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.empty = reference_sosi.empty REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ASSERT verify_sosi.sync = reference_sosi.sync REPORT "Unexpected difference between in / out sosi" SEVERITY ERROR; + ELSE -- we expect no block as there are errors + ASSERT verify_sosi.valid = '0' REPORT "Wrong, valid is not '0' which is unexpected." SEVERITY ERROR; + ASSERT verify_sosi.sop = '0' REPORT "Wrong, sop is not '0' which is unexpected." SEVERITY ERROR; + ASSERT verify_sosi.eop = '0' REPORT "Wrong, eop is not '0' which is unexpected." SEVERITY ERROR; + END IF; + END IF; + END PROCESS; + + p_verify_mm : PROCESS + VARIABLE v_X : INTEGER := 0; -- variable to hold 2**I * ((c_nof_blk-1) / 2**(I+1)) + VARIABLE v_Y : INTEGER := 0; -- variable to hold (c_nof_blk-1) + 1 - (2 * v_X) - 2**I + -- v_N is a variable to hold the expected cnt number for the error counter registers = v_X + v_Y for v_Y > 0, else = v_x. + -- this can be calculated as the dp error field is a counter up to c_nof_blk - 1. + VARIABLE v_N : INTEGER := 0; + BEGIN + proc_common_wait_until_lo_hi(dp_clk, stimuli_end); + proc_common_wait_some_cycles(dp_clk, c_dut_pipeline + 1); + proc_common_wait_until_lo_hi(mm_clk, mm_clk); + proc_mem_mm_bus_rd(c_mm_addr_dp_discarded_cnt, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT c_exp_discarded_cnt = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong total discarded block count" SEVERITY ERROR; + proc_mem_mm_bus_rd(c_mm_addr_dp_blk_cnt, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT c_exp_blk_cnt = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong total block count" SEVERITY ERROR; + FOR I IN 0 TO g_nof_err_counts-1 LOOP + v_X := 2**I * ((c_nof_blk-1) / 2**(I+1)); + v_Y := c_nof_blk - 2*v_X - 2**I; + IF v_Y < 0 THEN -- v_N = v_X + v_Y only holds for v_Y > 0. + v_N := v_X; + ELSE + v_N := v_X + v_Y; + END IF; + + IF v_N > c_max_cnt THEN + v_N := c_max_cnt; -- the DUT clips the counters + END IF; + + proc_mem_mm_bus_rd(I, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT v_N = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong error count" SEVERITY ERROR; + END LOOP; + proc_common_wait_some_cycles(dp_clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + + tb_end <= '0', stimuli_end AFTER (1 + 10*c_dut_pipeline)*c_dp_clk_period; + +END tb; diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_bsn_at_sync.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_bsn_at_sync.vhd new file mode 100644 index 0000000000000000000000000000000000000000..6828a0964eebc0d01f5d017ed4866020a4ce2b1d --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_bsn_at_sync.vhd @@ -0,0 +1,55 @@ +------------------------------------------------------------------------------- +-- +-- 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_bsn_at_sync +-- Usage: +-- > as 3 +-- > run -all + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_dp_block_validate_bsn_at_sync IS +END tb_tb_dp_block_validate_bsn_at_sync; + + +ARCHITECTURE tb OF tb_tb_dp_block_validate_bsn_at_sync 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; + +BEGIN +-- g_nof_blocks_per_sync : NATURAL := 5; +-- g_nof_data_per_blk : NATURAL := 6; +-- g_bsn_init : NATURAL := 7; -- >= g_nof_blocks_per_sync for discarded sync, < g_nof_blocks_per_sync for no discarded sync, +-- g_check_channel : NATURAL := 8 -- channel to check, the channel field is a counter value. + + u_smaller : ENTITY work.tb_dp_block_validate_bsn_at_sync GENERIC MAP(c_blk_per_sync, c_data_per_blk, 0, 8); -- g_bsn_init < g_nof_blocks_per_sync + u_equal : ENTITY work.tb_dp_block_validate_bsn_at_sync GENERIC MAP(c_blk_per_sync, c_data_per_blk, 5, 8); -- g_bsn_init = g_nof_blocks_per_sync + u_larger : ENTITY work.tb_dp_block_validate_bsn_at_sync GENERIC MAP(c_blk_per_sync, c_data_per_blk, 8, 8); -- g_bsn_init > g_nof_blocks_per_sync + u_ch_on_sync : ENTITY work.tb_dp_block_validate_bsn_at_sync GENERIC MAP(c_blk_per_sync, c_data_per_blk, 5, 10); -- g_check_channel MOD c_blk_per_sync = 0, + u_no_ch : ENTITY work.tb_dp_block_validate_bsn_at_sync GENERIC MAP(c_blk_per_sync, c_data_per_blk, 8, 500); -- channel will never reach 500 + +END tb; diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_err.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_err.vhd new file mode 100644 index 0000000000000000000000000000000000000000..800a23d1ea1485892223e9a5d6db79e97dedf032 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_validate_err.vhd @@ -0,0 +1,61 @@ +------------------------------------------------------------------------------- +-- +-- 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_err +-- Usage: +-- > as 3 +-- > run -all + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_dp_block_validate_err IS +END tb_tb_dp_block_validate_err; + + +ARCHITECTURE tb OF tb_tb_dp_block_validate_err 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_max_block_size : NATURAL := 9; + CONSTANT c_nof_err_counts : NATURAL := 5; + +BEGIN +-- g_nof_blocks_per_sync : NATURAL := 5; +-- g_nof_data_per_blk : NATURAL := 9; +-- g_max_block_size : NATURAL := 9; +-- g_nof_err_counts : NATURAL := 8; +-- g_gap_size : NATURAL := 4; +-- g_cnt_w : NATURAL := 3 + + u_normal : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 4, 3); + u_clip : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 4, 3); + u_small_cnt_w : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 4, 1); + u_large_cnt_w : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 4, 30); + u_small_gap : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 1, 16); + u_large_gap : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, c_nof_err_counts, 100, 16); + u_low_nof_cnt : ENTITY work.tb_dp_block_validate_err GENERIC MAP(c_blk_per_sync, c_data_per_blk, c_max_block_size, 1, 1, 16); + +END tb;