diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 08537b9386a3559f408af39417fe3e639007a298..da71a5d70f0be663752818236304b02296339746 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -108,6 +108,9 @@ synth_files = src/vhdl/dp_bsn_monitor.vhd src/vhdl/dp_bsn_monitor_reg.vhd src/vhdl/mms_dp_bsn_monitor.vhd + src/vhdl/dp_bsn_monitor_v2.vhd + src/vhdl/dp_bsn_monitor_reg_v2.vhd + src/vhdl/mms_dp_bsn_monitor_v2.vhd src/vhdl/dp_distribute.vhd src/vhdl/dp_ram_from_mm.vhd src/vhdl/dp_ram_from_mm_reg.vhd @@ -193,6 +196,7 @@ test_bench_files = tb/vhdl/tb_dp_bsn_align.vhd tb/vhdl/tb_mms_dp_bsn_align.vhd tb/vhdl/tb_dp_bsn_monitor.vhd + tb/vhdl/tb_dp_bsn_monitor_v2.vhd tb/vhdl/tb_dp_bsn_source.vhd tb/vhdl/tb_dp_bsn_source_v2.vhd tb/vhdl/tb_mms_dp_bsn_source.vhd diff --git a/libraries/base/dp/src/vhdl/dp_bsn_monitor_reg_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_monitor_reg_v2.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2c010ff1ce6a601a63f7a752870c2fbe435a100f --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_bsn_monitor_reg_v2.vhd @@ -0,0 +1,130 @@ +-- -------------------------------------------------------------------------- +-- 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: +-- . Reinier vd Walle +-- Purpose: Provide MM slave register for dp_bsn_monitor +-- Description: +-- +-- Read only monitor register for streams with sync. +-- +-- 31 24 23 16 15 8 7 0 wi +-- |-----------------|-----------------|-----------------|-----------------| +-- | sync timeout = [2], ready_stable = [1], xon_stable = [0] | 0 +-- |-----------------------------------------------------------------------| +-- | bsn_at_sync[31: 0] | 1 +-- |-----------------------------------------------------------------------| +-- | bsn_at_sync[63:32] | 2 +-- |-----------------------------------------------------------------------| +-- | nof_sop[31: 0] | 3 +-- |-----------------------------------------------------------------------| +-- | nof_valid[31: 0] | 4 +-- |-----------------------------------------------------------------------| +-- | nof_err[31: 0] | 5 +-- |-----------------------------------------------------------------------| +-- | latency[31: 0] | 6 +-- |-----------------------------------------------------------------------| +-- -------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +ENTITY dp_bsn_monitor_reg_v2 IS + GENERIC ( + g_cross_clock_domain : BOOLEAN := TRUE -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + st_rst : IN STD_LOGIC; -- reset synchronous with st_clk + st_clk : IN STD_LOGIC; -- other clock domain clock + + -- Memory Mapped Slave in mm_clk domain + sla_in : IN t_mem_mosi; -- actual ranges defined by c_mm_reg + sla_out : OUT t_mem_miso; -- actual ranges defined by c_mm_reg + + -- MM registers in st_clk domain + mon_evt : IN STD_LOGIC; -- pulses when new monitor data is available regarding the previous sync interval + mon_sync_timeout : IN STD_LOGIC; + -- . siso + mon_ready_stable : IN STD_LOGIC; + mon_xon_stable : IN STD_LOGIC; + -- . sosi + mon_bsn_at_sync : IN STD_LOGIC_VECTOR; + mon_nof_sop : IN STD_LOGIC_VECTOR; + mon_nof_err : IN STD_LOGIC_VECTOR; + mon_nof_valid : IN STD_LOGIC_VECTOR; + mon_latency : IN STD_LOGIC_VECTOR + ); +END dp_bsn_monitor_reg_v2; + + +ARCHITECTURE str OF dp_bsn_monitor_reg_v2 IS + + -- Define the actual size of the MM slave register + CONSTANT c_mm_reg : t_c_mem := (latency => 1, + adr_w => 3, + dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers + nof_dat => 7, + init_sl => '0'); + + -- Registers in st_clk domain + SIGNAL mon_reg : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); + +BEGIN + + -- Register mapping + mon_reg( 3-1 DOWNTO 0) <= mon_sync_timeout & mon_ready_stable & mon_xon_stable; + mon_reg(1*c_word_w-1 DOWNTO 3) <= (OTHERS=>'0'); + mon_reg(3*c_word_w-1 DOWNTO 1*c_word_w) <= RESIZE_UVEC(mon_bsn_at_sync, c_longword_w); + mon_reg(4*c_word_w-1 DOWNTO 3*c_word_w) <= RESIZE_UVEC(mon_nof_sop, c_word_w); + mon_reg(5*c_word_w-1 DOWNTO 4*c_word_w) <= RESIZE_UVEC(mon_nof_valid, c_word_w); + mon_reg(6*c_word_w-1 DOWNTO 5*c_word_w) <= RESIZE_UVEC(mon_nof_err, c_word_w); + mon_reg(7*c_word_w-1 DOWNTO 6*c_word_w) <= RESIZE_UVEC(mon_latency, c_word_w); + + u_reg : ENTITY common_lib.common_reg_r_w_dc + GENERIC MAP ( + g_cross_clock_domain => g_cross_clock_domain, + g_in_new_latency => 1, -- mon_evt to mon_reg has latency 1 in dp_bsn_monitor + g_readback => FALSE, + g_reg => c_mm_reg + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + + -- Memory Mapped Slave in mm_clk domain + sla_in => sla_in, + sla_out => sla_out, + + -- MM registers in st_clk domain + reg_wr_arr => OPEN, + reg_rd_arr => OPEN, + in_new => mon_evt, + in_reg => mon_reg, -- read only + out_reg => OPEN -- no write + ); + +END str; diff --git a/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd new file mode 100644 index 0000000000000000000000000000000000000000..fb11b08d928086630b22b7f35b1fd95b9644a950 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd @@ -0,0 +1,332 @@ +-- -------------------------------------------------------------------------- +-- 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: +-- . Reinier vd Walle +-- Purpose: Monitor the sosi and siso control of a stream per sync interval +-- Description: +-- The mon_evt pulses when new monitor output is available regarding the +-- previous in_sosi.sync interval: +-- . mon_sync_timeout = '1' when the in_sosi.sync did not occur +-- . mon_ready_stable = '1' when ready was always '1' during last sync interval +-- . mon_xon_stable = '1' when xon was always '1' during last sync interval +-- . mon_bsn_at_sync = BSN at sync +-- . mon_nof_sop = number of sop during last sync interval +-- . mon_nof_err = number of err at eop during last sync interval +-- . mon_nof_valid = number of valid during last sync interval; +-- . mon_latency = number of clock cycles between ref_sync and in_sosi.sync; +-- +-- Remarks: +-- . Assumes RL > 0 so each active valid indicates a new data (with RL = 0 the +-- valid remains active until an acknowledge by ready) +-- . If mon_sync_timeout = '1', all output vectors are forced -1 (all ones) to +-- indicate they are not valid. +-- -------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.all; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE work.dp_stream_pkg.ALL; + + +ENTITY dp_bsn_monitor_v2 IS + GENERIC ( + g_sync_timeout : NATURAL := 200*10**6; -- choose >= nof clk cycles per sync period + g_error_bi : NATURAL := 0 + ); + PORT ( + rst : IN STD_LOGIC := '0'; + clk : IN STD_LOGIC; + + -- ST interface + in_siso : IN t_dp_siso; + in_sosi : IN t_dp_sosi; + ref_sync : IN STD_LOGIC := '0'; -- reference sync input + -- MM interface + -- . control + mon_evt : OUT STD_LOGIC; -- pulses when new monitor output is available regarding the previous sync interval + mon_sync : OUT STD_LOGIC; -- pulses every in_sosi.sync interval + mon_sync_timeout : OUT STD_LOGIC; + -- . siso + mon_ready_stable : OUT STD_LOGIC; + mon_xon_stable : OUT STD_LOGIC; + -- . sosi + mon_bsn_at_sync : OUT STD_LOGIC_VECTOR; + mon_nof_sop : OUT STD_LOGIC_VECTOR; + mon_nof_err : OUT STD_LOGIC_VECTOR; + mon_nof_valid : OUT STD_LOGIC_VECTOR; + mon_latency : OUT STD_LOGIC_VECTOR + ); +END dp_bsn_monitor_v2; + + +ARCHITECTURE rtl OF dp_bsn_monitor_v2 IS + + CONSTANT c_sync_timeout_w : NATURAL := ceil_log2(g_sync_timeout); + CONSTANT c_bsn_w : NATURAL := mon_bsn_at_sync'LENGTH; + CONSTANT c_cnt_sop_w : NATURAL := mon_nof_sop'LENGTH; + CONSTANT c_cnt_valid_w : NATURAL := mon_nof_valid'LENGTH; + CONSTANT c_cnt_latency_w : NATURAL := mon_latency'LENGTH; + + CONSTANT inv_mon_bsn_at_sync : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT inv_mon_nof_sop : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT inv_mon_nof_err : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT inv_mon_nof_valid : STD_LOGIC_VECTOR(c_cnt_valid_w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT inv_mon_latency : STD_LOGIC_VECTOR(c_cnt_latency_w-1 DOWNTO 0) := (OTHERS => '1'); + + SIGNAL ready : STD_LOGIC; + SIGNAL nxt_ready : STD_LOGIC; + SIGNAL ready_stable : STD_LOGIC; + SIGNAL xon : STD_LOGIC; + SIGNAL nxt_xon : STD_LOGIC; + SIGNAL xon_stable : STD_LOGIC; + + SIGNAL err : STD_LOGIC; + SIGNAL nxt_err : STD_LOGIC; + SIGNAL valid : STD_LOGIC; + SIGNAL nxt_valid : STD_LOGIC; + SIGNAL sop : STD_LOGIC; + SIGNAL nxt_sop : STD_LOGIC; + SIGNAL sync : STD_LOGIC; + SIGNAL nxt_sync : STD_LOGIC; + SIGNAL bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + SIGNAL nxt_bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + SIGNAL cnt_sop : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL nof_sop : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL cnt_err : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); -- use c_cnt_sop_w, because at maximium all frames have an error + SIGNAL nof_err : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL cnt_valid : STD_LOGIC_VECTOR(c_cnt_valid_w-1 DOWNTO 0); + SIGNAL nof_valid : STD_LOGIC_VECTOR(c_cnt_valid_w-1 DOWNTO 0); + SIGNAL cnt_latency : STD_LOGIC_VECTOR(c_cnt_latency_w-1 DOWNTO 0); + SIGNAL latency : STD_LOGIC_VECTOR(c_cnt_latency_w-1 DOWNTO 0); + + SIGNAL i_mon_ready_stable : STD_LOGIC; + SIGNAL i_mon_xon_stable : STD_LOGIC; + SIGNAL i_mon_bsn_at_sync : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + SIGNAL i_mon_nof_sop : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL i_mon_nof_err : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL i_mon_nof_valid : STD_LOGIC_VECTOR(c_cnt_valid_w-1 DOWNTO 0); + SIGNAL i_mon_latency : STD_LOGIC_VECTOR(c_cnt_latency_w-1 DOWNTO 0); + SIGNAL i_current_bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + + SIGNAL sync_timeout_cnt : STD_LOGIC_VECTOR(c_sync_timeout_w-1 DOWNTO 0); + SIGNAL sync_timeout : STD_LOGIC; + SIGNAL sync_timeout_n : STD_LOGIC; + SIGNAL nxt_sync_timeout : STD_LOGIC; + SIGNAL sync_timeout_revt : STD_LOGIC; + + SIGNAL nxt_mon_evt : STD_LOGIC; + SIGNAL nxt_mon_ready_stable : STD_LOGIC; + SIGNAL nxt_mon_xon_stable : STD_LOGIC; + SIGNAL nxt_mon_bsn_at_sync : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + SIGNAL nxt_mon_nof_sop : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL nxt_mon_nof_err : STD_LOGIC_VECTOR(c_cnt_sop_w-1 DOWNTO 0); + SIGNAL nxt_mon_nof_valid : STD_LOGIC_VECTOR(c_cnt_valid_w-1 DOWNTO 0); + SIGNAL nxt_mon_latency : STD_LOGIC_VECTOR(c_cnt_latency_w-1 DOWNTO 0); + SIGNAL nxt_current_bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); + +BEGIN + + mon_sync <= sync; + mon_sync_timeout <= sync_timeout; + mon_ready_stable <= i_mon_ready_stable; + mon_xon_stable <= i_mon_xon_stable; + mon_bsn_at_sync <= i_mon_bsn_at_sync WHEN sync_timeout='0' ELSE inv_mon_bsn_at_sync; + mon_nof_sop <= i_mon_nof_sop WHEN sync_timeout='0' ELSE inv_mon_nof_sop; + mon_nof_err <= i_mon_nof_err WHEN sync_timeout='0' ELSE inv_mon_nof_err; + mon_nof_valid <= i_mon_nof_valid WHEN sync_timeout='0' ELSE inv_mon_nof_valid; + mon_latency <= i_mon_latency WHEN sync_timeout='0' ELSE inv_mon_latency; + + nxt_mon_evt <= sync OR sync_timeout_revt; + nxt_mon_ready_stable <= ready_stable WHEN sync='1' ELSE i_mon_ready_stable; + nxt_mon_xon_stable <= xon_stable WHEN sync='1' ELSE i_mon_xon_stable; + nxt_mon_bsn_at_sync <= bsn WHEN sync='1' ELSE i_mon_bsn_at_sync; + nxt_mon_nof_sop <= nof_sop WHEN sync='1' ELSE i_mon_nof_sop; + nxt_mon_nof_err <= nof_err WHEN sync='1' ELSE i_mon_nof_err; + nxt_mon_nof_valid <= nof_valid WHEN sync='1' ELSE i_mon_nof_valid; + nxt_mon_latency <= latency WHEN sync='1' ELSE i_mon_latency; + + nof_sop <= INCR_UVEC(cnt_sop, 1); -- +1 because the sop at the sync also counts + nof_err <= cnt_err; + nof_valid <= INCR_UVEC(cnt_valid, 1); -- +1 because the valid at the sync also counts + latency <= cnt_latency; + + u_sync_timeout_cnt : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_sync_timeout_w + ) + PORT MAP ( + rst => rst, + clk => clk, + cnt_clr => sync, + cnt_en => sync_timeout_n, + count => sync_timeout_cnt + ); + + sync_timeout_n <= NOT nxt_sync_timeout; + + nxt_sync_timeout <= '1' WHEN UNSIGNED(sync_timeout_cnt)>=g_sync_timeout ELSE '0'; + + u_sync_timeout_revt : ENTITY common_lib.common_evt + GENERIC MAP ( + g_evt_type => "RISING", + g_out_invert => FALSE, + g_out_reg => FALSE + ) + PORT MAP ( + rst => rst, + clk => clk, + in_sig => sync_timeout, + out_evt => sync_timeout_revt + ); + + p_clk : PROCESS(rst, clk) + BEGIN + IF rst = '1' THEN + -- internal + ready <= '0'; + xon <= '0'; + valid <= '0'; + sop <= '0'; + err <= '0'; + sync <= '0'; + bsn <= (OTHERS=>'0'); + -- output + mon_evt <= '0'; + sync_timeout <= '0'; + i_mon_ready_stable <= '0'; + i_mon_xon_stable <= '0'; + i_mon_bsn_at_sync <= (OTHERS=>'0'); + i_mon_nof_sop <= (OTHERS=>'0'); + i_mon_nof_err <= (OTHERS=>'0'); + i_mon_nof_valid <= (OTHERS=>'0'); + i_mon_latency <= (OTHERS=>'0'); + i_current_bsn <= (OTHERS=>'0'); + ELSIF rising_edge(clk) THEN + -- internal + ready <= nxt_ready; + xon <= nxt_xon; + valid <= nxt_valid; + sop <= nxt_sop; + err <= nxt_err; + sync <= nxt_sync; + bsn <= nxt_bsn; + -- output + mon_evt <= nxt_mon_evt; + sync_timeout <= nxt_sync_timeout; + i_mon_ready_stable <= nxt_mon_ready_stable; + i_mon_xon_stable <= nxt_mon_xon_stable; + i_mon_bsn_at_sync <= nxt_mon_bsn_at_sync; + i_mon_nof_sop <= nxt_mon_nof_sop; + i_mon_nof_err <= nxt_mon_nof_err; + i_mon_nof_valid <= nxt_mon_nof_valid; + i_mon_latency <= nxt_mon_latency; + i_current_bsn <= nxt_current_bsn; + END IF; + END PROCESS; + + -- siso + nxt_ready <= in_siso.ready; + nxt_xon <= in_siso.xon; + + u_ready_stable : ENTITY common_lib.common_stable_monitor + PORT MAP ( + rst => rst, + clk => clk, + -- MM + r_in => ready, + r_stable => ready_stable, + r_stable_ack => sync + ); + + u_xon_stable : ENTITY common_lib.common_stable_monitor + PORT MAP ( + rst => rst, + clk => clk, + -- MM + r_in => xon, + r_stable => xon_stable, + r_stable_ack => sync + ); + + -- Sample the BSN, because BSN is only valid during sop. + nxt_current_bsn <= in_sosi.bsn(c_bsn_w-1 DOWNTO 0) WHEN in_sosi.sop='1' ELSE i_current_bsn; + + -- sosi + -- . no need to AND sop, eop with valid, because can only be active when valid = '1' + -- . no need to AND sync with sop, because can only be active when sop = '1' + nxt_valid <= in_sosi.valid; + nxt_sop <= in_sosi.sop; + nxt_sync <= in_sosi.sync; + nxt_err <= in_sosi.err(g_error_bi) WHEN in_sosi.eop='1' ELSE '0'; -- assume sosi.err(g_error_bi) = '1' at eop indicates an error + nxt_bsn <= in_sosi.bsn(c_bsn_w-1 DOWNTO 0) WHEN in_sosi.sop='1' ELSE bsn; -- keep bsn as defined at sop + + u_cnt_sop : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_cnt_sop_w + ) + PORT MAP ( + rst => rst, + clk => clk, + cnt_clr => sync, + cnt_en => sop, + count => cnt_sop + ); + + u_nof_err : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_cnt_sop_w + ) + PORT MAP ( + rst => rst, + clk => clk, + cnt_clr => sync, + cnt_en => err, + count => cnt_err + ); + + u_cnt_valid : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_cnt_valid_w + ) + PORT MAP ( + rst => rst, + clk => clk, + cnt_clr => sync, + cnt_en => valid, + count => cnt_valid + ); + + u_cnt_latency : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => c_cnt_latency_w + ) + PORT MAP ( + rst => rst, + clk => clk, + cnt_clr => ref_sync, + cnt_en => '1', + count => cnt_latency + ); + +END rtl; + + + diff --git a/libraries/base/dp/src/vhdl/mms_dp_bsn_monitor_v2.vhd b/libraries/base/dp/src/vhdl/mms_dp_bsn_monitor_v2.vhd new file mode 100644 index 0000000000000000000000000000000000000000..64bf0567a6ecd37bef46fb2db0a67ed9019d7af9 --- /dev/null +++ b/libraries/base/dp/src/vhdl/mms_dp_bsn_monitor_v2.vhd @@ -0,0 +1,165 @@ +-- -------------------------------------------------------------------------- +-- 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: +-- . Reinier vd Walle +-- Purpose : MMS for dp_bsn_monitor_v2 +-- Description: See dp_bsn_monitor_v2.vhd +-- -------------------------------------------------------------------------- + +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 work.dp_stream_pkg.ALL; + +ENTITY mms_dp_bsn_monitor_v2 IS + GENERIC ( + g_nof_streams : POSITIVE := 1; + g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and dp_clk are the same, else use TRUE to cross the clock domain + g_sync_timeout : NATURAL := 200*10**6; + g_bsn_w : NATURAL := c_dp_stream_bsn_w; + g_error_bi : NATURAL := 0; + g_cnt_sop_w : NATURAL := c_word_w; + g_cnt_valid_w : NATURAL := c_word_w; + g_cnt_latency_w : NATURAL := c_word_w + ); + PORT ( + -- Memory-mapped clock domain + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + reg_mosi : IN t_mem_mosi; + reg_miso : OUT t_mem_miso; + + -- Streaming clock domain + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + ref_sync : IN STD_LOGIC := '0'; -- ref Sync input + + in_siso_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + in_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) + ); +END mms_dp_bsn_monitor_v2; + + +ARCHITECTURE str OF mms_dp_bsn_monitor_v2 IS + + CONSTANT c_reg_adr_w : NATURAL := ceil_log2(7); + + SIGNAL mon_evt_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + SIGNAL mon_sync_timeout_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + + SIGNAL mon_ready_stable_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + SIGNAL mon_xon_stable_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + + TYPE t_mon_bsn_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + TYPE t_mon_sop_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(g_cnt_sop_w-1 DOWNTO 0); + TYPE t_mon_val_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(g_cnt_valid_w-1 DOWNTO 0); + TYPE t_mon_lat_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(g_cnt_latency_w-1 DOWNTO 0); + + SIGNAL mon_bsn_at_sync_arr : t_mon_bsn_arr; + SIGNAL mon_nof_sop_arr : t_mon_sop_arr; + SIGNAL mon_nof_err_arr : t_mon_sop_arr; -- use g_cnt_sop_w, because at maximium all frames have an error + SIGNAL mon_nof_valid_arr : t_mon_val_arr; + SIGNAL mon_latency_arr : t_mon_lat_arr; + + SIGNAL reg_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL reg_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); + +BEGIN + + u_common_mem_mux : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_reg_adr_w + ) + PORT MAP ( + mosi => reg_mosi, + miso => reg_miso, + mosi_arr => reg_mosi_arr, + miso_arr => reg_miso_arr + ); + + gen_stream : FOR i IN 0 TO g_nof_streams-1 GENERATE + + u_reg : ENTITY work.dp_bsn_monitor_reg_v2 + GENERIC MAP ( + g_cross_clock_domain => g_cross_clock_domain + ) + 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_arr(i), + sla_out => reg_miso_arr(i), + + -- MM registers in dp_clk domain + -- . control + mon_evt => mon_evt_arr(i), + mon_sync_timeout => mon_sync_timeout_arr(i), + -- . siso + mon_ready_stable => mon_ready_stable_arr(i), + mon_xon_stable => mon_xon_stable_arr(i), + -- . sosi + mon_bsn_at_sync => mon_bsn_at_sync_arr(i), + mon_nof_sop => mon_nof_sop_arr(i), + mon_nof_err => mon_nof_err_arr(i), + mon_nof_valid => mon_nof_valid_arr(i), + mon_latency => mon_latency_arr(i) + ); + + u_mon : ENTITY work.dp_bsn_monitor_v2 + GENERIC MAP ( + g_sync_timeout => g_sync_timeout, + g_error_bi => g_error_bi + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + -- ST interface + in_siso => in_siso_arr(i), + in_sosi => in_sosi_arr(i), + ref_sync => ref_sync, + + -- MM interface + -- . control + mon_evt => mon_evt_arr(i), -- pulses when new monitor data is available regarding the previous sync interval + mon_sync => OPEN, + mon_sync_timeout => mon_sync_timeout_arr(i), + -- . siso + mon_ready_stable => mon_ready_stable_arr(i), + mon_xon_stable => mon_xon_stable_arr(i), + -- . sosi + mon_bsn_at_sync => mon_bsn_at_sync_arr(i), + mon_nof_sop => mon_nof_sop_arr(i), + mon_nof_err => mon_nof_err_arr(i), + mon_nof_valid => mon_nof_valid_arr(i), + mon_latency => mon_latency_arr(i) + ); + + END GENERATE; + +END str; + diff --git a/libraries/base/dp/tb/vhdl/tb_dp_bsn_monitor_v2.vhd b/libraries/base/dp/tb/vhdl/tb_dp_bsn_monitor_v2.vhd new file mode 100644 index 0000000000000000000000000000000000000000..09eeec859d5d0b885a9508a32c565ff0674afb5f --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_monitor_v2.vhd @@ -0,0 +1,343 @@ +-- -------------------------------------------------------------------------- +-- 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: +-- . Reinier vd Walle +-- Purpose: Verify dp_bsn_monitor_v2 for different RL +-- Description: +-- Usage: +-- > as 10 +-- > run -all -- signal tb_end will stop the simulation by stopping the clk +-- . The verify procedures check the correct input and monitor results +-- -------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + + +ENTITY tb_dp_bsn_monitor_v2 IS + GENERIC ( + g_in_en : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control + g_nof_sync : NATURAL := 11 + ); +END tb_dp_bsn_monitor_v2; + + +ARCHITECTURE tb OF tb_dp_bsn_monitor_v2 IS + + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_data_w : NATURAL := 16; + CONSTANT c_data_init : INTEGER := 0; + CONSTANT c_frame_len : NATURAL := 20; + CONSTANT c_pulse_active : NATURAL := 1; + CONSTANT c_pulse_period : NATURAL := 7; + CONSTANT c_sync_period : NATURAL := 17; + CONSTANT c_sync_offset : NATURAL := 0; + CONSTANT c_sync_timeout : NATURAL := c_frame_len*c_sync_period; + CONSTANT c_nof_repeat : NATURAL := g_nof_sync * c_sync_period + 1; + CONSTANT c_ref_sync_latency : NATURAL := 7; + + -- Error control + CONSTANT c_skip_sync_nr : INTEGER := -1; -- use e.g. 5 >= 0 to introduce a sync timeout at that sync interval 5 (causes missing sinc error by proc_dp_verify_sync), use -1 to disable skipping a sync + CONSTANT c_nof_err : NATURAL := 2; -- <= c_sync_period -- introduce frame errors + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + + -- Flow control + SIGNAL random_0 : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0'); -- use different lengths to have different random sequences + SIGNAL pulse_0 : STD_LOGIC; + SIGNAL pulse_en : STD_LOGIC := '1'; + + -- Stimuli + SIGNAL in_en : STD_LOGIC := '1'; + SIGNAL in_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL in_sosi : t_dp_sosi; + SIGNAL ref_sync : STD_LOGIC := '0'; + + -- Output + SIGNAL out_siso : t_dp_siso; + + -- Monitor in_sosi and out_siso + SIGNAL mon_evt : STD_LOGIC; -- pulses when new monitor output is available regarding the previous sync interval + SIGNAL mon_sync : STD_LOGIC; -- pulses every in_sync interval + SIGNAL mon_sync_timeout : STD_LOGIC; + SIGNAL mon_ready_stable : STD_LOGIC; + SIGNAL mon_xon_stable : STD_LOGIC; + SIGNAL mon_bsn_at_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mon_nof_sop : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mon_nof_err : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mon_nof_valid : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mon_latency : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + -- Verification + SIGNAL verify_en : STD_LOGIC := '0'; + SIGNAL verify_done : STD_LOGIC := '0'; + SIGNAL count_eop : NATURAL := 0; + + SIGNAL prev_in_ready : STD_LOGIC_VECTOR(0 TO c_rl); + SIGNAL prev_in_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0) := TO_SVEC(c_data_init-1, c_data_w); + SIGNAL in_bsn : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL in_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); + SIGNAL in_sync : STD_LOGIC; + SIGNAL in_val : STD_LOGIC; + SIGNAL in_sop : STD_LOGIC; + SIGNAL in_eop : STD_LOGIC; + SIGNAL expected_in_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); + + SIGNAL expected_bsn_at_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL expected_nof_sop : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL expected_nof_err : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL expected_nof_valid : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL expected_latency : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + +BEGIN + + clk <= (NOT clk) OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + + random_0 <= func_common_random(random_0) WHEN rising_edge(clk); + + proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period, '1', rst, clk, pulse_en, pulse_0); + + + ------------------------------------------------------------------------------ + -- SOSI DATA GENERATION + ------------------------------------------------------------------------------ + + in_en <= '1' WHEN g_in_en=e_active ELSE + random_0(random_0'HIGH) WHEN g_in_en=e_random ELSE + pulse_0 WHEN g_in_en=e_pulse; + + in_siso <= c_dp_siso_rdy; + + -- Generate data path input data + p_sosi_stimuli : PROCESS + VARIABLE v_data_init : NATURAL; + VARIABLE v_nof_err : NATURAL; + VARIABLE v_err : NATURAL; + VARIABLE v_sync_cnt : NATURAL; + VARIABLE v_sync : STD_LOGIC; + BEGIN + v_data_init := c_data_init; + v_sync_cnt := 0; + v_nof_err := 0; + in_sosi <= c_dp_sosi_rst; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 5); + + -- Begin of stimuli + FOR R IN 0 TO c_nof_repeat-1 LOOP + -- control the sync intervals + -- . introduce sync timeout by skipping a sync + -- . introduce frame errors via sosi.err + v_sync := sel_a_b(R MOD c_sync_period = c_sync_offset, '1', '0'); + IF v_sync='1' THEN + v_sync_cnt := v_sync_cnt + 1; + IF v_sync_cnt=c_skip_sync_nr THEN + v_sync := '0'; + END IF; + v_nof_err := 0; + ELSE + v_nof_err := v_nof_err + 1; + END IF; + v_err := 0; + IF v_nof_err<c_nof_err THEN + v_err := 1; + END IF; + + proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_data_w, v_data_init, 0, 0, c_frame_len, 0, v_err, v_sync, TO_DP_BSN(R), clk, in_en, in_siso, in_sosi); + --proc_common_wait_some_cycles(clk, 10); + v_data_init := v_data_init + c_frame_len; + END LOOP; + + -- End of stimuli + expected_in_data <= TO_UVEC(v_data_init-1, c_data_w); + + proc_common_wait_until_high(clk, verify_done); + proc_common_wait_some_cycles(clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + + expected_bsn_at_sync <= TO_UVEC( c_nof_repeat-1, c_word_w); + expected_nof_sop <= TO_UVEC( c_sync_period, c_word_w); + expected_nof_err <= TO_UVEC( c_nof_err, c_word_w); + expected_nof_valid <= TO_UVEC(c_frame_len*c_sync_period, c_word_w); + expected_latency <= TO_UVEC( c_ref_sync_latency, c_word_w); + + ------------------------------------------------------------------------------ + -- SISO FLOW CONTROL GENERATION + ------------------------------------------------------------------------------ + + p_siso_stimuli : PROCESS + BEGIN + out_siso <= c_dp_siso_rdy; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 5); + + -- Pulse ready low + proc_common_wait_until_hi_lo(clk, in_sosi.sync); + proc_common_wait_until_hi_lo(clk, in_sosi.sop); + proc_common_wait_until_hi_lo(clk, in_sosi.sop); + proc_common_wait_some_cycles(clk, 3); + out_siso.ready <= '0'; + proc_common_wait_some_cycles(clk, 1); + out_siso.ready <= '1'; + + -- Pulse xon low + proc_common_wait_until_hi_lo(clk, in_sosi.sop); + proc_common_wait_until_hi_lo(clk, in_sosi.sop); + proc_common_wait_some_cycles(clk, 3); + out_siso.xon <= '0'; + proc_common_wait_some_cycles(clk, 1); + out_siso.xon <= '1'; + + -- Keep ready active + -- Keep xon active + proc_common_wait_until_hi_lo(clk, in_sosi.sync); + proc_common_wait_until_hi_lo(clk, in_sosi.sync); + + -- Make xon low for whole interval + out_siso.xon <= '0'; + proc_common_wait_until_hi_lo(clk, in_sosi.sync); + -- Make xon high during the interval + proc_common_wait_some_cycles(clk, 1); + out_siso.xon <= '1'; + + WAIT; + END PROCESS; + + p_siso_verify : PROCESS + BEGIN + -- The assert conditions must manually be set such to fit the stimuli from p_siso_stimuli + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='0' REPORT "Wrong mon_ready_stable at sync 1" SEVERITY ERROR; + ASSERT mon_xon_stable='0' REPORT "Wrong mon_xon_stable at sync 1" SEVERITY ERROR; + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='0' REPORT "Wrong mon_ready_stable at sync 2" SEVERITY ERROR; + ASSERT mon_xon_stable='0' REPORT "Wrong mon_xon_stable at sync 2" SEVERITY ERROR; + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='1' REPORT "Wrong mon_ready_stable at sync 3" SEVERITY ERROR; + ASSERT mon_xon_stable='1' REPORT "Wrong mon_xon_stable at sync 3" SEVERITY ERROR; + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='1' REPORT "Wrong mon_ready_stable at sync 4" SEVERITY ERROR; + ASSERT mon_xon_stable='0' REPORT "Wrong mon_xon_stable at sync 4" SEVERITY ERROR; + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='1' REPORT "Wrong mon_ready_stable at sync 5" SEVERITY ERROR; + ASSERT mon_xon_stable='0' REPORT "Wrong mon_xon_stable at sync 5" SEVERITY ERROR; + proc_common_wait_until_hi_lo(clk, mon_sync); + ASSERT mon_ready_stable='1' REPORT "Wrong mon_ready_stable at sync 6" SEVERITY ERROR; + ASSERT mon_xon_stable='1' REPORT "Wrong mon_xon_stable at sync 6" SEVERITY ERROR; + WAIT; + END PROCESS; + + p_ref_sync_stimuli : PROCESS + BEGIN + ref_sync <= '0'; + proc_common_wait_until_low(clk, rst); + proc_common_wait_until_hi_lo(clk, in_sosi.sync); + proc_common_wait_some_cycles(clk, (c_sync_timeout-2-c_ref_sync_latency)); + FOR I IN 0 TO c_nof_repeat-2 LOOP + ref_sync <= '1'; + proc_common_wait_some_cycles(clk, 1); + ref_sync <= '0'; + proc_common_wait_some_cycles(clk, c_sync_timeout-1); + END LOOP; + WAIT; + END PROCESS; + + + ------------------------------------------------------------------------------ + -- DATA VERIFICATION + ------------------------------------------------------------------------------ + + -- Verification logistics + verify_en <= '1' WHEN rising_edge(clk) AND in_sosi.sop='1'; -- enable verify after first input sop + count_eop <= count_eop+1 WHEN rising_edge(clk) AND in_sosi.eop='1'; -- count number of input eop + verify_done <= '1' WHEN rising_edge(clk) AND count_eop = c_nof_repeat; -- signal verify done after c_nof_repeat frames + + -- Actual verification of the input streams + proc_dp_verify_data("in_sosi.data", c_rl, clk, verify_en, in_siso.ready, in_sosi.valid, in_data, prev_in_data); -- Verify that the input is incrementing data, like the input stimuli + proc_dp_verify_valid(c_rl, clk, verify_en, in_siso.ready, prev_in_ready, in_sosi.valid); -- Verify that the input valid fits with the input ready latency + proc_dp_verify_value(e_equal, clk, verify_done, expected_in_data, prev_in_data); -- Verify that the stimuli have been applied at all + proc_dp_verify_sync(c_sync_period, c_sync_offset, clk, verify_en, in_sosi.sync, in_sosi.sop, in_sosi.bsn); + + -- Monitoring + in_bsn <= in_sosi.bsn(c_word_w-1 DOWNTO 0); + in_data <= in_sosi.data(c_data_w-1 DOWNTO 0); + in_sync <= in_sosi.sync; + in_val <= in_sosi.valid; + in_sop <= in_sosi.sop; + in_eop <= in_sosi.eop; + + + ------------------------------------------------------------------------------ + -- MONITOR VERIFICATION + ------------------------------------------------------------------------------ + + proc_dp_verify_value(e_equal, clk, verify_done, expected_bsn_at_sync, mon_bsn_at_sync); + proc_dp_verify_value(e_equal, clk, verify_done, expected_nof_sop, mon_nof_sop); + proc_dp_verify_value(e_equal, clk, verify_done, expected_nof_err, mon_nof_err); + proc_dp_verify_value(e_equal, clk, verify_done, expected_nof_valid, mon_nof_valid); + proc_dp_verify_value(e_equal, clk, verify_done, expected_latency, mon_latency); + + + ------------------------------------------------------------------------------ + -- DUT dp_bsn_monitor_v2 + ------------------------------------------------------------------------------ + + -- Tap the stream to the monitor + dut : ENTITY work.dp_bsn_monitor_v2 + GENERIC MAP ( + g_sync_timeout => c_sync_timeout + ) + PORT MAP ( + rst => rst, + clk => clk, + + -- ST interface + in_siso => out_siso, + in_sosi => in_sosi, + ref_sync => ref_sync, + + -- MM interface + -- . control + mon_evt => mon_evt, + mon_sync => mon_sync, + mon_sync_timeout => mon_sync_timeout, + -- . siso + mon_ready_stable => mon_ready_stable, + mon_xon_stable => mon_xon_stable, + -- . sosi + mon_bsn_at_sync => mon_bsn_at_sync, + mon_nof_sop => mon_nof_sop, + mon_nof_err => mon_nof_err, + mon_nof_valid => mon_nof_valid, + mon_latency => mon_latency + ); + +END tb;