diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd index b14d63d3cc046861baef44eebfb98dce5ab46a48..a3aae746b9805eaa40045e50701aea0386337e6d 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd @@ -292,7 +292,8 @@ BEGIN g_data_w => c_longword_w, g_symbol_w => c_byte_w, g_hdr_field_arr => c_sdp_cep_hdr_field_arr, - g_hdr_field_sel => c_sdp_cep_hdr_field_sel + g_hdr_field_sel => c_sdp_cep_hdr_field_sel, + g_pipeline_ready => TRUE ) PORT MAP ( mm_rst => mm_rst, diff --git a/libraries/base/common/src/vhdl/common_network_layers_pkg.vhd b/libraries/base/common/src/vhdl/common_network_layers_pkg.vhd index 3d69a4f27e1f5a657af5c104111035daff98f6a0..55d5a853ebc8cb532ef9dab1119f8312609290e5 100644 --- a/libraries/base/common/src/vhdl/common_network_layers_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_network_layers_pkg.vhd @@ -51,9 +51,13 @@ PACKAGE common_network_layers_pkg IS -- | Frame Check Sequence | -- |------------------------------------------------------------ // ------| -- + -- . The word_align field is optional in and can only exist inside the + -- firmware, not on the link. It is removed by the TSE before transmit + -- and inserted by TSE after receive, -- field widths in bits '_w' or in bytes '_len', '_min', '_max', '_sz' CONSTANT c_network_eth_preamble_len : NATURAL := 8; + CONSTANT c_network_eth_word_align_len : NATURAL := 2; -- to align 14 octets eth header at 32b word CONSTANT c_network_eth_mac_addr_len : NATURAL := 6; CONSTANT c_network_eth_mac_addr_w : NATURAL := c_network_eth_mac_addr_len*c_8; CONSTANT c_network_eth_type_len : NATURAL := 2; diff --git a/libraries/base/common/src/vhdl/common_pkg.vhd b/libraries/base/common/src/vhdl/common_pkg.vhd index dd8e2b4c9e2b3864e09fddd1ca1780bee457813b..55bf1da32ec2cac8f6a1c035ea219a7c4ade3a75 100644 --- a/libraries/base/common/src/vhdl/common_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_pkg.vhd @@ -197,7 +197,9 @@ PACKAGE common_pkg IS -- use almost_equal(a/b, 1.0, max_ratio) to verify that a and b differ less than max_ratio/100 percent -- use almost_zero(a/b, max_ratio) to verify that a is less than max_ratio/100 percent of b, so almost zero FUNCTION almost_equal(a, b, delta : REAL) RETURN BOOLEAN; -- return TRUE when abs(a - b) < abs(delta), else return FALSE + FUNCTION almost_equal(a, b, delta : INTEGER) RETURN BOOLEAN; FUNCTION almost_zero(a, delta : REAL) RETURN BOOLEAN; -- return TRUE when abs(a) < abs(delta), else return FALSE + FUNCTION almost_zero(a, delta : INTEGER) RETURN BOOLEAN; FUNCTION ceil_div( n, d : NATURAL) RETURN NATURAL; -- ceil_div = n/d + (n MOD d)/=0 FUNCTION ceil_value( n, d : NATURAL) RETURN NATURAL; -- ceil_value = ceil_div(n, d) * d @@ -672,7 +674,16 @@ PACKAGE BODY common_pkg IS FUNCTION almost_equal(a, b, delta : REAL) RETURN BOOLEAN IS BEGIN - IF ABS(a - b) < ABS(delta) THEN + IF ABS(a - b) <= ABS(delta) THEN + RETURN TRUE; + ELSE + RETURN FALSE; + END IF; + END; + + FUNCTION almost_equal(a, b, delta : INTEGER) RETURN BOOLEAN IS + BEGIN + IF ABS(a - b) <= ABS(delta) THEN RETURN TRUE; ELSE RETURN FALSE; @@ -684,6 +695,11 @@ PACKAGE BODY common_pkg IS RETURN almost_equal(a, 0.0, delta); END; + FUNCTION almost_zero(a, delta : INTEGER) RETURN BOOLEAN IS + BEGIN + RETURN almost_equal(a, 0, delta); + END; + FUNCTION ceil_div(n, d : NATURAL) RETURN NATURAL IS BEGIN RETURN n/d + sel_a_b(n MOD d = 0, 0, 1); diff --git a/libraries/base/diag/src/vhdl/diag_block_gen.vhd b/libraries/base/diag/src/vhdl/diag_block_gen.vhd index 1956204af9265c2562b5343127229da3dbc8b9b7..7e48ee30e5199d813937d0747c05a394401df2b9 100644 --- a/libraries/base/diag/src/vhdl/diag_block_gen.vhd +++ b/libraries/base/diag/src/vhdl/diag_block_gen.vhd @@ -33,7 +33,10 @@ -- mem_low_adrs : slv -- block start address at MM interface -- mem_high_adrs : slv -- end address at MM interface -- bsn_init : slv -- BSN of first output block --- +-- +-- The samples_per_packet >= 2, because the in the p_comb state machine the +-- eop cannot occur at the sop. +-- -- The MM reading starts at mem_low_adrs when the BG is first enabled. If -- the mem_high_adrs-mem_low_adrs+1 < samples_per_packet then the reading -- wraps and continues from mem_low_adrs. For every new block the reading @@ -47,9 +50,10 @@ -- every blocks_per_sync. -- -- The current block is finished properly after enable gows low, to ensure --- that all blocks have the same length. A new ctrl is accepted after a --- current block has finished, to ensure that no fractional blocks will --- enter the stream. +-- that all blocks have the same length. A new ctrl is accepted only when +-- the BG is (re)started, to simplify the use of ctrl_hold. The ctrl_hold +-- holds the active control settings while BG is enabled. Note that +-- ctrl_hold.enable remains '1' after the BG has been enabled once. -- -- The BG supports block flow control via out_siso.xon. The BG also supports -- sample flow control via out_siso.ready. @@ -81,6 +85,7 @@ entity diag_block_gen is buf_rddat : in std_logic_vector(g_buf_dat_w-1 downto 0); buf_rdval : in std_logic; ctrl : in t_diag_block_gen; + ctrl_hold : out t_diag_block_gen; -- hold current active ctrl en_sync : in std_logic := '1'; out_siso : in t_dp_siso := c_dp_siso_rdy; out_sosi : out t_dp_sosi @@ -93,7 +98,7 @@ architecture rtl of diag_block_gen is type state_type is (s_idle, s_block, s_gap); type reg_type is record - ctrl_reg : t_diag_block_gen; -- capture ctrl + ctrl_hold : t_diag_block_gen; -- capture ctrl blk_en : std_logic; -- enable at block level blk_xon : std_logic; -- siso.xon at block level, the BG continues but the sosi control depend on xon (the BG does not support siso.ready) blk_sync : std_logic; -- block sync alternative of the pulse sync @@ -111,10 +116,14 @@ architecture rtl of diag_block_gen is signal r, rin : reg_type; signal out_sosi_i : t_dp_sosi := c_dp_sosi_rst; -- Signal used to assign reset values to output + signal xon_reg : std_logic := '0'; begin - p_comb : process(r, rst, ctrl, en_sync, out_siso) + -- xon is not clk cycle timing critical, so can use register xon to ease timing closure + xon_reg <= out_siso.xon when rising_edge(clk); + + p_comb : process(r, rst, ctrl, en_sync, out_siso, xon_reg) variable v : reg_type; variable v_samples_per_packet : natural; variable v_gapsize : natural; @@ -123,11 +132,11 @@ begin variable v_mem_high_adrs : natural; begin - v_samples_per_packet := TO_UINT(r.ctrl_reg.samples_per_packet); - v_gapsize := TO_UINT(r.ctrl_reg.gapsize); - v_blocks_per_sync := TO_UINT(r.ctrl_reg.blocks_per_sync); - v_mem_low_adrs := TO_UINT(r.ctrl_reg.mem_low_adrs); - v_mem_high_adrs := TO_UINT(r.ctrl_reg.mem_high_adrs); + v_samples_per_packet := TO_UINT(r.ctrl_hold.samples_per_packet); + v_gapsize := TO_UINT(r.ctrl_hold.gapsize); + v_blocks_per_sync := TO_UINT(r.ctrl_hold.blocks_per_sync); + v_mem_low_adrs := TO_UINT(r.ctrl_hold.mem_low_adrs); + v_mem_high_adrs := TO_UINT(r.ctrl_hold.mem_high_adrs); v := r; -- default hold all r fields v.pls_sync := '0'; @@ -157,15 +166,15 @@ begin case r.state is when s_idle => - v.ctrl_reg := ctrl; -- accept new control settings - v.blk_xon := out_siso.xon; + v.blk_xon := xon_reg; v.blk_sync := '0'; v.samples_cnt := 0; v.blocks_cnt := 0; - v.bsn_cnt := ctrl.bsn_init; v.mem_cnt := v_mem_low_adrs; - if r.blk_en = '1' then -- Wait until enabled - if out_siso.xon='1' then -- Wait until XON is 1 + if r.blk_en = '1' then -- Wait until enabled + if xon_reg = '1' then -- Wait until XON is 1 + v.ctrl_hold := ctrl; -- hold new control settings while BG is enabled + v.bsn_cnt := ctrl.bsn_init; v.rd_ena := '1'; v.state := s_block; end if; @@ -185,12 +194,10 @@ begin v.samples_cnt := v.samples_cnt + 1; elsif r.samples_cnt >= v_samples_per_packet-1 and v_gapsize = 0 and r.blocks_cnt >= v_blocks_per_sync-1 then v.eop := '1'; - v.ctrl_reg := ctrl; -- accept new control settings at end of block when gapsize=0 v.samples_cnt := 0; v.blocks_cnt := 0; elsif r.samples_cnt >= v_samples_per_packet-1 and v_gapsize = 0 then v.eop := '1'; - v.ctrl_reg := ctrl; -- accept new control settings at end of block when gapsize=0 v.samples_cnt := 0; v.blocks_cnt := r.blocks_cnt + 1; elsif r.samples_cnt >= v_samples_per_packet-1 then @@ -212,21 +219,18 @@ begin if v.eop = '1' and r.blk_en = '0' then v.state := s_idle; -- accept disable after eop, not during block end if; - if r.eop = '1' then - v.blk_xon := out_siso.xon; -- accept XOFF after eop, not during block - end if; - end if; -- out_siso.ready='1' + if r.eop = '1' then + v.blk_xon := xon_reg; -- accept XOFF after eop, not during block + end if; when s_gap => if r.samples_cnt >= v_gapsize-1 and r.blocks_cnt >= v_blocks_per_sync-1 then - v.ctrl_reg := ctrl; -- accept new control settings at end of gap v.samples_cnt := 0; v.blocks_cnt := 0; v.rd_ena := '1'; v.state := s_block; elsif r.samples_cnt >= v_gapsize-1 then - v.ctrl_reg := ctrl; -- accept new control settings at end of gap v.samples_cnt := 0; v.blocks_cnt := r.blocks_cnt + 1; v.rd_ena := '1'; @@ -238,7 +242,7 @@ begin if r.blk_en = '0' then v.state := s_idle; end if; - v.blk_xon := out_siso.xon; + v.blk_xon := xon_reg; when others => v.state := s_idle; @@ -246,7 +250,7 @@ begin end case; if rst = '1' then - v.ctrl_reg := c_diag_block_gen_rst; + v.ctrl_hold := c_diag_block_gen_rst; v.blk_en := '0'; v.blk_xon := '0'; v.blk_sync := '0'; @@ -286,5 +290,7 @@ begin out_sosi <= out_sosi_i; buf_addr <= TO_UVEC(r.mem_cnt, g_buf_addr_w); buf_rden <= r.rd_ena; + + ctrl_hold <= r.ctrl_hold; end rtl; diff --git a/libraries/base/diag/src/vhdl/diag_pkg.vhd b/libraries/base/diag/src/vhdl/diag_pkg.vhd index 1d1fd44248944908964c23a728736a66981a34ae..8e3c0eb5e50914ed7a5090ba1d3c5c19fd2dc169 100644 --- a/libraries/base/diag/src/vhdl/diag_pkg.vhd +++ b/libraries/base/diag/src/vhdl/diag_pkg.vhd @@ -102,9 +102,10 @@ PACKAGE diag_pkg IS ----------------------------------------------------------------------------- -- control register - CONSTANT c_diag_bg_reg_nof_dat : NATURAL := 8; - CONSTANT c_diag_bg_reg_adr_w : NATURAL := ceil_log2(c_diag_bg_reg_nof_dat); - + CONSTANT c_diag_bg_reg_nof_dat : NATURAL := 8; + CONSTANT c_diag_bg_reg_adr_w : NATURAL := ceil_log2(c_diag_bg_reg_nof_dat); + CONSTANT c_diag_bg_reg_adr_span : NATURAL := 2**c_diag_bg_reg_adr_w; + CONSTANT c_diag_bg_mode_w : NATURAL := 8; CONSTANT c_diag_bg_samples_per_packet_w : NATURAL := 24; CONSTANT c_diag_bg_blocks_per_sync_w : NATURAL := 24; @@ -112,6 +113,7 @@ PACKAGE diag_pkg IS CONSTANT c_diag_bg_mem_adrs_w : NATURAL := 24; CONSTANT c_diag_bg_mem_low_adrs_w : NATURAL := c_diag_bg_mem_adrs_w; CONSTANT c_diag_bg_mem_high_adrs_w : NATURAL := c_diag_bg_mem_adrs_w; + CONSTANT c_diag_bg_mem_max_adr : NATURAL := 2**c_diag_bg_mem_adrs_w-1; CONSTANT c_diag_bg_bsn_init_w : NATURAL := 64; TYPE t_diag_block_gen IS RECORD @@ -123,9 +125,20 @@ PACKAGE diag_pkg IS mem_low_adrs : STD_LOGIC_VECTOR(c_diag_bg_mem_low_adrs_w -1 DOWNTO 0); mem_high_adrs : STD_LOGIC_VECTOR(c_diag_bg_mem_high_adrs_w -1 DOWNTO 0); bsn_init : STD_LOGIC_VECTOR(c_diag_bg_bsn_init_w -1 DOWNTO 0); - END RECORD; - - CONSTANT c_diag_block_gen_rst : t_diag_block_gen := ( '0', + END RECORD; + + TYPE t_diag_block_gen_integer IS RECORD + enable : STD_LOGIC; + enable_sync : STD_LOGIC; + samples_per_packet : NATURAL; + blocks_per_sync : NATURAL; + gapsize : NATURAL; + mem_low_adrs : NATURAL; + mem_high_adrs : NATURAL; + bsn_init : NATURAL; + END RECORD; + + CONSTANT c_diag_block_gen_rst : t_diag_block_gen := ( '0', '0', TO_UVEC( 256, c_diag_bg_samples_per_packet_w), TO_UVEC( 10, c_diag_bg_blocks_per_sync_w), @@ -144,10 +157,14 @@ PACKAGE diag_pkg IS TO_UVEC( 0, c_diag_bg_bsn_init_w)); TYPE t_diag_block_gen_arr IS ARRAY (INTEGER RANGE <>) OF t_diag_block_gen; - + TYPE t_diag_block_gen_integer_arr IS ARRAY (INTEGER RANGE <>) OF t_diag_block_gen_integer; + -- Overloaded sel_a_b (from common_pkg) for t_diag_block_gen FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_diag_block_gen) RETURN t_diag_block_gen; + FUNCTION func_diag_bg_ctrl_integer_to_slv(bg_ctrl_int : t_diag_block_gen_integer) RETURN t_diag_block_gen; + FUNCTION func_diag_bg_ctrl_slv_to_integer(bg_ctrl_slv : t_diag_block_gen) RETURN t_diag_block_gen_integer; + ----------------------------------------------------------------------------- -- Data buffer ----------------------------------------------------------------------------- @@ -214,4 +231,28 @@ PACKAGE BODY diag_pkg IS END IF; END; + FUNCTION func_diag_bg_ctrl_integer_to_slv(bg_ctrl_int : t_diag_block_gen_integer) RETURN t_diag_block_gen IS + BEGIN + RETURN ( bg_ctrl_int.enable, + bg_ctrl_int.enable_sync, + TO_UVEC(bg_ctrl_int.samples_per_packet, c_diag_bg_samples_per_packet_w), + TO_UVEC(bg_ctrl_int.blocks_per_sync , c_diag_bg_blocks_per_sync_w), + TO_UVEC(bg_ctrl_int.gapsize , c_diag_bg_gapsize_w), + TO_UVEC(bg_ctrl_int.mem_low_adrs , c_diag_bg_mem_low_adrs_w), + TO_UVEC(bg_ctrl_int.mem_high_adrs , c_diag_bg_mem_high_adrs_w), + TO_UVEC(bg_ctrl_int.bsn_init , c_diag_bg_bsn_init_w)); + END; + + FUNCTION func_diag_bg_ctrl_slv_to_integer(bg_ctrl_slv : t_diag_block_gen) RETURN t_diag_block_gen_integer IS + BEGIN + RETURN ( bg_ctrl_slv.enable, + bg_ctrl_slv.enable_sync, + TO_UINT(bg_ctrl_slv.samples_per_packet), + TO_UINT(bg_ctrl_slv.blocks_per_sync), + TO_UINT(bg_ctrl_slv.gapsize), + TO_UINT(bg_ctrl_slv.mem_low_adrs), + TO_UINT(bg_ctrl_slv.mem_high_adrs), + TO_UINT(bg_ctrl_slv.bsn_init)); + END; + END diag_pkg; diff --git a/libraries/base/diag/src/vhdl/mms_diag_block_gen.vhd b/libraries/base/diag/src/vhdl/mms_diag_block_gen.vhd index 051b6cbe9f0a93e04e7e8f79ecffb236e7227b4c..93839197c820227c38c773b7a93429bef4e087a6 100644 --- a/libraries/base/diag/src/vhdl/mms_diag_block_gen.vhd +++ b/libraries/base/diag/src/vhdl/mms_diag_block_gen.vhd @@ -140,6 +140,7 @@ ENTITY mms_diag_block_gen IS reg_tx_seq_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- Tx seq control (one per stream because c_reg_tx_seq_broadcast=FALSE) reg_tx_seq_miso : OUT t_mem_miso; -- ST interface + bg_ctrl_hold_arr : OUT t_diag_block_gen_arr(g_nof_streams-1 DOWNTO 0); usr_siso_arr : OUT t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); -- connect when g_use_usr_input=TRUE, else leave not connected usr_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); out_siso_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); -- Default xon='1' @@ -283,7 +284,8 @@ BEGIN buf_rden => st_rd_arr(I), buf_rddat => st_rddata_arr(I), buf_rdval => st_rdval_arr(I), - ctrl => bg_ctrl, + ctrl => bg_ctrl, -- same BG control for all streams + ctrl_hold => bg_ctrl_hold_arr(I), -- active BG control can differ in time per stream en_sync => en_sync, out_siso => bg_src_in_arr(I), out_sosi => bg_src_out_arr(I) diff --git a/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd b/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd index af2edf040228ba8271222dd550e94407c7b3bb5f..c54f89ca2b88ddfb950a84562bf02a26d84009a3 100644 --- a/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd +++ b/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd @@ -134,7 +134,8 @@ ARCHITECTURE tb OF tb_diag_block_gen IS SIGNAL bg_buf_miso : t_mem_miso; SIGNAL bg_ctrl : t_diag_block_gen; - + SIGNAL bg_ctrl_hold : t_diag_block_gen; + SIGNAL random : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0'); -- use different lengths to have different random sequences SIGNAL toggle : STD_LOGIC := '0'; SIGNAL out_siso_bg : t_dp_siso := c_dp_siso_rdy; @@ -187,42 +188,7 @@ BEGIN bg_ctrl.mem_high_adrs <= TO_UVEC(c_alternative_mem_high_adrs, c_diag_bg_mem_high_adrs_w); bg_ctrl.enable <= '1'; proc_dp_verify_run_some_cycles(5, c_runtime, 0, clk, verify_en); - - -- Run and change bg_ctrl dynamically - bg_ctrl.enable <= '0'; - proc_common_wait_some_cycles(clk, c_offtime); - bg_ctrl <= c_bg_ctrl; - bg_ctrl.enable <= '1'; - proc_dp_verify_run_some_cycles(5, c_runtime, 0, clk, verify_en); - - -- . change gapsize dynamically - bg_ctrl.gapsize <= TO_UVEC(0, c_diag_bg_gapsize_w); - proc_dp_verify_run_some_cycles(0, c_runtime, 0, clk, verify_en); - bg_ctrl.gapsize <= c_bg_ctrl.gapsize; - proc_dp_verify_run_some_cycles(0, c_runtime, 0, clk, verify_en); - - -- . change mem_high_adrs dynamically - proc_common_wait_until_high(c_timeout, clk, out_sosi.eop); - bg_ctrl.mem_low_adrs <= TO_UVEC(c_alternative_mem_low_adrs, c_diag_bg_mem_low_adrs_w); - bg_ctrl.mem_high_adrs <= TO_UVEC(c_alternative_mem_high_adrs, c_diag_bg_mem_high_adrs_w); - proc_dp_verify_run_some_cycles(5, c_runtime, 0, clk, verify_en); - - bg_ctrl.mem_high_adrs <= c_bg_ctrl.mem_high_adrs; - proc_dp_verify_run_some_cycles(0, c_runtime, 0, clk, verify_en); - - -- . change samples_per_packet dynamically - proc_common_wait_until_high(c_timeout, clk, out_sosi.sop); - proc_common_wait_some_cycles(clk, 10); - bg_ctrl.samples_per_packet <= TO_UVEC(c_more_samples_per_packet, c_diag_bg_samples_per_packet_w); -- increase - proc_dp_verify_run_some_cycles(0, c_runtime, 0, clk, verify_en); - - -- . change samples_per_packet dynamically - proc_common_wait_until_high(c_timeout, clk, out_sosi.sop); - proc_common_wait_some_cycles(clk, c_less_samples_per_packet*2); - bg_ctrl.samples_per_packet <= TO_UVEC(c_less_samples_per_packet, c_diag_bg_samples_per_packet_w); -- decrease, could yield proc_dp_verify_block_size() error if it occurs during a packet - proc_dp_verify_run_some_cycles(0, c_runtime, 0, clk, verify_en); - -- Run with XON flow control (verified by proc_dp_verify_block_size) bg_ctrl.enable <= '0'; proc_common_wait_some_cycles(clk, c_offtime); @@ -300,6 +266,7 @@ BEGIN buf_rddat => bg_buf_miso.rddata(c_buf.dat_w-1 DOWNTO 0), buf_rdval => bg_buf_miso.rdval, ctrl => bg_ctrl, + ctrl_hold => bg_ctrl_hold, out_siso => out_siso_bg, out_sosi => out_sosi ); diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index db5cbc473d90fa0409bb0d748cd84ce3f2d2e370..5ec867ca066b2db19741171d7cf07c4b948cccd6 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -6,6 +6,7 @@ hdl_lib_technology = synth_files = src/vhdl/dp_stream_pkg.vhd + src/vhdl/dp_components_pkg.vhd src/vhdl/dp_example_dut.vhd src/vhdl/dp_packetizing_pkg.vhd src/vhdl/dp_packet_pkg.vhd diff --git a/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd index 78249aab7520bb47c4d9cd5349b74071898e3762..fd3981df8e0bf046b3ac5fcf5b806d6da1e99e21 100644 --- a/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd +++ b/libraries/base/dp/src/vhdl/dp_bsn_monitor_v2.vhd @@ -104,6 +104,7 @@ ARCHITECTURE rtl OF dp_bsn_monitor_v2 IS SIGNAL nxt_valid : STD_LOGIC; SIGNAL sop : STD_LOGIC; SIGNAL nxt_sop : STD_LOGIC; + SIGNAL sync_reg2 : STD_LOGIC; SIGNAL sync_reg : STD_LOGIC; SIGNAL sync : STD_LOGIC; SIGNAL nxt_sync : STD_LOGIC; @@ -163,7 +164,7 @@ BEGIN 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_reg='1' ELSE i_mon_latency; -- use sync_reg due to ref_sync_reg + nxt_mon_latency <= latency WHEN sync_reg2='1' ELSE i_mon_latency; -- use sync_reg2 due to ref_sync_reg nof_sop <= cnt_sop; nof_err <= cnt_err; @@ -171,9 +172,9 @@ BEGIN latency <= cnt_latency; -- Register ref_sync to ease timing closure for ref_sync fanout to (many) dp_bsn_monitor_v2 - -- instances. The ref_sync_reg is used to restart cnt_latency. Therefore the sync_reg - -- (instead of sync) is needed to capture latency (= cnt_latency) not too early, so capture - -- cnt_latency at or after the cnt_latency has restarted. + -- instances. The ref_sync_reg is used to restart cnt_latency. Therefore the sync_reg2 + -- (instead of sync) is needed to capture latency (= cnt_latency) not too early, in case + -- ref_sync = in_sosi.sync, so capture cnt_latency at or after the cnt_latency has restarted. ref_sync_reg <= ref_sync WHEN rising_edge(clk); u_sync_timeout_cnt : ENTITY common_lib.common_counter @@ -216,6 +217,7 @@ BEGIN err <= '0'; sync <= '0'; sync_reg <= '0'; + sync_reg2 <= '0'; bsn <= (OTHERS=>'0'); -- output mon_evt <= '0'; @@ -237,6 +239,7 @@ BEGIN err <= nxt_err; sync <= nxt_sync; sync_reg <= sync; + sync_reg2 <= sync_reg; bsn <= nxt_bsn; -- output mon_evt <= nxt_mon_evt; diff --git a/libraries/base/dp/src/vhdl/dp_components_pkg.vhd b/libraries/base/dp/src/vhdl/dp_components_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..994b5988181f6921038a36ca7ca57313c2ff9716 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_components_pkg.vhd @@ -0,0 +1,50 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Keep parameters of DP components +-- Description: + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; + +PACKAGE dp_components_pkg IS + + CONSTANT c_dp_clk_MHz : NATURAL := 200; + CONSTANT c_dp_sync_timeout : NATURAL := c_dp_clk_MHz*10**6 + c_dp_clk_MHz*10**5; -- 10% margin for nominal 1 s + + CONSTANT c_dp_bsn_monitor_v2_reg_adr_w : NATURAL := ceil_log2(7); -- = 3 + CONSTANT c_dp_bsn_monitor_v2_reg_adr_span : NATURAL := 2**c_dp_bsn_monitor_v2_reg_adr_w; -- = 8 + + CONSTANT c_dp_strobe_total_count_reg_nof_words : NATURAL := 15*2 + 1; -- = 31 + CONSTANT c_dp_strobe_total_count_reg_adr_w : NATURAL := ceil_log2(c_dp_strobe_total_count_reg_nof_words); -- = 5 + CONSTANT c_dp_strobe_total_count_reg_adr_span : NATURAL := 2**c_dp_strobe_total_count_reg_adr_w; -- = 32 + CONSTANT c_dp_strobe_total_count_reg_nof_counts_max : NATURAL := 2**c_dp_strobe_total_count_reg_adr_w / 2 - 1; -- = 15 + CONSTANT c_dp_strobe_total_count_reg_clear_adr : NATURAL := c_dp_strobe_total_count_reg_nof_counts_max*2; -- after counters in REGMAP + +END dp_components_pkg; + + +PACKAGE BODY dp_components_pkg IS +END dp_components_pkg; + diff --git a/libraries/base/dp/src/vhdl/dp_concat.vhd b/libraries/base/dp/src/vhdl/dp_concat.vhd index 46361034acb6da8466cb4a7e7262ff70f2a47eac..2cd1dc3b30d7b6e47b430e65824cdf7070203c86 100644 --- a/libraries/base/dp/src/vhdl/dp_concat.vhd +++ b/libraries/base/dp/src/vhdl/dp_concat.vhd @@ -259,6 +259,8 @@ BEGIN nxt_state <= s_sop; ELSE -- Output frame needs 2 words flush_arr(c_tail) <= c_dp_siso_rdy; -- also ready for hold input when the tail eop is there + v_out_empty := func_dp_empty_concat(head_empty_reg, tail_empty, c_nof_symbols_per_data); + nxt_out_empty_reg <= v_out_empty; -- capture the output empty field (needed in s_eop) nxt_state <= s_eop; END IF; END IF; diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd index 381cd124bba1ff193c3423fc76e24d20af32a686..62ddba22104d5a5ff2ba355a63bbe5150b39a20e 100644 --- a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd @@ -97,7 +97,7 @@ ENTITY dp_fifo_fill_eop IS snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; -- ST source - src_in : IN t_dp_siso; + src_in : IN t_dp_siso := c_dp_siso_rdy; src_out : OUT t_dp_sosi ); END dp_fifo_fill_eop; diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd index 6c677dc7e33bfe3a05394cd1edbce508aa8a0ced..db85d766fdeb1160ec49358fa622ac9e23bb66c8 100644 --- a/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd +++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd @@ -68,7 +68,7 @@ ENTITY dp_fifo_fill_sc IS snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; -- ST source - src_in : IN t_dp_siso; + src_in : IN t_dp_siso := c_dp_siso_rdy; src_out : OUT t_dp_sosi ); END dp_fifo_fill_sc; diff --git a/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd index 6421ae0d6ab3d7e4f2d61501a6be75bc1170026c..fb9570775d09d98e39f905748c21ad9ea61c5feb 100644 --- a/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd +++ b/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd @@ -62,7 +62,7 @@ ENTITY dp_fifo_sc IS snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; -- ST source - src_in : IN t_dp_siso; + src_in : IN t_dp_siso := c_dp_siso_rdy; src_out : OUT t_dp_sosi ); END dp_fifo_sc; diff --git a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd index ff1a52c71575982bedcdecf3eaa95edac477d7e2..6ce2e23d4cda4d15e7d7ad80eabee1b0a9729282 100644 --- a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd +++ b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd @@ -93,13 +93,13 @@ ARCHITECTURE str OF dp_offload_rx IS SIGNAL reg_hdr_dat_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL reg_hdr_dat_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); - SIGNAL dp_field_blk_slv_out : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_field_blk_slv_out : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0')); SIGNAL dp_field_blk_slv_out_val : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); SIGNAL dp_field_blk_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL reg_dp_field_blk_slv_out : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); - SIGNAL nxt_reg_dp_field_blk_slv_out : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL nxt_reg_dp_field_blk_slv_out : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0')); SIGNAL dp_tail_remove_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL dp_tail_remove_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd index f72352cd6925c80356551b0c2fa3b6761b1f9877..66551c1bc892ba343176675715242c43d81916b7 100644 --- a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd +++ b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd @@ -135,12 +135,24 @@ BEGIN snk_out_arr(i).xon <= src_in_arr(i).xon; -- Wire hdr_fields_out_arr - -- MM override bits determine source for each field - gen_field_wires: FOR j IN g_hdr_field_arr'RANGE GENERATE - hdr_fields_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) <= mm_fields_slv_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) - WHEN field_override_arr(j) = '1' ELSE - hdr_fields_in_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)); - END GENERATE; + p_hdr_fields_out_arr : PROCESS(mm_fields_slv_out_arr, hdr_fields_in_arr) + VARIABLE v_hi : NATURAL; + VARIABLE v_lo : NATURAL; + BEGIN + -- Default drive unused slv bit to 0 to avoid Warning: (vsim-8684) No drivers exist on out port + -- hdr_fields_out_arr(0)(1023 downto ...), and its initial value is not used. + hdr_fields_out_arr(i) <= (OTHERS => '0'); + FOR j IN g_hdr_field_arr'RANGE LOOP + v_hi := field_hi(g_hdr_field_arr, j); + v_lo := field_lo(g_hdr_field_arr, j); + -- MM override bits determine source for each field + IF field_override_arr(j) = '1' THEN + hdr_fields_out_arr(i)(v_hi DOWNTO v_lo) <= mm_fields_slv_out_arr(i)(v_hi DOWNTO v_lo); + ELSE + hdr_fields_out_arr(i)(v_hi DOWNTO v_lo) <= hdr_fields_in_arr(i)(v_hi DOWNTO v_lo); + END IF; + END LOOP; + END PROCESS; --------------------------------------------------------------------------------------- -- mm_fields for MM access to each field diff --git a/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd b/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd index 19c033c715a2f338236f57fe02356754f8ac4aa5..2a08ade6252bd31a5064cfbbe7c6f557f7c565e7 100644 --- a/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd +++ b/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd @@ -23,7 +23,7 @@ -- Purpose: -- Count strobes -- Description: --- * g_nof_counts >= 1, maximum g_nof_counts_max = 15 +-- * g_nof_counts >= 1, maximum c_nof_counts_max = 15 -- There are g_nof_counts in parallel, one clear that clears them all -- . count any strobe like e.g. sync, sop, valid, error flag, ... -- . MM read or write of clear registers clears all counter immediately, @@ -43,7 +43,8 @@ -- ------------------------------------------------------------------------------- -- REGMAP --- . address span is (g_nof_counts_max + 1)*2 = 32 +-- . address span is (c_nof_counts_max + 1)*2 = 32 +-- . address width is c_dp_strobe_total_count_reg_adr_w - ceil_log2(32) = 5 ------------------------------------------------------------------------------- -- wi Bits R/W Name Default -- =========================================================================== @@ -57,23 +58,27 @@ -- (g_nof_counts-1)*2 + 1 [63.32] -- . . . . . -- . . --- (g_nof_counts_max-1)*2 [31..0] RO count[g_nof_counts_max-1] 0x0 --- (g_nof_counts_max-1)*2 + 1 [63.32] --- g_nof_counts_max*2 [31..0] RW clear 0x0 --- g_nof_counts_max*2 + 1 [31..0] RO rsvd 0x0 +-- (c_nof_counts_max-1)*2 [31..0] RO count[c_nof_counts_max-1] 0x0 +-- (c_nof_counts_max-1)*2 + 1 [63.32] +-- c_nof_counts_max*2 [31..0] RW clear 0x0 +-- c_nof_counts_max*2 + 1 [31..0] RO rsvd 0x0 -- =========================================================================== -- +-- Remark: +-- * This dp_strobe_total_count could have been a common_strobe_total_count +-- component, because it does not use sosi/siso signals. However it is fine +-- to keep it in dp_lib, to avoid extra work of moving and renaming. 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_components_pkg.ALL; ENTITY dp_strobe_total_count IS GENERIC ( g_mm_w : NATURAL := c_word_w; - g_nof_counts_max : NATURAL := 15; -- fixed by REGMAP - g_nof_counts : NATURAL := 1; -- actual nof counts, <= g_nof_counts_max + g_nof_counts : NATURAL := 1; -- actual nof counts, <= c_nof_counts_max g_count_w : NATURAL := c_longword_w; -- actual count width, max is c_longword_w due to two mm word width g_clip : BOOLEAN := TRUE ); @@ -94,14 +99,15 @@ END dp_strobe_total_count; ARCHITECTURE rtl OF dp_strobe_total_count IS - CONSTANT c_nof_words : NATURAL := g_nof_counts_max*2 + 1; -- +1 for clear - CONSTANT c_clear_adr : NATURAL := g_nof_counts_max*2; -- after counters in REGMAP + -- Fixed by REGMAP + CONSTANT c_nof_counts_max : NATURAL := c_dp_strobe_total_count_reg_nof_counts_max; + CONSTANT c_clear_adr : NATURAL := c_dp_strobe_total_count_reg_clear_adr; -- Define the size of the MM slave register CONSTANT c_mm_reg : t_c_mem := (latency => 1, - adr_w => ceil_log2(c_nof_words), + adr_w => c_dp_strobe_total_count_reg_adr_w, dat_w => g_mm_w, -- Use MM bus data width = c_word_w = 32 for all MM registers - nof_dat => c_nof_words, + nof_dat => c_dp_strobe_total_count_reg_nof_words, init_sl => '0'); TYPE t_cnt_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_count_w-1 DOWNTO 0); @@ -119,7 +125,7 @@ ARCHITECTURE rtl OF dp_strobe_total_count IS BEGIN - ASSERT g_nof_counts <= g_nof_counts_max REPORT "Too many counters to fit REGMAP." SEVERITY FAILURE; + ASSERT g_nof_counts <= c_nof_counts_max REPORT "Too many counters to fit REGMAP." SEVERITY FAILURE; ASSERT g_count_w <= g_mm_w*2 REPORT "Too wide counter to fit REGMAP." SEVERITY FAILURE; 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' ; diff --git a/libraries/base/dp/src/vhdl/dp_tail_remove.vhd b/libraries/base/dp/src/vhdl/dp_tail_remove.vhd index 744d6199dd150d4fe2decd0cf69270f9256358c1..b03c31b05c7bd69e39538205f46601172d8964aa 100644 --- a/libraries/base/dp/src/vhdl/dp_tail_remove.vhd +++ b/libraries/base/dp/src/vhdl/dp_tail_remove.vhd @@ -104,6 +104,7 @@ BEGIN v_wr_sosi_arr(0).eop := '0'; v_wr_sosi_arr(c_nof_shiftreg_words-1).eop := '1'; v_wr_sosi_arr(c_nof_shiftreg_words-1).empty := rd_sosi_arr(0).empty; + v_wr_sosi_arr(c_nof_shiftreg_words-1).err := rd_sosi_arr(0).err; END IF; wr_sosi_arr <= v_wr_sosi_arr; 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 index 64bf0567a6ecd37bef46fb2db0a67ed9019d7af9..e94f3f21cc44c4a2f35572ae75c37fa6dd1c6512 100644 --- a/libraries/base/dp/src/vhdl/mms_dp_bsn_monitor_v2.vhd +++ b/libraries/base/dp/src/vhdl/mms_dp_bsn_monitor_v2.vhd @@ -29,12 +29,13 @@ USE IEEE.NUMERIC_STD.ALL; USE common_lib.common_pkg.ALL; USE common_lib.common_mem_pkg.ALL; USE work.dp_stream_pkg.ALL; +USE work.dp_components_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_sync_timeout : NATURAL := c_dp_sync_timeout; g_bsn_w : NATURAL := c_dp_stream_bsn_w; g_error_bi : NATURAL := 0; g_cnt_sop_w : NATURAL := c_word_w; @@ -61,7 +62,7 @@ END mms_dp_bsn_monitor_v2; ARCHITECTURE str OF mms_dp_bsn_monitor_v2 IS - CONSTANT c_reg_adr_w : NATURAL := ceil_log2(7); + CONSTANT c_reg_adr_w : NATURAL := c_dp_bsn_monitor_v2_reg_adr_w; 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); 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 index 09eeec859d5d0b885a9508a32c565ff0674afb5f..49596bc437a7c520c72e96b7b49e1a2004fcafa6 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_bsn_monitor_v2.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_monitor_v2.vhd @@ -58,7 +58,9 @@ ARCHITECTURE tb OF tb_dp_bsn_monitor_v2 IS 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; - + CONSTANT c_mon_sync_latency : NATURAL := 1; -- due to sync_reg2 in dp_bsn_monitor_v2 + CONSTANT c_exp_sync_latency : NATURAL := c_ref_sync_latency + c_mon_sync_latency; + -- 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 @@ -187,7 +189,7 @@ BEGIN 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); + expected_latency <= TO_UVEC( c_exp_sync_latency, c_word_w); ------------------------------------------------------------------------------ -- SISO FLOW CONTROL GENERATION diff --git a/libraries/base/dp/tb/vhdl/tb_dp_strobe_total_count.vhd b/libraries/base/dp/tb/vhdl/tb_dp_strobe_total_count.vhd index 24f22387fdcd454352a37f80ca0b964ae7e47553..9a62cd3808a47f746877d7ad58155abfbdef299f 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_strobe_total_count.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_strobe_total_count.vhd @@ -40,6 +40,7 @@ USE common_lib.tb_common_mem_pkg.ALL; USE common_lib.common_str_pkg.ALL; USE common_lib.tb_common_pkg.ALL; USE work.dp_stream_pkg.ALL; +USE work.dp_components_pkg.ALL; ENTITY tb_dp_strobe_total_count IS GENERIC ( @@ -66,10 +67,10 @@ ARCHITECTURE tb OF tb_dp_strobe_total_count IS CONSTANT c_clip : BOOLEAN := TRUE; -- dut - CONSTANT c_nof_counts_max : NATURAL := 15; + CONSTANT c_nof_counts_max : NATURAL := c_dp_strobe_total_count_reg_nof_counts_max; -- fixed by REGMAP CONSTANT c_nof_counts : NATURAL := 3; -- count stimuli.sync, sop, valid CONSTANT c_count_max : NATURAL := 2**g_count_w - 1; - CONSTANT c_mm_addr_clear : NATURAL := c_nof_counts_max*2; + CONSTANT c_mm_addr_clear : NATURAL := c_dp_strobe_total_count_reg_clear_adr; -- c_tb_nof_sync - c_skip_nof_sync because first sync intervals are skipped -- by using clear, and -1, because stimuli_sosi.sync is used as ref_sync, @@ -140,7 +141,6 @@ BEGIN u_dut : ENTITY work.dp_strobe_total_count GENERIC MAP ( g_mm_w => g_mm_w, - g_nof_counts_max => c_nof_counts_max, g_nof_counts => c_nof_counts, g_count_w => g_count_w, g_clip => c_clip diff --git a/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd b/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd index c66a1b87fd2f9a1803d06e30dacd2c89a8f2f11a..fc46753c9debdd6578358bdf47a2b7b7f5c20b18 100644 --- a/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd +++ b/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd @@ -80,6 +80,7 @@ ARCHITECTURE tb OF tb_mmp_dp_bsn_align_v2 IS CONSTANT c_nof_clk_per_sync : NATURAL := c_block_per_sync * c_block_period; CONSTANT c_nof_input_bsn_monitors : NATURAL := c_nof_streams; CONSTANT c_use_bsn_output_monitor : BOOLEAN := TRUE; + CONSTANT c_mon_sync_latency : NATURAL := 1; -- due to sync_reg2 in dp_bsn_monitor_v2 CONSTANT c_reg_bsn_monitor_adr_w : NATURAL := ceil_log2(7); CONSTANT c_reg_bsn_monitor_span : NATURAL := 2**c_reg_bsn_monitor_adr_w; @@ -216,7 +217,8 @@ BEGIN FOR I IN 0 TO c_nof_streams-1 LOOP proc_mem_mm_bus_rd(2*I, mm_clk, reg_bsn_align_cipo, reg_bsn_align_copi); proc_mem_mm_bus_rd_latency(1, mm_clk); - ASSERT reg_bsn_align_cipo.rddata(0) = '1' REPORT "Wrong stream disable for output " & int_to_str(I) SEVERITY ERROR; + ASSERT reg_bsn_align_cipo.rddata(0) = '1' REPORT + "Wrong stream disable for output " & int_to_str(I) SEVERITY ERROR; END LOOP; -- Write stream enable bits for stream_en_arr @@ -230,7 +232,8 @@ BEGIN FOR I IN 0 TO c_nof_streams-1 LOOP proc_mem_mm_bus_rd(2*I, mm_clk, reg_bsn_align_cipo, reg_bsn_align_copi); proc_mem_mm_bus_rd_latency(1, mm_clk); - ASSERT reg_bsn_align_cipo.rddata(0) = '0' REPORT "Wrong BSN align stream enable for output " & int_to_str(I) SEVERITY ERROR; + ASSERT reg_bsn_align_cipo.rddata(0) = '0' REPORT + "Wrong BSN align stream enable for output " & int_to_str(I) SEVERITY ERROR; END LOOP; -- Write stream enable bits for stream_en_arr @@ -244,7 +247,8 @@ BEGIN FOR I IN 0 TO c_nof_streams-1 LOOP proc_mem_mm_bus_rd(2*I, mm_clk, reg_bsn_align_cipo, reg_bsn_align_copi); proc_mem_mm_bus_rd_latency(1, mm_clk); - ASSERT reg_bsn_align_cipo.rddata(0) = '1' REPORT "Wrong BSN align stream enable for output " & int_to_str(I) SEVERITY ERROR; + ASSERT reg_bsn_align_cipo.rddata(0) = '1' REPORT + "Wrong BSN align stream enable for output " & int_to_str(I) SEVERITY ERROR; END LOOP; -- End of MM test @@ -253,6 +257,7 @@ BEGIN END PROCESS; p_mm_verify_bsn_monitors : PROCESS + VARIABLE v_exp_latency : INTEGER; BEGIN proc_common_wait_until_high(mm_clk, verify_done); @@ -263,11 +268,19 @@ BEGIN mon_latency_input_arr(I) <= TO_SINT(reg_input_monitor_cipo.rddata(31 DOWNTO 0)); proc_common_wait_some_cycles(mm_clk, 1); IF g_lost_input = TRUE AND I = c_nof_streams-1 THEN - ASSERT mon_latency_input_arr(I) = -1 REPORT "Wrong input BSN monitor latency timeout for input " & int_to_str(I) & - " (" & int_to_str(mon_latency_input_arr(I)) & " /= -1)" SEVERITY ERROR; + v_exp_latency := -1; -- -1 for BSN monitor timeout due to lost input + ASSERT mon_latency_input_arr(I) = v_exp_latency REPORT + "Wrong input BSN monitor latency timeout for input " & int_to_str(I) & + " (" & int_to_str(mon_latency_input_arr(I)) & + " /= " & int_to_str(v_exp_latency) & + ")" SEVERITY ERROR; ELSE - ASSERT mon_latency_input_arr(I) = func_input_delay(I) REPORT "Wrong input BSN monitor latency for input " & int_to_str(I) & - " (" & int_to_str(mon_latency_input_arr(I)) & " /= " & int_to_str(func_input_delay(I)) & ")" SEVERITY ERROR; + v_exp_latency := c_mon_sync_latency + func_input_delay(I); + ASSERT mon_latency_input_arr(I) = v_exp_latency REPORT + "Wrong input BSN monitor latency for input " & int_to_str(I) & + " (" & int_to_str(mon_latency_input_arr(I)) & + " /= " & int_to_str(v_exp_latency) & + ")" SEVERITY ERROR; END IF; END LOOP; @@ -277,7 +290,11 @@ BEGIN mon_latency_output <= TO_SINT(reg_output_monitor_cipo.rddata(31 DOWNTO 0)); proc_common_wait_some_cycles(mm_clk, 1); - ASSERT mon_latency_output = c_total_latency REPORT "Wrong output BSN monitor latency" SEVERITY ERROR; + v_exp_latency := c_mon_sync_latency + c_total_latency; + ASSERT mon_latency_output = v_exp_latency REPORT + "Wrong output BSN monitor latency (" & int_to_str(mon_latency_output) & + " /= " & int_to_str(v_exp_latency) & + ")" SEVERITY ERROR; -- End of MM test mm_end <= '1'; diff --git a/libraries/io/eth/eth.peripheral.yaml b/libraries/io/eth/eth.peripheral.yaml index b887db31986ab67e390213cd6b06844e5147cedb..321706436eb9bc52210d67d1da407f3fb5c71fb5 100644 --- a/libraries/io/eth/eth.peripheral.yaml +++ b/libraries/io/eth/eth.peripheral.yaml @@ -233,5 +233,49 @@ peripherals: number_of_fields: 1024 # = c_eth_ram_nof_words in eth_pkg.vhd access_mode: RO - - + - peripheral_name: eth_tester_offload_hdr_dat + peripheral_description: "UDP offload header for the eth tester [1]." + mm_ports: + # MM port for eth_tester.vhd / dp_offload_tx_v3.vhd + - mm_port_name: REG_DP_OFFLOAD_TX_HDR_DAT + mm_port_type: REG + mm_port_span: 32 * MM_BUS_SIZE + mm_port_description: | + "The ETH/IP/UDP/application header fields for the 1GbE eth_tester offload UDP packets. + + The RO value reads the MM value, not the used data path value. Therefore simply use access + mode RW for all fields. Whether the write RW MM value is used in the packet header depends + on the c_eth_tester_hdr_field_sel bit selection setting in eth_tester_pkg.vhd. + + [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + " + fields: + # eth field group + - - { field_name: word_align, mm_width: 16, access_mode: RW, address_offset: 0x68 } + - - { field_name: eth_destination_mac, mm_width: 32, user_width: 48, radix: uint64, access_mode: RW, address_offset: 0x60 } + - - { field_name: eth_source_mac, mm_width: 32, user_width: 48, radix: uint64, access_mode: RW, address_offset: 0x58 } + - - { field_name: eth_type, mm_width: 16, access_mode: RW, address_offset: 0x54 } + # ip field group + - - { field_name: ip_version, mm_width: 4, access_mode: RW, address_offset: 0x50 } + - - { field_name: ip_header_length, mm_width: 4, access_mode: RW, address_offset: 0x4c } + - - { field_name: ip_services, mm_width: 8, access_mode: RW, address_offset: 0x48 } + - - { field_name: ip_total_length, mm_width: 16, access_mode: RW, address_offset: 0x44 } + - - { field_name: ip_identification, mm_width: 16, access_mode: RW, address_offset: 0x40 } + - - { field_name: ip_flags, mm_width: 3, access_mode: RW, address_offset: 0x3c } + - - { field_name: ip_fragment_offset, mm_width: 13, access_mode: RW, address_offset: 0x38 } + - - { field_name: ip_time_to_live, mm_width: 8, access_mode: RW, address_offset: 0x34 } + - - { field_name: ip_protocol, mm_width: 8, access_mode: RW, address_offset: 0x30 } + - - { field_name: ip_header_checksum, mm_width: 16, access_mode: RW, address_offset: 0x2c } + - - { field_name: ip_source_address, mm_width: 32, access_mode: RW, address_offset: 0x28 } + - - { field_name: ip_destination_address, mm_width: 32, access_mode: RW, address_offset: 0x24 } + # udp field group + - - { field_name: udp_source_port, mm_width: 16, access_mode: RW, address_offset: 0x20 } + - - { field_name: udp_destination_port, mm_width: 16, access_mode: RW, address_offset: 0x1c } + - - { field_name: udp_length, mm_width: 16, access_mode: RW, address_offset: 0x18 } + - - { field_name: udp_checksum, mm_width: 16, access_mode: RW, address_offset: 0x14 } + # application field group + - - { field_name: dp_length, mm_width: 16, access_mode: RW, address_offset: 0x10 } + - - { field_name: dp_reserved, mm_width: 15, access_mode: RW, address_offset: 0xC } + - - { field_name: dp_sync, mm_width: 1, access_mode: RW, address_offset: 0x8 } + - - { field_name: dp_bsn, mm_width: 32, user_width: 64, radix: uint64, access_mode: RW, address_offset: 0x0 } + diff --git a/libraries/io/eth/hdllib.cfg b/libraries/io/eth/hdllib.cfg index 5c3fb5fb6901a606b031a2c9f80e7f44f51ffc10..11d97855c2d2c66fc69d0db9120c34e4d56095d3 100644 --- a/libraries/io/eth/hdllib.cfg +++ b/libraries/io/eth/hdllib.cfg @@ -1,6 +1,6 @@ hdl_lib_name = eth hdl_library_clause_name = eth_lib -hdl_lib_uses_synth = dp common tech_tse +hdl_lib_uses_synth = dp common diag tech_tse hdl_lib_uses_sim = hdl_lib_technology = @@ -22,14 +22,21 @@ synth_files = src/vhdl/eth_control.vhd src/vhdl/eth_ihl_to_20.vhd src/vhdl/eth.vhd - + src/vhdl/eth_tester_pkg.vhd + src/vhdl/eth_tester_tx.vhd + src/vhdl/eth_tester_rx.vhd + src/vhdl/eth_tester.vhd + test_bench_files = src/vhdl/eth_statistics.vhd tb/vhdl/tb_eth_checksum.vhd tb/vhdl/tb_eth_crc_ctrl.vhd tb/vhdl/tb_eth_hdr.vhd tb/vhdl/tb_eth.vhd + tb/vhdl/tb_eth_tester_pkg.vhd + tb/vhdl/tb_eth_tester.vhd tb/vhdl/tb_tb_eth.vhd + tb/vhdl/tb_tb_eth_tester.vhd tb/vhdl/tb_eth_udp_offload.vhd tb/vhdl/tb_eth_ihl_to_20.vhd tb/vhdl/tb_tb_tb_eth_regression.vhd @@ -41,6 +48,7 @@ regression_test_vhdl = tb/vhdl/tb_eth_udp_offload.vhd tb/vhdl/tb_eth_ihl_to_20.vhd tb/vhdl/tb_tb_eth.vhd + tb/vhdl/tb_tb_eth_tester.vhd [modelsim_project_file] @@ -51,4 +59,4 @@ modelsim_copy_files = [quartus_project_file] quartus_copy_files = #src/vhdl/avs2_eth_coe_hw_<buildset_name>.tcl $RADIOHDL_BUILD_DIR/<buildset_name>/avs2_eth_coe_hw.tcl - src/vhdl/avs2_eth_coe_hw_<buildset_name>.tcl $RADIOHDL_WORK/libraries/io/eth/src/vhdl/avs2_eth_coe_hw.tcl \ No newline at end of file + src/vhdl/avs2_eth_coe_hw_<buildset_name>.tcl $RADIOHDL_WORK/libraries/io/eth/src/vhdl/avs2_eth_coe_hw.tcl diff --git a/libraries/io/eth/src/vhdl/eth_pkg.vhd b/libraries/io/eth/src/vhdl/eth_pkg.vhd index f8df9fb044aca2ab6473089a7bc262edb7d38650..eb4f556c1b29f3bd5bc7cb8f949bda396653bc28 100644 --- a/libraries/io/eth/src/vhdl/eth_pkg.vhd +++ b/libraries/io/eth/src/vhdl/eth_pkg.vhd @@ -204,9 +204,10 @@ PACKAGE eth_pkg IS c_eth_reg_config_nof_words + c_eth_reg_control_nof_words + c_eth_reg_frame_nof_words + - c_eth_reg_status_nof_words; - CONSTANT c_eth_reg_addr_w : NATURAL := ceil_log2(c_eth_reg_nof_words + 1); -- + 1 for c_eth_continue_wi - + c_eth_reg_status_nof_words; -- 4 + 4 + 1 + 1 + 1 = 11 + CONSTANT c_eth_reg_addr_w : NATURAL := ceil_log2(c_eth_reg_nof_words + 1); -- 11 + 1 for c_eth_continue_wi = 12 + CONSTANT c_eth_reg_addr_span : NATURAL := 2**c_eth_reg_addr_w; -- = 16 + ------------------------------------------------------------------------------ -- Definitions for ETH Rx packet buffer and Tx packet buffer ------------------------------------------------------------------------------ diff --git a/libraries/io/eth/src/vhdl/eth_tester.vhd b/libraries/io/eth/src/vhdl/eth_tester.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9ff3d07b8fae0fb274410b2b1076e17ac906403b --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_tester.vhd @@ -0,0 +1,249 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Test the 1GbE interface by sending and counting received packets. +-- Description: See detailed design in [1] +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +LIBRARY IEEE, common_lib, dp_lib, diag_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.dp_components_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.eth_pkg.ALL; +USE work.eth_tester_pkg.ALL; + +ENTITY eth_tester IS + GENERIC ( + g_nof_streams : NATURAL := 1; + g_bg_sync_timeout : NATURAL := 220*10**6; -- 10% margin for nominal 1 s with st_clk at 200MHz + g_remove_crc : BOOLEAN := TRUE -- use TRUE when using sim_tse and tech_tse link interface, + -- use FALSE when streaming link interface + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + st_rst : IN STD_LOGIC; + st_clk : IN STD_LOGIC; + st_pps : IN STD_LOGIC; + + -- UDP transmit interface + eth_src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_src_addr : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0); + udp_src_port : IN STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0); + + tx_fifo_rd_emp_arr : OUT STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + + tx_udp_sosi_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + tx_udp_siso_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=> c_dp_siso_rdy); + + -- UDP receive interface + rx_udp_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=> c_dp_sosi_rst); + + -- Memory Mapped Slaves (one per stream) + -- . Tx + reg_bg_ctrl_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bg_ctrl_cipo : OUT t_mem_cipo; + reg_hdr_dat_copi : IN t_mem_copi := c_mem_copi_rst; + reg_hdr_dat_cipo : OUT t_mem_cipo; + reg_bsn_monitor_v2_tx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bsn_monitor_v2_tx_cipo : OUT t_mem_cipo; + reg_strobe_total_count_tx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_strobe_total_count_tx_cipo : OUT t_mem_cipo; + -- . Rx + reg_bsn_monitor_v2_rx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bsn_monitor_v2_rx_cipo : OUT t_mem_cipo; + reg_strobe_total_count_rx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_strobe_total_count_rx_cipo : OUT t_mem_cipo + ); +END eth_tester; + + +ARCHITECTURE str OF eth_tester IS + + SIGNAL ref_sync_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + + SIGNAL dp_length_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); -- tx block length + + -- MM port multiplexers + -- . Tx + SIGNAL reg_bg_ctrl_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_bg_ctrl_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + SIGNAL reg_hdr_dat_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_hdr_dat_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + SIGNAL reg_bsn_monitor_v2_tx_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_bsn_monitor_v2_tx_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + SIGNAL reg_strobe_total_count_tx_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_strobe_total_count_tx_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + -- . Rx + SIGNAL reg_bsn_monitor_v2_rx_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_bsn_monitor_v2_rx_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + SIGNAL reg_strobe_total_count_rx_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst); + SIGNAL reg_strobe_total_count_rx_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst); + +BEGIN + + gen_streams : FOR I IN 0 TO g_nof_streams-1 GENERATE + u_tx : ENTITY work.eth_tester_tx + GENERIC MAP ( + g_bg_sync_timeout => g_bg_sync_timeout + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + st_pps => st_pps, + ref_sync => ref_sync_arr(I), + + -- UDP transmit interface + eth_src_mac => eth_src_mac, + ip_src_addr => ip_src_addr, + udp_src_port => udp_src_port, + + tx_length => dp_length_arr(I), + tx_fifo_rd_emp => tx_fifo_rd_emp_arr(I), + + tx_udp_sosi => tx_udp_sosi_arr(I), + tx_udp_siso => tx_udp_siso_arr(I), + + -- Memory Mapped Slaves (one per stream) + reg_bg_ctrl_copi => reg_bg_ctrl_copi_arr(I), + reg_bg_ctrl_cipo => reg_bg_ctrl_cipo_arr(I), + reg_hdr_dat_copi => reg_hdr_dat_copi_arr(I), + reg_hdr_dat_cipo => reg_hdr_dat_cipo_arr(I), + reg_bsn_monitor_v2_tx_copi => reg_bsn_monitor_v2_tx_copi_arr(I), + reg_bsn_monitor_v2_tx_cipo => reg_bsn_monitor_v2_tx_cipo_arr(I), + reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi_arr(I), + reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo_arr(I) + ); + + u_rx : ENTITY work.eth_tester_rx + GENERIC MAP ( + g_bg_sync_timeout => g_bg_sync_timeout, + g_remove_crc => g_remove_crc + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + ref_sync => ref_sync_arr(I), + + exp_length => dp_length_arr(I), + + -- UDP transmit interface + rx_udp_sosi => rx_udp_sosi_arr(I), + + -- Memory Mapped Slaves (one per stream) + reg_bsn_monitor_v2_rx_copi => reg_bsn_monitor_v2_rx_copi_arr(I), + reg_bsn_monitor_v2_rx_cipo => reg_bsn_monitor_v2_rx_cipo_arr(I), + reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi_arr(I), + reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo_arr(I) + ); + END GENERATE; + + ----------------------------------------------------------------------------- + -- MM port multiplexers for g_nof_streams + ----------------------------------------------------------------------------- + + -- Tx + u_common_mem_mux_bg : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_diag_bg_reg_adr_w + ) + PORT MAP ( + mosi => reg_bg_ctrl_copi, + miso => reg_bg_ctrl_cipo, + mosi_arr => reg_bg_ctrl_copi_arr, + miso_arr => reg_bg_ctrl_cipo_arr + ); + + u_common_mem_mux_hdr_dat : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_eth_tester_reg_hdr_dat_addr_w + ) + PORT MAP ( + mosi => reg_hdr_dat_copi, + miso => reg_hdr_dat_cipo, + mosi_arr => reg_hdr_dat_copi_arr, + miso_arr => reg_hdr_dat_cipo_arr + ); + + u_common_mem_mux_bsn_monitor_v2_tx : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_dp_bsn_monitor_v2_reg_adr_w + ) + PORT MAP ( + mosi => reg_bsn_monitor_v2_tx_copi, + miso => reg_bsn_monitor_v2_tx_cipo, + mosi_arr => reg_bsn_monitor_v2_tx_copi_arr, + miso_arr => reg_bsn_monitor_v2_tx_cipo_arr + ); + + u_common_mem_mux_strobe_total_count_tx : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_dp_strobe_total_count_reg_adr_w + ) + PORT MAP ( + mosi => reg_strobe_total_count_tx_copi, + miso => reg_strobe_total_count_tx_cipo, + mosi_arr => reg_strobe_total_count_tx_copi_arr, + miso_arr => reg_strobe_total_count_tx_cipo_arr + ); + + -- Rx + u_common_mem_mux_bsn_monitor_v2_rx : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_dp_bsn_monitor_v2_reg_adr_w + ) + PORT MAP ( + mosi => reg_bsn_monitor_v2_rx_copi, + miso => reg_bsn_monitor_v2_rx_cipo, + mosi_arr => reg_bsn_monitor_v2_rx_copi_arr, + miso_arr => reg_bsn_monitor_v2_rx_cipo_arr + ); + + u_common_mem_mux_strobe_total_count_rx : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => c_dp_strobe_total_count_reg_adr_w + ) + PORT MAP ( + mosi => reg_strobe_total_count_rx_copi, + miso => reg_strobe_total_count_rx_cipo, + mosi_arr => reg_strobe_total_count_rx_copi_arr, + miso_arr => reg_strobe_total_count_rx_cipo_arr + ); + +END str; diff --git a/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd b/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..a60dc6c2e381120c811770d11e5100a14d1ac4be --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd @@ -0,0 +1,163 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: This package contains eth_tester specific constants and functions +-- Description: +-- +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; + +PACKAGE eth_tester_pkg is + + CONSTANT c_eth_tester_bg_block_len_max : NATURAL := c_network_eth_payload_jumbo_max; -- 9000 octets + CONSTANT c_eth_tester_rx_block_len_max : NATURAL := c_network_eth_payload_jumbo_max + c_network_eth_crc_len; -- 9004 octets + CONSTANT c_eth_tester_eth_packet_len_max : NATURAL := c_network_eth_word_align_len + c_network_eth_frame_jumbo_max; -- 9020 octets = 2 word align + 14 header + 9000 + 4 crc + + -- hdr_field_sel bit selects where the hdr_field value is set: + -- . 0 = data path controlled, value is set in data path, so field_default() + -- is not used. + -- . 1 = MM controlled, value is set via MM or by the field_default(), so any + -- data path setting in eth_tester.vhd is not used. + -- Remarks: + -- . For constant values it is convenient to use MM controlled, because then + -- the field_default() is used that can be set here in + -- c_eth_tester_hdr_field_arr. + -- . For reserved values it is convenient to use MM controlled, because then + -- in future they could still be changed via MM without having to recompile + -- the FW. + -- . Typically only use data path controlled if the value has to be set + -- dynamically, so dependent on the state of the FW. + -- . If a data path controlled field is not set in the FW, then it defaults + -- to 0 by declaring hdr_fields_in_arr with all 0. Hence e.g. udp_checksum + -- = 0 can be achieve via data path and default hdr_fields_in_arr = 0 or + -- via MM controlled and field_default(0). + CONSTANT c_eth_tester_nof_hdr_fields : NATURAL := 1+3+12+4+4; + CONSTANT c_eth_tester_hdr_field_sel : STD_LOGIC_VECTOR(c_eth_tester_nof_hdr_fields-1 DOWNTO 0) := "1"&"101"&"111011111001"&"0100"&"0100"; + + -- Default use destination MAC/IP/UDP = 0, so these have to be MM programmed + -- before eth_tester packets can be send. + CONSTANT c_eth_tester_hdr_field_arr : t_common_field_arr(c_eth_tester_nof_hdr_fields-1 DOWNTO 0) := ( + ( field_name_pad("word_align" ), "RW", 16, field_default(0) ), -- Tx TSE IP will strip these 2 padding bytes + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), -- c_eth_tester_eth_dst_mac + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), + ( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- c_eth_tester_ip_dst_addr + + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- c_eth_tester_udp_dst_port + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + + ( field_name_pad("dp_length" ), "RW", 16, field_default(0) ), + ( field_name_pad("dp_reserved" ), "RW", 15, field_default(0) ), + ( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ), + ( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) ) + ); + CONSTANT c_eth_tester_reg_hdr_dat_addr_w : NATURAL := ceil_log2(field_nof_words(c_eth_tester_hdr_field_arr, c_word_w)); -- = 5 + CONSTANT c_eth_tester_reg_hdr_dat_addr_span : NATURAL := 2**c_eth_tester_reg_hdr_dat_addr_w; -- = 32 + + CONSTANT c_eth_tester_app_hdr_len : NATURAL := 12; -- octets + + -- Destinations: + -- . MAC address 00:22:86:08:pp:qq = UNB_ETH_SRC_MAC_BASE in + -- libraries/unb_osy/unbos_eth.h, pp = backplane ID, qq = node ID + -- . IP address 10.99.xx.yy = g_base_ip in ctrl_unb2#_board.vhd used in + -- libraries/unb_osy/unbos_eth.c, xx = backplane ID, yy = node ID + 1 + -- . UDP port 15:8 = E0, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0]) + CONSTANT c_eth_tester_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608"; + CONSTANT c_eth_tester_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"0A63"; + CONSTANT c_eth_tester_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"E0"; + + TYPE t_eth_tester_app_header IS RECORD + dp_length : STD_LOGIC_VECTOR(15 DOWNTO 0); + dp_reserved : STD_LOGIC_VECTOR(14 DOWNTO 0); + dp_sync : STD_LOGIC; + dp_bsn : STD_LOGIC_VECTOR(63 DOWNTO 0); + END RECORD; + + TYPE t_eth_tester_header IS RECORD + eth : t_network_eth_header; + ip : t_network_ip_header; + udp : t_network_udp_header; + app : t_eth_tester_app_header; + END RECORD; + + FUNCTION func_eth_tester_map_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_eth_tester_header; + +END eth_tester_pkg; + + +PACKAGE BODY eth_tester_pkg IS + + FUNCTION func_eth_tester_map_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_eth_tester_header IS + VARIABLE v : t_eth_tester_header; + BEGIN + -- eth header + v.eth.dst_mac := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_dst_mac") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_dst_mac")); + v.eth.src_mac := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_src_mac") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_src_mac")); + v.eth.eth_type := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_type") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_type")); + + -- ip header + v.ip.version := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_version") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_version")); + v.ip.header_length := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_header_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_header_length")); + v.ip.services := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_services") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_services")); + v.ip.total_length := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_total_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_total_length")); + v.ip.identification := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_identification") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_identification")); + v.ip.flags := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_flags") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_flags")); + v.ip.fragment_offset := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_fragment_offset") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_fragment_offset")); + v.ip.time_to_live := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_time_to_live") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_time_to_live")); + v.ip.protocol := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_protocol") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_protocol")); + v.ip.header_checksum := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_header_checksum") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_header_checksum")); + v.ip.src_ip_addr := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_src_addr") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_src_addr")); + v.ip.dst_ip_addr := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_dst_addr") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_dst_addr")); + + -- udp header + v.udp.src_port := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_src_port") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_src_port")); + v.udp.dst_port := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_dst_port") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_dst_port")); + v.udp.total_length := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_total_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_total_length")); + v.udp.checksum := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_checksum") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_checksum")); + + -- app header + v.app.dp_length := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length")); + v.app.dp_reserved := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_reserved") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_reserved")); + v.app.dp_sync := sl(hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync"))); + v.app.dp_bsn := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn")); + RETURN v; + END func_eth_tester_map_header; + +END eth_tester_pkg; + diff --git a/libraries/io/eth/src/vhdl/eth_tester_rx.vhd b/libraries/io/eth/src/vhdl/eth_tester_rx.vhd new file mode 100644 index 0000000000000000000000000000000000000000..982054836a1dd884878c733548be96fc41ee054e --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_tester_rx.vhd @@ -0,0 +1,266 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Test the 1GbE interface by sending and counting received packets. +-- Description: Rx part of eth_tester, see detailed design in [1] +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +LIBRARY IEEE, common_lib, dp_lib, diag_lib, tech_tse_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.common_field_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE work.eth_tester_pkg.ALL; + +ENTITY eth_tester_rx IS + GENERIC ( + g_bg_sync_timeout : NATURAL := 220*10**6; -- 10% margin for nominal 1 s with st_clk at 200MHz + g_remove_crc : BOOLEAN := TRUE -- use TRUE when using sim_tse and tech_tse link interface, + -- use FALSE when streaming link interface + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + st_rst : IN STD_LOGIC; + st_clk : IN STD_LOGIC; + ref_sync : IN STD_LOGIC; + + exp_length : IN NATURAL RANGE 0 TO 2**c_halfword_w - 1; -- 16 bit + + -- UDP receive interface + rx_udp_sosi : IN t_dp_sosi; + + -- Memory Mapped Slaves (one per stream) + reg_bsn_monitor_v2_rx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bsn_monitor_v2_rx_cipo : OUT t_mem_cipo; + reg_strobe_total_count_rx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_strobe_total_count_rx_cipo : OUT t_mem_cipo + ); +END eth_tester_rx; + + +ARCHITECTURE str OF eth_tester_rx IS + + CONSTANT c_nof_total_counts : NATURAL := 3; -- 0 = nof_sop, 1 = nof_valid, 2 = nof_crc_corrupt + + CONSTANT c_empty_w : NATURAL := 2; -- for 0, 1, 2, 3 empty octets per word + CONSTANT c_error_w : NATURAL := 1; + + -- Rx FIFO size can be much less than rx_block_sz_max, because st_clk > + -- eth_clk rate, but with st level tx-rx loopback the Rx FIFO does need + -- rx_block_sz_max FIFO size. + CONSTANT rx_block_sz_max : NATURAL := c_eth_tester_rx_block_len_max / c_word_sz; -- = 9004 / 4 = 2251 + CONSTANT c_fifo_size : NATURAL := true_log_pow2(rx_block_sz_max); -- = 4096 words + + SIGNAL rx_udp_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL rx_offload_sosi : t_dp_sosi; + SIGNAL rx_offload_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL decoded_sosi : t_dp_sosi; + SIGNAL decoded_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL decoded_length : NATURAL; + SIGNAL rx_fifo_siso : t_dp_siso; + SIGNAL rx_fifo_sosi : t_dp_sosi; + SIGNAL rx_fifo_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL rx_fifo_wr_ful : STD_LOGIC; + SIGNAL rx_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_fifo_size)-1 DOWNTO 0); + SIGNAL unpacked_sosi : t_dp_sosi; + SIGNAL unpacked_data : STD_LOGIC_VECTOR(c_octet_w-1 DOWNTO 0); + SIGNAL crc_corrupt : STD_LOGIC := '0'; + + SIGNAL in_strobe_arr : STD_LOGIC_VECTOR(c_nof_total_counts-1 DOWNTO 0); + + SIGNAL hdr_fields_out_slv : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL hdr_fields_raw_slv : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL hdr_fields_out_rec : t_eth_tester_header; + SIGNAL hdr_fields_raw_rec : t_eth_tester_header; + +BEGIN + + -- View sosi.data in Wave Window + rx_udp_data <= rx_udp_sosi.data(c_word_w-1 DOWNTO 0); + rx_offload_data <= rx_offload_sosi.data(c_word_w-1 DOWNTO 0); + decoded_data <= decoded_sosi.data(c_word_w-1 DOWNTO 0); + rx_fifo_data <= rx_fifo_sosi.data(c_word_w-1 DOWNTO 0); + unpacked_data <= unpacked_sosi.data(c_octet_w-1 DOWNTO 0); + + ------------------------------------------------------------------------------- + -- Rx ETH/UDP/IP packets with packed BG data + ------------------------------------------------------------------------------- + + u_dp_offload_rx : ENTITY dp_lib.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_symbol_w => c_octet_w, + g_hdr_field_arr => c_eth_tester_hdr_field_arr, + g_remove_crc => g_remove_crc, + g_crc_nof_words => 1 + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + dp_rst => st_rst, + dp_clk => st_clk, + + snk_in_arr(0) => rx_udp_sosi, + src_out_arr(0) => rx_offload_sosi, + + hdr_fields_out_arr(0) => hdr_fields_out_slv, -- Valid at src_out_arr(i).sop, use for sosi.sync + hdr_fields_raw_arr(0) => hdr_fields_raw_slv -- Valid at src_out_arr(i).sop and beyond, use for sosi.bsn + ); + + -- View record in Wave Window + hdr_fields_out_rec <= func_eth_tester_map_header(hdr_fields_out_slv); + hdr_fields_raw_rec <= func_eth_tester_map_header(hdr_fields_raw_slv); + + p_set_meta: PROCESS(rx_offload_sosi, hdr_fields_out_slv, hdr_fields_raw_slv) + BEGIN + decoded_sosi <= rx_offload_sosi; + decoded_length <= TO_UINT(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length"))); + decoded_sosi.sync <= sl(hdr_fields_out_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync"))); + decoded_sosi.bsn <= RESIZE_DP_BSN(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn"))); + -- Map rx_offload_sosi.err c_tech_tse_error_w = 6 bit value on to c_error_w = 1 bit decoded_sosi.err value + decoded_sosi.err <= TO_DP_ERROR(0); + IF UNSIGNED(rx_offload_sosi.err(c_tech_tse_error_w-1 DOWNTO 0)) /= 0 THEN + decoded_sosi.err <= TO_DP_ERROR(1); + END IF; + END PROCESS; + + -- synthesis translate_off + p_verify_length : PROCESS(st_clk) + BEGIN + IF rising_edge(st_clk) THEN + IF decoded_sosi.sop = '1' THEN + ASSERT decoded_length = exp_length REPORT "Unexpected Rx length" & NATURAL'IMAGE(decoded_length) & " /= " & NATURAL'IMAGE(exp_length) & " expected length from Tx" SEVERITY ERROR; + END IF; + END IF; + END PROCESS; + -- synthesis translate_on + + u_rx_fifo : ENTITY dp_lib.dp_fifo_sc + GENERIC MAP ( + g_data_w => c_word_w, + g_bsn_w => c_diag_bg_bsn_init_w, -- = 64 bit + g_empty_w => c_empty_w, + g_error_w => c_error_w, + g_use_bsn => TRUE, + g_use_empty => TRUE, + g_use_sync => TRUE, + g_use_error => TRUE, + g_fifo_size => c_fifo_size + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + -- Monitor FIFO filling + wr_ful => rx_fifo_wr_ful, + usedw => rx_fifo_usedw, + -- ST sink + snk_in => decoded_sosi, + -- ST source + src_in => rx_fifo_siso, + src_out => rx_fifo_sosi + ); + + u_unpack : ENTITY dp_lib.dp_repack_data -- unpack 32b words into 8b octets + GENERIC MAP ( + g_in_dat_w => c_word_w, -- = 32 + g_in_nof_words => 1, + g_in_symbol_w => c_octet_w, + g_out_dat_w => c_octet_w, -- = 8 + g_out_nof_words => c_word_sz, -- = 4 + g_out_symbol_w => c_octet_w + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + snk_out => rx_fifo_siso, + snk_in => rx_fifo_sosi, + src_out => unpacked_sosi + ); + + ------------------------------------------------------------------------------- + -- Rx packet monitors + ------------------------------------------------------------------------------- + + u_mms_dp_bsn_monitor_v2 : ENTITY dp_lib.mms_dp_bsn_monitor_v2 + GENERIC MAP ( + g_nof_streams => 1, + g_sync_timeout => g_bg_sync_timeout + ) + PORT MAP ( + -- Memory-mapped clock domain + mm_rst => mm_rst, + mm_clk => mm_clk, + reg_mosi => reg_bsn_monitor_v2_rx_copi, + reg_miso => reg_bsn_monitor_v2_rx_cipo, + + -- Streaming clock domain + dp_rst => st_rst, + dp_clk => st_clk, + ref_sync => ref_sync, + + in_sosi_arr(0) => unpacked_sosi + ); + + -- Rx CRC result is available at last octet + p_crc_corrupt : PROCESS(st_clk) + BEGIN + IF rising_edge(st_clk) THEN + crc_corrupt <= '0'; + IF unpacked_sosi.eop = '1' AND unpacked_sosi.err(0) = '1' THEN + crc_corrupt <= '1'; + END IF; + END IF; + END PROCESS; + + in_strobe_arr(0) <= unpacked_sosi.sop; -- count total nof Rx packets + in_strobe_arr(1) <= unpacked_sosi.valid; -- count total nof Rx valid octets + in_strobe_arr(2) <= crc_corrupt; -- count total nof corrupted Rx packets + + u_dp_strobe_total_count : ENTITY dp_lib.dp_strobe_total_count + GENERIC MAP ( + g_nof_counts => c_nof_total_counts, + g_count_w => c_longword_w, + g_clip => TRUE + ) + PORT MAP ( + dp_rst => st_rst, + dp_clk => st_clk, + + ref_sync => unpacked_sosi.sync, + in_strobe_arr => in_strobe_arr, + + mm_rst => mm_rst, + mm_clk => mm_clk, + + reg_mosi => reg_strobe_total_count_rx_copi, + reg_miso => reg_strobe_total_count_rx_cipo + ); + +END str; diff --git a/libraries/io/eth/src/vhdl/eth_tester_tx.vhd b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b4d2201a231e12ae4d740cac6cdc5561904ec466 --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd @@ -0,0 +1,356 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Test the 1GbE interface by sending and counting received packets. +-- Description: Tx part of eth_tester, see detailed design in [1] +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +LIBRARY IEEE, common_lib, dp_lib, diag_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.eth_tester_pkg.ALL; + +ENTITY eth_tester_tx IS + GENERIC ( + g_bg_sync_timeout : NATURAL := 220*10**6 -- 10% margin for nominal 1 s with st_clk at 200MHz + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + st_rst : IN STD_LOGIC; + st_clk : IN STD_LOGIC; + st_pps : IN STD_LOGIC; + ref_sync : OUT STD_LOGIC; + + -- UDP transmit interface + eth_src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_src_addr : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0); + udp_src_port : IN STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0); + + tx_length : OUT NATURAL RANGE 0 TO 2**c_halfword_w - 1; -- 16 bit + tx_fifo_rd_emp : OUT STD_LOGIC; + + tx_udp_sosi : OUT t_dp_sosi; + tx_udp_siso : IN t_dp_siso := c_dp_siso_rdy; + + -- Memory Mapped Slaves (one per stream) + reg_bg_ctrl_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bg_ctrl_cipo : OUT t_mem_cipo; + reg_hdr_dat_copi : IN t_mem_copi := c_mem_copi_rst; + reg_hdr_dat_cipo : OUT t_mem_cipo; + reg_bsn_monitor_v2_tx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_bsn_monitor_v2_tx_cipo : OUT t_mem_cipo; + reg_strobe_total_count_tx_copi : IN t_mem_copi := c_mem_copi_rst; + reg_strobe_total_count_tx_cipo : OUT t_mem_cipo + ); +END eth_tester_tx; + + +ARCHITECTURE str OF eth_tester_tx IS + + CONSTANT c_empty_w : NATURAL := 2; -- for 0, 1, 2, 3 empty octets per word + + -- Choose 10% extra margin for FIFO fill level that will result in BG block + -- level flow control via bg_siso.xon. The input eop will release blocks + -- for FIFO output already before the FIFO is fill level is reached. + -- Choose FIFO size to fit one more packet on top of FIFO fill level. + CONSTANT c_fifo_fill : NATURAL := c_eth_tester_bg_block_len_max * 11 / c_word_sz / 10; + CONSTANT c_fifo_size : NATURAL := true_log_pow2(c_fifo_fill + c_eth_tester_bg_block_len_max); -- = 8192 + + CONSTANT c_nof_total_counts : NATURAL := 1; -- one to count Tx packets + + SIGNAL ip_total_length : NATURAL; + SIGNAL udp_total_length : NATURAL; + SIGNAL app_total_length : NATURAL; + + SIGNAL bg_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL bg_sosi : t_dp_sosi; + SIGNAL bg_data : STD_LOGIC_VECTOR(c_octet_w-1 DOWNTO 0); + SIGNAL bg_ctrl_hold : t_diag_block_gen; + SIGNAL bg_block_len : NATURAL; + SIGNAL tx_packed_siso : t_dp_siso; + SIGNAL tx_packed_sosi : t_dp_sosi; + SIGNAL tx_packed_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL tx_fifo_sosi : t_dp_sosi; + SIGNAL tx_fifo_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL tx_fifo_siso : t_dp_siso; + SIGNAL tx_fifo_wr_ful : STD_LOGIC; + SIGNAL tx_fifo_wr_usedw : STD_LOGIC_VECTOR(ceil_log2(c_fifo_size)-1 DOWNTO 0); + SIGNAL i_tx_fifo_rd_emp : STD_LOGIC; + + SIGNAL i_ref_sync : STD_LOGIC := '0'; + SIGNAL in_strobe_arr : STD_LOGIC_VECTOR(c_nof_total_counts-1 DOWNTO 0); + SIGNAL i_tx_udp_sosi : t_dp_sosi; + SIGNAL tx_udp_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + -- Use hdr_fields_slv_in default 0, to have DP driven fields ip_header_checksum = 0 and udp_checksum = 0 + SIGNAL hdr_fields_slv_in : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0'); + SIGNAL hdr_fields_slv_tx : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL hdr_fields_rec_in : t_eth_tester_header; + SIGNAL hdr_fields_rec_tx : t_eth_tester_header; + +BEGIN + + ref_sync <= i_ref_sync; + tx_length <= app_total_length; + tx_fifo_rd_emp <= i_tx_fifo_rd_emp; + tx_udp_sosi <= i_tx_udp_sosi; + + -- View sosi.data in Wave Window + bg_data <= bg_sosi.data(c_octet_w-1 DOWNTO 0); + tx_packed_data <= tx_packed_sosi.data(c_word_w-1 DOWNTO 0); + tx_fifo_data <= tx_fifo_sosi.data(c_word_w-1 DOWNTO 0); + tx_udp_data <= i_tx_udp_sosi.data(c_word_w-1 DOWNTO 0); + + ------------------------------------------------------------------------------- + -- Generate packed data blocks + ------------------------------------------------------------------------------- + u_bg : ENTITY diag_lib.mms_diag_block_gen + GENERIC MAP ( + g_nof_streams => 1, + g_use_bg_buffer_ram => FALSE, + g_buf_addr_w => c_diag_bg_mem_adrs_w -- = 24, use full range 2**24 for BG addr --> data values + ) + PORT MAP ( + -- System + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => st_rst, + dp_clk => st_clk, + en_sync => st_pps, -- block generator enable sync pulse in ST clock domain + -- MM interface + reg_bg_ctrl_mosi => reg_bg_ctrl_copi, -- BG control register (one for all streams) + reg_bg_ctrl_miso => reg_bg_ctrl_cipo, + -- ST interface + bg_ctrl_hold_arr(0) => bg_ctrl_hold, + out_sosi_arr(0) => bg_sosi, + out_siso_arr(0) => bg_siso + ); + + -- BG clock level flow control, needed when the dp_repack_data has to insert + -- empty octets into the last packed word. + bg_siso.ready <= tx_packed_siso.ready; + + -- BG block level flow control, needed in case BG settings result in eth bit + -- rate > 1 Gbps, to avoid u_tx_fifo overflow. + p_bg_siso_xon : PROCESS(st_clk) + BEGIN + IF rising_edge(st_clk) THEN + bg_siso.xon <= '1'; + IF TO_UINT(tx_fifo_wr_usedw) > c_fifo_fill THEN + bg_siso.xon <= '0'; + END IF; + END IF; + END PROCESS; + + u_pack : ENTITY dp_lib.dp_repack_data -- pack 8b octets into 32b words + GENERIC MAP ( + g_in_dat_w => c_octet_w, -- = 8 + g_in_nof_words => c_word_sz, -- = 4 + g_in_symbol_w => c_octet_w, + g_out_dat_w => c_word_w, -- = 32 + g_out_nof_words => 1, + g_out_symbol_w => c_octet_w + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + snk_out => tx_packed_siso, + snk_in => bg_sosi, + src_out => tx_packed_sosi + ); + + u_tx_fifo : ENTITY dp_lib.dp_fifo_fill_eop + GENERIC MAP ( + g_data_w => c_word_w, + g_bsn_w => c_diag_bg_bsn_init_w, -- = 64 bit + g_empty_w => c_empty_w, + g_use_bsn => TRUE, + g_use_empty => TRUE, + g_use_sync => TRUE, + g_fifo_fill => c_fifo_fill, + g_fifo_size => c_fifo_size + ) + PORT MAP ( + wr_rst => st_rst, + wr_clk => st_clk, + rd_rst => st_rst, + rd_clk => st_clk, + -- Monitor FIFO filling + wr_ful => tx_fifo_wr_ful, + wr_usedw => tx_fifo_wr_usedw, + rd_emp => i_tx_fifo_rd_emp, + -- ST sink + snk_in => tx_packed_sosi, + -- ST source + src_in => tx_fifo_siso, + src_out => tx_fifo_sosi + ); + + ------------------------------------------------------------------------------- + -- Assemble header info + ------------------------------------------------------------------------------- + -- Whether the dp_offload_tx_hdr_fields value is actually used in the Tx + -- header depends on: + -- c_eth_tester_hdr_field_sel = "1"&"101"&"111011111001"&"0100"&"100" + -- eth ip udp app + -- where 0 = data path, 1 = MM controlled. The '0' fields are assigned here + -- in hdr_fields_slv_in in order: + -- access field + -- MM word_align + -- + -- MM eth_dst_mac + -- DP eth_src_mac + -- MM eth_type + -- + -- MM ip_version + -- MM ip_header_length + -- MM ip_services + -- DP ip_total_length + -- MM ip_identification + -- MM ip_flags + -- MM ip_fragment_offset + -- MM ip_time_to_live + -- MM ip_protocol + -- DP ip_header_checksum --> not here, will be filled in by 1GbE + -- eth component + -- DP ip_src_addr + -- MM ip_dst_addr + -- + -- DP udp_src_port + -- MM udp_dst_port + -- DP udp_total_length + -- DP udp_checksum --> default fixed 0, so not used, not calculated + -- here or in 1GbE eth component because would + -- require store and forward + -- DP dp_length + -- MM dp_reserved + -- DP dp_sync + -- DP dp_bsn + + -- The bg_block_len is still valid because bg_ctrl_hold holds the BG settings + -- until it restarts, so no need to pass bg_block_len on via e.g. the channel + -- field in u_fifo. + bg_block_len <= TO_UINT(bg_ctrl_hold.samples_per_packet(15 DOWNTO 0)); -- packet lenghts fit in 16b + app_total_length <= c_eth_tester_app_hdr_len + bg_block_len WHEN rising_edge(st_clk); + udp_total_length <= c_network_udp_header_len + app_total_length WHEN rising_edge(st_clk); + ip_total_length <= c_network_ip_header_len + udp_total_length WHEN rising_edge(st_clk); + + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "eth_src_mac" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_src_mac" )) <= eth_src_mac; + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "ip_total_length" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_total_length" )) <= TO_UVEC(ip_total_length, 16); + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "ip_src_addr" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_src_addr" )) <= ip_src_addr; + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "udp_src_port" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_src_port" )) <= udp_src_port; + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "udp_total_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_total_length")) <= TO_UVEC(udp_total_length, 16); + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_length" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length" )) <= TO_UVEC(app_total_length, 16); + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_sync" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync" )) <= slv(tx_fifo_sosi.sync); + hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn" )) <= tx_fifo_sosi.bsn; + + ------------------------------------------------------------------------------- + -- Tx ETH/UDP/IP packets with packed BG data + ------------------------------------------------------------------------------- + u_dp_offload_tx : ENTITY dp_lib.dp_offload_tx_v3 + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_symbol_w => c_octet_w, + g_hdr_field_arr => c_eth_tester_hdr_field_arr, + g_hdr_field_sel => c_eth_tester_hdr_field_sel, + g_pipeline_ready => TRUE + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => st_rst, + dp_clk => st_clk, + + reg_hdr_dat_mosi => reg_hdr_dat_copi, + reg_hdr_dat_miso => reg_hdr_dat_cipo, + + snk_in_arr(0) => tx_fifo_sosi, + snk_out_arr(0) => tx_fifo_siso, + + src_out_arr(0) => i_tx_udp_sosi, + src_in_arr(0) => tx_udp_siso, + + hdr_fields_in_arr(0) => hdr_fields_slv_in, -- hdr_fields_slv_in_arr(i) is considered valid @ snk_in_arr(i).sop + hdr_fields_out_arr(0) => hdr_fields_slv_tx + ); + + -- View record in Wave Window + hdr_fields_rec_in <= func_eth_tester_map_header(hdr_fields_slv_in); + hdr_fields_rec_tx <= func_eth_tester_map_header(hdr_fields_slv_tx); + + ------------------------------------------------------------------------------- + -- Tx packet monitors + ------------------------------------------------------------------------------- + i_ref_sync <= tx_fifo_sosi.sync WHEN rising_edge(st_clk); + + u_mms_dp_bsn_monitor_v2 : ENTITY dp_lib.mms_dp_bsn_monitor_v2 + GENERIC MAP ( + g_nof_streams => 1, + g_sync_timeout => g_bg_sync_timeout + ) + PORT MAP ( + -- Memory-mapped clock domain + mm_rst => mm_rst, + mm_clk => mm_clk, + reg_mosi => reg_bsn_monitor_v2_tx_copi, + reg_miso => reg_bsn_monitor_v2_tx_cipo, + + -- Streaming clock domain + dp_rst => st_rst, + dp_clk => st_clk, + ref_sync => i_ref_sync, + + in_siso_arr(0) => tx_fifo_siso, + in_sosi_arr(0) => tx_fifo_sosi + ); + + in_strobe_arr(0) <= tx_fifo_sosi.sop; -- count total nof Tx packets + + u_dp_strobe_total_count : ENTITY dp_lib.dp_strobe_total_count + GENERIC MAP ( + g_nof_counts => c_nof_total_counts, + g_count_w => c_longword_w, + g_clip => TRUE + ) + PORT MAP ( + dp_rst => st_rst, + dp_clk => st_clk, + + ref_sync => i_ref_sync, + in_strobe_arr => in_strobe_arr, + + mm_rst => mm_rst, + mm_clk => mm_clk, + + reg_mosi => reg_strobe_total_count_tx_copi, + reg_miso => reg_strobe_total_count_tx_cipo + ); + +END str; diff --git a/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd b/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f0f0574905364b3ac22679e2f80e0799a633fc9c --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd @@ -0,0 +1,686 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Test bench for eth_tester +-- Description: See detailed design in [1] +-- The g_nof_streams >= 1 are tested independently, using g_bg_ctrl_first for +-- BG in stream 0 and g_bg_ctrl_others for all other streams. +-- +-- Usage: +-- > as 8 +-- # * E.g. view sosi/data signals in dut/gen_streams/u_rx and u_tx +-- # * Cannot use run -a when g_loopback_eth=TRUE and g_eth_sim_level=0, +-- # because the TSE IP model remains active internally after tb_end +-- > run 100 us # when g_loopback_eth=TRUE and g_eth_sim_level=0, else: +-- > run -a +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE +-- [2] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Application+header+size+in+Ethernet+packets + +LIBRARY IEEE, common_lib, dp_lib, diag_lib, technology_lib, tech_tse_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.common_str_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.dp_components_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.eth_pkg.ALL; +USE work.eth_tester_pkg.ALL; +USE work.tb_eth_tester_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE tech_tse_lib.tb_tech_tse_pkg.ALL; + +ENTITY tb_eth_tester IS + GENERIC ( + g_tb_index : NATURAL := 0; -- use to incremental delay logging from tb instances in tb_tb + g_nof_sync : NATURAL := 2; -- number of BG sync intervals to set c_run_time + g_nof_streams : NATURAL := 1; -- <= c_eth_nof_udp_ports = 4 when g_loopback_tx_rx = 1 + g_loopback_eth : BOOLEAN := TRUE; -- FALSE = sosi loopback, TRUE = eth loopback (using sim_tse or tech_tse) + g_eth_sim_level : NATURAL := 0; -- when g_loopback_eth = TRUE, then 0 = use tech_tse IP; 1 = use fast sim_tse model + g_corrupted_en : BOOLEAN := FALSE; -- when TRUE cause a corrupted Rx packet, when tech_tse is used + + -- t_diag_block_gen_integer = + -- sl: enable + -- sl: enable_sync + -- nat: samples_per_packet + -- nat: blocks_per_sync + -- nat: gapsize + -- nat: mem_low_adrs + -- nat: mem_high_adrs + -- nat: bsn_init + --g_bg_ctrl_first : t_diag_block_gen_integer := ('1', '1', 50, 3, 100, 0, c_diag_bg_mem_max_adr, 0); -- for first stream + --g_bg_ctrl_others : t_diag_block_gen_integer := ('1', '1', 30, 3, 10, 0, c_diag_bg_mem_max_adr, 0) -- for other streams + g_bg_ctrl_first : t_diag_block_gen_integer := ('1', '1', 50, 3, 200, 0, c_diag_bg_mem_max_adr, 0); -- for first stream + g_bg_ctrl_others : t_diag_block_gen_integer := ('1', '1', 30, 3, 10, 0, c_diag_bg_mem_max_adr, 0) -- for other streams + ); + PORT ( + tb_end : OUT STD_LOGIC + ); +END tb_eth_tester; + + +ARCHITECTURE tb OF tb_eth_tester IS + + CONSTANT c_tb_str : STRING := "tb-" & NATURAL'IMAGE(g_tb_index) & " : "; -- use to distinguish logging from tb instances in tb_tb + CONSTANT eth_clk_period : TIME := 8 ns; -- 125 MHz + CONSTANT mm_clk_period : TIME := 10 ns; -- 100 MHz + CONSTANT c_nof_st_clk_per_s : NATURAL := 200 * 10**6; + CONSTANT st_clk_period : TIME := (10**9 / c_nof_st_clk_per_s) * 1 ns; -- 5 ns, 200 MHz + + CONSTANT c_bg_block_len_first : NATURAL := g_bg_ctrl_first.samples_per_packet; + CONSTANT c_bg_block_len_others : NATURAL := g_bg_ctrl_others.samples_per_packet; + CONSTANT c_bg_block_len_max : NATURAL := largest(c_bg_block_len_first, c_bg_block_len_others); + + CONSTANT c_bg_slot_len_first : NATURAL := c_bg_block_len_first + g_bg_ctrl_first.gapsize; + CONSTANT c_bg_slot_len_others : NATURAL := c_bg_block_len_others + g_bg_ctrl_others.gapsize; + CONSTANT c_bg_slot_len_max : NATURAL := largest(c_bg_slot_len_first, c_bg_slot_len_others); + + CONSTANT c_eth_packet_len_first : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len_first); + CONSTANT c_eth_packet_len_others : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len_others); + + -- Use REAL to avoid NATURAL overflow in bps calculation + CONSTANT c_bg_nof_bps_first : REAL := REAL(c_bg_block_len_first * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_first); + CONSTANT c_bg_nof_bps_others : REAL := REAL(c_bg_block_len_others * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_others); + CONSTANT c_bg_nof_bps_total : REAL := c_bg_nof_bps_first + REAL(g_nof_streams - 1) * c_bg_nof_bps_others; + + CONSTANT c_bg_sync_period_first : NATURAL := c_bg_slot_len_first * g_bg_ctrl_first.blocks_per_sync; + CONSTANT c_bg_sync_period_others : NATURAL := c_bg_slot_len_others * g_bg_ctrl_others.blocks_per_sync; + CONSTANT c_bg_sync_period_max : NATURAL := largest(c_bg_sync_period_first, c_bg_sync_period_others); + + CONSTANT c_run_time : NATURAL := g_nof_sync * c_bg_sync_period_max; + CONSTANT c_nof_sync_first : NATURAL := c_run_time / c_bg_sync_period_first; + CONSTANT c_nof_sync_others : NATURAL := c_run_time / c_bg_sync_period_others; + + -- Expected Tx --> Rx latency values obtained from a tb run + CONSTANT c_tx_exp_latency : NATURAL := 0; + CONSTANT c_rx_exp_latency_en : BOOLEAN := c_bg_block_len_max >= 50; + CONSTANT c_rx_exp_latency_st : NATURAL := 27; + CONSTANT c_rx_exp_latency_sim_tse : NATURAL := 165; + CONSTANT c_rx_exp_latency_tech_tse : NATURAL := 375; + + -- CRC is added by Tx TSE IP and removed by dp_offload_rx when g_remove_crc = + -- g_loopback_eth = TRUE. Therefore internally only application payload + -- (= block_len) octets are counted. + CONSTANT c_nof_valid_per_packet_first : NATURAL := c_bg_block_len_first; + CONSTANT c_nof_valid_per_packet_others : NATURAL := c_bg_block_len_others; + + CONSTANT c_total_count_nof_valid_per_sync_first : NATURAL := g_bg_ctrl_first.blocks_per_sync * c_nof_valid_per_packet_first; + CONSTANT c_total_count_nof_valid_per_sync_others : NATURAL := g_bg_ctrl_others.blocks_per_sync * c_nof_valid_per_packet_others; + + CONSTANT c_mon_nof_sop_first : NATURAL := g_bg_ctrl_first.blocks_per_sync; + CONSTANT c_mon_nof_sop_others : NATURAL := g_bg_ctrl_others.blocks_per_sync; + CONSTANT c_mon_nof_valid_first_tx : NATURAL := c_mon_nof_sop_first * ceil_div(c_bg_block_len_first * c_octet_w, c_word_w); + CONSTANT c_mon_nof_valid_first_rx : NATURAL := c_mon_nof_sop_first * c_nof_valid_per_packet_first; + CONSTANT c_mon_nof_valid_others_tx : NATURAL := c_mon_nof_sop_others * ceil_div(c_bg_block_len_others* c_octet_w, c_word_w); + CONSTANT c_mon_nof_valid_others_rx : NATURAL := c_mon_nof_sop_others * c_nof_valid_per_packet_others; + + -- Use sim default src MAC, IP, UDP port from eth_tester_pkg.vhd and based on c_gn_index + CONSTANT c_gn_index : NATURAL := 17; -- global node index + CONSTANT c_gn_eth_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := c_eth_tester_eth_src_mac_47_16 & func_eth_tester_gn_index_to_mac_15_0(c_gn_index); + CONSTANT c_gn_ip_src_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := c_eth_tester_ip_src_addr_31_16 & func_eth_tester_gn_index_to_ip_15_0(c_gn_index); + CONSTANT c_gn_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := c_eth_tester_udp_src_port_15_8 & TO_UVEC(c_gn_index, 8); + + -- Clocks and reset + SIGNAL mm_rst : STD_LOGIC := '1'; + SIGNAL mm_clk : STD_LOGIC := '1'; + SIGNAL st_rst : STD_LOGIC := '1'; + SIGNAL st_clk : STD_LOGIC := '1'; + SIGNAL st_pps : STD_LOGIC := '0'; + SIGNAL stimuli_end : STD_LOGIC := '0'; + SIGNAL i_tb_end : STD_LOGIC := '0'; + + SIGNAL eth_clk : STD_LOGIC := '1'; + SIGNAL eth_txp : STD_LOGIC; + SIGNAL eth_rxp : STD_LOGIC; + SIGNAL eth_corrupt : STD_LOGIC := '0'; + + -- Use same bg_ctrl for all streams, this provides sufficient test coverage + SIGNAL bg_ctrl_arr : t_diag_block_gen_integer_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL tx_fifo_rd_emp_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); + + -- ETH UDP data path interface + SIGNAL tx_udp_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL tx_udp_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL rx_udp_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + + -- MM interface + -- . Tx + SIGNAL reg_bg_ctrl_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bg_ctrl_cipo : t_mem_cipo; + SIGNAL reg_hdr_dat_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_hdr_dat_cipo : t_mem_cipo; + SIGNAL reg_bsn_monitor_v2_tx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bsn_monitor_v2_tx_cipo : t_mem_cipo; + SIGNAL reg_strobe_total_count_tx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_strobe_total_count_tx_cipo : t_mem_cipo; + -- . Rx + SIGNAL reg_bsn_monitor_v2_rx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bsn_monitor_v2_rx_cipo : t_mem_cipo; + SIGNAL reg_strobe_total_count_rx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_strobe_total_count_rx_cipo : t_mem_cipo; + + -- . reg_strobe_total_count + SIGNAL tx_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL exp_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); -- same for both tx and rx + + SIGNAL rx_total_count_nof_valid_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_exp_total_count_nof_valid_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL rx_total_count_nof_corrupted_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_exp_total_count_nof_corrupted_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + + -- . reg_bsn_monitor_v2 + SIGNAL tx_mon_nof_sop_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL tx_mon_nof_valid_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL tx_mon_latency_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_mon_nof_sop_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_mon_nof_valid_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL rx_mon_latency_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + + -- ETH link, used when g_loopback_eth = TRUE + SIGNAL eth_tx_udp_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_sosi_rst); -- default rst if not used + SIGNAL eth_tx_udp_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL eth_rx_udp_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL eth_rx_udp_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_siso_rst); -- default rst if not used + + SIGNAL reg_eth_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_eth_cipo : t_mem_cipo; + + -- . set up eth when g_eth_sim_level = 0 + SIGNAL tse_init : STD_LOGIC := '1'; + SIGNAL tse_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL tse_cipo : t_mem_cipo; + SIGNAL tse_psc_access : STD_LOGIC; + + -- View in Wave window + SIGNAL dbg_c_run_time : NATURAL := c_run_time; + SIGNAL dbg_c_mon_nof_sop_first : NATURAL := c_mon_nof_sop_first; + SIGNAL dbg_c_mon_nof_sop_others : NATURAL := c_mon_nof_sop_others; + SIGNAL dbg_c_mon_nof_valid_first_tx : NATURAL := c_mon_nof_valid_first_tx; + SIGNAL dbg_c_mon_nof_valid_first_rx : NATURAL := c_mon_nof_valid_first_rx; + SIGNAL dbg_c_mon_nof_valid_others_tx : NATURAL := c_mon_nof_valid_others_tx; + SIGNAL dbg_c_mon_nof_valid_others_rx : NATURAL := c_mon_nof_valid_others_rx; + +BEGIN + + tb_end <= i_tb_end; + + eth_clk <= (NOT eth_clk) OR i_tb_end AFTER eth_clk_period/2; + mm_clk <= (NOT mm_clk) OR i_tb_end AFTER mm_clk_period/2; + st_clk <= (NOT st_clk) OR i_tb_end AFTER st_clk_period/2; + mm_rst <= '1', '0' AFTER mm_clk_period*5; + st_rst <= '1', '0' AFTER st_clk_period*5; + + -- Using + --SIGNAL exp_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + -- (g_nof_streams-1 DOWNTO 1 => g_nof_sync * g_bg_ctrl_others.blocks_per_sync, + -- 0 => g_nof_sync * g_bg_ctrl_first.blocks_per_sync); + -- yields verror 1074, verror 1048, therefor use p_init instead, and + -- therefor use bg_ctrl_arr instead of c_bg_ctrl_arr. + p_init : PROCESS + BEGIN + bg_ctrl_arr <= (OTHERS => g_bg_ctrl_others); + bg_ctrl_arr(0) <= g_bg_ctrl_first; + + exp_total_count_nof_packet_arr <= (OTHERS => c_nof_sync_others * g_bg_ctrl_others.blocks_per_sync); + exp_total_count_nof_packet_arr(0) <= c_nof_sync_first * g_bg_ctrl_first.blocks_per_sync; + + rx_exp_total_count_nof_valid_arr <= (OTHERS => c_nof_sync_others * c_total_count_nof_valid_per_sync_others); + rx_exp_total_count_nof_valid_arr(0) <= c_nof_sync_first * c_total_count_nof_valid_per_sync_first; + + rx_exp_total_count_nof_corrupted_arr <= (OTHERS => 0); -- default no Rx errors + IF g_corrupted_en = TRUE THEN + rx_exp_total_count_nof_corrupted_arr(0) <= 1; + END IF; + WAIT; + END PROCESS; + + ----------------------------------------------------------------------------- + -- MM control and monitoring + ----------------------------------------------------------------------------- + p_mm : PROCESS + VARIABLE v_value : NATURAL; + VARIABLE v_offset : NATURAL; + VARIABLE v_udp_dst_port : NATURAL; + BEGIN + i_tb_end <= '0'; + + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + + proc_common_wait_until_low(mm_clk, tse_init); + proc_common_wait_some_cycles(mm_clk, 10); + + --------------------------------------------------------------------------- + -- Rx UDP offload port + --------------------------------------------------------------------------- + v_udp_dst_port := TO_UINT(c_eth_tester_udp_dst_port); + + IF g_loopback_eth = TRUE THEN + -- Set up demux in eth Rx based on destination UDP port + v_value := 2**16 + v_udp_dst_port; -- enable bit 16, udp port number [15:0] + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + proc_mem_mm_bus_wr(0 + I, v_value + I, mm_clk, reg_eth_copi); -- increment udp_dst_port per stream + END LOOP; + END IF; + + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + v_offset := I * c_eth_tester_reg_hdr_dat_addr_span; + -- Set destination MAC/IP/UDP port in tx header, increment udp_dst_port per stream + -- The MM addresses follow from byte address_offset // 4 in eth.peripheral.yaml + proc_mem_mm_bus_wr(v_offset + 16#7#, v_udp_dst_port + I, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + proc_mem_mm_bus_wr(v_offset + 16#10#, TO_SINT(c_eth_tester_ip_dst_addr), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); -- use signed to fit 32 b in INTEGER + proc_mem_mm_bus_wr(v_offset + 16#18#, TO_SINT(c_eth_tester_eth_dst_mac(31 DOWNTO 0)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); -- use signed to fit 32 b in INTEGER + proc_mem_mm_bus_wr(v_offset + 16#19#, TO_UINT(c_eth_tester_eth_dst_mac(47 DOWNTO 32)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + END LOOP; + + --------------------------------------------------------------------------- + -- Stimuli + --------------------------------------------------------------------------- + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + v_offset := I * c_diag_bg_reg_adr_span; + -- Prepare the BG + proc_mem_mm_bus_wr(v_offset + 1, bg_ctrl_arr(I).samples_per_packet, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 2, bg_ctrl_arr(I).blocks_per_sync, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 3, bg_ctrl_arr(I).gapsize, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 4, bg_ctrl_arr(I).mem_low_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 5, bg_ctrl_arr(I).mem_high_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 6, bg_ctrl_arr(I).bsn_init, mm_clk, reg_bg_ctrl_copi); -- low part + proc_mem_mm_bus_wr(v_offset + 7, 0, mm_clk, reg_bg_ctrl_copi); -- high part + -- Enable the BG at st_pps pulse. + proc_mem_mm_bus_wr(v_offset + 0, 3, mm_clk, reg_bg_ctrl_copi); + END LOOP; + proc_common_wait_some_cycles(mm_clk, 10); + -- Issue an st_pps pulse to start the enabled BG + proc_common_gen_pulse(st_clk, st_pps); + + -- Run test + proc_common_wait_some_cycles(st_clk, c_run_time); + + -- Disable the BG + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + v_offset := I * c_diag_bg_reg_adr_span; + -- Disable the other BG + proc_mem_mm_bus_wr(v_offset + 0, 0, mm_clk, reg_bg_ctrl_copi); + END LOOP; + + -- Wait until Tx FIFOs have emptied for all streams + WHILE UNSIGNED(tx_fifo_rd_emp_arr(g_nof_streams-1 DOWNTO 0)) /= 2**g_nof_streams - 1 LOOP + proc_common_wait_some_cycles(st_clk, 1); + END LOOP; + proc_common_wait_some_cycles(st_clk, c_bg_sync_period_max); + stimuli_end <= '1'; + + -- Delay logging between different tb instances + proc_common_wait_some_cycles(st_clk, g_tb_index * 100); + + -- Print logging + print_str(""); -- log empty line between tb results + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + IF I = 0 THEN + print_str(c_tb_str & + "ETH bit rate (" & NATURAL'IMAGE(I) & ") :" & + " c_bg_nof_bps_first = " & REAL'IMAGE(c_bg_nof_bps_first) & " bps"); + ELSE + print_str(c_tb_str & + "ETH bit rate (" & NATURAL'IMAGE(I) & ") :" & + " c_bg_nof_bps_others = " & REAL'IMAGE(c_bg_nof_bps_others) & " bps"); + END IF; + END LOOP; + IF g_nof_streams > 1 THEN + print_str(c_tb_str & + "ETH bit rate total :" & + " c_bg_nof_bps_total = " & REAL'IMAGE(c_bg_nof_bps_total) & " bps"); + END IF; + ASSERT c_bg_nof_bps_total < 10.0**9 REPORT "Tx flow control will keep ETH bitrate < 1Gbps." SEVERITY NOTE; + + ------------------------------------------------------------------------- + -- Verification: Total counts + ------------------------------------------------------------------------- + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + -- . read low part, ignore high part (= 0) of two word total counts + v_offset := I * c_dp_strobe_total_count_reg_adr_span; + -- Tx total nof packets + proc_mem_mm_bus_rd(v_offset + 0, mm_clk, reg_strobe_total_count_tx_cipo, reg_strobe_total_count_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_total_count_nof_packet_arr(I) <= TO_UINT(reg_strobe_total_count_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- Rx total nof packets + proc_mem_mm_bus_rd(v_offset + 0, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_packet_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- Rx total nof valids + proc_mem_mm_bus_rd(v_offset + 2, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_valid_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- Rx total nof corrupted + proc_mem_mm_bus_rd(v_offset + 4, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_corrupted_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(mm_clk, 1); + + -- Print logging + print_str(c_tb_str & + "Tx total counts monitor(" & NATURAL'IMAGE(I) & ") :" & + " nof_packet = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I))); + + print_str(c_tb_str & + "Rx total counts monitor(" & NATURAL'IMAGE(I) & ") :" & + " nof_packet = " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) & + ", nof_valid = " & NATURAL'IMAGE(rx_total_count_nof_valid_arr(I)) & + ", nof_corrupted = " & NATURAL'IMAGE(rx_total_count_nof_corrupted_arr(I))); + + -- Verify, only log when wrong + IF g_corrupted_en = FALSE THEN + IF c_bg_nof_bps_total < 10.0**9 THEN + ASSERT tx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) REPORT c_tb_str & + "Wrong Tx total nof packets count(" & NATURAL'IMAGE(I) & + "), Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) & + " /= " & NATURAL'IMAGE(exp_total_count_nof_packet_arr(I)) & + " = Expected count" SEVERITY ERROR; + + ASSERT rx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) REPORT c_tb_str & + "Wrong Rx total nof packets count(" & NATURAL'IMAGE(I) & + "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) & + " /= " & NATURAL'IMAGE(exp_total_count_nof_packet_arr(I)) & + " = Expected count" SEVERITY ERROR; + + ASSERT rx_total_count_nof_valid_arr(I) = rx_exp_total_count_nof_valid_arr(I) REPORT c_tb_str & + "Wrong Rx total nof valids count(" & NATURAL'IMAGE(I) & + "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_valid_arr(I)) & + " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_valid_arr(I)) & + " = Expected count" SEVERITY ERROR; + + ASSERT rx_total_count_nof_corrupted_arr(I) = rx_exp_total_count_nof_corrupted_arr(I) REPORT c_tb_str & + "Wrong Rx total nof corrupted count(" & NATURAL'IMAGE(I) & + "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_corrupted_arr(I)) & + " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_corrupted_arr(I)) & + " = Expected count" SEVERITY ERROR; + ELSE + -- Verify that Tx total nof packets = Rx total nof packets, also when + -- BG experiences siso.xon block level flow control, to stay below + -- 1 Gbps of the 1GbE link rate. + ASSERT tx_total_count_nof_packet_arr(I) = rx_total_count_nof_packet_arr(I) REPORT c_tb_str & + "Wrong Tx-Rx total nof packets count(" & NATURAL'IMAGE(I) & + "), Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) & + " /= " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) & + " = Rx count" SEVERITY ERROR; + END IF; + ELSE + -- g_corrupted_en = TRUE + ASSERT rx_total_count_nof_corrupted_arr(I) = rx_exp_total_count_nof_corrupted_arr(I) REPORT c_tb_str & + "Wrong Rx total nof corrupted count(" & NATURAL'IMAGE(I) & + "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_corrupted_arr(I)) & + " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_corrupted_arr(I)) & + " = Expected count" SEVERITY ERROR; + END IF; + END LOOP; + + ------------------------------------------------------------------------- + -- Verification: BSN monitors (yield same values in every sync interval) + ------------------------------------------------------------------------- + FOR I IN g_nof_streams-1 DOWNTO 0 LOOP + v_offset := I * c_dp_bsn_monitor_v2_reg_adr_span; + -- 3 = nof_sop + -- 4 = nof_valid + -- 6 = latency + -- . Tx + proc_mem_mm_bus_rd(v_offset + 3, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_sop_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(v_offset + 4, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_valid_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(v_offset + 6, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_latency_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- . Rx + proc_mem_mm_bus_rd(v_offset + 3, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_nof_sop_arr(I) <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(v_offset + 4, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_nof_valid_arr(I) <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(v_offset + 6, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_latency_arr(I) <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(mm_clk, 1); + + -- Print logging + print_str(c_tb_str & + "Tx BSN monitor(" & NATURAL'IMAGE(I) & ") :" & + " nof_sop = " & NATURAL'IMAGE(tx_mon_nof_sop_arr(I)) & + ", nof_valid = " & NATURAL'IMAGE(tx_mon_nof_valid_arr(I)) & + ", latency = " & NATURAL'IMAGE(tx_mon_latency_arr(I))); + + print_str(c_tb_str & + "Rx BSN monitor(" & NATURAL'IMAGE(I) & ") :" & + " nof_sop = " & NATURAL'IMAGE(rx_mon_nof_sop_arr(I)) & + ", nof_valid = " & NATURAL'IMAGE(rx_mon_nof_valid_arr(I)) & + ", latency = " & NATURAL'IMAGE(rx_mon_latency_arr(I))); + + IF c_bg_nof_bps_total < 10.0**9 THEN + -- Verify BSN monitors only when the BG sync interval is stable, so + -- the ETH data rate < 1 Gbps and no BG block flow control. + -- Verify, only log when wrong + IF I = 0 THEN + ASSERT tx_mon_nof_sop_arr(I) = c_mon_nof_sop_first REPORT c_tb_str & "Wrong tx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT rx_mon_nof_sop_arr(I) = c_mon_nof_sop_first REPORT c_tb_str & "Wrong rx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT tx_mon_nof_valid_arr(I) = c_mon_nof_valid_first_tx REPORT c_tb_str & "Wrong tx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT rx_mon_nof_valid_arr(I) = c_mon_nof_valid_first_rx REPORT c_tb_str & "Wrong rx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ELSE + ASSERT tx_mon_nof_sop_arr(I) = c_mon_nof_sop_others REPORT c_tb_str & "Wrong tx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT rx_mon_nof_sop_arr(I) = c_mon_nof_sop_others REPORT c_tb_str & "Wrong rx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT tx_mon_nof_valid_arr(I) = c_mon_nof_valid_others_tx REPORT c_tb_str & "Wrong tx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + ASSERT rx_mon_nof_valid_arr(I) = c_mon_nof_valid_others_rx REPORT c_tb_str & "Wrong rx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + END IF; + ASSERT tx_mon_latency_arr(I) = c_tx_exp_latency REPORT c_tb_str & "Wrong tx latency for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + + -- For short block lengths the Rx latency appears to become less, the + -- exact Rx latency is therefore hard to predetermine. The actual + -- latency is not critical, therefore it is sufficient to only very + -- the latency when it is more or less fixed. + IF c_rx_exp_latency_en THEN + -- The rx_exp_latency is fixed when: + -- . g_loopback_eth = FALSE: the streams operate in parallel. + -- . g_loopback_eth = TRUE and g_nof_streams = 1, because for + -- g_nof_streams > 1 the streams are multiplexed, so then the Rx + -- latency will vary. + IF g_loopback_eth = TRUE THEN + IF g_nof_streams = 1 THEN + IF g_eth_sim_level = 0 THEN + ASSERT almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_tech_tse, 10) REPORT + c_tb_str & "Wrong rx latency using tech_tse interface" SEVERITY ERROR; + ELSIF g_eth_sim_level = 1 THEN + ASSERT almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_sim_tse, 10) REPORT + c_tb_str & "Wrong rx latency using sim_tse interface" SEVERITY ERROR; + END IF; + END IF; + ELSE + ASSERT almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_st, 0) REPORT + c_tb_str & "Wrong rx latency using st interface (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR; + END IF; + END IF; + END IF; + END LOOP; + + ------------------------------------------------------------------------- + -- End of test + ------------------------------------------------------------------------- + proc_common_wait_some_cycles(mm_clk, 100); + i_tb_end <= '1'; + WAIT; + END PROCESS; + + dut : ENTITY work.eth_tester + GENERIC MAP ( + g_nof_streams => g_nof_streams, + g_remove_crc => g_loopback_eth -- remove CRC inserted by TSE (sim or tech) + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + st_pps => st_pps, + + -- UDP transmit interface + eth_src_mac => c_gn_eth_src_mac, + ip_src_addr => c_gn_ip_src_addr, + udp_src_port => c_gn_udp_src_port, + + tx_fifo_rd_emp_arr => tx_fifo_rd_emp_arr, + + tx_udp_sosi_arr => tx_udp_sosi_arr, + tx_udp_siso_arr => tx_udp_siso_arr, + + -- UDP receive interface + rx_udp_sosi_arr => rx_udp_sosi_arr, + + -- Memory Mapped Slaves (one per stream) + -- . Tx + reg_bg_ctrl_copi => reg_bg_ctrl_copi, + reg_bg_ctrl_cipo => reg_bg_ctrl_cipo, + reg_hdr_dat_copi => reg_hdr_dat_copi, + reg_hdr_dat_cipo => reg_hdr_dat_cipo, + reg_bsn_monitor_v2_tx_copi => reg_bsn_monitor_v2_tx_copi, + reg_bsn_monitor_v2_tx_cipo => reg_bsn_monitor_v2_tx_cipo, + reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi, + reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo, + -- . Rx + reg_bsn_monitor_v2_rx_copi => reg_bsn_monitor_v2_rx_copi, + reg_bsn_monitor_v2_rx_cipo => reg_bsn_monitor_v2_rx_cipo, + reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi, + reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo + ); + + -- Wire Tx to Rx + gen_loopback_st : IF g_loopback_eth = FALSE GENERATE + -- Loop back at streaming sosi level + + rx_udp_sosi_arr <= tx_udp_sosi_arr; + tse_init <= '0'; + END GENERATE; + + gen_loopback_eth : IF g_loopback_eth = TRUE GENERATE + -- Loop back at ethernet 1Gbps line level + + eth_tx_udp_sosi_arr(g_nof_streams-1 DOWNTO 0) <= tx_udp_sosi_arr; + tx_udp_siso_arr <= eth_tx_udp_siso_arr(g_nof_streams-1 DOWNTO 0); + + rx_udp_sosi_arr <= eth_rx_udp_sosi_arr(g_nof_streams-1 DOWNTO 0); + eth_rx_udp_siso_arr(g_nof_streams-1 DOWNTO 0) <= (OTHERS => c_dp_siso_rdy); + + -- Copied from tb_tech_tse.vhd + use_sim_tse : IF g_eth_sim_level > 0 GENERATE + eth_rxp <= eth_txp; + tse_init <= '0'; + END GENERATE; + use_tech_tse : IF g_eth_sim_level = 0 GENERATE + p_eth_link : PROCESS(eth_txp) + BEGIN + eth_rxp <= TRANSPORT eth_txp AFTER 12 ns; -- apply cable delay + eth_corrupt <= '0'; + + -- Optionally force eth_rxp low to cause a CRC error + IF g_corrupted_en = TRUE THEN + -- Use long BG block_len to easy timing of eth_corrupt during a + -- payload. Not during header to avoid lost packet and not + -- during idle to have no effect. E.g. g_bg_ctrl_first = + -- ('1', '1', 1000, 1, 200, 0, c_diag_bg_mem_max_adr, 0) + IF (NOW > 30000 ns) AND (NOW <= 30000 ns + eth_clk_period * 2) THEN + eth_corrupt <= '1'; + eth_rxp <= '0'; + END IF; + END IF; + END PROCESS; + + p_tech_tse_setup : PROCESS + -- When c_promis_en = FALSE then only accept broadcast and packets with + -- dst_mac for this src_mac, else accept packets for any dst MAC + -- Therefore when c_promis_en = FALSE the TSE c_src_mac must be equal + -- to the Tx packet dst_mac to be able to receive the Tx packets via + -- the tx-rx loopback. + CONSTANT c_promis_en : BOOLEAN := FALSE; + CONSTANT c_src_mac : STD_LOGIC_VECTOR(47 DOWNTO 0) := sel_a_b(c_promis_en, c_gn_eth_src_mac, c_eth_tester_eth_dst_mac); + BEGIN + tse_init <= '1'; + tse_copi.wr <= '0'; + tse_copi.rd <= '0'; + + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + + proc_tech_tse_setup(c_tech_select_default, + c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tech_tse_tx_ready_latency, + c_src_mac, tse_psc_access, + mm_clk, tse_cipo, tse_copi); + tse_init <= '0'; + WAIT; + END PROCESS; + END GENERATE; + + -- ETH module, see [1] + u_eth : ENTITY work.eth + GENERIC MAP ( + g_init_ip_address => X"0A630000", + g_cross_clock_domain => TRUE, + g_sim => TRUE, + g_sim_level => g_eth_sim_level + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + eth_clk => eth_clk, -- ethernet phy reference clock + st_rst => st_rst, + st_clk => st_clk, + + -- UDP transmit interface + udp_tx_snk_in_arr => eth_tx_udp_sosi_arr, + udp_tx_snk_out_arr => eth_tx_udp_siso_arr, + -- UDP receive interface + udp_rx_src_in_arr => eth_rx_udp_siso_arr, + udp_rx_src_out_arr => eth_rx_udp_sosi_arr, + + -- Memory Mapped Slaves + tse_sla_in => tse_copi, -- ETH TSE MAC registers + tse_sla_out => tse_cipo, + reg_sla_in => reg_eth_copi, -- ETH control and status registers + reg_sla_out => reg_eth_cipo, + reg_sla_interrupt => OPEN, -- Interrupt + ram_sla_in => c_mem_copi_rst, -- ETH rx frame and tx frame memory + ram_sla_out => OPEN, + + -- PHY interface + eth_txp => eth_txp, + eth_rxp => eth_rxp + ); + END GENERATE; +END tb; diff --git a/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd b/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e0fd29ce23adf74df9ea0ccd9ef1bad4eb36e924 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd @@ -0,0 +1,88 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: This package contains eth_tester specific constants and functions +-- for use in a test bench +-- Description: See [1] +-- References: +-- . [1] https://support.astron.nl/confluence/display/L2M/L3+SDP+Decision%3A+SDP+Parameter+definitions +-- +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE work.eth_tester_pkg.ALL; + +PACKAGE tb_eth_tester_pkg is + + CONSTANT c_eth_tester_eth_dst_mac : STD_LOGIC_VECTOR(47 DOWNTO 0) := x"001B217176B9"; -- 001B217176B9 = DOP36-enp2s0 + CONSTANT c_eth_tester_ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"0A6300FE"; -- 0A6300FE = '10.99.0.254' = DOP36-enp2s0 + CONSTANT c_eth_tester_udp_dst_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(6001, 16); -- 0x1771 = 6001 + + -- Map global node index on UniBoard2 to node MAC address and node IP address + FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR; + FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR; + + -- Ethernet packet length in octets inclduing eth header and CRC + FUNCTION func_eth_tester_eth_packet_length(block_len : NATURAL) RETURN NATURAL; + + -- Ethernet packet lenght on link including c_network_eth_preamble_len and one idle word + FUNCTION func_eth_tester_eth_packet_on_link_length(block_len : NATURAL) RETURN NATURAL; + +END tb_eth_tester_pkg; + + +PACKAGE BODY tb_eth_tester_pkg IS + + FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS + CONSTANT c_unb_nr : NATURAL := gn_index / 4; -- 4 PN per Uniboard2 + CONSTANT c_node_nr : NATURAL := gn_index MOD 4; + CONSTANT c_mac_15_0 : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr, 8); + BEGIN + RETURN c_mac_15_0; + END func_eth_tester_gn_index_to_mac_15_0; + + FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS + CONSTANT c_unb_nr : NATURAL := gn_index / 4; -- 4 PN per Uniboard2 + CONSTANT c_node_nr : NATURAL := gn_index MOD 4; + CONSTANT c_ip_15_0 : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr+1, 8); -- +1 to avoid IP = *.*.*.0 + BEGIN + RETURN c_ip_15_0; + END func_eth_tester_gn_index_to_ip_15_0; + + FUNCTION func_eth_tester_eth_packet_length(block_len : NATURAL) RETURN NATURAL IS + CONSTANT c_app_len : NATURAL := c_eth_tester_app_hdr_len + block_len; + CONSTANT c_udp_len : NATURAL := c_network_udp_header_len + c_app_len; + CONSTANT c_ip_len : NATURAL := c_network_ip_header_len + c_udp_len; + CONSTANT c_eth_len : NATURAL := c_network_eth_header_len + c_ip_len + c_network_eth_crc_len; + BEGIN + RETURN c_eth_len; + END func_eth_tester_eth_packet_length; + + FUNCTION func_eth_tester_eth_packet_on_link_length(block_len : NATURAL) RETURN NATURAL IS + BEGIN + RETURN c_network_eth_preamble_len + func_eth_tester_eth_packet_length(block_len) + c_word_sz; + END func_eth_tester_eth_packet_on_link_length; + +END tb_eth_tester_pkg; + diff --git a/libraries/io/eth/tb/vhdl/tb_tb_eth_tester.vhd b/libraries/io/eth/tb/vhdl/tb_tb_eth_tester.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f4c8b3b8b12cdfc551dbd6b0a2a2e3db042afab5 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_tb_eth_tester.vhd @@ -0,0 +1,231 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Multi test bench for eth_tester +-- Description: See detailed design in [1] +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE +-- [2] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Application+header+size+in+Ethernet+packets +-- +-- Usage: +-- > as 8 +-- > run -all +-- Takes about 25 m + +LIBRARY IEEE, diag_lib; +USE IEEE.std_logic_1164.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.tb_eth_tester_pkg.ALL; + +ENTITY tb_tb_eth_tester IS +END tb_tb_eth_tester; + +ARCHITECTURE tb OF tb_tb_eth_tester IS + + -- Multi tb + CONSTANT c_tb_w : NATURAL := 100; -- sufficiently long to fit all tb instances + CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(c_tb_w-1 DOWNTO 0) := (OTHERS=>'1'); + + SIGNAL tb_end_vec : STD_LOGIC_VECTOR(c_tb_w-1 DOWNTO 0) := c_tb_end_vec; -- best view as hex in Wave Window + SIGNAL tb_end : STD_LOGIC := '0'; + + -- Tb + CONSTANT c_eth_clk_MHz : NATURAL := 125; + CONSTANT c_st_clk_MHz : NATURAL := 200; + CONSTANT c_nof_sync : NATURAL := 2; + CONSTANT c_nof_sync_many : NATURAL := 50; -- sufficient to achieve Tx FIFO fill level + CONSTANT c_nof_streams : NATURAL := 3; + CONSTANT c_nof_blk : NATURAL := 3; -- nof_blk per sync + + -- Tx packet size and gap size in octets + CONSTANT c_block_len : NATURAL := 50; -- BG block length of first stream [0] + CONSTANT c_block_len_odd : NATURAL := 51; + CONSTANT c_block_len_jumbo : NATURAL := 9000; + CONSTANT c_link_len : NATURAL := func_eth_tester_eth_packet_on_link_length(c_block_len); + + -- For near maximum 1Gbps link rate the c_block_len + c_gap_len_min time + -- in the st_clk domain equals c_link_len time in eth_clk domain. + CONSTANT c_gap_len_min : NATURAL := c_link_len * c_st_clk_MHz / c_eth_clk_MHz - c_block_len; + CONSTANT c_slot_len_min : NATURAL := c_block_len + c_gap_len_min; + + -- Choose c_gap_len somewhat larger to have packet link rate < 1 Gbps + CONSTANT c_gap_len : NATURAL := c_gap_len_min * 2; -- for g_nof_streams = 1 + CONSTANT c_long_gap : NATURAL := c_gap_len_min * 10; + CONSTANT c_short_gap : NATURAL := 10; -- to cause BG xon/xoff flow control + CONSTANT c_zero_gap : NATURAL := 0; -- to verify BG ready flow control + + -- Choose c_others_len > c_block_len, so same c_gap_len is suitable to + -- keep Ethernet link rate < 1 Gbps + CONSTANT c_others_len : NATURAL := 65; -- BG block length of other streams [c_nof_streams-1 : 1] + + -- BG ctrl + CONSTANT c_high : NATURAL := c_diag_bg_mem_max_adr; -- = 2**24 + + CONSTANT c_bg_ctrl_rst : t_diag_block_gen_integer := ('0', '0', 1, c_nof_blk, c_gap_len, 0, c_high, 0); -- place holder for unused stream + + CONSTANT c_bg_ctrl_one : t_diag_block_gen_integer := ('1', '1', c_block_len, c_nof_blk, c_gap_len, 0, c_high, 0); -- for first stream + CONSTANT c_bg_ctrl_others : t_diag_block_gen_integer := ('1', '1', c_others_len, c_nof_blk, c_gap_len, 0, c_high, 0); -- for other streams + + -- . BG with different block lengths and other payload values + -- The payload values are only verified manually using the Wave Window + CONSTANT c_bg_ctrl_len_0 : t_diag_block_gen_integer := ('1', '1', c_block_len+0, c_nof_blk, c_gap_len, 0, 0, 0); -- nof octets + CONSTANT c_bg_ctrl_len_1 : t_diag_block_gen_integer := ('1', '1', c_block_len+1, c_nof_blk, c_gap_len, 1, 1, 0); -- nof octets + CONSTANT c_bg_ctrl_len_2 : t_diag_block_gen_integer := ('1', '1', c_block_len+2, c_nof_blk, c_gap_len, 1, 7, 0); -- nof octets + CONSTANT c_bg_ctrl_len_3 : t_diag_block_gen_integer := ('1', '1', c_block_len+3, c_nof_blk, c_gap_len, c_high-1, c_high-1, 0); -- nof octets + + CONSTANT c_bg_ctrl_corrupted : t_diag_block_gen_integer := ('1', '1', 1000, 1, 200, 0, c_high, 0); + + CONSTANT c_bg_ctrl_multiple_first : t_diag_block_gen_integer := ('1', '1', c_block_len, c_nof_blk, c_nof_streams * c_gap_len, 0, c_high, 0); -- for first stream + CONSTANT c_bg_ctrl_multiple_others : t_diag_block_gen_integer := ('1', '1', c_others_len, c_nof_blk, c_nof_streams * c_gap_len, 0, c_high, 0); -- for other streams + +BEGIN + +-- g_tb_index : NATURAL := 0; -- use to incremental delay logging from tb instances in tb_tb +-- g_nof_sync : NATURAL := 3; -- number of BG sync intervals to set c_run_time +-- g_nof_streams : NATURAL := 2; +-- g_loopback_eth : BOOLEAN := FALSE; -- FALSE = sosi loopback, TRUE = eth loopback +-- g_eth_sim_level : NATURAL := 0; -- when g_loopback_eth = TRUE, then 0 = use IP; 1 = use fast serdes model +-- g_corrupted_en : BOOLEAN := FALSE; -- when TRUE cause a corrupted Rx packet +-- +-- -- t_diag_block_gen_integer = +-- -- sl: enable +-- -- sl: enable_sync +-- -- nat: samples_per_packet +-- -- nat: blocks_per_sync +-- -- nat: gapsize +-- -- nat: mem_low_adrs +-- -- nat: mem_high_adrs +-- -- nat: bsn_init +-- g_bg_ctrl_first : t_diag_block_gen_integer := ('1', '1', 50, c_nof_blk, 100, 0, 30, 0); -- for first stream +-- g_bg_ctrl_others : t_diag_block_gen_integer := ('1', '1', 30, c_nof_blk, 10, 0, 30, 0) -- for other streams + + -- Tb instance prefix: + -- . u_st : uses streaming Tx-Rx interface + -- . u_sim : uses sim_tse Tx-Rx interface + -- . u_tech : uses tech_tse Tx-Rx interface + + ----------------------------------------------------------------------------- + -- Single stream + ----------------------------------------------------------------------------- + -- Try different loopback interfaces + u_st : ENTITY work.tb_eth_tester GENERIC MAP (0, c_nof_sync, 1, FALSE, 1, FALSE, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(0)); + u_sim_tse : ENTITY work.tb_eth_tester GENERIC MAP (1, c_nof_sync, 1, TRUE, 1, FALSE, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(1)); + u_tech_tse : ENTITY work.tb_eth_tester GENERIC MAP (2, c_nof_sync, 1, TRUE, 0, FALSE, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(2)); + + -- Try large block size and nof blocks_per_sync = 1 + u_st_jumbo1 : ENTITY work.tb_eth_tester GENERIC MAP (10, c_nof_sync, 1, FALSE, 1, FALSE, + ('1', '1', c_block_len_jumbo, 1, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(10)); + + -- Try large block sizes + u_st_jumbo2 : ENTITY work.tb_eth_tester GENERIC MAP (11, c_nof_sync, 1, FALSE, 1, FALSE, + ('1', '1', c_block_len_jumbo, 2, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(11)); + + u_sim_tse_jumbo : ENTITY work.tb_eth_tester GENERIC MAP (12, c_nof_sync, 1, TRUE, 1, FALSE, + ('1', '1', c_block_len_jumbo, 2, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(12)); + + u_tech_tse_jumbo : ENTITY work.tb_eth_tester GENERIC MAP (13, c_nof_sync, 1, TRUE, 0, FALSE, + ('1', '1', c_block_len_jumbo, 2, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(13)); + + -- Try small block sizes + -- . BG supports samples_per_packet >= 2, BG treats samples_per_packet = 1 as 2 + -- . ETH MAC pads samples_per_packet <= 6 to 6, to have minimum packet length of 64 octets, + -- because hdr = 14 + 20 + 8 + 12 and crc = 4 have 58 octets. + u_st_len2 : ENTITY work.tb_eth_tester GENERIC MAP (20, c_nof_sync, 1, FALSE, 1, FALSE, + ('1', '1', 2, c_nof_blk, c_gap_len, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(20)); + u_sim_tse_len2 : ENTITY work.tb_eth_tester GENERIC MAP (21, c_nof_sync, 1, TRUE, 1, FALSE, + ('1', '1', 2, c_nof_blk, c_gap_len, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(21)); + u_tech_tse_len6 : ENTITY work.tb_eth_tester GENERIC MAP (22, c_nof_sync, 1, TRUE, 0, FALSE, + ('1', '1', 6, c_nof_blk, c_gap_len, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(22)); + + -- Try different BG block lengths to verify sosi.empty nof octets in last word + u_st_bg_len_0 : ENTITY work.tb_eth_tester GENERIC MAP (30, c_nof_sync, 1, FALSE, 1, FALSE, c_bg_ctrl_len_0, c_bg_ctrl_rst) PORT MAP (tb_end_vec(30)); + u_st_bg_len_1 : ENTITY work.tb_eth_tester GENERIC MAP (31, c_nof_sync, 1, FALSE, 1, FALSE, c_bg_ctrl_len_1, c_bg_ctrl_rst) PORT MAP (tb_end_vec(31)); + u_st_bg_len_2 : ENTITY work.tb_eth_tester GENERIC MAP (32, c_nof_sync, 1, FALSE, 1, FALSE, c_bg_ctrl_len_2, c_bg_ctrl_rst) PORT MAP (tb_end_vec(32)); + u_st_bg_len_3 : ENTITY work.tb_eth_tester GENERIC MAP (33, c_nof_sync, 1, FALSE, 1, FALSE, c_bg_ctrl_len_3, c_bg_ctrl_rst) PORT MAP (tb_end_vec(33)); + + -- Try BG xon/xoff block flow control by using smaller gapsize that would + -- exceed 1 Gbps. Use c_nof_sync_many to fill Tx FIFO. Use tse because + -- tse is limited to 1 Gbps, the st interface can achieve > 1 Gbps. + -- Try BG ready clock flow control by using c_block_len_odd to have BG + -- sosi.empy /= 0 and use zero gapsize to have BG blocks directly after + -- each other. + u_sim_tse_bg_flow_control : ENTITY work.tb_eth_tester + GENERIC MAP (40, c_nof_sync_many, 1, TRUE, 1, FALSE, + ('1', '1', c_block_len_odd, c_nof_blk, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(40)); + + u_tech_tse_bg_flow_control : ENTITY work.tb_eth_tester + GENERIC MAP (41, c_nof_sync_many, 1, TRUE, 0, FALSE, + ('1', '1', c_block_len_odd, c_nof_blk, c_zero_gap, 0, c_high, 0), + c_bg_ctrl_rst) + PORT MAP (tb_end_vec(41)); + + -- Try corrupted packet + u_tech_tse_corrupted : ENTITY work.tb_eth_tester GENERIC MAP (50, c_nof_sync, 1, TRUE, 0, TRUE, c_bg_ctrl_corrupted, c_bg_ctrl_rst) PORT MAP (tb_end_vec(50)); + + ----------------------------------------------------------------------------- + -- Multiple streams + ----------------------------------------------------------------------------- + u_st_multiple_streams : ENTITY work.tb_eth_tester + GENERIC MAP (80, c_nof_sync, c_nof_streams, FALSE, 1, FALSE, + c_bg_ctrl_multiple_first, + c_bg_ctrl_multiple_others) + PORT MAP (tb_end_vec(80)); + + -- Use tse to verify dp_mux and dp_demux in ETH module [1] + u_sim_tse_multiple_streams : ENTITY work.tb_eth_tester + GENERIC MAP (81, c_nof_sync, c_nof_streams, TRUE, 1, FALSE, + c_bg_ctrl_multiple_first, + c_bg_ctrl_multiple_others) + PORT MAP (tb_end_vec(81)); + + u_sim_tse_multiple_bg_flow_control : ENTITY work.tb_eth_tester + GENERIC MAP (82, c_nof_sync_many, c_nof_streams, TRUE, 1, FALSE, + ('1', '1', c_block_len, c_nof_blk, c_short_gap, 0, c_high, 0), + ('1', '1', c_others_len, c_nof_blk, c_short_gap, 0, c_high, 0)) + PORT MAP (tb_end_vec(82)); + + tb_end <= '1' WHEN tb_end_vec = c_tb_end_vec ELSE '0'; + + p_tb_end : PROCESS + BEGIN + WAIT UNTIL tb_end='1'; + WAIT FOR 1 ns; + REPORT "Multi tb simulation finished." SEVERITY FAILURE; + WAIT; + END PROCESS; + +END tb;