-------------------------------------------------------------------------------- -- ifc1210_wrapper testbench -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_textio.all; use ieee.std_logic_1164.all; library std; use std.env.all; use std.textio.all; library tosca2; use tosca2.ifc1210_simu_procedures_pkg.all; library uvvm_util; context uvvm_util.uvvm_util_context; -- Work library (application) -------------------------------------------------- library work; use work.evr320_pkg.all; use work.psi_common_math_pkg.all; entity evr320_ifc1210_wrapper_tb is end entity; architecture testbench of evr320_ifc1210_wrapper_tb is --------------------------------------------------------------------------- -- System --------------------------------------------------------------------------- constant C_RXUSRCLK_CYCLE : time := 7 ns; constant C_USRCLK_CYCLE : time := 8 ns; constant C_EVT_NR : integer := 4; constant C_MEM_DATA_WIDTH : integer := 32; -- 32|64 (64 bit used for tosca2 on ifc1210) constant C_EVENT_RECORDER : boolean := true; constant C_EVENT_REC_FLAGS : std_logic_vector(11 downto 6) := B"1101_11"; constant g_EVENT_NR_SOS : integer range 0 to 255 := 16#20#; constant g_EVENT_NR_0 : integer range 0 to 255 := 16#00#; constant g_EVENT_NR_1 : integer range 0 to 255 := 16#04#; constant g_EVENT_NR_2 : integer range 0 to 255 := 16#00#; constant g_EVENT_NR_3 : integer range 0 to 255 := 16#00#; --------------------------------------------------------------------------- -- MGT stream --------------------------------------------------------------------------- type mgt_stream_sample_type is record data : std_logic_vector(7 downto 0); data_k : std_logic_vector(0 downto 0); event : std_logic_vector(7 downto 0); event_k : std_logic_vector(0 downto 0); end record mgt_stream_sample_type; type mgt_stream_type is array (natural range <>) of mgt_stream_sample_type; signal mgt_stream_index : integer range 0 to 511 := 0; signal mgt_stream : mgt_stream_type(511 downto 0) := (others => (others => (others => '0'))); ----------------------------------------------------------------------------- -- Timing decoder interface ----------------------------------------------------------------------------- signal usr_clk : std_logic := '0'; signal evr_params : typ_evr320_params; signal mem_addr : std_logic_vector(11 downto 0) := (others => '0'); signal mem_data : std_logic_vector(31 downto 0) := (others => '0'); -- Decoder stream type dec_stream_type is record data : std_logic_vector(7 downto 0); addr : std_logic_vector(10 downto 0); end record dec_stream_type; type dec_stream_check_arr is array (natural range <>) of dec_stream_type; signal dec_stream_data : std_logic_vector(7 downto 0) := (others => '0'); signal dec_stream_addr : std_logic_vector(10 downto 0) := (others => '0'); signal dec_stream_valid : std_logic; signal dec_stream_check : dec_stream_check_arr(0 to 2047); signal dec_stream_recv_bytes : integer range 0 to 2047; type segment_data_arr is array (natural range <>) of std_logic_vector(7 downto 0); signal segment_addr : std_logic_vector(7 downto 0); signal segment_data : segment_data_arr(0 to 2047); signal segment_length : natural range 0 to 2047; constant FILTER_ADDRESS : std_logic_vector(11 downto 0) := x"028"; constant FILTER_NUM_BYTES : integer := 8; constant STIMULI_RUNS : integer := 2; signal filter_data, filter_data_check : std_logic_vector(63 downto 0) := (others => '0'); signal filter_valid : std_logic := '0'; signal tmem_i : tmem_bus_in_t; signal tmem_o : tmem_bus_out_t; signal tmem_clk : std_logic; signal tmem_rst : std_logic; signal tmem_data_rd : std_logic_vector(63 downto 0); signal tick1sec : std_logic; alias rxlos is <>; alias clk_evr is <>; alias rxdata is <>; alias rxcharisk is <>; alias sos_event is <>; alias usr_events is <>; alias evr_stable is <>; --*** stimuli for delay & pulse width *** signal usr_event_width_sti : typ_arr_width := (to_uslv(2, log2ceil(MaxDuration_c)), --sos set to 2 to_uslv(3, log2ceil(MaxDuration_c)), --0 to_uslv(4, log2ceil(MaxDuration_c)), --1 to_uslv(5, log2ceil(MaxDuration_c)), --2 to_uslv(6, log2ceil(MaxDuration_c)) --3 ); signal usr_event_delay_sti : typ_arr_delay := (to_uslv(2, log2ceil(MaxDelay_c)), --sos set to 2 to_uslv(3, log2ceil(MaxDelay_c)), --0 to_uslv(4, log2ceil(MaxDelay_c)), --1 to_uslv(5, log2ceil(MaxDelay_c)), --2 to_uslv(6, log2ceil(MaxDelay_c)) --3 ); begin tmem_o.TMEM_BUSY_o <= '0'; tmem_o.TMEM_PIPE_o <= "10"; ----------------------------------------------------------------------------- -- Timing decoder ----------------------------------------------------------------------------- evr320_ifc1210_wrapper_inst : entity work.evr320_ifc1210_wrapper generic map( g_MGT_LOCATION => "GTXE1_X0Y16", -- "GTXE1_X0Y0" to "GTXE1_X0Y11" | "GTXE1_X0Y16" to "GTXE1_X0Y19" g_FACILITY => "SFEL", -- "HIPA" | "SFEL" g_EVENT_RECORDER => C_EVENT_RECORDER, -- enable/disable Event Recorder functionality g_XUSER_CLK_FREQ => 125000000 -- Xuser Clk Frequency in Hz ) port map( -------------------------------------------------------------------------- -- Debug interface -------------------------------------------------------------------------- debug_clk => open, debug => open, -------------------------------------------------------------------------- -- TOSCA2 TMEM interface -------------------------------------------------------------------------- xuser_CLK => tmem_clk, xuser_RESET => tmem_rst, xuser_TMEM_ENA => tmem_i.TMEM_ENA_i, xuser_TMEM_WE => tmem_i.TMEM_WE_i, xuser_TMEM_ADD => tmem_i.TMEM_ADD_i(13 downto 3), xuser_TMEM_DATW => tmem_i.TMEM_DATW_i, xuser_TMEM_DATR => tmem_o.TMEM_DATR_o, -- ------------------------------------------------------------------------ -- MGT Interface -- ------------------------------------------------------------------------ mgt_refclk_i => '0', mgt_sfp_los_i => '0', mgt_rx_n => '0', mgt_rx_p => '0', mgt_tx_n => open, mgt_tx_p => open, mgt_status_o => open, mgt_control_i => (others => '0'), --------------------------------------------------------------------------- -- User interface MGT clock --------------------------------------------------------------------------- clk_evr_o => open, usr_events_o => open, sos_event_o => open, usr_events_adj_o => open, sos_events_adj_o => open, -------------------------------------------------------------------------- -- Decoder axi stream interface, User clock -------------------------------------------------------------------------- stream_clk_i => '1', stream_data_o => open, stream_addr_o => open, stream_valid_o => open ); gen_pulse(tick1sec, '1', usr_clk, 1, ""); ----------------------------------------------------------------------------- -- MGT / User clock ----------------------------------------------------------------------------- clock_generator(usr_clk, C_USRCLK_CYCLE); tmem_clk <= usr_clk; -- Simulate MGT Clock mgt_clk_proc : process begin clk_evr <= force in '0'; loop wait for C_RXUSRCLK_CYCLE / 2; clk_evr <= force in not (clk_evr); end loop; end process; ----------------------------------------------------------------------------- -- Decoder reset due to MGT main status ----------------------------------------------------------------------------- process begin rxlos <= force in '1'; tmem_rst <= '1'; wait for 50 ns; wait until (falling_edge(clk_evr)); rxlos <= force in '0'; tmem_rst <= '0'; wait; end process; ----------------------------------------------------------------------------- -- Read stimuli file ----------------------------------------------------------------------------- file_blk : block file file_stimuli : text; type parse_fsm_state is (idle, seg_start, seg_addr, seg_Wait, seg_payload, seg_payload_wait, seg_done); begin process variable file_line : line; variable data, event : std_logic_vector(7 downto 0); variable data_k, event_k : std_logic_vector(0 downto 0); variable space : character; variable i : integer; variable parse_fsm : parse_fsm_state := idle; variable payload_cnt : integer range 0 to 2047; variable event_cnt_total : integer := 0; variable event_cnt_0 : integer := 0; variable event_cnt_1 : integer := 0; variable event_cnt_2 : integer := 0; variable event_cnt_3 : integer := 0; variable event_cnt_user : integer := 0; begin file_open(file_stimuli, "../tb/stimuli_mgt.dat", read_mode); readline(file_stimuli, file_line); -- comment readline(file_stimuli, file_line); -- comment i := 0; -- read line by line from .dat file: while not endfile(file_stimuli) loop readline(file_stimuli, file_line); hread(file_line, event); read(file_line, event_k); read(file_line, space); read(file_line, space); hread(file_line, data); read(file_line, space); read(file_line, data_k); -- write to array: mgt_stream(i).data <= data; mgt_stream(i).data_k <= data_k; mgt_stream(i).event <= event; mgt_stream(i).event_k <= event_k; mgt_stream_index <= i; --debug output: --log(ID_SEGMENT_DATA, "stimuli file: i=" & integer'image(i) & " event=0x" & to_string(event, HEX) & " k=" & to_string(event_k, HEX) -- & " data=0x" & to_string(data, HEX) & " k=" & to_string(data_k, HEX) & " "); -- Parse only segment: ---------------------- case (parse_fsm) is when idle => if (data = x"5C" and data_k = "1") then -- check if frame start parse_fsm := seg_start; end if; when seg_start => parse_fsm := seg_addr; when seg_addr => segment_addr <= data; parse_fsm := seg_wait; when seg_wait => parse_fsm := seg_payload; payload_cnt := 0; when seg_payload => if (data = x"3C" and data_k = "1") then -- check if frame end parse_fsm := seg_done; else segment_data(payload_cnt) <= data; parse_fsm := seg_payload_wait; segment_length <= payload_cnt + 1; end if; when seg_payload_wait => payload_cnt := payload_cnt + 1; parse_fsm := seg_payload; when seg_done => -- done end case; i := i + 1; end loop; file_close(file_stimuli); wait; end process; end block; --------------------------------------------------------- -- Wait for Start of Sequence Event --------------------------------------------------------- process begin wait until rising_edge(sos_event); log(ID_CTRL, "Start of Sequence Event Received: " & to_string(std_logic_vector(to_unsigned(g_EVENT_NR_SOS, 8)), HEX, AS_IS, INCL_RADIX)); -- change to await_value end process; -------------------------------------------------------------------------- -- Stimuli MGT -------------------------------------------------------------------------- process begin wait until rising_edge(clk_evr); for b in 0 to STIMULI_RUNS - 1 loop log(ID_LOG_HDR, "Send stimuli stream to MGT - RUN " & to_string(b + 1)); for idx in 0 to mgt_stream_index loop --log(ID_FRAME_DATA, to_string(mgt_stream(idx).data, HEX), to_string(mgt_stream(idx).event, HEX)); wait until rising_edge(clk_evr); rxdata <= force out mgt_stream(idx).data & mgt_stream(idx).event; rxcharisk <= force out mgt_stream(idx).data_k & mgt_stream(idx).event_k; end loop; wait for 3 us; end loop; wait; end process; ----------------------------------------------------------------------------- -- Main Process ----------------------------------------------------------------------------- process constant C_SCOPE : string := C_TB_SCOPE_DEFAULT; constant c_TB_NAME : string := "evr320_decoder_tb"; variable latency_cnt_val : unsigned(31 downto 0); begin disable_log_msg(ID_GEN_PULSE); -------------------------------------------------------------------------- log(ID_LOG_HDR, "Start Simulation of evr320 decoder", C_SCOPE); -------------------------------------------------------------------------- -------------------------------------------------------------------------- -- Get out of reset, enable events -------------------------------------------------------------------------- evr_params.event_enable(0) <= '0' when g_EVENT_NR_0 = 0 else '1'; evr_params.event_enable(1) <= '0' when g_EVENT_NR_1 = 0 else '1'; evr_params.event_enable(2) <= '0' when g_EVENT_NR_2 = 0 else '1'; evr_params.event_enable(3) <= '0' when g_EVENT_NR_3 = 0 else '1'; evr_params.event_numbers(0) <= std_logic_vector(to_unsigned(g_EVENT_NR_0, 8)); evr_params.event_numbers(1) <= std_logic_vector(to_unsigned(g_EVENT_NR_1, 8)); evr_params.event_numbers(2) <= std_logic_vector(to_unsigned(g_EVENT_NR_2, 8)); evr_params.event_numbers(3) <= std_logic_vector(to_unsigned(g_EVENT_NR_3, 8)); evr_params.cs_min_cnt <= X"00000000"; evr_params.cs_min_time <= X"00000000"; mem_addr <= x"000"; await_value(rxlos, '0', 0 ns, 10 us, FAILURE, "wait for release RX LOS"); -- overwrite evr_stable flag: evr_stable <= force '1'; -- enable sos event and set event number: TMEM_BUS_WRITE(seqid => "A00_001", tmem_add => x"00_0040", tmem_we => x"0F", tmem_burst => 1, tmem_data_wr => x"0000_0000_0000_2001", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back sos event and event number: TMEM_BUS_READ(seqid => "A00_001", tmem_add => x"00_0040", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- --------------------------------------------------------- -- send delay and width parameters: TMEM_BUS_WRITE(seqid => "A00_002", tmem_add => x"00_0050", tmem_we => x"FF", tmem_burst => 1, tmem_data_wr => x"0005_0004_0003_0002", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back delay parameters: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0050", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; check_value(tmem_data_rd, x"0005_0004_0003_0002", ERROR, "TMEM Write/Read check: EVR Puls delay Event Cfg"); -- --------------------------------------------------------- -- --------------------------------------------------------- -- send width and width parameters: TMEM_BUS_WRITE(seqid => "A00_003", tmem_add => x"00_0058", tmem_we => x"FF", tmem_burst => 1, tmem_data_wr => x"0009_0008_0007_0006", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back delay parameters: TMEM_BUS_READ(seqid => "A00_003", tmem_add => x"00_0058", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; check_value(tmem_data_rd, x"0009_0008_0007_0006", ERROR, "TMEM Write/Read check: EVR Puls Width Event Cfg"); -- --------------------------------------------------------- -- --------------------------------------------------------- -- send width and width parameters for SOS: TMEM_BUS_WRITE(seqid => "A00_004", tmem_add => x"00_0060", tmem_we => x"FF", tmem_burst => 1, tmem_data_wr => x"0000_0000_0001_0001", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back delay parameters: TMEM_BUS_READ(seqid => "A00_004", tmem_add => x"00_0060", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; check_value(tmem_data_rd, x"0000_0000_0001_0001", ERROR, "TMEM Write/Read check: SOS width & delay Event Cfg"); -- --------------------------------------------------------- -- latency measurement: set event nr: TMEM_BUS_WRITE(seqid => "A00_002", tmem_add => x"00_0030", tmem_we => x"0F", tmem_burst => 1, tmem_data_wr => x"0000_0000_0000_0020", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back sos event and event number: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0030", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- latency measurement: set event nr: TMEM_BUS_WRITE(seqid => "A00_002", tmem_add => x"00_0030", tmem_we => x"0F", tmem_burst => 1, tmem_data_wr => x"0000_0000_0000_0020", xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; -- read back sos event and event number: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0030", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; check_value(tmem_data_rd, x"0000_0000_0000_0020", ERROR, "TMEM Write/Read check: lat. meas. event nr"); -- 1. check latency measurement counter: ---------------------------------------- await_value(sos_event, '1', 0 ns, 2 us, ERROR, "wait for sos event"); wait for 2000 ns; latency_cnt_val := x"00000000"; -- read latency measurement counter without rearm: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0030", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; latency_cnt_val := unsigned(tmem_data_rd(63 downto 32)); log(ID_CTRL, "Latency Counter: 0x" & to_string(latency_cnt_val, HEX)); check_value_in_range(latency_cnt_val, x"000000F5", x"000000FE", ERROR, "Latency Counter Value (no-rearm) Check after 2us"); -- 2. read latency measurement counter again with rearm: -------------------------------------------------------- latency_cnt_val := x"00000000"; TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0038", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; latency_cnt_val := unsigned(tmem_data_rd(31 downto 0)); log(ID_CTRL, "Latency Counter: 0x" & to_string(latency_cnt_val, HEX)); check_value_in_range(latency_cnt_val, x"000000FA", x"00000102", ERROR, "Latency Counter Value (rearm) Check directly after first read"); -- read 2. time rearm latency counter which should be cleared now: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0038", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; latency_cnt_val := unsigned(tmem_data_rd(31 downto 0)); check_value(latency_cnt_val, x"00000000", ERROR, "Check if counter is cleared"); -- 4. read latency measurement counter with rearm: -------------------------------------------------- await_value(sos_event, '1', 0 ns, 3 us, ERROR, "wait for sos event"); wait for 1 us; -- read counter and rearm: TMEM_BUS_READ(seqid => "A00_002", tmem_add => x"00_0038", tmem_burst => 1, tmem_data_rd => tmem_data_rd, xuser_clk_i => tmem_clk, xuser_tmem_bus_o => tmem_i, xuser_tmem_bus_i => tmem_o); wait for 20 ns; latency_cnt_val := unsigned(tmem_data_rd(31 downto 0)); log(ID_CTRL, "Latency Counter: 0x" & to_string(latency_cnt_val, HEX)); check_value_in_range(latency_cnt_val, x"0000007A", x"00000080", ERROR, "Latency Counter Value (rearm) Check after 1us"); -------------------------------------------------------------------------- -- Test Done -------------------------------------------------------------------------- wait for 1000 ns; -- to allow some time for completion report_alert_counters(FINAL); -- Report final counters and print conclusion for simulation (Success/Fail) -- ------------------------------------------------------------------------ log(ID_LOG_HDR, "SIMULATION COMPLETED", C_SCOPE); -- ------------------------------------------------------------------------ -- assert error if UVVM mismatch flag is 1 => upstream info for scripts/jenkins assert shared_uvvm_status.mismatch_on_expected_simulation_errors_or_worse = 0 report "###ERROR### - UVVM Mismatch Errors with Expected Errors -> Check Log for details" severity ERROR; std.env.stop(0); wait; -- stop simulation end process; end architecture testbench; -------------------------------------------------------------------------------- -- End of file --------------------------------------------------------------------------------