diff --git a/boards/uniboard1/designs/unb1_bn_capture/hdllib.cfg b/boards/uniboard1/designs/unb1_bn_capture/hdllib.cfg index b6e76a12701cc4c151ad88069b535b236a2d0628..85f3b9dc6dafaa0a574e95c72e1c50432fdbebcf 100644 --- a/boards/uniboard1/designs/unb1_bn_capture/hdllib.cfg +++ b/boards/uniboard1/designs/unb1_bn_capture/hdllib.cfg @@ -11,8 +11,9 @@ synth_files = src/vhdl/unb1_bn_capture.vhd test_bench_files = - tb/vhdl/tb_unb1_bn_capture.vhd + tb/vhdl/tb_unb1_bn_capture_input.vhd tb/vhdl/tb_node_unb1_bn_capture.vhd + #tb/vhdl/tb_unb1_bn_capture.vhd [modelsim_project_file] diff --git a/boards/uniboard1/designs/unb1_bn_capture/tb/vhdl/tb_unb1_bn_capture_input.vhd b/boards/uniboard1/designs/unb1_bn_capture/tb/vhdl/tb_unb1_bn_capture_input.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b6aebeed8a751fa6b6ffad51490fa4a79cf296d1 --- /dev/null +++ b/boards/uniboard1/designs/unb1_bn_capture/tb/vhdl/tb_unb1_bn_capture_input.vhd @@ -0,0 +1,616 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: +-- Test bench for unb1_bn_capture_input +-- +-- Features: +-- . View sp_sosi_arr at the sample rate using the 4 SP scope_sosi_arr().data +-- in unb1_bn_capture_input/aduh_quad_scope/dp_wideband_sp_arr_scope and +-- viewing these integer data fields as Radix=decimal and Format=analogue. +-- . Read waveform buffer for all 4 wideband waveform generators (ram_wg_rddata) +-- . Select 1 or 2 ADU data or wideband WG data +-- . Read current BSN +-- . Schedule WG start at a BSN +-- . Schedule ADUH monitor data read at a BSN +-- . Sync interval drives the ADUH monitor statistics period and buffer trigger +-- . Read ADUH mean and power statistics for all 4 wideband signal paths +-- . Read ADUH monitor buffer for all 4 wideband signal paths (ram_mon_rddata) +-- . View ram_mon_rddata at the 4x rate using MCLK and ram_mon_sample +-- . Stop WG at the end, to continue with ADU data +-- +-- Usage: +-- . as 10 +-- . run 10 us +-- . Manually change Radix=decimal and Format=analogue for all SP=4 or only sp +-- index 0 scope_sosi_arr().data in the Wave window. +-- . run -all +-- . The self test only verifies the exp_mean_sum and exp_power_sum for the WG +-- data. The tb_end depends on verify done and stimuli done so that proves +-- that the tb has run. + +LIBRARY IEEE, common_lib, dp_lib, diag_lib, aduh_lib, unb1_board_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE IEEE.MATH_REAL.ALL; +USE work.unb1_bn_capture_pkg.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE aduh_lib.aduh_dd_pkg.ALL; +USE unb1_board_lib.unb1_board_pkg.ALL; +USE unb1_board_lib.unb1_board_peripherals_pkg.ALL; + +ENTITY tb_unb1_bn_capture_input IS +END tb_unb1_bn_capture_input; + +ARCHITECTURE tb OF tb_unb1_bn_capture_input IS + + CONSTANT c_sim : BOOLEAN := TRUE; + + CONSTANT c_bn_capture_sp_sim : t_c_bn_capture_sp := (800, 1024, 48*1024, 4*1024, TRUE); -- 800 MSps, block size 1024 samples, 48 blocks per sync interval, monitor buffer 4096 samples using sync + CONSTANT c_bn_capture : t_c_bn_capture := (c_unb1_board_mm_clk_freq_50M, + c_unb1_board_ext_clk_freq_200M, + c_bn_capture_sp_sim); + + CONSTANT c_ram_wg_dat_w : NATURAL := c_unb1_board_peripherals_mm_reg_default.ram_diag_wg_dat_w; + CONSTANT c_ram_wg_size : NATURAL := 2**c_unb1_board_peripherals_mm_reg_default.ram_diag_wg_adr_w; + CONSTANT c_ram_mon_dat_w : NATURAL := c_unb1_board_peripherals_mm_reg_default.ram_aduh_mon_dat_w; + CONSTANT c_ram_mon_size : NATURAL := 2**c_unb1_board_peripherals_mm_reg_default.ram_aduh_mon_adr_w; + + CONSTANT c_nof_block_per_sync : NATURAL := c_bn_capture.sp.nof_samples_per_sync / c_bn_capture.sp.nof_samples_per_block; + CONSTANT c_nof_block_per_monitor_buffer : NATURAL := c_bn_capture.sp.monitor_buffer_nof_samples / c_bn_capture.sp.nof_samples_per_block; + + CONSTANT c_bsn_schedule_wg_on : NATURAL := c_nof_block_per_sync*4; + CONSTANT c_bsn_schedule_aduh_verify : NATURAL := c_nof_block_per_sync*7; + CONSTANT c_bsn_schedule_aduh_monitor : NATURAL := c_nof_block_per_sync + c_nof_block_per_monitor_buffer; -- read aduh monitor after buffer was filled again + CONSTANT c_bsn_schedule_nof_events : NATURAL := 8; + + -- ADU + --CONSTANT c_ai : t_c_aduh_dd_ai := (4, 2, 2, 8, 2, 2, FALSE, FALSE, c_aduh_delays); -- keep DCLK_RST = '0', others as in c_aduh_dd_ai + CONSTANT c_ai : t_c_aduh_dd_ai := c_aduh_dd_ai; + + CONSTANT c_dp_factor : NATURAL := c_ai.rx_factor * c_ai.dd_factor; + CONSTANT c_wideband_factor : NATURAL := c_dp_factor; -- = 4 + + CONSTANT c_mm_clk_period : TIME := 20 ns; -- 50 MHz + CONSTANT c_sample_period : TIME := 1250 ps; -- 800 MSps + CONSTANT c_dp_clk_period : TIME := c_sample_period *c_wideband_factor; -- 200 MHz external reference clock for data path processing + CONSTANT c_dp_phs_clk_step : TIME := c_dp_clk_period/32; -- the PLL can output clocks with phase shifts of 360/32 = 11.25 degrees + CONSTANT c_dp_phs_clk_div : NATURAL := 32; + + CONSTANT c_ana_diff : NATURAL := 16; -- analogue offset value between the port A, B, C, D, use 0 to have same data on all ports + + -- ADC + SIGNAL ANA_DAT : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0'); -- Common ADC reference data source + SIGNAL ANA_A : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0'); -- ADC port A + SIGNAL ANA_B : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0'); -- ADC port B + SIGNAL ANA_C : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0'); -- ADC port C + SIGNAL ANA_D : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0'); -- ADC port D + SIGNAL SCLK : STD_LOGIC := '1'; -- central sample clock = 800 MHz + SIGNAL DCLK_AB : STD_LOGIC; -- digital lvds clock = 400 MHz (DDR) + SIGNAL DCLK_CD : STD_LOGIC; -- digital lvds clock = 400 MHz (DDR) + SIGNAL DCLK_RST_AB : STD_LOGIC; -- synchronise digital lvds clock + SIGNAL DCLK_RST_CD : STD_LOGIC; -- synchronise digital lvds clock + SIGNAL DIG_A : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0); + SIGNAL DIG_B : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0); + SIGNAL DIG_C : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0); + SIGNAL DIG_D : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0); + + SIGNAL test_pattern_en : STD_LOGIC := '0'; + + -- DUT + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL mm_rst : STD_LOGIC; + SIGNAL mm_clk : STD_LOGIC := '0'; + SIGNAL dp_rst : STD_LOGIC; + SIGNAL dp_clk : STD_LOGIC := '0'; + SIGNAL dp_phs_clk : STD_LOGIC := '0'; + SIGNAL dp_phs_clk_vec : STD_LOGIC_VECTOR(0 DOWNTO 0); + SIGNAL dp_pps : STD_LOGIC; + + -- tb_end control + SIGNAL verify_stat_done : STD_LOGIC := '0'; + SIGNAL ram_wg_stimuli_done : STD_LOGIC := '0'; + SIGNAL ram_mon_stimuli_done : STD_LOGIC := '0'; + + -- Control and status registers + + -- MM bsn source + SIGNAL current_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL nof_block_per_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + SIGNAL reg_bsn_source_mosi : t_mem_mosi := c_mem_mosi_rst; -- Start a BSN timestamp + SIGNAL reg_bsn_source_miso : t_mem_miso; + + -- MM bsn schedule WG + SIGNAL reg_bsn_scheduler_wg_mosi : t_mem_mosi := c_mem_mosi_rst; -- Schedule WG restart at a BSN, read current BSN + SIGNAL reg_bsn_scheduler_wg_miso : t_mem_miso; + + -- MM aduh quad + SIGNAL aduh_ab_locked : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL aduh_cd_locked : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + SIGNAL reg_adc_quad_mosi : t_mem_mosi := c_mem_mosi_rst; -- ADUH locked status and pattern verify for two half ADUs so 4 ADC inputs A, B, C and D + SIGNAL reg_adc_quad_miso : t_mem_miso; + + -- Wideband waveform generators + SIGNAL reg_wg_mosi_arr : t_mem_mosi_arr(0 TO c_ai.nof_sp-1) := (OTHERS=>c_mem_mosi_rst); -- = [0:3] = WG ports [A,B,C,D] + SIGNAL reg_wg_miso_arr : t_mem_miso_arr(0 TO c_ai.nof_sp-1); -- = [0:3] = WG ports [A,B,C,D] + SIGNAL ram_wg_mosi_arr : t_mem_mosi_arr(0 TO c_ai.nof_sp-1) := (OTHERS=>c_mem_mosi_rst); -- = [0:3] = WG ports [A,B,C,D] + SIGNAL ram_wg_miso_arr : t_mem_miso_arr(0 TO c_ai.nof_sp-1); -- = [0:3] = WG ports [A,B,C,D] + SIGNAL ram_wg_mosi_sel : t_mem_mosi; + SIGNAL ram_wg_miso_sel : t_mem_miso; + SIGNAL ram_wg_sel : NATURAL; + SIGNAL ram_wg_rddata : STD_LOGIC_VECTOR(c_ram_wg_dat_w-1 DOWNTO 0); + SIGNAL ram_wg_rdval : STD_LOGIC; + + -- Data monitor buffers + SIGNAL stat_mean_sum : t_slv_64_arr(0 TO c_ai.nof_sp-1); -- use fixed 64 bit sum width, expected value for sinus ~ 0 + SIGNAL stat_power_sum : t_slv_64_arr(0 TO c_ai.nof_sp-1); -- use fixed 64 bit sum width, expected value for sinus ~ (Amplitude**2)/2 * c_bn_capture.sp.nof_samples_per_sync = 117**2 * 48 * 1024 = 396386304 + SIGNAL exp_mean_sum : t_slv_64_arr(0 TO c_ai.nof_sp-1); -- exact expected mean sum for Fs/16 full scale sinus = 0 + SIGNAL exp_power_sum : t_slv_64_arr(0 TO c_ai.nof_sp-1); -- exact expected power sum for Fs/16 full scale sinus = [4*(49**2 + 90**2 + 117**2) + 2*(0**2 + 127**2)] * 48/16 * 1024 = 396343296 + + SIGNAL reg_mon_mosi_arr : t_mem_mosi_arr(0 TO c_ai.nof_sp-1) := (OTHERS=>c_mem_mosi_rst); -- = [0:3] read only access to the data monitor mean sums and power sums [A,B,C,D] + SIGNAL reg_mon_miso_arr : t_mem_miso_arr(0 TO c_ai.nof_sp-1); + SIGNAL ram_mon_mosi_arr : t_mem_mosi_arr(0 TO c_ai.nof_sp-1) := (OTHERS=>c_mem_mosi_rst); -- = [0:3] read only access to the data monitor buffers [A,B,C,D] + SIGNAL ram_mon_miso_arr : t_mem_miso_arr(0 TO c_ai.nof_sp-1); + SIGNAL ram_mon_mosi_sel : t_mem_mosi; + SIGNAL ram_mon_miso_sel : t_mem_miso; + SIGNAL ram_mon_sel : NATURAL; + SIGNAL ram_mon_rddata : STD_LOGIC_VECTOR(c_ram_mon_dat_w-1 DOWNTO 0); + SIGNAL ram_mon_rdval : STD_LOGIC; + SIGNAL MCLK : STD_LOGIC := '1'; -- MCLK is 4 times mm_clk, similar as SCLK and dp_clk + SIGNAL ram_mon_cnt : NATURAL; + SIGNAL ram_mon_sample : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0); + SIGNAL ram_mon_sample_val : STD_LOGIC; + + -- Signal paths + SIGNAL sp_sosi_arr : t_dp_sosi_arr(0 TO c_ai.nof_sp-1); -- = [0:3] = Signal Paths [A,B,C,D] + SIGNAL sp_siso_arr : t_dp_siso_arr(0 TO c_ai.nof_sp-1); + +BEGIN + + gen_rdy : FOR I IN 0 TO c_ai.nof_sp-1 GENERATE + sp_siso_arr(I) <= c_dp_siso_rdy; + END GENERATE; + + mm_rst <= '1', '0' AFTER c_mm_clk_period*10; + dp_rst <= '1', '0' AFTER c_dp_clk_period*20; -- Release dp_rst after mm_rst + + mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2; -- MM clock (125 MHz) + dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2; -- DP clock (200 MHz) + dp_phs_clk <= NOT dp_phs_clk OR tb_end AFTER c_dp_clk_period*c_dp_phs_clk_div/2; -- DP phase clock + dp_phs_clk_vec <= TRANSPORT (OTHERS=>dp_phs_clk) AFTER c_dp_phs_clk_step; + + tb_end <= '0', verify_stat_done AND ram_wg_stimuli_done AND ram_mon_stimuli_done AFTER c_mm_clk_period*100; + + ---------------------------------------------------------------------------- + -- Stimuli for MM REG slave port + ---------------------------------------------------------------------------- + + p_mm_reg_stimuli : PROCESS + VARIABLE v_bsn : NATURAL; + VARIABLE vI : NATURAL; + VARIABLE vJ : NATURAL; + BEGIN + reg_bsn_source_mosi <= c_mem_mosi_rst; + reg_bsn_scheduler_wg_mosi <= c_mem_mosi_rst; + reg_adc_quad_mosi <= c_mem_mosi_rst; + reg_wg_mosi_arr <= (OTHERS=>c_mem_mosi_rst); + reg_mon_mosi_arr <= (OTHERS=>c_mem_mosi_rst); + + dp_pps <= '0'; + + ---------------------------------------------------------------------------- + -- Initialisations + ---------------------------------------------------------------------------- + + -- Use while instead of WAIT UNTIL mm_rst='0' because wait until requires a change + WHILE mm_rst='1' LOOP + WAIT UNTIL rising_edge(mm_clk); + END LOOP; + proc_common_wait_some_cycles(mm_clk, 10); + + -- BSN source register settings + -- * address 0 + -- mm_bs_enable : bit 0 + -- mm_bs_restart_evt : bit 1 -- write '1' indicates the event + -- * address 2, 3 + -- mm_bs_init_bsn : BSN[47:0] + proc_mem_mm_bus_wr(2, 16#00000007#, mm_clk, reg_bsn_source_mosi); + proc_mem_mm_bus_wr(3, 16#00000000#, mm_clk, reg_bsn_source_mosi); -- Init BSN = 7 + proc_mem_mm_bus_wr(0, 16#00000001#, mm_clk, reg_bsn_source_mosi); -- Enable BS + + -- * address 1: Nof block per sync + proc_mem_mm_bus_rd(1, mm_clk, reg_bsn_source_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + nof_block_per_sync <= reg_bsn_source_miso.rddata(31 DOWNTO 0); + + -- Run the data path processing for some time with this default start + proc_common_wait_some_cycles(mm_clk, 1000); + + -- Prepare for data path restart at next PPS and init BSN = 0 + proc_mem_mm_bus_wr(2, 0, mm_clk, reg_bsn_source_mosi); -- Init BSN = 0 + proc_mem_mm_bus_wr(3, 0, mm_clk, reg_bsn_source_mosi); -- Init BSN = 0 + proc_mem_mm_bus_wr(0, 16#00000000#, mm_clk, reg_bsn_source_mosi); -- Disable the BS output to prepare for restart with new BSN at the next PPS + proc_common_wait_some_cycles(mm_clk, 100); -- wait for at least one block + proc_mem_mm_bus_wr(0, 16#00000003#, mm_clk, reg_bsn_source_mosi); -- Keep the BS enabled and restart the time stamp at the next PPS + + ---------------------------------------------------------------------------- + -- ADUH activated so the data path now carries ADU data + ---------------------------------------------------------------------------- + -- . mode[7:0] --> off=0, calc=1, repeat=2, single=3) + -- nof_samples[31:16] --> <= c_ram_wg_size=1024 + -- . phase[15:0] + -- . freq[30:0] + -- . ampl[16:0] + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(0)); -- mode off, nof_sample + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(3)); + proc_mem_mm_bus_wr(1, INTEGER( 0.0 * c_diag_wg_phase_unit), mm_clk, reg_wg_mosi_arr(0)); -- phase offset in degrees + proc_mem_mm_bus_wr(1, INTEGER( 90.0 * c_diag_wg_phase_unit), mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(1, INTEGER(180.0 * c_diag_wg_phase_unit), mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(1, INTEGER(270.0 * c_diag_wg_phase_unit), mm_clk, reg_wg_mosi_arr(3)); + proc_mem_mm_bus_wr(2, INTEGER(0.0625 * c_diag_wg_freq_unit), mm_clk, reg_wg_mosi_arr(0)); -- freq = Fs/16 = 800 MSps/16 = 50 MHz sinus + proc_mem_mm_bus_wr(2, INTEGER(0.0625 * c_diag_wg_freq_unit), mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(2, INTEGER(0.0625 * c_diag_wg_freq_unit), mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(2, INTEGER(0.0625 * c_diag_wg_freq_unit), mm_clk, reg_wg_mosi_arr(3)); + proc_mem_mm_bus_wr(3, INTEGER(1.0 * c_diag_wg_ampl_unit), mm_clk, reg_wg_mosi_arr(0)); -- full scale sinus + proc_mem_mm_bus_wr(3, INTEGER(1.0 * c_diag_wg_ampl_unit), mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(3, INTEGER(1.0 * c_diag_wg_ampl_unit), mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(3, INTEGER(1.0 * c_diag_wg_ampl_unit), mm_clk, reg_wg_mosi_arr(3)); + + -- Run the data path processing for the ADC data for some time + proc_common_wait_some_cycles(mm_clk, 1000); + + -- Issue a PPS pulse to restart the BS due to the pending mm_bs_restart_evt + WAIT UNTIL rising_edge(dp_clk); -- to dp_clk domain + dp_pps <= '1'; + WAIT UNTIL rising_edge(dp_clk); + dp_pps <= '0'; + WAIT UNTIL rising_edge(mm_clk); -- back to mm_clk domain + + ---------------------------------------------------------------------------- + -- Enable WG, so the data path will carry WG data + ---------------------------------------------------------------------------- + + -- Enable calc mode + proc_mem_mm_bus_wr(0, 1024*2**16 + 1, mm_clk, reg_wg_mosi_arr(0)); -- mode calc, nof_sample + proc_mem_mm_bus_wr(0, 1024*2**16 + 1, mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 1, mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 1, mm_clk, reg_wg_mosi_arr(3)); + + -- Write BSN scheduler to trigger start of WG at specific block + v_bsn := c_bsn_schedule_wg_on; + proc_mem_mm_bus_wr(0, v_bsn, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_wr(1, 0, mm_clk, reg_bsn_scheduler_wg_mosi); -- assume v_bsn < 2**31-1 + + -- Read aduh locked status for AB, CD to set initial stable reference moment + proc_mem_mm_bus_rd(0, mm_clk, reg_adc_quad_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_ab_locked <= reg_adc_quad_miso.rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_adc_quad_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_cd_locked <= reg_adc_quad_miso.rddata(31 DOWNTO 0); + + -- Read ADUH monitor statistics + FOR K IN 0 TO c_bsn_schedule_nof_events-1 LOOP + WHILE UNSIGNED(current_bsn) < c_bsn_schedule_aduh_monitor + K*c_nof_block_per_sync LOOP + -- Read current BSN + -- * address 0, 1: BSN current + proc_mem_mm_bus_rd(0, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + current_bsn(31 DOWNTO 0) <= reg_bsn_scheduler_wg_miso.rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + current_bsn(47 DOWNTO 32) <= reg_bsn_scheduler_wg_miso.rddata(15 DOWNTO 0); + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + + -- Read aduh locked status for AB, CD again to get the recent locked status + proc_common_wait_some_cycles(mm_clk, 10); + proc_mem_mm_bus_rd(0, mm_clk, reg_adc_quad_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_ab_locked <= reg_adc_quad_miso.rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_adc_quad_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_cd_locked <= reg_adc_quad_miso.rddata(31 DOWNTO 0); + proc_common_wait_some_cycles(mm_clk, 1); + ASSERT TO_UINT(aduh_ab_locked(1 DOWNTO 0))=3 REPORT "ADU-AB input not locked" SEVERITY ERROR; + ASSERT TO_UINT(aduh_cd_locked(1 DOWNTO 0))=3 REPORT "ADU-CD input not locked" SEVERITY ERROR; + + -- Read signal path statistics for [0,1,2,3] = [A,B,C,D] + -- * address 0:1 = 64b mean sum (LSWord first) + -- * address 2:3 = 64b power sum (LSWord first) + proc_common_wait_some_cycles(mm_clk, 10); + proc_mem_mm_bus_rd(0, mm_clk, reg_mon_mosi_arr(0)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 0)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(0).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_mon_mosi_arr(0)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 0)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(0).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(2, mm_clk, reg_mon_mosi_arr(0)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(0)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(0).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(3, mm_clk, reg_mon_mosi_arr(0)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(0)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(0).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(0, mm_clk, reg_mon_mosi_arr(1)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 1)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(1).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_mon_mosi_arr(1)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 1)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(1).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(2, mm_clk, reg_mon_mosi_arr(1)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(1)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(1).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(3, mm_clk, reg_mon_mosi_arr(1)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(1)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(1).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(0, mm_clk, reg_mon_mosi_arr(2)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 2)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(2).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_mon_mosi_arr(2)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 2)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(2).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(2, mm_clk, reg_mon_mosi_arr(2)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(2)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(2).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(3, mm_clk, reg_mon_mosi_arr(2)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(2)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(2).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(0, mm_clk, reg_mon_mosi_arr(3)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 3)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(3).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_mon_mosi_arr(3)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_mean_sum( 3)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(3).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(2, mm_clk, reg_mon_mosi_arr(3)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(3)( c_word_w-1 DOWNTO 0) <= reg_mon_miso_arr(3).rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(3, mm_clk, reg_mon_mosi_arr(3)); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); stat_power_sum(3)(2*c_word_w-1 DOWNTO c_word_w) <= reg_mon_miso_arr(3).rddata(31 DOWNTO 0); + END LOOP; + + -- Disable WG takes effect immediatly + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(0)); -- mode off, nof_sample + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(1)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(2)); + proc_mem_mm_bus_wr(0, 1024*2**16 + 0, mm_clk, reg_wg_mosi_arr(3)); + + -- Write scheduler BSN to trigger WG at specific block (no effect, because WG off already takes effect immediatly) + v_bsn := TO_UINT(current_bsn) + 2; + proc_mem_mm_bus_wr(0, v_bsn, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_wr(1, 0, mm_clk, reg_bsn_scheduler_wg_mosi); -- assume v_bsn < 2**31-1 + + + -- Continue forever with WG data and keep reading the current BSN + WHILE TRUE LOOP + -- Read current BSN + -- * address 0, 1: BSN current + proc_mem_mm_bus_rd(0, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + current_bsn(31 DOWNTO 0) <= reg_bsn_scheduler_wg_miso.rddata(31 DOWNTO 0); + proc_mem_mm_bus_rd(1, mm_clk, reg_bsn_scheduler_wg_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + current_bsn(47 DOWNTO 32) <= reg_bsn_scheduler_wg_miso.rddata(15 DOWNTO 0); + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + + WAIT; + END PROCESS; + + -- Verify ADUH statistics + p_verify_stat : PROCESS + BEGIN + WHILE UNSIGNED(current_bsn) < c_bsn_schedule_aduh_verify LOOP + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + + exp_mean_sum <= (OTHERS=>TO_UVEC( 0, 64)); -- exact expected mean sum for Fs/16 full scale sinus = 0 + exp_power_sum <= (OTHERS=>TO_UVEC(396343296, 64)); -- exact expected power sum for Fs/16 full scale sinus = [4*(49**2 + 90**2 + 117**2) + 2*(0**2 + 127**2)] * 48/16 * 1024 = 396343296 + proc_common_wait_some_cycles(mm_clk, 1); + FOR I IN 0 TO c_ai.nof_sp-1 LOOP + ASSERT stat_mean_sum(I) = exp_mean_sum(I) REPORT "Wrong mean sum value for sinus" SEVERITY ERROR; + ASSERT stat_power_sum(I) = exp_power_sum(I) REPORT "Wrong power sum value for sinus" SEVERITY ERROR; + END LOOP; + + verify_stat_done <= '1'; + WAIT; + END PROCESS; + + + + ---------------------------------------------------------------------------- + -- Stimuli for MM RAM WG slave port + ---------------------------------------------------------------------------- + + -- VHDL does not allow using static indexed ram_wg_mosi_arr(I) in proc_mem_mm_bus_rd, therefore implement this using a separate mux via ram_wg_sel + ram_wg_mosi_arr(ram_wg_sel) <= ram_wg_mosi_sel; + ram_wg_miso_sel <= ram_wg_miso_arr(ram_wg_sel); + + p_mm_ram_wg_stimuli : PROCESS + BEGIN + ram_wg_mosi_sel <= c_mem_mosi_rst; + ram_wg_sel <= 0; + + -- Use while instead of WAIT UNTIL mm_rst='0' because wait until requires a change + WHILE mm_rst='1' LOOP + WAIT UNTIL rising_edge(mm_clk); + END LOOP; + + -- Read the RAM waveform buffer for all 4 wideband waveform generators + FOR I IN 0 TO c_ai.nof_sp-1 LOOP + ram_wg_sel <= I; + proc_common_wait_some_cycles(mm_clk, 100); -- wait some time between the RAM WG buffers to easy recognition in the Wave window + FOR J IN 0 TO c_ram_wg_size-1 LOOP + proc_mem_mm_bus_rd(J, mm_clk, ram_wg_mosi_sel); -- read request, result will be available after read latency, use ram_wg_rddata to view it in the Wave window + END LOOP; + proc_common_wait_some_cycles(mm_clk, 1); -- extra cycle to release read request + END LOOP; + + ram_wg_stimuli_done <= '1'; + WAIT; + END PROCESS; + + ram_wg_rddata <= ram_wg_miso_sel.rddata(ram_wg_rddata'RANGE); + ram_wg_rdval <= ram_wg_miso_sel.rdval; + + ---------------------------------------------------------------------------- + -- Stimuli for MM RAM Monitor slave port + ---------------------------------------------------------------------------- + + -- VHDL does not allow using static indexed ram_mon_mosi_arr(I) in proc_mem_mm_bus_rd, therefore implement this using a separate mux via ram_mon_sel + ram_mon_mosi_arr(ram_mon_sel) <= ram_mon_mosi_sel; + ram_mon_miso_sel <= ram_mon_miso_arr(ram_mon_sel); + + p_mm_ram_mon_stimuli : PROCESS + BEGIN + ram_mon_mosi_sel <= c_mem_mosi_rst; + ram_mon_sel <= 0; + + -- Use while instead of WAIT UNTIL mm_rst='0' because wait until requires a change + WHILE mm_rst='1' LOOP + WAIT UNTIL rising_edge(mm_clk); + END LOOP; + + -- Read ADUH monitor buffer at BSN + FOR K IN 0 TO c_bsn_schedule_nof_events-1 LOOP + WHILE UNSIGNED(current_bsn) < c_bsn_schedule_aduh_monitor + K*c_nof_block_per_sync LOOP + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + + -- Read the RAM waveform buffer for all 4 wideband waveform generators + FOR I IN 0 TO c_ai.nof_sp-1 LOOP + ram_mon_sel <= I; + FOR J IN 0 TO c_ram_mon_size-1 LOOP + proc_mem_mm_bus_rd(J, mm_clk, ram_mon_mosi_sel); -- read request, result will be available after read latency, use ram_mon_rddata to view it in the Wave window + END LOOP; + proc_common_wait_some_cycles(mm_clk, 1); -- extra cycle to release read request + proc_common_wait_some_cycles(mm_clk, 100); -- wait some time between the RAM Monitor buffers to easy recognition in the Wave window + END LOOP; + END LOOP; + + ram_mon_stimuli_done <= '1'; + WAIT; + END PROCESS; + + ram_mon_rddata <= ram_mon_miso_sel.rddata(ram_mon_rddata'RANGE); + ram_mon_rdval <= ram_mon_miso_sel.rdval; + + -- View ram_mon_rddata at the 4 * mm_clk rate + MCLK <= NOT MCLK OR tb_end AFTER c_mm_clk_period/2/c_wideband_factor; + + p_ram_mon_sample : PROCESS(MCLK) + VARIABLE vI : NATURAL; + BEGIN + IF rising_edge(MCLK) THEN + ram_mon_sample_val <= '0'; + IF ram_mon_rdval='1' THEN + vI := ram_mon_cnt; + ram_mon_cnt <= 0; + IF ram_mon_cnt < c_wideband_factor-1 THEN + ram_mon_cnt <= ram_mon_cnt+1; + END IF; + ram_mon_sample <= ram_mon_rddata((c_wideband_factor-vI)*c_ai.port_w-1 DOWNTO (c_wideband_factor-vI-1)*c_ai.port_w); + ram_mon_sample_val <= ram_mon_rdval; + END IF; + END IF; + END PROCESS; + + + ----------------------------------------------------------------------------- + -- ADU0 and ADU1 for BN port A,B and C,D + ----------------------------------------------------------------------------- + + -- Same sample clock for all ADC + SCLK <= NOT SCLK OR tb_end AFTER c_sample_period/2; + + -- Same analogue reference signal for all ADC, use incrementing data to ease the verification + ANA_DAT <= INCR_UVEC(ANA_DAT, 1) WHEN rising_edge(SCLK); + ANA_A <= INCR_UVEC(ANA_DAT, 0*c_ana_diff); + ANA_B <= INCR_UVEC(ANA_DAT, 1*c_ana_diff); + ANA_C <= INCR_UVEC(ANA_DAT, 2*c_ana_diff); + ANA_D <= INCR_UVEC(ANA_DAT, 3*c_ana_diff); + + -- National ADC + u_adc_AB : ENTITY aduh_lib.adu_half + PORT MAP ( + AI => TO_SINT(ANA_A), + AQ => TO_SINT(ANA_B), + CLK => SCLK, + DCLK => DCLK_AB, + DCLK_RST => DCLK_RST_AB, + DI => DIG_A, + DQ => DIG_B, + test_pattern_en => test_pattern_en + ); + + u_adc_CD : ENTITY aduh_lib.adu_half + PORT MAP ( + AI => TO_SINT(ANA_C), + AQ => TO_SINT(ANA_D), + CLK => SCLK, + DCLK => DCLK_CD, + DCLK_RST => DCLK_RST_CD, + DI => DIG_C, + DQ => DIG_D, + test_pattern_en => test_pattern_en + ); + + ------------------------------------------------------------------------------ + -- DUT + ------------------------------------------------------------------------------ + + dut : ENTITY work.unb1_bn_capture_input + GENERIC MAP ( + g_sim => c_sim, + g_bn_capture => c_bn_capture, + g_nof_dp_phs_clk => dp_phs_clk_vec'LENGTH, + g_ai => c_ai + ) + PORT MAP ( + -- ADC Interface + SCLK => SCLK, + + -- . ADU_AB + ADC_BI_A => DIG_A, + ADC_BI_B => DIG_B, + ADC_BI_A_CLK => DCLK_AB, + ADC_BI_A_CLK_RST => DCLK_RST_AB, + + -- . ADU_CD + ADC_BI_C => DIG_C, + ADC_BI_D => DIG_D, + ADC_BI_D_CLK => DCLK_CD, + ADC_BI_D_CLK_RST => DCLK_RST_CD, + + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + dp_phs_clk_vec => dp_phs_clk_vec, + dp_pps => dp_pps, + + -- MM bsn source + reg_bsn_source_mosi => reg_bsn_source_mosi, + reg_bsn_source_miso => reg_bsn_source_miso, + + -- MM bsn schedule WG + reg_bsn_scheduler_wg_mosi => reg_bsn_scheduler_wg_mosi, + reg_bsn_scheduler_wg_miso => reg_bsn_scheduler_wg_miso, + + -- MM aduh quad + reg_adc_quad_mosi => reg_adc_quad_mosi, + reg_adc_quad_miso => reg_adc_quad_miso, + + -- MM waveform generators + reg_wg_mosi_arr => reg_wg_mosi_arr, + reg_wg_miso_arr => reg_wg_miso_arr, + ram_wg_mosi_arr => ram_wg_mosi_arr, + ram_wg_miso_arr => ram_wg_miso_arr, + + -- MM signal path monitors + reg_mon_mosi_arr => reg_mon_mosi_arr, + reg_mon_miso_arr => reg_mon_miso_arr, + ram_mon_mosi_arr => ram_mon_mosi_arr, + ram_mon_miso_arr => ram_mon_miso_arr, + + -- Streaming output (can be from ADU or from internal WG) + sp_sosi_arr => sp_sosi_arr, + sp_siso_arr => sp_siso_arr + ); + + ------------------------------------------------------------------------------ + -- Verify + ------------------------------------------------------------------------------ + + -- View sp_sosi_arr in Wave Window with aduh_quad_scope in unb1_bn_capture_input + +END tb;