diff --git a/applications/lofar2/designs/lofar2_unb2b_ring/lofar2_unb2b_ring.fpga.yaml b/applications/lofar2/designs/lofar2_unb2b_ring/lofar2_unb2b_ring.fpga.yaml index 51766f1eec63cc09ca5e8a895394e1123f72e8d2..953084dfb15b258fc2f18a990383f0973c966c7c 100644 --- a/applications/lofar2/designs/lofar2_unb2b_ring/lofar2_unb2b_ring.fpga.yaml +++ b/applications/lofar2/designs/lofar2_unb2b_ring/lofar2_unb2b_ring.fpga.yaml @@ -9,7 +9,7 @@ parameters: - { name: c_nof_lanes, value: 8 } - { name: c_nof_rx_monitors, value: 16 } # per lane - { name: c_nof_tx_monitors, value: 16 } # per lane - - { name: c_nof_err_counts, value: 8 } # per lane + - { name: c_nof_err_counts, value: 8 } # per lane, per bit in sosi.err field - { name: c_nof_mac, value: 12 } # 4 TX/RX for RING0 + 4 TX/RX for RING1 + 4 TX/RX for QSFP0 peripherals: diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.fpga.yaml b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.fpga.yaml index 4a1e54c46bed030a4ae613518e16590e61adf506..c8ed157e255422e409f972b72348c86edd889005 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.fpga.yaml +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.fpga.yaml @@ -11,10 +11,11 @@ parameters: - { name: c_N_beamsets, value: 2 } - { name: c_N_sub, value: 512 } - { name: c_N_fft, value: 1024 } - - { name: c_N_pn_lb, value: 16 } + - { name: c_N_pn_max, value: 16 } - { name: c_S_pn, value: 12 } - { name: c_Q_fft, value: 2 } - - { name: c_P_sq, value: 1 + c_N_pn_lb // 2 } # = 1 + 16 // 2 = 9, on revision xsub_one only first X_sq cell is used + - { name: c_P_sum, value: 2 } + - { name: c_P_sq, value: 1 + c_N_pn_max // 2 } # = 1 + 16 // 2 = 9, on revision xsub_one only first X_sq cell is used - { name: c_X_sq, value: c_S_pn * c_S_pn } # = 144 - { name: c_N_crosslets, value: 7 } - { name: c_N_taps, value: 16 } @@ -37,10 +38,8 @@ parameters: - { name: c_W_beamlet, value: 8 } - { name: c_stat_data_sz, value: 2 } - { name: c_nof_clk_per_pps, value: c_f_adc_MHz * 10**6 } # = 200000000 - - { name: c_lane_nof_rx_monitors, value: 16 } # per lane - - { name: c_lane_nof_tx_monitors, value: 16 } # per lane - - { name: c_lane_nof_err_counts, value: 8 } # per lane - - { name: c_ring_nof_mac, value: 3 } # 1 TX/RX for RING0 + 1 TX/RX for RING1 + 1 TX/RX for QSFP0 + - { name: c_lane_nof_err_counts, value: 8 } # per lane, per bit in RX sosi.err field + - { name: c_ring_nof_mac, value: 3 } # 1 TX/RX for RING0 + 1 TX/RX for RING1 + 1 TX/RX for QSFP0 peripherals: ############################################################################# @@ -312,14 +311,14 @@ peripherals: - peripheral_name: dp/dp_bsn_monitor_v2 peripheral_group: ring_rx parameter_overrides: - - { name: g_nof_streams, value: c_lane_nof_rx_monitors } + - { name: g_nof_streams, value: c_N_pn_max } mm_port_names: - REG_BSN_MONITOR_V2_RING_RX_XST - peripheral_name: dp/dp_bsn_monitor_v2 peripheral_group: ring_tx parameter_overrides: - - { name: g_nof_streams, value: c_lane_nof_tx_monitors } + - { name: g_nof_streams, value: c_N_pn_max } mm_port_names: - REG_BSN_MONITOR_V2_RING_TX_XST @@ -369,7 +368,7 @@ peripherals: peripheral_group: bf number_of_peripherals: c_N_beamsets parameter_overrides: - - { name: g_nof_streams, value: 2 } + - { name: g_nof_streams, value: c_P_sum } mm_port_names: - REG_BSN_ALIGN_V2_BF @@ -377,7 +376,7 @@ peripherals: peripheral_group: rx_align_bf number_of_peripherals: c_N_beamsets parameter_overrides: - - { name: g_nof_streams, value: 2 } + - { name: g_nof_streams, value: c_P_sum } mm_port_names: - REG_BSN_MONITOR_V2_RX_ALIGN_BF diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.gold b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.gold index 4b6c9fffb9a9e31af03621f421bc35602d71864e..b93a5deca279b552603d25ee778c900276dfe1ec 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.gold +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.gold @@ -92,11 +92,16 @@ number_of_columns = 13 - - - - rx_lane_ctrl_7 0x00070008 1 RW uint32 b[2:0] - - - - - - - rx_dll_ctrl 0x00070014 1 RW uint32 b[16:0] - - - - - - - rx_syncn_sysref_ctrl 0x00070015 1 RW uint32 b[24:0] - - - - - - - - rx_csr_sysref_always_on 0x00070015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_link_reinit 0x00070015 1 RW uint32 b[0:0] - - - + - - - - rx_csr_sysref_alwayson 0x00070015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_sysref_singled 0x00070015 1 RW uint32 b[2:2] - - - - - - - rx_csr_rbd_offset 0x00070015 1 RW uint32 b[10:3] - - - - - - - rx_csr_lmfc_offset 0x00070015 1 RW uint32 b[19:12] - - - + - - - - ctrl_reserve 0x00070016 1 RO uint32 b[31:0] - - - - - - - rx_err0 0x00070018 1 RW uint32 b[8:0] - - - - - - - rx_err1 0x00070019 1 RW uint32 b[9:0] - - - + - - - - rx_err_enable 0x0007001d 1 RW uint32 b[31:0] - - - + - - - - rx_err_link_reinit 0x0007001e 1 RW uint32 b[31:0] - - - - - - - csr_dev_syncn 0x00070020 1 RO uint32 b[0:0] - - - - - - - csr_rbd_count 0x00070020 1 RO uint32 b[10:3] - - - - - - - rx_status1 0x00070021 1 RW uint32 b[23:0] - - - diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.qsys.gold b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.qsys.gold index 285520e5ff934775956cbe638728d49176b2fa59..0d6932609ae58168aeefd5a07ac8448ba329ca75 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.qsys.gold +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/lofar2_unb2b_sdp_station.mmap.qsys.gold @@ -92,11 +92,16 @@ number_of_columns = 13 - - - - rx_lane_ctrl_7 0x00042008 1 RW uint32 b[2:0] - - - - - - - rx_dll_ctrl 0x00042014 1 RW uint32 b[16:0] - - - - - - - rx_syncn_sysref_ctrl 0x00042015 1 RW uint32 b[24:0] - - - - - - - - rx_csr_sysref_always_on 0x00042015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_link_reinit 0x00042015 1 RW uint32 b[0:0] - - - + - - - - rx_csr_sysref_alwayson 0x00042015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_sysref_singled 0x00042015 1 RW uint32 b[2:2] - - - - - - - rx_csr_rbd_offset 0x00042015 1 RW uint32 b[10:3] - - - - - - - rx_csr_lmfc_offset 0x00042015 1 RW uint32 b[19:12] - - - + - - - - ctrl_reserve 0x00042016 1 RO uint32 b[31:0] - - - - - - - rx_err0 0x00042018 1 RW uint32 b[8:0] - - - - - - - rx_err1 0x00042019 1 RW uint32 b[9:0] - - - + - - - - rx_err_enable 0x0004201d 1 RW uint32 b[31:0] - - - + - - - - rx_err_link_reinit 0x0004201e 1 RW uint32 b[31:0] - - - - - - - csr_dev_syncn 0x00042020 1 RO uint32 b[0:0] - - - - - - - csr_rbd_count 0x00042020 1 RO uint32 b[10:3] - - - - - - - rx_status1 0x00042021 1 RW uint32 b[23:0] - - - diff --git a/applications/lofar2/designs/lofar2_unb2c_ddrctrl/hdllib.cfg b/applications/lofar2/designs/lofar2_unb2c_ddrctrl/hdllib.cfg index 838e1ad84288d5232b536d59091fbcd9c6785b93..b04f1f5de30527b0e3fc298646ff667eef02370d 100644 --- a/applications/lofar2/designs/lofar2_unb2c_ddrctrl/hdllib.cfg +++ b/applications/lofar2/designs/lofar2_unb2c_ddrctrl/hdllib.cfg @@ -15,7 +15,7 @@ test_bench_files = tb/vhdl/tb_lofar2_unb2c_ddrctrl.vhd regression_test_vhdl = - tb/vhdl/tb_lofar2_unb2c_ddrctrl.vhd + #tb/vhdl/tb_lofar2_unb2c_ddrctrl.vhd [modelsim_project_file] modelsim_copy_files = diff --git a/applications/lofar2/designs/lofar2_unb2c_ring/lofar2_unb2c_ring.fpga.yaml b/applications/lofar2/designs/lofar2_unb2c_ring/lofar2_unb2c_ring.fpga.yaml index 7ce0a03e8f89d22aa77db970324a3dca874c394e..da16eb02707f4d94c2dc05ac22492678e925388e 100644 --- a/applications/lofar2/designs/lofar2_unb2c_ring/lofar2_unb2c_ring.fpga.yaml +++ b/applications/lofar2/designs/lofar2_unb2c_ring/lofar2_unb2c_ring.fpga.yaml @@ -9,7 +9,7 @@ parameters: - { name: c_nof_lanes, value: 8 } - { name: c_nof_rx_monitors, value: 16 } # per lane - { name: c_nof_tx_monitors, value: 16 } # per lane - - { name: c_nof_err_counts, value: 8 } # per lane + - { name: c_nof_err_counts, value: 8 } # per lane, per bit in sosi.err field - { name: c_nof_mac, value: 12 } # 4 TX/RX for RING0 + 4 TX/RX for RING1 + 4 TX/RX for QSFP0 peripherals: diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.fpga.yaml b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.fpga.yaml index 751f16099e932392bf770b5203193847d771ec5a..6f9cb187f829e008ca22aa579fdcd4605bafe222 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.fpga.yaml +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.fpga.yaml @@ -11,10 +11,11 @@ parameters: - { name: c_N_beamsets, value: 2 } - { name: c_N_sub, value: 512 } - { name: c_N_fft, value: 1024 } - - { name: c_N_pn_lb, value: 16 } + - { name: c_N_pn_max, value: 16 } - { name: c_S_pn, value: 12 } - { name: c_Q_fft, value: 2 } - - { name: c_P_sq, value: 1 + c_N_pn_lb // 2 } # = 1 + 16 // 2 = 9, on revision xsub_one only first X_sq cell is used + - { name: c_P_sum, value: 2 } + - { name: c_P_sq, value: 1 + c_N_pn_max // 2 } # = 1 + 16 // 2 = 9, on revision xsub_one only first X_sq cell is used - { name: c_X_sq, value: c_S_pn * c_S_pn } # = 144 - { name: c_N_crosslets, value: 7 } - { name: c_N_taps, value: 16 } @@ -37,10 +38,8 @@ parameters: - { name: c_W_beamlet, value: 8 } - { name: c_stat_data_sz, value: 2 } - { name: c_nof_clk_per_pps, value: c_f_adc_MHz * 10**6 } # = 200000000 - - { name: c_lane_nof_rx_monitors, value: 16 } # per lane - - { name: c_lane_nof_tx_monitors, value: 16 } # per lane - - { name: c_lane_nof_err_counts, value: 8 } # per lane - - { name: c_ring_nof_mac, value: 3 } # 1 TX/RX for RING0 + 1 TX/RX for RING1 + 1 TX/RX for QSFP0 + - { name: c_lane_nof_err_counts, value: 8 } # per lane, per bit in RX sosi.err field + - { name: c_ring_nof_mac, value: 3 } # 1 TX/RX for RING0 + 1 TX/RX for RING1 + 1 TX/RX for QSFP0 peripherals: ############################################################################# @@ -312,14 +311,14 @@ peripherals: - peripheral_name: dp/dp_bsn_monitor_v2 peripheral_group: ring_rx parameter_overrides: - - { name: g_nof_streams, value: c_lane_nof_rx_monitors } + - { name: g_nof_streams, value: c_N_pn_max } mm_port_names: - REG_BSN_MONITOR_V2_RING_RX_XST - peripheral_name: dp/dp_bsn_monitor_v2 peripheral_group: ring_tx parameter_overrides: - - { name: g_nof_streams, value: c_lane_nof_tx_monitors } + - { name: g_nof_streams, value: c_N_pn_max } mm_port_names: - REG_BSN_MONITOR_V2_RING_TX_XST @@ -369,7 +368,7 @@ peripherals: peripheral_group: bf number_of_peripherals: c_N_beamsets parameter_overrides: - - { name: g_nof_streams, value: 2 } + - { name: g_nof_streams, value: c_P_sum } mm_port_names: - REG_BSN_ALIGN_V2_BF @@ -377,7 +376,7 @@ peripherals: peripheral_group: rx_align_bf number_of_peripherals: c_N_beamsets parameter_overrides: - - { name: g_nof_streams, value: 2 } + - { name: g_nof_streams, value: c_P_sum } mm_port_names: - REG_BSN_MONITOR_V2_RX_ALIGN_BF diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.gold b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.gold index 69273a6077bb1b683d940528b9ade583dd7d9423..619efda88ac7ab59aaab42e723cb4e9f3b13410a 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.gold +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.gold @@ -92,11 +92,16 @@ number_of_columns = 13 - - - - rx_lane_ctrl_7 0x00070008 1 RW uint32 b[2:0] - - - - - - - rx_dll_ctrl 0x00070014 1 RW uint32 b[16:0] - - - - - - - rx_syncn_sysref_ctrl 0x00070015 1 RW uint32 b[24:0] - - - - - - - - rx_csr_sysref_always_on 0x00070015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_link_reinit 0x00070015 1 RW uint32 b[0:0] - - - + - - - - rx_csr_sysref_alwayson 0x00070015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_sysref_singled 0x00070015 1 RW uint32 b[2:2] - - - - - - - rx_csr_rbd_offset 0x00070015 1 RW uint32 b[10:3] - - - - - - - rx_csr_lmfc_offset 0x00070015 1 RW uint32 b[19:12] - - - + - - - - ctrl_reserve 0x00070016 1 RO uint32 b[31:0] - - - - - - - rx_err0 0x00070018 1 RW uint32 b[8:0] - - - - - - - rx_err1 0x00070019 1 RW uint32 b[9:0] - - - + - - - - rx_err_enable 0x0007001d 1 RW uint32 b[31:0] - - - + - - - - rx_err_link_reinit 0x0007001e 1 RW uint32 b[31:0] - - - - - - - csr_dev_syncn 0x00070020 1 RO uint32 b[0:0] - - - - - - - csr_rbd_count 0x00070020 1 RO uint32 b[10:3] - - - - - - - rx_status1 0x00070021 1 RW uint32 b[23:0] - - - diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.qsys.gold b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.qsys.gold index c06a5a7ca701657c1967ecc67a5b1c705ca4b407..082553d43ada9140f1aef08d6e21bb3e2ce49b06 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.qsys.gold +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/lofar2_unb2c_sdp_station.mmap.qsys.gold @@ -92,11 +92,16 @@ number_of_columns = 13 - - - - rx_lane_ctrl_7 0x00042008 1 RW uint32 b[2:0] - - - - - - - rx_dll_ctrl 0x00042014 1 RW uint32 b[16:0] - - - - - - - rx_syncn_sysref_ctrl 0x00042015 1 RW uint32 b[24:0] - - - - - - - - rx_csr_sysref_always_on 0x00042015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_link_reinit 0x00042015 1 RW uint32 b[0:0] - - - + - - - - rx_csr_sysref_alwayson 0x00042015 1 RW uint32 b[1:1] - - - + - - - - rx_csr_sysref_singled 0x00042015 1 RW uint32 b[2:2] - - - - - - - rx_csr_rbd_offset 0x00042015 1 RW uint32 b[10:3] - - - - - - - rx_csr_lmfc_offset 0x00042015 1 RW uint32 b[19:12] - - - + - - - - ctrl_reserve 0x00042016 1 RO uint32 b[31:0] - - - - - - - rx_err0 0x00042018 1 RW uint32 b[8:0] - - - - - - - rx_err1 0x00042019 1 RW uint32 b[9:0] - - - + - - - - rx_err_enable 0x0004201d 1 RW uint32 b[31:0] - - - + - - - - rx_err_link_reinit 0x0004201e 1 RW uint32 b[31:0] - - - - - - - csr_dev_syncn 0x00042020 1 RO uint32 b[0:0] - - - - - - - csr_rbd_count 0x00042020 1 RO uint32 b[10:3] - - - - - - - rx_status1 0x00042021 1 RW uint32 b[23:0] - - - diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_adc/tb_lofar2_unb2c_sdp_station_adc_jesd.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_adc/tb_lofar2_unb2c_sdp_station_adc_jesd.vhd index 5cf5c737e6530ee05b3721fe0e4d4a83315656e1..817155f4a16145c8ad74f626da15f0a3ad245af6 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_adc/tb_lofar2_unb2c_sdp_station_adc_jesd.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_adc/tb_lofar2_unb2c_sdp_station_adc_jesd.vhd @@ -49,6 +49,8 @@ -- > as 16 # for detailed debugging of JESD204B IP -- > run -a -- +-- View ait_sosi_arr, to see that only complete blocks are passed on. +-- ------------------------------------------------------------------------------- LIBRARY IEEE, common_lib, unb2c_board_lib, i2c_lib, mm_lib, dp_lib, diag_lib, lofar2_sdp_lib, wpfb_lib, lofar2_unb2c_sdp_station_lib, tech_jesd204b_lib; USE IEEE.std_logic_1164.ALL; @@ -114,6 +116,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_adc_jesd IS CONSTANT c_mm_file_reg_bsn_scheduler_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SCHEDULER"; CONSTANT c_mm_file_reg_diag_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_WG"; CONSTANT c_mm_file_reg_aduh_mon : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_ADUH_MONITOR"; + CONSTANT c_mm_file_reg_dp_shiftram : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_DP_SHIFTRAM"; CONSTANT c_mm_file_jesd204b : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "JESD204B"; CONSTANT c_mm_file_pio_jesd_ctrl : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "PIO_JESD_CTRL"; @@ -126,6 +129,9 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_adc_jesd IS SIGNAL pps_rst : STD_LOGIC := '1'; SIGNAL gen_pps : STD_LOGIC := '0'; + -- Input delay + SIGNAL rd_input_delay : NATURAL; + -- WG SIGNAL dbg_c_exp_wg_power_sp_0 : REAL := c_exp_wg_power_sp_0; SIGNAL sp_samples : t_integer_arr(0 TO c_mon_buffer_nof_samples-1) := (OTHERS=>0); @@ -204,11 +210,12 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_adc_jesd IS SIGNAL pio_jesd_ctrl_reset : STD_LOGIC; -- Debug signals to track progress of p_stimuli in Wave Window - SIGNAL dbg_restart : NATURAL := 0; - SIGNAL dbg_bsn_source_en : STD_LOGIC := '0'; - SIGNAL dbg_jesd_ctrl_reset : STD_LOGIC := '0'; - SIGNAL dbg_read_jesd204b : STD_LOGIC := '0'; - SIGNAL dbg_link_reinit : STD_LOGIC := '0'; + SIGNAL dbg_restart : NATURAL := 0; + SIGNAL dbg_bsn_source_en : STD_LOGIC := '0'; + SIGNAL dbg_jesd_ctrl_reset_ignore : STD_LOGIC := '0'; + SIGNAL dbg_jesd_ctrl_reset : STD_LOGIC := '0'; + SIGNAL dbg_read_jesd204b : STD_LOGIC := '0'; + SIGNAL dbg_link_reinit : STD_LOGIC := '0'; -- Read JESD204B IP status per signal input c_si PROCEDURE proc_read_jesd204b(c_si : IN NATURAL; @@ -471,11 +478,21 @@ BEGIN VARIABLE v_sp_power_sum_0 : REAL; VARIABLE v_sp_subband_power : REAL; VARIABLE v_W, v_T, v_U, v_S, v_B : NATURAL; -- array indicies + VARIABLE v_exp_input_delay : NATURAL; BEGIN dbg_restart <= 0; FOR REP IN 0 TO c_nof_restarts LOOP -- Wait for DUT power up after reset or after AIT rx_clk domain restart - WAIT FOR 1 us; + WAIT FOR 2 us; + + ---------------------------------------------------------------------------- + -- Set and readback input delay for si = 0 + ---------------------------------------------------------------------------- + v_exp_input_delay := 10 + REP; + mmf_mm_bus_wr(c_mm_file_reg_dp_shiftram, 0, v_exp_input_delay, tb_clk); + proc_common_wait_cross_clock_domain_latency(tb_clk, ext_clk); + mmf_mm_bus_rd(c_mm_file_reg_dp_shiftram, 0, rd_data, tb_clk); + rd_input_delay <= TO_UINT(rd_data); ---------------------------------------------------------------------------- -- Enable BS @@ -576,6 +593,31 @@ BEGIN ASSERT v_sp_power_sum_0 > c_lo_factor * c_exp_wg_power_sp_0 REPORT "Wrong SP power for SP 0" SEVERITY ERROR; ASSERT v_sp_power_sum_0 < c_hi_factor * c_exp_wg_power_sp_0 REPORT "Wrong SP power for SP 0" SEVERITY ERROR; + -- Try to reset via JESD_CTRL. This JESD_CTRL should be ignored. + -- Note: Awkward way to set MSbit without negative integer warning, using TO_SINT(v_word). + dbg_jesd_ctrl_reset_ignore <= '1'; -- marker in wave window + -- apply JESD_CTRL reset + v_word := (OTHERS => '0'); + v_word(c_sdp_jesd_ctrl_reset_bi) := '1'; -- reset + mmf_mm_bus_wr(c_mm_file_pio_jesd_ctrl, 0, TO_SINT(v_word), tb_clk); + proc_common_wait_cross_clock_domain_latency(tb_clk, ext_clk); + mmf_mm_bus_rd(c_mm_file_pio_jesd_ctrl, 0, rd_data, tb_clk); + pio_jesd_ctrl <= rd_data; + pio_jesd_ctrl_enable <= rd_data(c_sdp_jesd_ctrl_enable_w-1 DOWNTO 0); + pio_jesd_ctrl_reset <= rd_data(c_sdp_jesd_ctrl_reset_bi); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT pio_jesd_ctrl_reset = '0' REPORT "JESD_CTRL reset should be ignored when BSN source is on." SEVERITY ERROR; + -- remove JESD_CTRL reset + v_word := (OTHERS => '0'); + v_word(c_sdp_jesd_ctrl_reset_bi) := '0'; -- reset + mmf_mm_bus_wr(c_mm_file_pio_jesd_ctrl, 0, TO_SINT(v_word), tb_clk); + proc_common_wait_cross_clock_domain_latency(tb_clk, ext_clk); + mmf_mm_bus_rd(c_mm_file_pio_jesd_ctrl, 0, rd_data, tb_clk); + pio_jesd_ctrl <= rd_data; + pio_jesd_ctrl_enable <= rd_data(c_sdp_jesd_ctrl_enable_w-1 DOWNTO 0); + pio_jesd_ctrl_reset <= rd_data(c_sdp_jesd_ctrl_reset_bi); + dbg_jesd_ctrl_reset_ignore <= '0'; + ---------------------------------------------------------------------------- -- Restart AIT -- . JESD_CTRL reset stops JESD204B OUT rx_clk and asserts JESD204B OUT @@ -603,6 +645,8 @@ BEGIN pio_jesd_ctrl <= rd_data; pio_jesd_ctrl_enable <= rd_data(c_sdp_jesd_ctrl_enable_w-1 DOWNTO 0); pio_jesd_ctrl_reset <= rd_data(c_sdp_jesd_ctrl_reset_bi); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT pio_jesd_ctrl_reset = '1' REPORT "JESD_CTRL reset should be applied when BSN source is off." SEVERITY ERROR; WAIT FOR 1 us; -- Read Rx JESD_204B IP status during reset @@ -615,6 +659,12 @@ BEGIN reg_jesd204b_csr_rbd_count, reg_jesd204b_csr_dev_syncn); + -- Read input delay during reset + mmf_mm_bus_rd(c_mm_file_reg_dp_shiftram, 0, rd_data, tb_clk); + rd_input_delay <= TO_UINT(rd_data); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT rd_input_delay = v_exp_input_delay REPORT "wrong rd_input_delay during JESD reset." SEVERITY ERROR; + -- Hold JESD_CTRL reset for > one sync period, so also during a JESD204B_SYSREF pulse, -- to see that JESD_CTRL reset stops JESD204B OUT rx_sysref too. WAIT FOR c_pps_period; @@ -630,6 +680,12 @@ BEGIN pio_jesd_ctrl_reset <= rd_data(c_sdp_jesd_ctrl_reset_bi); dbg_jesd_ctrl_reset <= '0'; -- marker in wave window + -- Read input delay after reset + mmf_mm_bus_rd(c_mm_file_reg_dp_shiftram, 0, rd_data, tb_clk); + rd_input_delay <= TO_UINT(rd_data); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT rd_input_delay = v_exp_input_delay REPORT "wrong rd_input_delay after JESD reset." SEVERITY ERROR; + -- Wait for a JESD204B_SYSREF pulse WAIT FOR c_pps_period; -- Read Rx JESD_204B IP status diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd index d7f13a3d36a8bbe8dbb0ba7d4c6d5b86f60a3229..c249bdfbf36cd3bfb72c435d906390f3187bf112 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd @@ -211,6 +211,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS CONSTANT c_exp_ip_header_checksum : NATURAL := 16#5BDE#; -- value obtained from rx_sdp_cep_header.ip.header_checksum in wave window CONSTANT c_exp_beamlet_scale : NATURAL := NATURAL(g_beamlet_scale * REAL(c_sdp_unit_beamlet_scale)); -- c_sdp_unit_beamlet_scale = 2**15; + CONSTANT c_exp_beamlet_index : NATURAL := 0; -- depends on beamset bset * c_sdp_S_sub_bf CONSTANT c_exp_sdp_info : t_sdp_info := ( TO_UVEC(601, 16), -- station_id @@ -1213,57 +1214,68 @@ BEGIN -- Prepare exp_sdp_cep_header before rx_beamlet_sosi.eop, so that -- p_exp_sdp_cep_header can verify it at rx_beamlet_sosi.eop. - p_exp_sdp_cep_header : PROCESS(exp_dp_bsn) - BEGIN - -- eth header - exp_sdp_cep_header.eth.dst_mac <= c_cep_eth_dst_mac; - exp_sdp_cep_header.eth.src_mac <= c_cep_eth_src_mac; - exp_sdp_cep_header.eth.eth_type <= x"0800"; - - -- ip header - exp_sdp_cep_header.ip.version <= TO_UVEC( 4, c_network_ip_version_w); - exp_sdp_cep_header.ip.header_length <= TO_UVEC( 5, c_network_ip_header_length_w); - exp_sdp_cep_header.ip.services <= TO_UVEC( 0, c_network_ip_services_w); - exp_sdp_cep_header.ip.total_length <= c_sdp_cep_ip_total_length; -- 7868, see ICD STAT-CEP - exp_sdp_cep_header.ip.identification <= TO_UVEC( 0, c_network_ip_identification_w); - exp_sdp_cep_header.ip.flags <= TO_UVEC( 2, c_network_ip_flags_w); - exp_sdp_cep_header.ip.fragment_offset <= TO_UVEC( 0, c_network_ip_fragment_offset_w); - exp_sdp_cep_header.ip.time_to_live <= TO_UVEC( 127, c_network_ip_time_to_live_w); - exp_sdp_cep_header.ip.protocol <= TO_UVEC( 17, c_network_ip_protocol_w); - exp_sdp_cep_header.ip.header_checksum <= TO_UVEC( c_exp_ip_header_checksum, c_network_ip_header_checksum_w); - exp_sdp_cep_header.ip.src_ip_addr <= c_cep_ip_src_addr; -- c_network_ip_addr_w - exp_sdp_cep_header.ip.dst_ip_addr <= c_cep_ip_dst_addr; -- c_network_ip_addr_w - - -- udp header - exp_sdp_cep_header.udp.src_port <= c_cep_udp_src_port; - exp_sdp_cep_header.udp.dst_port <= c_cep_udp_dst_port; - exp_sdp_cep_header.udp.total_length <= c_sdp_cep_udp_total_length; -- 7848, see ICD STAT-CEP - exp_sdp_cep_header.udp.checksum <= TO_UVEC( 0, c_network_udp_checksum_w); - - -- app header - exp_sdp_cep_header.app.sdp_marker <= TO_UVEC(c_sdp_marker_beamlets, 8); -- 98 = x"62" = 'b' - exp_sdp_cep_header.app.sdp_version_id <= TO_UVEC(c_sdp_cep_version_id, 8); -- 5 - exp_sdp_cep_header.app.sdp_observation_id <= c_exp_sdp_info.observation_id; - exp_sdp_cep_header.app.sdp_station_id <= c_exp_sdp_info.station_id; - - exp_sdp_cep_header.app.sdp_source_info_antenna_band_id <= slv(c_exp_sdp_info.antenna_band_index); - exp_sdp_cep_header.app.sdp_source_info_nyquist_zone_id <= c_exp_sdp_info.nyquist_zone_index; - exp_sdp_cep_header.app.sdp_source_info_f_adc <= slv(c_exp_sdp_info.f_adc); - exp_sdp_cep_header.app.sdp_source_info_fsub_type <= slv(c_exp_sdp_info.fsub_type); - exp_sdp_cep_header.app.sdp_source_info_payload_error <= TO_UVEC(0, 1); - exp_sdp_cep_header.app.sdp_source_info_repositioning_flag <= slv(c_exp_sdp_info.beam_repositioning_flag); - exp_sdp_cep_header.app.sdp_source_info_beamlet_width <= TO_UVEC(c_sdp_W_beamlet, 4); - exp_sdp_cep_header.app.sdp_source_info_gn_id <= TO_UVEC(c_gn_index, 5); - - exp_sdp_cep_header.app.sdp_reserved <= TO_UVEC( 0, 40); - exp_sdp_cep_header.app.sdp_beamlet_scale <= TO_UVEC( c_exp_beamlet_scale, 16); - exp_sdp_cep_header.app.sdp_beamlet_index <= TO_UVEC( 0, 16); -- depends on bset - exp_sdp_cep_header.app.sdp_nof_blocks_per_packet <= TO_UVEC( c_sdp_cep_nof_blocks_per_packet, 8); - exp_sdp_cep_header.app.sdp_nof_beamlets_per_block <= TO_UVEC(c_sdp_cep_nof_beamlets_per_block, 16); - exp_sdp_cep_header.app.sdp_block_period <= c_exp_sdp_info.block_period; - - exp_sdp_cep_header.app.dp_bsn <= TO_UVEC(exp_dp_bsn, 64); -- depends on bset and time - END PROCESS; + exp_sdp_cep_header <= func_sdp_compose_cep_header(c_cep_eth_dst_mac, + c_cep_eth_src_mac, + c_cep_ip_src_addr, + c_cep_ip_dst_addr, + c_exp_ip_header_checksum, + c_exp_sdp_info, + c_gn_index, + c_exp_beamlet_scale, + c_exp_beamlet_index, + exp_dp_bsn); + + --p_exp_sdp_cep_header : PROCESS(exp_dp_bsn) + --BEGIN + -- -- eth header + -- exp_sdp_cep_header.eth.dst_mac <= c_cep_eth_dst_mac; + -- exp_sdp_cep_header.eth.src_mac <= c_cep_eth_src_mac; + -- exp_sdp_cep_header.eth.eth_type <= x"0800"; + -- + -- -- ip header + -- exp_sdp_cep_header.ip.version <= TO_UVEC( 4, c_network_ip_version_w); + -- exp_sdp_cep_header.ip.header_length <= TO_UVEC( 5, c_network_ip_header_length_w); + -- exp_sdp_cep_header.ip.services <= TO_UVEC( 0, c_network_ip_services_w); + -- exp_sdp_cep_header.ip.total_length <= c_sdp_cep_ip_total_length; -- 7868, see ICD STAT-CEP + -- exp_sdp_cep_header.ip.identification <= TO_UVEC( 0, c_network_ip_identification_w); + -- exp_sdp_cep_header.ip.flags <= TO_UVEC( 2, c_network_ip_flags_w); + -- exp_sdp_cep_header.ip.fragment_offset <= TO_UVEC( 0, c_network_ip_fragment_offset_w); + -- exp_sdp_cep_header.ip.time_to_live <= TO_UVEC( 127, c_network_ip_time_to_live_w); + -- exp_sdp_cep_header.ip.protocol <= TO_UVEC( 17, c_network_ip_protocol_w); + -- exp_sdp_cep_header.ip.header_checksum <= TO_UVEC( c_exp_ip_header_checksum, c_network_ip_header_checksum_w); + -- exp_sdp_cep_header.ip.src_ip_addr <= c_cep_ip_src_addr; -- c_network_ip_addr_w + -- exp_sdp_cep_header.ip.dst_ip_addr <= c_cep_ip_dst_addr; -- c_network_ip_addr_w + -- + -- -- udp header + -- exp_sdp_cep_header.udp.src_port <= c_cep_udp_src_port; + -- exp_sdp_cep_header.udp.dst_port <= c_cep_udp_dst_port; + -- exp_sdp_cep_header.udp.total_length <= c_sdp_cep_udp_total_length; -- 7848, see ICD STAT-CEP + -- exp_sdp_cep_header.udp.checksum <= TO_UVEC( 0, c_network_udp_checksum_w); + -- + -- -- app header + -- exp_sdp_cep_header.app.sdp_marker <= TO_UVEC(c_sdp_marker_beamlets, 8); -- 98 = x"62" = 'b' + -- exp_sdp_cep_header.app.sdp_version_id <= TO_UVEC(c_sdp_cep_version_id, 8); -- 5 + -- exp_sdp_cep_header.app.sdp_observation_id <= c_exp_sdp_info.observation_id; + -- exp_sdp_cep_header.app.sdp_station_id <= c_exp_sdp_info.station_id; + -- + -- exp_sdp_cep_header.app.sdp_source_info_antenna_band_id <= slv(c_exp_sdp_info.antenna_band_index); + -- exp_sdp_cep_header.app.sdp_source_info_nyquist_zone_id <= c_exp_sdp_info.nyquist_zone_index; + -- exp_sdp_cep_header.app.sdp_source_info_f_adc <= slv(c_exp_sdp_info.f_adc); + -- exp_sdp_cep_header.app.sdp_source_info_fsub_type <= slv(c_exp_sdp_info.fsub_type); + -- exp_sdp_cep_header.app.sdp_source_info_payload_error <= TO_UVEC(0, 1); + -- exp_sdp_cep_header.app.sdp_source_info_repositioning_flag <= slv(c_exp_sdp_info.beam_repositioning_flag); + -- exp_sdp_cep_header.app.sdp_source_info_beamlet_width <= TO_UVEC(c_sdp_W_beamlet, 4); + -- exp_sdp_cep_header.app.sdp_source_info_gn_id <= TO_UVEC(c_gn_index, 5); + -- + -- exp_sdp_cep_header.app.sdp_reserved <= TO_UVEC( 0, 40); + -- exp_sdp_cep_header.app.sdp_beamlet_scale <= TO_UVEC( c_exp_beamlet_scale, 16); + -- exp_sdp_cep_header.app.sdp_beamlet_index <= TO_UVEC( 0, 16); -- depends on bset + -- exp_sdp_cep_header.app.sdp_nof_blocks_per_packet <= TO_UVEC( c_sdp_cep_nof_blocks_per_packet, 8); + -- exp_sdp_cep_header.app.sdp_nof_beamlets_per_block <= TO_UVEC(c_sdp_cep_nof_beamlets_per_block, 16); + -- exp_sdp_cep_header.app.sdp_block_period <= c_exp_sdp_info.block_period; + -- + -- exp_sdp_cep_header.app.dp_bsn <= TO_UVEC(exp_dp_bsn, 64); -- depends on bset and time + --END PROCESS; rx_sdp_cep_header <= func_sdp_map_cep_header(rx_hdr_fields_raw); diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf_bst_offload.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf_bst_offload.vhd index 5930355ea60378745c482fe374b8f529f4f51448..dd52d4eb206cf007076a9b100f4e9e00400e8d28 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf_bst_offload.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf_bst_offload.vhd @@ -75,6 +75,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf_bst_offload IS CONSTANT c_nof_clk_per_sync : NATURAL := c_nof_block_per_sync*c_sdp_N_fft; CONSTANT c_pps_period : NATURAL := c_nof_clk_per_sync; CONSTANT c_wpfb_sim : t_wpfb := func_wpfb_set_nof_block_per_sync(c_sdp_wpfb_subbands, c_nof_block_per_sync); + CONSTANT c_nof_sync : NATURAL := 1; -- MM CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; @@ -88,12 +89,12 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf_bst_offload IS SIGNAL eth_done : STD_LOGIC := '0'; -- . 1GbE output - CONSTANT c_eth_check_nof_packets : NATURAL := 1; -- received packets in 1 sync period + CONSTANT c_eth_check_nof_packets : NATURAL := c_nof_sync * 1; CONSTANT c_eth_header_size : NATURAL := 19; -- words CONSTANT c_eth_crc_size : NATURAL := 1; -- word CONSTANT c_eth_packet_size : NATURAL := c_eth_header_size + c_eth_crc_size + (c_sdp_W_statistic / c_word_w) * c_sdp_S_sub_bf * c_sdp_N_pol; -- 20 + 2 * 488 * 2 = 1972 CONSTANT c_eth_check_nof_valid : NATURAL := c_eth_check_nof_packets * c_eth_packet_size; - CONSTANT c_eth_runtime_timeout : TIME := 2 * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done at the second sync interval + CONSTANT c_eth_runtime_timeout : TIME := (c_nof_sync + 1) * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done after c_nof_sync intervals -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; @@ -109,6 +110,16 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf_bst_offload IS SIGNAL eth_txp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); SIGNAL eth_rxp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); + -- Rx packets + SIGNAL eth_rx_sosi : t_dp_sosi; + SIGNAL eth_rx_data : STD_LOGIC_VECTOR(c_32-1 downto 0); + + -- Decode packets + SIGNAL rx_offload_sosi : t_dp_sosi; + SIGNAL rx_hdr_fields_out : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL rx_hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0'); + SIGNAL rx_sdp_stat_header : t_sdp_stat_header; + -- back transceivers SIGNAL JESD204B_SERIAL_DATA : STD_LOGIC_VECTOR(c_sdp_S_pn-1 downto 0); SIGNAL JESD204B_REFCLK : STD_LOGIC := '1'; @@ -200,7 +211,7 @@ BEGIN ---------------------------------------------------------------------------- -- Offload enable ---------------------------------------------------------------------------- - mmf_mm_bus_wr(c_mm_file_reg_stat_enable_bst, 0, 1, tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_stat_enable_bst, 0, 1, tb_clk); -- only beamset 0 -- wait for udp offload is done proc_common_wait_until_high(ext_clk, eth_done); @@ -224,9 +235,38 @@ BEGIN g_check_nof_valid => TRUE, g_check_nof_valid_ref => c_eth_check_nof_valid ) - PORT MAP ( + PORT MAP ( eth_serial_in => eth_txp(0), + eth_src_out => eth_rx_sosi, tb_end => eth_done ); + eth_rx_data <= eth_rx_sosi.data(c_32-1 DOWNTO 0); + + -- . Verify XST packet header + u_rx_statistics : ENTITY dp_lib.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_hdr_field_arr => c_sdp_stat_hdr_field_arr, + g_remove_crc => FALSE, + g_crc_nof_words => 0 + ) + PORT MAP ( + mm_rst => pps_rst, + mm_clk => tb_clk, + + dp_rst => pps_rst, + dp_clk => eth_clk(0), + + snk_in_arr(0) => eth_rx_sosi, + + src_out_arr(0) => rx_offload_sosi, + + hdr_fields_out_arr(0) => rx_hdr_fields_out, + hdr_fields_raw_arr(0) => rx_hdr_fields_raw + ); + + rx_sdp_stat_header <= func_sdp_map_stat_header(rx_hdr_fields_raw); + END tb; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub_sst_offload.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub_sst_offload.vhd index 80a3fbf828e332298152bccadb5b6ee33fe80641..5b14cb9aea233df7b59df0ff7031032d571d7f40 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub_sst_offload.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub_sst_offload.vhd @@ -74,6 +74,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub_sst_offload IS CONSTANT c_nof_clk_per_sync : NATURAL := c_nof_block_per_sync*c_sdp_N_fft; CONSTANT c_pps_period : NATURAL := c_nof_clk_per_sync; CONSTANT c_wpfb_sim : t_wpfb := func_wpfb_set_nof_block_per_sync(c_sdp_wpfb_subbands, c_nof_block_per_sync); + CONSTANT c_nof_sync : NATURAL := 2; -- MM CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; @@ -87,12 +88,12 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub_sst_offload IS SIGNAL eth_done : STD_LOGIC := '0'; -- . 1GbE output - CONSTANT c_eth_check_nof_packets : NATURAL := c_sdp_S_pn; -- received packets in 1 sync period + CONSTANT c_eth_check_nof_packets : NATURAL := c_nof_sync * c_sdp_S_pn; CONSTANT c_eth_header_size : NATURAL := 19; -- words CONSTANT c_eth_crc_size : NATURAL := 1; -- word CONSTANT c_eth_packet_size : NATURAL := c_eth_header_size + c_eth_crc_size + c_sdp_N_sub * (c_sdp_W_statistic / c_word_w); -- 20 + 512 * 2 = 1044 CONSTANT c_eth_check_nof_valid : NATURAL := c_eth_check_nof_packets * c_eth_packet_size; - CONSTANT c_eth_runtime_timeout : TIME := 2 * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done at the second sync interval + CONSTANT c_eth_runtime_timeout : TIME := (c_nof_sync + 1) * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done after c_nof_sync intervals -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; @@ -108,6 +109,16 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub_sst_offload IS SIGNAL eth_txp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); SIGNAL eth_rxp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); + -- Rx packets + SIGNAL eth_rx_sosi : t_dp_sosi; + SIGNAL eth_rx_data : STD_LOGIC_VECTOR(c_32-1 downto 0); + + -- Decode packets + SIGNAL rx_offload_sosi : t_dp_sosi; + SIGNAL rx_hdr_fields_out : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL rx_hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0'); + SIGNAL rx_sdp_stat_header : t_sdp_stat_header; + -- back transceivers SIGNAL JESD204B_SERIAL_DATA : STD_LOGIC_VECTOR(c_sdp_S_pn-1 downto 0); SIGNAL JESD204B_REFCLK : STD_LOGIC := '1'; @@ -225,7 +236,36 @@ BEGIN ) PORT MAP ( eth_serial_in => eth_txp(0), + eth_src_out => eth_rx_sosi, tb_end => eth_done ); + eth_rx_data <= eth_rx_sosi.data(c_32-1 DOWNTO 0); + + -- . Verify XST packet header + u_rx_statistics : ENTITY dp_lib.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_hdr_field_arr => c_sdp_stat_hdr_field_arr, + g_remove_crc => FALSE, + g_crc_nof_words => 0 + ) + PORT MAP ( + mm_rst => pps_rst, + mm_clk => tb_clk, + + dp_rst => pps_rst, + dp_clk => eth_clk(0), + + snk_in_arr(0) => eth_rx_sosi, + + src_out_arr(0) => rx_offload_sosi, + + hdr_fields_out_arr(0) => rx_hdr_fields_out, + hdr_fields_raw_arr(0) => rx_hdr_fields_raw + ); + + rx_sdp_stat_header <= func_sdp_map_stat_header(rx_hdr_fields_raw); + END tb; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_xsub_one/tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_xsub_one/tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload.vhd index 8219a71f3fe2fbf6a0159224c884afb7a95321b9..a11dac56788bf43d7cbb73d8bfba830f7a65832e 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_xsub_one/tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_xsub_one/tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload.vhd @@ -76,11 +76,17 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload IS CONSTANT c_pps_period : NATURAL := c_nof_clk_per_sync; CONSTANT c_wpfb_sim : t_wpfb := func_wpfb_set_nof_block_per_sync(c_sdp_wpfb_subbands, c_nof_block_per_sync); CONSTANT c_ctrl_interval_size : NATURAL := c_nof_clk_per_sync; + CONSTANT c_subband_select_arr : t_natural_arr(0 TO c_sdp_N_crosslets_max-1) := (10, 11, 12, 13, 14, 15, 16); + CONSTANT c_subband_step : NATURAL := 0; + CONSTANT c_nof_crosslets : NATURAL := 3; + CONSTANT c_nof_sync : NATURAL := 2; -- MM CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; - CONSTANT c_mm_file_reg_stat_enable_xst : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_STAT_ENABLE_XST"; + CONSTANT c_mm_file_reg_crosslets_info : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_CROSSLETS_INFO"; + CONSTANT c_mm_file_reg_nof_crosslets : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_NOF_CROSSLETS"; CONSTANT c_mm_file_reg_bsn_sync_scheduler_xsub : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SYNC_SCHEDULER_XSUB"; + CONSTANT c_mm_file_reg_stat_enable_xst : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_STAT_ENABLE_XST"; -- Tb SIGNAL tb_end : STD_LOGIC := '0'; @@ -90,12 +96,12 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload IS SIGNAL eth_done : STD_LOGIC := '0'; -- . 1GbE output - CONSTANT c_eth_check_nof_packets : NATURAL := 1; -- received packets in 1 sync period + CONSTANT c_eth_check_nof_packets : NATURAL := c_nof_sync * c_nof_crosslets; CONSTANT c_eth_header_size : NATURAL := 19; -- words CONSTANT c_eth_crc_size : NATURAL := 1; -- word - CONSTANT c_eth_packet_size : NATURAL := c_eth_header_size + c_eth_crc_size + (c_sdp_W_statistic / c_word_w) * c_sdp_S_pn * c_sdp_S_pn * c_nof_complex; -- 20 + 2 * 12 * 12 * 2 = 596 + CONSTANT c_eth_packet_size : NATURAL := c_eth_header_size + c_eth_crc_size + (c_sdp_W_statistic / c_word_w) * c_sdp_S_pn * c_sdp_S_pn * c_nof_complex; -- 20 + 2 * 12 * 12 * 2 = 596 CONSTANT c_eth_check_nof_valid : NATURAL := c_eth_check_nof_packets * c_eth_packet_size; - CONSTANT c_eth_runtime_timeout : TIME := 3 * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done at the third sync interval + CONSTANT c_eth_runtime_timeout : TIME := (c_nof_sync + 2) * c_nof_clk_per_sync * c_ext_clk_period; -- eth statistics should be done after c_nof_sync -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; @@ -111,6 +117,16 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_xsub_one_xst_offload IS SIGNAL eth_txp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); SIGNAL eth_rxp : STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 downto 0) := (OTHERS => '0'); + -- Rx packets + SIGNAL eth_rx_sosi : t_dp_sosi; + SIGNAL eth_rx_data : STD_LOGIC_VECTOR(c_32-1 downto 0); + + -- Decode packets + SIGNAL rx_offload_sosi : t_dp_sosi; + SIGNAL rx_hdr_fields_out : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL rx_hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0'); + SIGNAL rx_sdp_stat_header : t_sdp_stat_header; + -- back transceivers SIGNAL JESD204B_SERIAL_DATA : STD_LOGIC_VECTOR(c_sdp_S_pn-1 downto 0); SIGNAL JESD204B_REFCLK : STD_LOGIC := '1'; @@ -204,15 +220,26 @@ BEGIN pps_rst <= '0'; ---------------------------------------------------------------------------- - -- Enable xsub + -- Setup and enable xsub ---------------------------------------------------------------------------- + + -- Crosslets info + FOR I IN 0 TO c_sdp_N_crosslets_max-1 LOOP + mmf_mm_bus_wr(c_mm_file_reg_crosslets_info, I, c_subband_select_arr(I), tb_clk); -- offsets + END LOOP; + mmf_mm_bus_wr(c_mm_file_reg_crosslets_info, 15, c_subband_step, tb_clk); -- step size + + -- Number of crosslets + mmf_mm_bus_wr(c_mm_file_reg_nof_crosslets, 0, c_nof_crosslets, tb_clk); + + -- Integration interval and enable mmf_mm_bus_wr(c_mm_file_reg_bsn_sync_scheduler_xsub, 1, c_ctrl_interval_size, tb_clk); -- Interval size mmf_mm_bus_wr(c_mm_file_reg_bsn_sync_scheduler_xsub, 2, c_nof_block_per_sync, tb_clk); -- first write bsn low then bsn high part mmf_mm_bus_wr(c_mm_file_reg_bsn_sync_scheduler_xsub, 3, 0, tb_clk); -- bsn high, assume v_bsn < 2**31-1 mmf_mm_bus_wr(c_mm_file_reg_bsn_sync_scheduler_xsub, 0, 1, tb_clk); -- enable ---------------------------------------------------------------------------- - -- Offload enable + -- XST offload enable ---------------------------------------------------------------------------- mmf_mm_bus_wr(c_mm_file_reg_stat_enable_xst, 0, 1, tb_clk); @@ -229,8 +256,9 @@ BEGIN END PROCESS; ------------------------------------------------------------------------- - -- Verify proper DUT 1GbE offload output using Ethernet packet statistics + -- Verify proper DUT 1GbE offload output ------------------------------------------------------------------------- + -- . Verify Ethernet packet statistics u_eth_statistics : ENTITY eth_lib.eth_statistics GENERIC MAP ( g_runtime_nof_packets => c_eth_check_nof_packets, @@ -240,7 +268,36 @@ BEGIN ) PORT MAP ( eth_serial_in => eth_txp(0), + eth_src_out => eth_rx_sosi, tb_end => eth_done ); + eth_rx_data <= eth_rx_sosi.data(c_32-1 DOWNTO 0); + + -- . Verify XST packet header + u_rx_statistics : ENTITY dp_lib.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_hdr_field_arr => c_sdp_stat_hdr_field_arr, + g_remove_crc => FALSE, + g_crc_nof_words => 0 + ) + PORT MAP ( + mm_rst => pps_rst, + mm_clk => tb_clk, + + dp_rst => pps_rst, + dp_clk => eth_clk(0), + + snk_in_arr(0) => eth_rx_sosi, + + src_out_arr(0) => rx_offload_sosi, + + hdr_fields_out_arr(0) => rx_hdr_fields_out, + hdr_fields_raw_arr(0) => rx_hdr_fields_raw + ); + + rx_sdp_stat_header <= func_sdp_map_stat_header(rx_hdr_fields_raw); + END tb; diff --git a/applications/lofar2/doc/prestudy/lift_lightning.txt b/applications/lofar2/doc/prestudy/lift_lightning.txt new file mode 100644 index 0000000000000000000000000000000000000000..c647d462e54725f240bf3a51c2701c8ba58a856a --- /dev/null +++ b/applications/lofar2/doc/prestudy/lift_lightning.txt @@ -0,0 +1,28 @@ + + + +1) LIFT 27 June 2022 meeting + +https://support.astron.nl/confluence/display/L2M/2022-06-27+LIFT+system+implementation+meeting+notes + +a) Transient buffer: +- only raw, no subband data +- cosmic ray uses all antennas of one station, lightning ~ 6 antennas but all Dutch stations + . 6 dual pol antennas per station with long baselines + . 96 LBA --> 8 - 16 possible useful combinations of 6 antennas --> dependent on RCU allocation +- cosmic ray is commensal, lightning is dedicated mode +- cosmic ray 2 ms event, lightning 1 s events +- individually controlled antenna buffers +- read out via 10GbE via LCU (with local storage, later TCP to CEP) or directly to CEP (UDP) + . one signal input for 1 s takes 200M * 16b = 0.4 GByte = 3.2 Gbit, so 0.3 s + . 192 signal inputs for 1 s takes 3.2 Gbit * 192 ~= 0.6 Tbit, so 60 s +- 2 * 8 GB / (12 * 16b / 8b * 0.2 GHz) = 3.33 s seems enough storage + . 3.33 * 16b / 14b = 3.81 s + . header overhead 5 % --> 3.81 * 0.95 = 3.61 s + +b) Transient detection: +- notch filter ? +- transient detection based on power after 40 - 80 MHz BPF +- measure power during 10 us to detect pulse, if > threshold then send pulse detection events + per signal input via 1GbE +- e.g. use dead time after a detection to avoid storm of event messages diff --git a/applications/lofar2/images/images.txt b/applications/lofar2/images/images.txt index 4b35ff48de1d38867791841c2039091ec93b9c42..341a2e0d00c96fd10ee5e2f0f7915fe90bef5451 100644 --- a/applications/lofar2/images/images.txt +++ b/applications/lofar2/images/images.txt @@ -11,5 +11,7 @@ lofar2_unb2b_sdp_station_xsub_one-r087d98be6 | 2021-06-14 | R vd Walle unb2b_minimal-rce6b96eed | 2021-08-26 | P. Donker | unb2b_minimal with new mmap, rbf maid with option --unb2_factory lofar2_unb2b_sdp_station_full-r9ff51058a | 2022-01-12 | R vd Walle | Old Lofar2 SDP station full design for UniBoard2b without ring. lofar2_unb2b_sdp_station_full-r2c3958e1f | 2022-04-29 | R vd Walle | Lofar2 SDP station full design for UniBoard2b. -lofar2_unb2b_sdp_station_full_wg-r241070441 | 2022-04-13 | R vd Walle | Lofar2 SDP station design without ADC inputs, only WG. Uses dp_clk + dp_pps instead of rx_clk + rx_sysref. +lofar2_unb2b_sdp_station_full_wg-r70b28ffc3 | 2022-06-15 | R vd Walle | Lofar2 SDP station design without ADC inputs, only WG. Uses dp_clk + dp_pps instead of rx_clk + rx_sysref. +lofar2_unb2b_sdp_station_full_wg-rf8e898438 | 2022-07-11 | R vd Walle | Lofar2 SDP station design without ADC inputs, only WG. Uses dp_clk + dp_pps instead of rx_clk + rx_sysref. lofar2_unb2c_sdp_station_full-r70484fd08 | 2022-04-29 | R vd Walle | Lofar2 SDP station full design for UniBoard2c. +lofar2_unb2c_sdp_station_full-rf8e898438 | 2022-07-11 | R vd Walle | Lofar2 SDP station full design for UniBoard2c. diff --git a/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r241070441.tar.gz b/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r241070441.tar.gz deleted file mode 100644 index 3da58680470a8eb1488dd7127ad5ccef85a2d6e7..0000000000000000000000000000000000000000 Binary files a/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r241070441.tar.gz and /dev/null differ diff --git a/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r70b28ffc3.tar.gz b/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r70b28ffc3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3ff9e5eb8f7267e683133f0d70425b36398bada8 Binary files /dev/null and b/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-r70b28ffc3.tar.gz differ diff --git a/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-rf8e898438.tar.gz b/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-rf8e898438.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9920dd7f307b96622cc35684b1d348a2f36be47d Binary files /dev/null and b/applications/lofar2/images/lofar2_unb2b_sdp_station_full_wg-rf8e898438.tar.gz differ diff --git a/applications/lofar2/images/lofar2_unb2c_sdp_station_full-rf8e898438.tar.gz b/applications/lofar2/images/lofar2_unb2c_sdp_station_full-rf8e898438.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..308eb264cbb7a46b94a3ba6db271e4b0e222d27a Binary files /dev/null and b/applications/lofar2/images/lofar2_unb2c_sdp_station_full-rf8e898438.tar.gz differ diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd index 5b110bfb743ac919ebcbfabb9466f16cb0b9a54e..6fa7c9cf74f206ff9710b89107ab1822c7f389f4 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd @@ -140,9 +140,11 @@ ARCHITECTURE str OF node_sdp_adc_input_and_timing IS SIGNAL nxt_mux_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); SIGNAL st_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); - SIGNAL mm_rst_internal : STD_LOGIC; - SIGNAL mm_jesd_ctrl_reg : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mm_rst_jesd : STD_LOGIC; + SIGNAL mm_jesd_ctrl_reg_wr : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + SIGNAL mm_jesd_ctrl_reg_rd : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); SIGNAL jesd204b_disable_arr : STD_LOGIC_VECTOR(c_sdp_S_pn-1 DOWNTO 0); + SIGNAL jesd204b_reset_request : STD_LOGIC := '0'; BEGIN @@ -152,18 +154,30 @@ BEGIN rx_sysref <= dp_pps; END GENERATE; - -- The node AIT is reset at power up by mm_rst and under software control by jesd204b_disable_arr. - -- The mm_rst internal will cause a reset on the rx_rst by the reset sequencer in the u_jesd204b. - -- The MM jesd204b_disable_arr is intended for node AIT resynchronisation tests of the u_jesd204b. - -- The MM jesd204b_disable_arr should not be applied in an SDP application, because this will cause + -- The node AIT is reset at power up by mm_rst and under software control by mm_rst_jesd. + -- The mm_rst_jesd will cause a reset on the rx_rst by the reset sequencer in the u_jesd204b. + -- The mm_rst_jesd is intended for node AIT resynchronisation tests of the u_jesd204b. + -- The mm_rst_jesd should not be applied in an active SDP application, because this will cause -- a disturbance in the block timing of the out_sosi_arr(i).sync,bsn,sop,eop. The other logic -- in an SDP application assumes that the block timing of the out_sosi_arr(i) only contains - -- complete blocks, so from sop to eop. + -- complete blocks, so from sop to eop. Therefore, first mms_dp_bsn_source_v2 should be + -- disabled to stop and flush the block processing, before applying mm_rst_jesd. - mm_rst_internal <= mm_rst OR mm_jesd_ctrl_reg(c_sdp_jesd_ctrl_reset_bi); - gen_jesd_disable : FOR I IN 0 TO c_sdp_S_pn-1 GENERATE - jesd204b_disable_arr(i) <= mm_jesd_ctrl_reg(i); - END GENERATE; + -- Only accept JESD204B IP reset when the processing is disabled (indicated by bs_sosi.valid + -- = '0'), to avoid corrupt bs_sosi blocks entering the subsequent processing due to that a + -- JESD204B IP reset causes that the rx_clk stops. + mm_rst_jesd <= mm_rst OR jesd204b_reset_request; + + jesd204b_disable_arr <= mm_jesd_ctrl_reg_wr(c_sdp_S_pn-1 DOWNTO 0); + jesd204b_reset_request <= mm_jesd_ctrl_reg_wr(c_sdp_jesd_ctrl_reset_bi) AND NOT bs_sosi.valid; + + p_mm_jesd_ctrl_reg_rd : PROCESS(mm_jesd_ctrl_reg_wr, jesd204b_reset_request) + BEGIN + -- default readback what was written + mm_jesd_ctrl_reg_rd <= mm_jesd_ctrl_reg_wr; + -- report actual JESD204B reset status + mm_jesd_ctrl_reg_rd(c_sdp_jesd_ctrl_reset_bi) <= jesd204b_reset_request; + END PROCESS; gen_jesd : IF g_no_jesd = FALSE GENERATE ----------------------------------------------------------------------------- @@ -191,7 +205,7 @@ BEGIN -- MM mm_clk => mm_clk, - mm_rst => mm_rst_internal, + mm_rst => mm_rst_jesd, jesd204b_mosi => jesd204b_mosi, jesd204b_miso => jesd204b_miso, @@ -200,8 +214,7 @@ BEGIN serial_tx_arr => open, serial_rx_arr => JESD204B_SERIAL_DATA(c_sdp_S_pn-1 downto 0) ); - - + ----------------------------------------------------------------------------- -- Time delay: dp_shiftram -- . copied from unb1_bn_capture_input (apertif) @@ -214,13 +227,12 @@ BEGIN dp_shiftram_snk_in_arr <= rx_sosi_arr; FOR I IN 0 TO c_sdp_S_pn-1 LOOP -- ADC data is stored in the upper 14 bits of the jesd rx_sosi. - dp_shiftram_snk_in_arr(I).data <= RESIZE_DP_SDATA(rx_sosi_arr(I).data(c_sdp_W_adc_jesd-1 DOWNTO (c_sdp_W_adc_jesd - c_sdp_W_adc) )); + dp_shiftram_snk_in_arr(I).data <= RESIZE_DP_SDATA(rx_sosi_arr(I).data(c_sdp_W_adc_jesd-1 DOWNTO (c_sdp_W_adc_jesd - c_sdp_W_adc) )); -- Force valid. - dp_shiftram_snk_in_arr(I).valid <= '1'; + dp_shiftram_snk_in_arr(I).valid <= '1'; END LOOP; END PROCESS; - u_dp_shiftram : ENTITY dp_lib.dp_shiftram GENERIC MAP ( g_nof_streams => c_sdp_S_pn, @@ -232,7 +244,7 @@ BEGIN dp_rst => rx_rst, dp_clk => rx_clk, - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, sync_in => bs_sosi.sync, @@ -258,7 +270,7 @@ BEGIN ) PORT MAP ( -- Clocks and reset - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, dp_rst => rx_rst, dp_clk => rx_clk, @@ -281,7 +293,7 @@ BEGIN ) PORT MAP ( -- Memory-mapped clock domain - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, reg_mosi => reg_bsn_scheduler_wg_mosi, @@ -318,7 +330,7 @@ BEGIN ) PORT MAP ( -- Memory-mapped clock domain - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, reg_mosi => reg_wg_mosi, @@ -387,7 +399,7 @@ BEGIN ) PORT MAP ( -- Memory-mapped clock domain - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, reg_mosi => reg_bsn_monitor_input_mosi, reg_miso => reg_bsn_monitor_input_miso, @@ -412,7 +424,7 @@ BEGIN ) PORT MAP ( -- Memory-mapped clock domain - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, reg_mosi => reg_aduh_monitor_mosi, -- read only access to the signal path data mean sum and power sum registers @@ -440,7 +452,7 @@ BEGIN g_buf_use_sync => TRUE -- when TRUE start filling the buffer at the in_sync, else after the last word was read ) PORT MAP ( - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, dp_rst => rx_rst, dp_clk => rx_clk, @@ -466,7 +478,7 @@ BEGIN g_nof_data_per_sync_diff => c_sdp_N_fft/2 ) PORT MAP ( - mm_rst => mm_rst_internal, + mm_rst => mm_rst, mm_clk => mm_clk, dp_rst => rx_rst, dp_clk => rx_clk, @@ -527,8 +539,8 @@ BEGIN rd_dat => jesd_ctrl_miso.rddata(c_sdp_mm_jesd_ctrl_reg.dat_w-1 DOWNTO 0), rd_val => OPEN, -- data side - out_reg => mm_jesd_ctrl_reg, - in_reg => mm_jesd_ctrl_reg + out_reg => mm_jesd_ctrl_reg_wr, + in_reg => mm_jesd_ctrl_reg_rd ); END str; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_correlator.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_correlator.vhd index ec8180f396e3c3a6837878b26792c6f01f29274b..43c17b7a7734a746960722a9ccb37fe0a608027f 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_correlator.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_correlator.vhd @@ -325,7 +325,7 @@ BEGIN g_use_mm_output => TRUE, g_rd_latency => 1, -- Required for st_xst -- for mms_dp_bsn_monitor_v2 - g_nof_clk_per_sync => c_sdp_N_clk_sync_timeout, -- Using c_sdp_N_clk_sync_timeout as g_nof_clk_per_sync is used for BSN monitor timeout. + g_nof_clk_per_sync => c_sdp_N_clk_sync_timeout_xsub, -- Using c_sdp_N_clk_sync_timeout_xsub as g_nof_clk_per_sync is used for BSN monitor timeout. g_nof_input_bsn_monitors => g_P_sq, g_use_bsn_output_monitor => TRUE ) @@ -436,10 +436,11 @@ BEGIN xst_udp_sosi <= mon_xst_udp_sosi_arr(0); u_sdp_xst_udp_offload: ENTITY work.sdp_statistics_offload GENERIC MAP ( - g_statistics_type => "XST", - g_offload_time => sel_a_b(g_sim, g_sim_sdp.offload_time, c_sdp_offload_time), - g_P_sq => g_P_sq, - g_crosslets_direction => 1 -- = lane direction + g_statistics_type => "XST", + g_offload_time => sel_a_b(g_sim, g_sim_sdp.offload_time, c_sdp_offload_time), + g_P_sq => g_P_sq, + g_crosslets_direction => 1, -- = lane direction + g_bsn_monitor_sync_timeout => c_sdp_N_clk_sync_timeout_xsub ) PORT MAP ( mm_clk => mm_clk, diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index 7fe6896838ac5d2c86cb3e6e0444368a82759418..ff1b1565b89a30808872ffaf4392ce4ca297bac8 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -69,7 +69,6 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_N_cross_sets_sdp : NATURAL := 1; CONSTANT c_sdp_N_crosslets_max : NATURAL := 7; CONSTANT c_sdp_N_fft : NATURAL := 1024; - CONSTANT c_sdp_N_pn_lb : NATURAL := 16; CONSTANT c_sdp_N_pn_max : NATURAL := 16; -- gn 0:31 --> pn 0:15, pn 0:15 per antenna band CONSTANT c_sdp_N_pol : NATURAL := 2; CONSTANT c_sdp_N_pol_bf : NATURAL := 2; @@ -110,23 +109,24 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_N_ring_nof_mac10g : NATURAL := 3; -- for sdp_station_xsub_ring design. -- Derived constants - CONSTANT c_sdp_FS_adc : NATURAL := 2**(c_sdp_W_adc - 1); -- full scale FS corresponds to amplitude 1.0, will just cause clipping of +FS to +FS-1 - CONSTANT c_sdp_wg_ampl_lsb : REAL := c_diag_wg_ampl_unit / REAL(c_sdp_FS_adc); -- WG amplitude in number of LSbit resolution steps - CONSTANT c_sdp_wg_subband_freq_unit : REAL := c_diag_wg_freq_unit/REAL(c_sdp_N_fft); -- subband freq = Fs/1024 = 200 MSps/1024 = 195312.5 Hz sinus - CONSTANT c_sdp_N_clk_per_sync : NATURAL := c_sdp_f_adc_MHz*10**6; -- Default 200M clock cycles per second - CONSTANT c_sdp_N_clk_sync_timeout : NATURAL := c_sdp_f_adc_MHz*10**6 + c_sdp_f_adc_MHz*10**5; -- 10% margin. - CONSTANT c_sdp_N_sync_jesd : NATURAL := c_sdp_S_pn * c_sdp_N_sync_rcu / c_sdp_S_rcu; -- = 4, nof JESD IP sync outputs per PN - CONSTANT c_sdp_f_sub_Hz : REAL := REAL(c_sdp_f_adc_MHz * 10**6) / REAL(c_sdp_N_fft); - CONSTANT c_sdp_N_int : NATURAL := c_sdp_f_adc_MHz * 10**6; -- nof ADC sample periods per 1 s integration interval - CONSTANT c_sdp_N_int_sub : REAL := c_sdp_f_sub_Hz; -- nof subband sample periods per 1 s integration interval - CONSTANT c_sdp_A_pn : NATURAL := c_sdp_S_pn / c_sdp_N_pol; -- = 6 dual pol antenna per PN, is 6 signal input pairs - CONSTANT c_sdp_P_pfb : NATURAL := c_sdp_S_pn / c_sdp_Q_fft; -- = 6 PFB units, for 6 signal input pairs - CONSTANT c_sdp_T_adc : TIME := (10**6 / c_sdp_f_adc_MHz) * 1 ps; -- = 5 ns @ 200MHz - CONSTANT c_sdp_T_sub : TIME := c_sdp_N_fft * c_sdp_T_adc; -- = 5.12 us @ 200MHz - CONSTANT c_sdp_W_bf_product : NATURAL := c_sdp_W_subband + c_sdp_W_bf_weight -1; - CONSTANT c_sdp_X_sq : NATURAL := c_sdp_S_pn * c_sdp_S_pn; -- = 144 - CONSTANT c_sdp_block_period : NATURAL := c_sdp_N_fft * 1000 / c_sdp_f_adc_MHz; -- = 5120 [ns] - CONSTANT c_sdp_N_beamlets_sdp : NATURAL := c_sdp_N_beamsets * c_sdp_S_sub_bf; -- = 976 + CONSTANT c_sdp_FS_adc : NATURAL := 2**(c_sdp_W_adc - 1); -- full scale FS corresponds to amplitude 1.0, will just cause clipping of +FS to +FS-1 + CONSTANT c_sdp_wg_ampl_lsb : REAL := c_diag_wg_ampl_unit / REAL(c_sdp_FS_adc); -- WG amplitude in number of LSbit resolution steps + CONSTANT c_sdp_wg_subband_freq_unit : REAL := c_diag_wg_freq_unit/REAL(c_sdp_N_fft); -- subband freq = Fs/1024 = 200 MSps/1024 = 195312.5 Hz sinus + CONSTANT c_sdp_N_clk_per_sync : NATURAL := c_sdp_f_adc_MHz*10**6; -- Default 200M clock cycles per second + CONSTANT c_sdp_N_clk_sync_timeout : NATURAL := c_sdp_f_adc_MHz*10**6 + c_sdp_f_adc_MHz*10**5; -- 10% margin. + CONSTANT c_sdp_N_clk_sync_timeout_xsub : NATURAL := 2**31 - 1; -- 10.7 seconds = largest value for NATURAL. + CONSTANT c_sdp_N_sync_jesd : NATURAL := c_sdp_S_pn * c_sdp_N_sync_rcu / c_sdp_S_rcu; -- = 4, nof JESD IP sync outputs per PN + CONSTANT c_sdp_f_sub_Hz : REAL := REAL(c_sdp_f_adc_MHz * 10**6) / REAL(c_sdp_N_fft); + CONSTANT c_sdp_N_int : NATURAL := c_sdp_f_adc_MHz * 10**6; -- nof ADC sample periods per 1 s integration interval + CONSTANT c_sdp_N_int_sub : REAL := c_sdp_f_sub_Hz; -- nof subband sample periods per 1 s integration interval + CONSTANT c_sdp_A_pn : NATURAL := c_sdp_S_pn / c_sdp_N_pol; -- = 6 dual pol antenna per PN, is 6 signal input pairs + CONSTANT c_sdp_P_pfb : NATURAL := c_sdp_S_pn / c_sdp_Q_fft; -- = 6 PFB units, for 6 signal input pairs + CONSTANT c_sdp_T_adc : TIME := (10**6 / c_sdp_f_adc_MHz) * 1 ps; -- = 5 ns @ 200MHz + CONSTANT c_sdp_T_sub : TIME := c_sdp_N_fft * c_sdp_T_adc; -- = 5.12 us @ 200MHz + CONSTANT c_sdp_W_bf_product : NATURAL := c_sdp_W_subband + c_sdp_W_bf_weight -1; + CONSTANT c_sdp_X_sq : NATURAL := c_sdp_S_pn * c_sdp_S_pn; -- = 144 + CONSTANT c_sdp_block_period : NATURAL := c_sdp_N_fft * 1000 / c_sdp_f_adc_MHz; -- = 5120 [ns] + CONSTANT c_sdp_N_beamlets_sdp : NATURAL := c_sdp_N_beamsets * c_sdp_S_sub_bf; -- = 976 -- . unit weights CONSTANT c_sdp_unit_sub_weight : NATURAL := 2**c_sdp_W_sub_weight_fraction; -- 2**13, so range +-4.0 for 16 bit signed weight @@ -199,7 +199,7 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_stat_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608"; -- 00:22:86:08:pp:qq CONSTANT c_sdp_stat_ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"0A6300FE"; -- 0A6300FE = '10.99.0.254' = DOP36-enp2s0 CONSTANT c_sdp_stat_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"0A63"; -- 10.99.xx.yy - CONSTANT c_sdp_stat_udp_dst_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5001, 16); + CONSTANT c_sdp_stat_udp_dst_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5001, 16); -- 0x1389 = 5001 CONSTANT c_sdp_sst_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D0"; -- TBC, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0]) CONSTANT c_sdp_bst_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D1"; -- TBC CONSTANT c_sdp_xst_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D2"; -- TBC @@ -319,7 +319,7 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_cep_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"C0A8"; -- 31:16, 15:8 = backplane, 7:0 = node + 1 = 192.168.xx.yy CONSTANT c_sdp_cep_ip_total_length : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(7868, 16); -- see ICD STAT-CEP CONSTANT c_sdp_cep_udp_total_length : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(7848, 16); -- see ICD STAT-CEP - CONSTANT c_sdp_cep_udp_dst_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5000, 16); + CONSTANT c_sdp_cep_udp_dst_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5000, 16); -- 0x1380 = 5000 CONSTANT c_sdp_cep_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D0"; -- 15:8, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0]) CONSTANT c_sdp_cep_app_header_len : NATURAL := 32; @@ -567,6 +567,7 @@ PACKAGE sdp_pkg is FUNCTION func_sdp_get_stat_app_total_length(g_statistics_type : STRING) RETURN NATURAL; FUNCTION func_sdp_get_stat_udp_total_length(g_statistics_type : STRING) RETURN NATURAL; FUNCTION func_sdp_get_stat_ip_total_length(g_statistics_type : STRING) RETURN NATURAL; + FUNCTION func_sdp_get_stat_udp_src_port(g_statistics_type : STRING; gn_index : NATURAL) RETURN STD_LOGIC_VECTOR; FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING; S_pn, P_sq, N_crosslets : NATURAL) RETURN NATURAL; FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING) RETURN NATURAL; -- use c_sdp_S_pn, c_sdp_P_sq, c_sdp_N_crosslets_max @@ -592,8 +593,7 @@ PACKAGE BODY sdp_pkg IS -- pn_index = gn_index MOD c_sdp_N_pn_max -- -- The c_sdp_N_pn_max = 16 fits the LB and HB of LOFAR2: - -- . The LB starts at GN index = 0 and has c_sdp_N_pn_lb = c_sdp_N_pn_max - -- = 16 nodes. + -- . The LB starts at GN index = 0 and has c_sdp_N_pn_max = 16 nodes. -- . The HB starts at GN index = c_sdp_N_pn_max, and has 8 or 16 nodes -- dependent on the type of station. -- @@ -703,6 +703,14 @@ PACKAGE BODY sdp_pkg IS RETURN c_sdp_udp_total_length + c_network_ip_header_len; END func_sdp_get_stat_ip_total_length; + FUNCTION func_sdp_get_stat_udp_src_port(g_statistics_type : STRING; gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS + CONSTANT c_gn_index : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(gn_index, 8); + BEGIN + RETURN sel_a_b(g_statistics_type="BST", c_sdp_bst_udp_src_port_15_8 & c_gn_index, -- BST = 0xD0 & gn_index + sel_a_b(g_statistics_type="XST", c_sdp_xst_udp_src_port_15_8 & c_gn_index, -- XST = 0xD1 & gn_index + c_sdp_sst_udp_src_port_15_8 & c_gn_index)); -- SST = 0xD2 & gn_index + END func_sdp_get_stat_udp_src_port; + FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING; S_pn, P_sq, N_crosslets : NATURAL) RETURN NATURAL IS BEGIN RETURN sel_a_b(g_statistics_type="BST", 1, diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd index 934dbb94caddf710fb87cdda18238fa359dc3b2b..1338fe6d15b0c5bec083dd968b12817a003e259c 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd @@ -109,12 +109,13 @@ USE work.sdp_pkg.ALL; ENTITY sdp_statistics_offload IS GENERIC ( - g_statistics_type : STRING := "SST"; - g_offload_time : NATURAL := c_sdp_offload_time; - g_beamset_id : NATURAL := 0; - g_P_sq : NATURAL := c_sdp_P_sq; -- number of available correlator cells, - g_crosslets_direction : NATURAL := 1; -- > 0 for crosslet transport in positive direction (incrementing RN), else 0 for negative direction - g_reverse_word_order : BOOLEAN := TRUE -- default word order is MSB after LSB, we need to stream LSB after MSB. + g_statistics_type : STRING := "SST"; + g_offload_time : NATURAL := c_sdp_offload_time; + g_beamset_id : NATURAL := 0; + g_P_sq : NATURAL := c_sdp_P_sq; -- number of available correlator cells, + g_crosslets_direction : NATURAL := 1; -- > 0 for crosslet transport in positive direction (incrementing RN), else 0 for negative direction + g_reverse_word_order : BOOLEAN := TRUE; -- default word order is MSB after LSB, we need to stream LSB after MSB. + g_bsn_monitor_sync_timeout : NATURAL := c_sdp_N_clk_sync_timeout ); PORT ( -- Clocks and reset @@ -187,7 +188,7 @@ ARCHITECTURE str OF sdp_statistics_offload IS packet_count : NATURAL RANGE 0 TO c_nof_packets_max; start_address : NATURAL RANGE 0 TO c_mm_ram_size; start_pulse : STD_LOGIC; - sync : STD_LOGIC; + start_sync : STD_LOGIC; dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0); payload_err : STD_LOGIC; in_sop_cnt : NATURAL; @@ -337,7 +338,7 @@ BEGIN END PROCESS; -- Assign application header data_id for different statistic types, use - -- GENERATE to keep unused fields at 0. + -- GENERATE to keep unused fields at 0 (all fields are NATURAL, so default to 0). gen_data_id_sst : IF g_statistics_type = "SST" GENERATE data_id_rec.sst_signal_input_index <= r.packet_count + local_si_offset; END GENERATE; @@ -358,7 +359,7 @@ BEGIN BEGIN v := r; v.start_pulse := '0'; - v.sync := '0'; + v.start_sync := '0'; -- Count number of sop in a sync interval and get payload errors and keep them till next sync. IF in_sosi.sync = '1' THEN @@ -378,7 +379,7 @@ BEGIN -- For XST offload capture nof_crosslets and crosslets_info at in_sosi.sync, -- to make sure they do not change during packets offload. - -- . The sdp_crosslets_subband_select.vhd takes in [2] takes care that + -- . The sdp_crosslets_subband_select.vhd in [2] takes care that -- nof_crosslets and crosslets_info are valid at the xsel_sosi.sync. The -- mmp_dp_bsn_align_v2 in [2] then aligns the local xsel_sosi with the -- remote data and passes on the sync. After some latency the sync @@ -403,7 +404,7 @@ BEGIN -- Use trigger_offload to start first packet offload, all -- g_statistics_type start from start address 0 v.start_pulse := '1'; - v.sync := '1'; + v.start_sync := '1'; v.start_address := 0; v.packet_count := 0; v.interleave_count := 0; -- only used for SST @@ -414,9 +415,7 @@ BEGIN -- The dp_sop = '1' when the packet has been read from statistics memory -- and is about to get out of the dp_fifo_fill_eop in - -- u_dp_block_from_mm_dc. The difference between dp_sop and the mm_done - -- output of u_dp_block_from_mm_dc, is that dp_sop also includes any - -- dp_fifo_fill_eop latency. This ensures that the dp_sop identifies the + -- u_dp_block_from_mm_dc. This ensures that the dp_sop identifies the -- sop of the offload packet. At the dp_sop: -- . the dp_header_info per packet offload can be released -- . the next packet offload can be prepared @@ -446,7 +445,7 @@ BEGIN ELSIF g_statistics_type = "XST" THEN -- start_address: - -- nof_crosslets: 0, 1, 2, 3, 4, 5, 6 + -- nof_crosslets: 1, 2, 3, 4, 5, 6, 7 -- X_sq instance: -- 0 0, 576, 1152, 1728, 2304, 2880, 3456 -- 1 4096, 4672, 5248, 5824, 6400, 6976, 7552 @@ -502,7 +501,8 @@ BEGIN g_nof_data => c_mm_nof_data, g_word_w => c_word_w, g_reverse_word_order => g_reverse_word_order, - g_bsn_w => c_dp_stream_bsn_w + g_bsn_w => c_dp_stream_bsn_w, + g_bsn_incr_enable => FALSE -- all offload block have same bsn_at_sync ) PORT MAP( dp_rst => dp_rst, @@ -510,26 +510,23 @@ BEGIN mm_rst => mm_rst, mm_clk => mm_clk, start_pulse => r.start_pulse, - sync_in => r.sync, - bsn_at_sync => bsn_at_sync, + sync_in => r.start_sync, + bsn_at_sync => bsn_at_sync, start_address => r.start_address, - done => mm_done, -- not used, use dp_sop instead mm_mosi => master_mosi, mm_miso => master_miso, + out_sop => dp_sop, -- = dp_block_from_mm_src_out.sop out_sosi => dp_block_from_mm_src_out, out_siso => dp_block_from_mm_src_in ); - -- Use dp_block_from_mm_src_out.sop as dp_sop, to include the - -- dp_fifo_fill_eop that is in dp_block_from_mm_dc. The dp_sop thus is the - -- sop of the packet that is about to be offloaded by u_dp_offload_tx_v3. - -- The r.dp_header_info must be available at the dp_offload_snk_in.sop. - -- This is guaranteed because: + -- The dp_sop is the sop of the packet that is about to be offloaded by + -- u_dp_offload_tx_v3. The r.dp_header_info must be available at the + -- dp_offload_snk_in.sop. This is guaranteed because: -- . r.dp_header_info is available one clock cycle after dp_sop in -- p_control_packet_offload. -- . The dp_offload_snk_in is delayed also by at least one clock cycle by -- u_dp_pipeline_ready. - dp_sop <= dp_block_from_mm_src_out.sop; u_dp_pipeline_ready : ENTITY dp_lib.dp_pipeline_ready PORT MAP( @@ -543,6 +540,13 @@ BEGIN src_out => dp_offload_snk_in ); + -- The bsn_at_sync is passed on via r.dp_header_info so that + -- u_dp_offload_tx_v3 can put it in the udp_sosi header. + -- The dp_offload_snk_in.bsn that is passed on by u_dp_block_from_mm_dc is + -- in fact not used, but useful to see in udp_sosi.bsn in the Wave Window. + -- Similar dp_offload_snk_in.sync that is passed on by u_dp_block_from_mm_dc + -- is in fact not used, but useful to have in udp_sosi.sync (e.g. for the + -- tb). u_dp_offload_tx_v3: ENTITY dp_lib.dp_offload_tx_v3 GENERIC MAP ( g_nof_streams => c_nof_streams, @@ -572,7 +576,7 @@ BEGIN GENERIC MAP ( g_nof_streams => 1, g_cross_clock_domain => TRUE, - g_sync_timeout => c_sdp_N_clk_sync_timeout, + g_sync_timeout => g_bsn_monitor_sync_timeout, g_bsn_w => c_dp_stream_bsn_w, g_error_bi => 0, g_cnt_sop_w => c_word_w, @@ -594,7 +598,4 @@ BEGIN in_sosi_arr(0) => udp_sosi ); - - - END str; diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd index 7c2e39c5f1af617d757ee4fe815428bedac881ce..529ca373069abab0a5067ea4975abb1fab15ab13 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd @@ -28,17 +28,45 @@ LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE common_lib.common_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; USE work.sdp_pkg.ALL; PACKAGE tb_sdp_pkg is ----------------------------------------------------------------------------- -- Statistics offload ----------------------------------------------------------------------------- + FUNCTION func_sdp_compose_stat_header(eth_dst_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); -- eth header + eth_src_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); + ip_src_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); -- ip header + ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); + sdp_info : t_sdp_info; -- app header + g_statistics_type : STRING; + weighted_subbands_flag : STD_LOGIC; + gn_index : NATURAL; + nof_block_per_sync : NATURAL; + sst_signal_input : NATURAL; + beamlet_index : NATURAL; + subband_index : NATURAL; + xst_signal_input_A : NATURAL; + xst_signal_input_B : NATURAL; + dp_bsn : NATURAL) RETURN t_sdp_stat_header; + FUNCTION func_sdp_verify_stat_header(g_statistics_type : STRING; in_hdr, exp_hdr : t_sdp_stat_header) RETURN BOOLEAN; ----------------------------------------------------------------------------- -- Beamlet output via 10GbE to CEP (= central processor) ----------------------------------------------------------------------------- + FUNCTION func_sdp_compose_cep_header(eth_dst_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); -- eth header + eth_src_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); + ip_src_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); -- ip header + ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); + ip_header_checksum : NATURAL; + sdp_info : t_sdp_info; -- app header + gn_index : NATURAL; + beamlet_scale : NATURAL; + beamlet_index : NATURAL; + dp_bsn : NATURAL) RETURN t_sdp_cep_header; + FUNCTION func_sdp_verify_cep_header(in_hdr, exp_hdr : t_sdp_cep_header) RETURN BOOLEAN; @@ -46,6 +74,99 @@ END PACKAGE tb_sdp_pkg; PACKAGE BODY tb_sdp_pkg IS + FUNCTION func_sdp_compose_stat_header(eth_dst_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); -- eth header + eth_src_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); + ip_src_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); -- ip header + ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); + sdp_info : t_sdp_info; -- app header + g_statistics_type : STRING; + weighted_subbands_flag : STD_LOGIC; + gn_index : NATURAL; + nof_block_per_sync : NATURAL; + sst_signal_input : NATURAL; + beamlet_index : NATURAL; + subband_index : NATURAL; + xst_signal_input_A : NATURAL; + xst_signal_input_B : NATURAL; + dp_bsn : NATURAL) RETURN t_sdp_stat_header IS + CONSTANT c_nof_statistics_per_packet : NATURAL := func_sdp_get_stat_nof_statistics_per_packet(g_statistics_type); + CONSTANT c_udp_total_length : NATURAL := func_sdp_get_stat_udp_total_length(g_statistics_type); + CONSTANT c_ip_total_length : NATURAL := func_sdp_get_stat_ip_total_length(g_statistics_type); + CONSTANT c_marker : NATURAL := func_sdp_get_stat_marker(g_statistics_type); + CONSTANT c_nof_signal_inputs : NATURAL := func_sdp_get_stat_nof_signal_inputs(g_statistics_type); + + VARIABLE v_hdr : t_sdp_stat_header; + BEGIN + -- eth header + v_hdr.eth.dst_mac := eth_dst_mac; + v_hdr.eth.src_mac := eth_src_mac; + v_hdr.eth.eth_type := x"0800"; + + -- ip header + v_hdr.ip.version := TO_UVEC( 4, c_network_ip_version_w); + v_hdr.ip.header_length := TO_UVEC( 5, c_network_ip_header_length_w); + v_hdr.ip.services := TO_UVEC( 0, c_network_ip_services_w); + v_hdr.ip.total_length := TO_UVEC(c_ip_total_length, c_network_ip_total_length_w); + v_hdr.ip.identification := TO_UVEC( 0, c_network_ip_identification_w); + v_hdr.ip.flags := TO_UVEC( 2, c_network_ip_flags_w); + v_hdr.ip.fragment_offset := TO_UVEC( 0, c_network_ip_fragment_offset_w); + v_hdr.ip.time_to_live := TO_UVEC( 127, c_network_ip_time_to_live_w); + v_hdr.ip.protocol := TO_UVEC( 17, c_network_ip_protocol_w); + v_hdr.ip.header_checksum := TO_UVEC( 0, c_network_ip_header_checksum_w); + v_hdr.ip.src_ip_addr := ip_src_addr; -- c_network_ip_addr_w + v_hdr.ip.dst_ip_addr := ip_dst_addr; -- c_network_ip_addr_w + + -- udp header + IF g_statistics_type = "SST" THEN + v_hdr.udp.src_port := c_sdp_sst_udp_src_port_15_8 & TO_UVEC(gn_index, 8); + ELSIF g_statistics_type = "BST" THEN + v_hdr.udp.src_port := c_sdp_bst_udp_src_port_15_8 & TO_UVEC(gn_index, 8); + ELSIF g_statistics_type = "XST" THEN + v_hdr.udp.src_port := c_sdp_xst_udp_src_port_15_8 & TO_UVEC(gn_index, 8); + END IF; + v_hdr.udp.dst_port := c_sdp_stat_udp_dst_port; + v_hdr.udp.total_length := TO_UVEC(c_udp_total_length, c_network_udp_port_w); + v_hdr.udp.checksum := TO_UVEC( 0, c_network_udp_checksum_w); + + -- app header + v_hdr.app.sdp_marker := TO_UVEC(c_marker, 8); + v_hdr.app.sdp_version_id := TO_UVEC(c_sdp_stat_version_id, 8); + v_hdr.app.sdp_observation_id := sdp_info.observation_id; + v_hdr.app.sdp_station_id := sdp_info.station_id; + + v_hdr.app.sdp_source_info_antenna_band_id := slv(sdp_info.antenna_band_index); + v_hdr.app.sdp_source_info_nyquist_zone_id := sdp_info.nyquist_zone_index; + v_hdr.app.sdp_source_info_f_adc := slv(sdp_info.f_adc); + v_hdr.app.sdp_source_info_fsub_type := slv(sdp_info.fsub_type); + v_hdr.app.sdp_source_info_payload_error := TO_UVEC(0, 1); + v_hdr.app.sdp_source_info_beam_repositioning_flag := slv(sdp_info.beam_repositioning_flag); + v_hdr.app.sdp_source_info_weighted_subbands_flag := slv(weighted_subbands_flag); + v_hdr.app.sdp_source_info_reserved := TO_UVEC(0, 3); + v_hdr.app.sdp_source_info_gn_id := TO_UVEC(gn_index, 5); + + v_hdr.app.sdp_reserved := TO_UVEC( 0, 8); + v_hdr.app.sdp_integration_interval := TO_UVEC(nof_block_per_sync, 24); + IF g_statistics_type = "SST" THEN + v_hdr.app.sdp_data_id := TO_UVEC(sst_signal_input, 32); + v_hdr.app.sdp_data_id_sst_signal_input_index := TO_UVEC(sst_signal_input, 8); + ELSIF g_statistics_type = "BST" THEN + v_hdr.app.sdp_data_id := TO_UVEC(beamlet_index, 32); + v_hdr.app.sdp_data_id_bst_beamlet_index := TO_UVEC(beamlet_index, 16); + ELSIF g_statistics_type = "XST" THEN + v_hdr.app.sdp_data_id := TO_UVEC(0, 7) & TO_UVEC(subband_index, 9) & TO_UVEC(xst_signal_input_A, 8) & TO_UVEC(xst_signal_input_B, 8); + v_hdr.app.sdp_data_id_xst_subband_index := TO_UVEC(subband_index, 9); + v_hdr.app.sdp_data_id_xst_signal_input_A_index := TO_UVEC(xst_signal_input_A, 8); + v_hdr.app.sdp_data_id_xst_signal_input_B_index := TO_UVEC(xst_signal_input_B, 8); + END IF; + v_hdr.app.sdp_nof_signal_inputs := TO_UVEC( c_nof_signal_inputs, 8); + v_hdr.app.sdp_nof_bytes_per_statistic := TO_UVEC(c_sdp_nof_bytes_per_statistic, 8); + v_hdr.app.sdp_nof_statistics_per_packet := TO_UVEC( c_nof_statistics_per_packet, 16); + v_hdr.app.sdp_block_period := sdp_info.block_period; + + v_hdr.app.dp_bsn := TO_UVEC(dp_bsn, 64); + RETURN v_hdr; + END func_sdp_compose_stat_header; + FUNCTION func_sdp_verify_stat_header(g_statistics_type : STRING; in_hdr, exp_hdr : t_sdp_stat_header) RETURN BOOLEAN IS BEGIN -- eth header @@ -116,6 +237,69 @@ PACKAGE BODY tb_sdp_pkg IS END func_sdp_verify_stat_header; + FUNCTION func_sdp_compose_cep_header(eth_dst_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); -- eth header + eth_src_mac : STD_LOGIC_VECTOR(47 DOWNTO 0); + ip_src_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); -- ip header + ip_dst_addr : STD_LOGIC_VECTOR(31 DOWNTO 0); + ip_header_checksum : NATURAL; + sdp_info : t_sdp_info; -- app header + gn_index : NATURAL; + beamlet_scale : NATURAL; + beamlet_index : NATURAL; + dp_bsn : NATURAL) RETURN t_sdp_cep_header IS + VARIABLE v_hdr : t_sdp_cep_header; + BEGIN + -- eth header + v_hdr.eth.dst_mac := eth_dst_mac; + v_hdr.eth.src_mac := eth_src_mac; + v_hdr.eth.eth_type := x"0800"; + + -- ip header + v_hdr.ip.version := TO_UVEC( 4, c_network_ip_version_w); + v_hdr.ip.header_length := TO_UVEC( 5, c_network_ip_header_length_w); + v_hdr.ip.services := TO_UVEC( 0, c_network_ip_services_w); + v_hdr.ip.total_length := c_sdp_cep_ip_total_length; + v_hdr.ip.identification := TO_UVEC( 0, c_network_ip_identification_w); + v_hdr.ip.flags := TO_UVEC( 2, c_network_ip_flags_w); + v_hdr.ip.fragment_offset := TO_UVEC( 0, c_network_ip_fragment_offset_w); + v_hdr.ip.time_to_live := TO_UVEC( 127, c_network_ip_time_to_live_w); + v_hdr.ip.protocol := TO_UVEC( 17, c_network_ip_protocol_w); + v_hdr.ip.header_checksum := TO_UVEC( ip_header_checksum, c_network_ip_header_checksum_w); + v_hdr.ip.src_ip_addr := ip_src_addr; -- c_network_ip_addr_w + v_hdr.ip.dst_ip_addr := ip_dst_addr; -- c_network_ip_addr_w + + -- udp header + v_hdr.udp.src_port := c_sdp_cep_udp_src_port_15_8 & TO_UVEC(gn_index, 8); + v_hdr.udp.dst_port := c_sdp_cep_udp_dst_port; + v_hdr.udp.total_length := c_sdp_cep_udp_total_length; + v_hdr.udp.checksum := TO_UVEC(0, c_network_udp_checksum_w); + + -- app header + v_hdr.app.sdp_marker := TO_UVEC(c_sdp_marker_beamlets, 8); + v_hdr.app.sdp_version_id := TO_UVEC(c_sdp_cep_version_id, 8); + v_hdr.app.sdp_observation_id := sdp_info.observation_id; + v_hdr.app.sdp_station_id := sdp_info.station_id; + + v_hdr.app.sdp_source_info_antenna_band_id := slv(sdp_info.antenna_band_index); + v_hdr.app.sdp_source_info_nyquist_zone_id := sdp_info.nyquist_zone_index; + v_hdr.app.sdp_source_info_f_adc := slv(sdp_info.f_adc); + v_hdr.app.sdp_source_info_fsub_type := slv(sdp_info.fsub_type); + v_hdr.app.sdp_source_info_payload_error := TO_UVEC(0, 1); + v_hdr.app.sdp_source_info_repositioning_flag := slv(sdp_info.beam_repositioning_flag); + v_hdr.app.sdp_source_info_beamlet_width := TO_UVEC(c_sdp_W_beamlet, 4); + v_hdr.app.sdp_source_info_gn_id := TO_UVEC(gn_index, 5); + + v_hdr.app.sdp_reserved := TO_UVEC(0, 40); + v_hdr.app.sdp_beamlet_scale := TO_UVEC(beamlet_scale, 16); + v_hdr.app.sdp_beamlet_index := TO_UVEC(beamlet_index, 16); + v_hdr.app.sdp_nof_blocks_per_packet := TO_UVEC(c_sdp_cep_nof_blocks_per_packet, 8); + v_hdr.app.sdp_nof_beamlets_per_block := TO_UVEC(c_sdp_cep_nof_beamlets_per_block, 16); + v_hdr.app.sdp_block_period := sdp_info.block_period; + + v_hdr.app.dp_bsn := TO_UVEC(dp_bsn, 64); + RETURN v_hdr; + END func_sdp_compose_cep_header; + FUNCTION func_sdp_verify_cep_header(in_hdr, exp_hdr : t_sdp_cep_header) RETURN BOOLEAN IS VARIABLE v_beamlet_index : NATURAL; BEGIN diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd index 99ebd6f839aef1583d421cee33c40dfcca70927a..1193efc51d1626ac76565c476870d39bcff62236 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd @@ -85,7 +85,7 @@ ARCHITECTURE tb OF tb_sdp_statistics_offload IS -- In this tb simply use fixed network src addresses CONSTANT c_eth_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := x"123456789ABC"; CONSTANT c_ip_src_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := x"0A090807"; - CONSTANT c_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := x"D001"; + CONSTANT c_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := func_sdp_get_stat_udp_src_port(g_statistics_type, g_gn_index); -- Used mm_adresses on mm bus "enable_mosi/miso". CONSTANT c_reg_enable_mm_addr_enable : NATURAL := 0; @@ -191,7 +191,7 @@ ARCHITECTURE tb OF tb_sdp_statistics_offload IS SIGNAL rx_sdp_stat_header : t_sdp_stat_header; SIGNAL exp_sdp_stat_header : t_sdp_stat_header; - SIGNAL exp_dp_bsn : STD_LOGIC_VECTOR(63 DOWNTO 0); + SIGNAL exp_dp_bsn : NATURAL; SIGNAL exp_sst_signal_input : NATURAL; SIGNAL exp_bst_beamlet_index : NATURAL; SIGNAL cur_X_sq_cell : NATURAL; @@ -354,7 +354,7 @@ BEGIN -- verify it at rx_offload_sosi.eop. -- For all statistics - exp_dp_bsn <= TO_SVEC(c_bsn_init + 1 + rx_sync_cnt * c_nof_block_per_sync, 64); + exp_dp_bsn <= c_bsn_init + 1 + rx_sync_cnt * c_nof_block_per_sync; -- SST exp_sst_signal_input <= rx_packet_cnt + c_sdp_S_pn * gn_index; -- BST @@ -369,70 +369,21 @@ BEGIN -- . prepare expected XST signal_input_B index, assume crosslet transport in positive direction exp_xst_signal_input_B <= (source_gn MOD c_sdp_N_pn_max) * c_sdp_S_pn; - p_exp_sdp_stat_header : PROCESS(weighted_subbands_flag, gn_index, exp_dp_bsn, exp_sst_signal_input, exp_subband_index, exp_xst_signal_input_A, exp_xst_signal_input_B) - BEGIN - -- eth header - exp_sdp_stat_header.eth.dst_mac <= c_sdp_stat_eth_dst_mac; - exp_sdp_stat_header.eth.src_mac <= c_eth_src_mac; - exp_sdp_stat_header.eth.eth_type <= x"0800"; - - -- ip header - exp_sdp_stat_header.ip.version <= TO_UVEC( 4, c_network_ip_version_w); - exp_sdp_stat_header.ip.header_length <= TO_UVEC( 5, c_network_ip_header_length_w); - exp_sdp_stat_header.ip.services <= TO_UVEC( 0, c_network_ip_services_w); - exp_sdp_stat_header.ip.total_length <= TO_UVEC(c_ip_total_length, c_network_ip_total_length_w); - exp_sdp_stat_header.ip.identification <= TO_UVEC( 0, c_network_ip_identification_w); - exp_sdp_stat_header.ip.flags <= TO_UVEC( 2, c_network_ip_flags_w); - exp_sdp_stat_header.ip.fragment_offset <= TO_UVEC( 0, c_network_ip_fragment_offset_w); - exp_sdp_stat_header.ip.time_to_live <= TO_UVEC( 127, c_network_ip_time_to_live_w); - exp_sdp_stat_header.ip.protocol <= TO_UVEC( 17, c_network_ip_protocol_w); - exp_sdp_stat_header.ip.header_checksum <= TO_UVEC( 0, c_network_ip_header_checksum_w); - exp_sdp_stat_header.ip.src_ip_addr <= c_ip_src_addr; -- c_network_ip_addr_w - exp_sdp_stat_header.ip.dst_ip_addr <= c_sdp_stat_ip_dst_addr; -- c_network_ip_addr_w - - -- udp header - exp_sdp_stat_header.udp.src_port <= c_udp_src_port; - exp_sdp_stat_header.udp.dst_port <= TO_UVEC( 5001, c_network_udp_port_w); - exp_sdp_stat_header.udp.total_length <= TO_UVEC(c_udp_total_length, c_network_udp_port_w); - exp_sdp_stat_header.udp.checksum <= TO_UVEC( 0, c_network_udp_checksum_w); - - -- app header - exp_sdp_stat_header.app.sdp_marker <= TO_UVEC(c_marker, 8); - exp_sdp_stat_header.app.sdp_version_id <= TO_UVEC(c_sdp_stat_version_id, 8); - exp_sdp_stat_header.app.sdp_observation_id <= c_exp_sdp_info.observation_id; - exp_sdp_stat_header.app.sdp_station_id <= c_exp_sdp_info.station_id; - - exp_sdp_stat_header.app.sdp_source_info_antenna_band_id <= slv(c_exp_sdp_info.antenna_band_index); - exp_sdp_stat_header.app.sdp_source_info_nyquist_zone_id <= c_exp_sdp_info.nyquist_zone_index; - exp_sdp_stat_header.app.sdp_source_info_f_adc <= slv(c_exp_sdp_info.f_adc); - exp_sdp_stat_header.app.sdp_source_info_fsub_type <= slv(c_exp_sdp_info.fsub_type); - exp_sdp_stat_header.app.sdp_source_info_payload_error <= TO_UVEC(0, 1); - exp_sdp_stat_header.app.sdp_source_info_beam_repositioning_flag <= slv(c_exp_sdp_info.beam_repositioning_flag); - exp_sdp_stat_header.app.sdp_source_info_weighted_subbands_flag <= slv(weighted_subbands_flag); - exp_sdp_stat_header.app.sdp_source_info_reserved <= TO_UVEC(0, 3); - exp_sdp_stat_header.app.sdp_source_info_gn_id <= TO_UVEC(gn_index, 5); - - exp_sdp_stat_header.app.sdp_reserved <= TO_UVEC( 0, 8); - exp_sdp_stat_header.app.sdp_integration_interval <= TO_UVEC(c_nof_block_per_sync, 24); - IF g_statistics_type = "SST" THEN - exp_sdp_stat_header.app.sdp_data_id <= TO_UVEC(exp_sst_signal_input, 32); - exp_sdp_stat_header.app.sdp_data_id_sst_signal_input_index <= TO_UVEC(exp_sst_signal_input, 8); - ELSIF g_statistics_type = "BST" THEN - exp_sdp_stat_header.app.sdp_data_id <= TO_UVEC(c_beamlet_index, 32); - exp_sdp_stat_header.app.sdp_data_id_bst_beamlet_index <= TO_UVEC(c_beamlet_index, 16); - ELSIF g_statistics_type = "XST" THEN - exp_sdp_stat_header.app.sdp_data_id <= TO_UVEC(0, 7) & TO_UVEC(exp_subband_index, 9) & TO_UVEC(exp_xst_signal_input_A, 8) & TO_UVEC(exp_xst_signal_input_B, 8); - exp_sdp_stat_header.app.sdp_data_id_xst_subband_index <= TO_UVEC(exp_subband_index, 9); - exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_A_index <= TO_UVEC(exp_xst_signal_input_A, 8); - exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_B_index <= TO_UVEC(exp_xst_signal_input_B, 8); - END IF; - exp_sdp_stat_header.app.sdp_nof_signal_inputs <= TO_UVEC( c_nof_signal_inputs, 8); - exp_sdp_stat_header.app.sdp_nof_bytes_per_statistic <= TO_UVEC(c_sdp_nof_bytes_per_statistic, 8); - exp_sdp_stat_header.app.sdp_nof_statistics_per_packet <= TO_UVEC( c_nof_statistics_per_packet, 16); - exp_sdp_stat_header.app.sdp_block_period <= c_exp_sdp_info.block_period; - - exp_sdp_stat_header.app.dp_bsn <= exp_dp_bsn; - END PROCESS; + exp_sdp_stat_header <= func_sdp_compose_stat_header(c_sdp_stat_eth_dst_mac, + c_eth_src_mac, + c_ip_src_addr, + c_sdp_stat_ip_dst_addr, + c_exp_sdp_info, + g_statistics_type, + weighted_subbands_flag, + gn_index, + c_nof_block_per_sync, + exp_sst_signal_input, + c_beamlet_index, + exp_subband_index, + exp_xst_signal_input_A, + exp_xst_signal_input_B, + exp_dp_bsn); rx_sdp_stat_header <= func_sdp_map_stat_header(rx_hdr_fields_raw); diff --git a/applications/lofar2/model/lofar2_station_sdp_firmware_model.ipynb b/applications/lofar2/model/lofar2_station_sdp_firmware_model.ipynb index 7bc831760d58699f007b41422a6ccf8f4278bef9..bc89897d52492e1ac09a26718b35e1d832bcf88d 100644 --- a/applications/lofar2/model/lofar2_station_sdp_firmware_model.ipynb +++ b/applications/lofar2/model/lofar2_station_sdp_firmware_model.ipynb @@ -24,7 +24,6 @@ "metadata": {}, "outputs": [], "source": [ - "import math\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] @@ -47,13 +46,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "N_int = 200000000\n" + "N_int = 200000000\n", + "N_int_sub = 195312.5\n" ] } ], "source": [ "# SDP\n", - "N_ant = 96\n", "N_complex = 2\n", "N_fft = 1024\n", "N_sub = N_fft / N_complex\n", @@ -63,7 +62,8 @@ "N_int = f_adc * T_int\n", "N_int_sub = f_sub * T_int\n", "\n", - "print(f\"N_int = {N_int:.0f}\")" + "print(f\"N_int = {N_int:.0f}\")\n", + "print(f\"N_int_sub = {N_int_sub:.1f}\")" ] }, { @@ -90,7 +90,7 @@ "W_beamlet = 8\n", "W_statistic = 64\n", "FS = 2**(W_adc - 1) # full scale\n", - "sigma_fs_sine = FS / math.sqrt(2)\n", + "sigma_fs_sine = FS / np.sqrt(2)\n", "\n", "print(\"FS =\", FS)\n", "print(f\"sigma_fs_sine = {sigma_fs_sine:.1f}\")" @@ -135,80 +135,222 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "0ec00484", + "execution_count": 7, + "id": "def6eba7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "W_sub_proc = 4.5\n", - "W_bf_proc = 3.29 for N_ant = 96\n" + "Conclusion: G_fft_real_input_sine = 0.5\n" ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 720x288 with 2 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" } ], "source": [ - "# Signal level bit growth to accomodate processing gain\n", - "W_sub_proc = math.log2(math.sqrt(N_sub))\n", - "W_sub_gain = 4\n", - "W_bf_proc = math.log2(math.sqrt(N_ant))\n", + "# DFT of real sine input --> show that:\n", + "G_fft_real_input_sine = 0.5\n", + "G_fft_real_input_dc = 1.0\n", + "\n", + "# . DFT size\n", + "N_points = 1024\n", + "N_bins = N_points // 2 + 1 # positive frequency bins including DC and F_s/2\n", + "\n", + "# . select a bin\n", + "i_bin = 200 # bin index in range(N_points // 2 )\n", + "\n", + "# . time and frequency axis\n", + "f_s = f_adc # sample frequency\n", + "f_s = 1 # normalized sample frequency\n", + "T_s = 1 / f_s # sample period\n", + "T_fft = N_points * T_s # DFT period\n", + "t_axis = np.linspace(0, T_fft, N_points, endpoint=False)\n", + "f_axis = np.linspace(0, f_s, N_points, endpoint=False)\n", + "f_axis_fft = f_axis - f_s/2 # fftshift axis\n", + "f_axis_rfft = f_axis[0:N_bins] # positive frequency bins\n", + "\n", + "f_bin = i_bin / N_points * f_s # bin frequency\n", + "\n", + "# . create sine at bin, use cos to see DC at i_bin = 0 \n", + "x = np.cos(2 * np.pi * f_bin * t_axis)\n", + "\n", + "# . DFT using complex input fft()\n", + "X_fft = np.fft.fftshift(np.fft.fft(x) / N_points)\n", + "\n", + "# . DFT using real input rfft()\n", + "X_rfft = np.fft.rfft(x) / N_points\n", + "\n", + "plt.figure(figsize=(10, 4))\n", + "plt.subplot(1, 2, 1)\n", + "plt.title('DFT of real sine using fft')\n", + "plt.plot(f_axis_fft, abs(X_fft))\n", + "plt.grid()\n", + "plt.subplot(1, 2, 2)\n", + "plt.title('DFT of real sine using rfft')\n", + "plt.plot(f_axis_rfft, abs(X_rfft))\n", + "plt.grid()\n", "\n", - "print(\"W_sub_proc =\", W_sub_proc)\n", - "print(f\"W_bf_proc = {W_bf_proc:.2f} for N_ant = {N_ant}\")" - ] - }, - { - "cell_type": "markdown", - "id": "d942fcc6", - "metadata": {}, - "source": [ - "## 2 Quantization model" + "print(\"Conclusion: G_fft_real_input_sine =\", G_fft_real_input_sine)" ] }, { "cell_type": "code", - "execution_count": 6, - "id": "f66c5028", + "execution_count": 12, + "id": "0ec00484", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "P_bit_dB = 6.02 dB\n" + "subband_weight_gain = 1.0\n", + "subband_weight_phase = 0\n", + "subband_weight_re = 8192\n", + "subband_weight_im = 0\n", + "\n", + "G_subband = 0.994817 * 0.5 * 2**4 * 1.0 = 7.958536\n", + " . G_fir_dc = 0.994817\n", + " . G_fft_real_input_sine = 0.5\n", + " . W_sub_gain = 4\n", + " . subband_weight_gain = 1.0\n" ] } ], "source": [ - "# Bit\n", - "P_bit = 2**2\n", - "P_bit_dB = 10 * math.log10(P_bit)\n", - "print(f\"P_bit_dB = {P_bit_dB:.2f} dB\")" + "# Subband filterbank (F_sub)\n", + "# . FIR filter DC gain\n", + "G_fir_dc = 0.994817\n", + "\n", + "# . Signal level bit growth to accomodate processing gain of FFT\n", + "W_sub_proc = np.log2(np.sqrt(N_sub))\n", + "W_sub_gain = 4\n", + "\n", + "# Subband equalizer (E_sub)\n", + "subband_weight_gain = 1.0\n", + "subband_weight_phase = 0\n", + "subband_weight_re = int(subband_weight_gain * Unit_sub_weight * np.cos(subband_weight_phase))\n", + "subband_weight_im = int(subband_weight_gain * Unit_sub_weight * np.sin(subband_weight_phase))\n", + "\n", + "print(\"subband_weight_gain =\", subband_weight_gain)\n", + "print(\"subband_weight_phase =\", subband_weight_phase)\n", + "print(f\"subband_weight_re = {subband_weight_re:d}\")\n", + "print(f\"subband_weight_im = {subband_weight_im:d}\")\n", + "print()\n", + "\n", + "# . Expected factor between subband amplitude and real signal input amplitude\n", + "G_subband = G_fir_dc * G_fft_real_input_sine * 2**W_sub_gain * subband_weight_gain\n", + "\n", + "print(f\"G_subband = {G_fir_dc} * {G_fft_real_input_sine} * 2**{W_sub_gain} * {subband_weight_gain} = {G_subband}\")\n", + "print(\" . G_fir_dc =\", G_fir_dc)\n", + "print(\" . G_fft_real_input_sine =\", G_fft_real_input_sine)\n", + "print(\" . W_sub_gain =\", W_sub_gain)\n", + "print(\" . subband_weight_gain =\", subband_weight_gain)" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "a9fca052", + "execution_count": 18, + "id": "4d197368", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "beamlet_weight_gain = 1.0\n", + "beamlet_weight_phase = 0\n", + "beamlet_weight_re = 16384\n", + "beamlet_weight_im = 0\n", "\n", - "P_quant = 0.083333\n", - "P_quant_dB = -10.79 dB = -1.8 bit\n", - "sigma_quant = 0.29 q\n" + "BF for coherent input:\n", + " . W_bf_proc = 10.00 for N_ant = 10\n", + "\n", + "BF for incoherent input:\n", + " . W_bf_proc = 3.16 for N_ant = 10\n", + "\n" ] } ], + "source": [ + "# Digital beamformer (BF)\n", + "N_ant = 10\n", + "\n", + "# Assume all N_ant use same BF weight\n", + "beamlet_weight_gain = 1.0\n", + "beamlet_weight_phase = 0\n", + "beamlet_weight_re = int(beamlet_weight_gain * Unit_bf_weight * np.cos(beamlet_weight_phase))\n", + "beamlet_weight_im = int(beamlet_weight_gain * Unit_bf_weight * np.sin(beamlet_weight_phase))\n", + "\n", + "print(\"beamlet_weight_gain =\", beamlet_weight_gain)\n", + "print(\"beamlet_weight_phase =\", beamlet_weight_phase)\n", + "print(f\"beamlet_weight_re = {beamlet_weight_re:d}\")\n", + "print(f\"beamlet_weight_im = {beamlet_weight_im:d}\")\n", + "print()\n", + "\n", + "si_types = [\"coherent\", \"incoherent\"]\n", + "for si_type in si_types:\n", + "\n", + " # . BF processing gain\n", + " if si_type == \"coherent\":\n", + " bf_proc = N_ant\n", + " else:\n", + " bf_proc = np.sqrt(N_ant)\n", + " \n", + " # . Normalize BF weights to get BF DC gain is 1.0\n", + " beamlet_weight_gain = 1 / bf_proc\n", + "\n", + " # . Expected factor between beamlet amplitude and real signal input amplitude\n", + " G_beamlet_sum = N_ant * beamlet_weight_gain * G_subband\n", + "\n", + " print(f\"BF for {si_type} input:\")\n", + " print(f\" . bf_proc = {bf_proc:.2f} for N_ant = {N_ant}\")\n", + " print()\n" + ] + }, + { + "cell_type": "markdown", + "id": "d942fcc6", + "metadata": {}, + "source": [ + "## 2 Quantization model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f66c5028", + "metadata": {}, + "outputs": [], + "source": [ + "# Bit\n", + "P_bit = 2**2\n", + "P_bit_dB = 10 * np.log10(P_bit)\n", + "print(f\"P_bit_dB = {P_bit_dB:.2f} dB\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9fca052", + "metadata": {}, + "outputs": [], "source": [ "# Quantization noise\n", "P_quant = 1 / 12 # for W >> 1 [2]\n", - "P_quant_dB = 10 * math.log10(P_quant)\n", - "sigma_quant = math.sqrt(P_quant)\n", + "P_quant_dB = 10 * np.log10(P_quant)\n", + "sigma_quant = np.sqrt(P_quant)\n", "print()\n", "print(f\"P_quant = {P_quant:.6f}\")\n", "print(f\"P_quant_dB = {P_quant_dB:.2f} dB = {P_quant_dB / P_bit_dB:.1f} bit\")\n", @@ -217,23 +359,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "d9972b6b", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# System noise\n", "n = np.arange(1,9)\n", @@ -252,25 +381,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "be2d952f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "W_adc = {W_adc} bits\n", - "FS = 8192\n", - "sigma_fs_sine = 5792.6 q\n", - "P_fs_sine_dB = 75.26 dB = 12.5 bit\n" - ] - } - ], + "outputs": [], "source": [ "# FS sine\n", "P_fs_sine = FS**2 / 2\n", - "P_fs_sine_dB = 10 * math.log10(P_fs_sine)\n", + "P_fs_sine_dB = 10 * np.log10(P_fs_sine)\n", "print(\"W_adc = {W_adc} bits\")\n", "print(\"FS =\", FS)\n", "print(f\"sigma_fs_sine = {sigma_fs_sine:.1f} q\")\n", @@ -279,23 +397,14 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "a9e7fabc", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "SNR_dB = P_fs_sine_dB - P_quant_dB = 75.26 - -10.79 = 86.05 dB\n" - ] - } - ], + "outputs": [], "source": [ "# SNR\n", "SNR = P_fs_sine / P_quant\n", - "SNR_dB = 10 * math.log10(SNR)\n", + "SNR_dB = 10 * np.log10(SNR)\n", "\n", "print()\n", "print(f\"SNR_dB = P_fs_sine_dB - P_quant_dB = {P_fs_sine_dB:.2f} - {P_quant_dB:.2f} = {SNR_dB:.2f} dB\")" @@ -303,39 +412,27 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "92852a53", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Power at -50dBFS = 25.26 dB, so sigma = 18.3 q\n", - "\n", - "sigma = 16 q corresponds to:\n", - " . Power = 24.08 dB, so at -51.2 dBFS\n", - " . Range 3 sigma = +-48 q\n", - " . Sine with amplitude A = sigma * sqrt(2) = 22.6 q\n" - ] - } - ], + "outputs": [], "source": [ "# -50 dbFS level\n", "Power_50dBFS = P_fs_sine_dB - 50 \n", "sigma_50dBFS = 10**(Power_50dBFS / 20)\n", + "ampl_50dBFS = sigma_50dBFS * np.sqrt(2)\n", "\n", - "print(f\"Power at -50dBFS = {Power_50dBFS:.2f} dB, so sigma = {sigma_50dBFS:.1f} q\")\n", + "print(f\"Power at -50dBFS = {Power_50dBFS:.2f} dB, so sigma = {sigma_50dBFS:.1f} q, ampl = {ampl_50dBFS:.1f} q\")\n", "\n", "# Assume sigma = 16 q\n", "sigma = 16\n", "Power = sigma**2\n", - "Power_dB = 10 * math.log10(Power)\n", + "Power_dB = 10 * np.log10(Power)\n", "print()\n", "print(f\"sigma = {sigma:.0f} q corresponds to:\")\n", "print(f\" . Power = {Power_dB:.2f} dB, so at {Power_dB - P_fs_sine_dB:.1f} dBFS\")\n", "print(f\" . Range 3 sigma = +-{3 * sigma:.0f} q\")\n", - "print(f\" . Sine with amplitude A = sigma * sqrt(2) = {math.sqrt(2) * sigma:.1f} q\")\n" + "print(f\" . Sine with amplitude A = sigma * sqrt(2) = {np.sqrt(2) * sigma:.1f} q\")\n" ] }, { @@ -348,22 +445,12 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "a04af043", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ADC sigma = 5792.6 q = 12.5 bits: P_ast = 6.710886e+15, uses 52.6 bits, is 0 dBFS = FS sine\n", - "ADC sigma = 18.3 q = 4.2 bits: P_ast = 6.710886e+10, uses 36.0 bits, is -50dBFS\n", - "ADC sigma = 16.0 q = 4.0 bits: P_ast = 5.120000e+10, uses 35.6 bits\n" - ] - } - ], + "outputs": [], "source": [ - "# ADC power statistic\n", + "# ADC power statistic (AST)\n", "sigma = sigma_fs_sine\n", "sigma_bits = np.log2(sigma)\n", "P_ast = (sigma)**2 * N_int\n", @@ -380,318 +467,49 @@ "print(f\"ADC sigma = {sigma:6.1f} q = {sigma_bits:4.1f} bits: P_ast = {P_ast:e}, uses {np.log2(P_ast):.1f} bits\")" ] }, - { - "cell_type": "code", - "execution_count": 27, - "id": "0b2ac36c", - "metadata": {}, - "outputs": [], - "source": [ - "# Subband filterbank" - ] - }, { "cell_type": "code", "execution_count": null, - "id": "a656367f", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "27d0fe5a", - "metadata": {}, - "source": [ - "## 4 Signal statistics" - ] - }, - { - "cell_type": "markdown", - "id": "4ddef2d8", - "metadata": {}, - "source": [ - "### 4.1 Statistics basics:\n", - "\n", - "* dc = mean # direct current\n", - "* sigma = std # standard deviation\n", - "* var = std**2 # variance\n", - "* mean power = var + mean**2\n", - "* rms = sqrt(mean power) = sqrt(var + mean**2)\n", - "\n", - "Coherent and incoherent signals. With S signals, the std of their sum:\n", - " \n", - "* increases by S for coherent signals\n", - "* increases by sqrt(S) for incoherent signals" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "9c55fb7b", + "id": "0b2ac36c", "metadata": {}, "outputs": [], "source": [ - "def rms(arr):\n", - " \"\"\"Root mean square of values in arr\n", - " \n", - " rms = sqrt(mean powers) = sqrt(std**2 + mean**2)\n", - " \n", - " The rms() also works for complex input thanks to using np.abs().\n", - " \"\"\"\n", - " return np.sqrt(np.mean(np.abs(arr)**2.0))" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "74edfe32", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "mean(si) = -0.204032, expected -0.2\n", - "std(si) = 0.500000, expected 0.5\n", - "rms(si) = 0.540027, expected 0.538516\n" - ] - } - ], - "source": [ - "N_samples = 10000\n", - "sigma = 0.5\n", - "var = sigma**2\n", - "dc = -0.2\n", - "\n", - "# Signal input voltages\n", - "si = np.random.randn(N_samples)\n", - "si *= sigma / np.std(si) # apply requested sigma\n", - "si += dc # add offset\n", - "\n", - "print(f\"mean(si) = {np.mean(si):.6f}, expected {dc}\")\n", - "print(f\"std(si) = {np.std(si):.6f}, expected {sigma}\")\n", - "print(f\"rms(si) = {rms(si):.6f}, expected {np.sqrt(var + dc**2):.6f}\") " - ] - }, - { - "cell_type": "markdown", - "id": "17d333f1", - "metadata": {}, - "source": [ - "### 4.2 Beamforming\n", + "# Subband filterbank (F_sub)\n", + "ampl_sub_fs = FS * G_subband # subband amplitude for FS signal input sine\n", + "SST_fs = ampl_sub_fs**2 * N_int_sub\n", "\n", - "In the beamformer the weak signal in the beamlet adds coherently and the sky\n", - "signals from other directions add incoherently. Hence the SNR of the weak\n", - "signal in the BF output improves by factor S/sqrt(S) = sqrt(S)." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "89845ec3", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Signal inputs\n", - "# . Warning: do use not too high values for N_samples and S_max to avoid too long compute time.\n", - "N_samples = 1000\n", - "S_max = 200\n", - "S_arr = np.arange(1, S_max + 1)\n", - "\n", - "sigma_weak = 0.05\n", - "sigma_other = 0.5\n", - "\n", - "si_weak = np.random.randn(N_samples)\n", - "si_weak *= sigma_weak / np.std(si_weak)\n", - "\n", - "# Beamformer sum(S)\n", - "bf_weak_std_arr = []\n", - "bf_other_std_arr = []\n", - "bf_sys_std_arr = []\n", - "bf_SNR_dB_arr = []\n", - "for S in S_arr:\n", - " # The weak signal in the beamlet adds coherently for all signal inputs\n", - " bf_weak = S * si_weak\n", - " bf_weak_std = np.std(bf_weak)\n", - " bf_weak_std_arr.append(bf_weak_std)\n", - " \n", - " # The other signals from other directions add incoherently\n", - " bf_other = np.zeros(N_samples)\n", - " for si in range(1, S + 1):\n", - " si_other = np.random.randn(N_samples)\n", - " si_other *= sigma_other / np.std(si_other)\n", - " bf_other += si_other\n", - " bf_other_std = np.std(bf_other)\n", - " bf_other_std_arr.append(bf_other_std)\n", - " \n", - " # Total BF output\n", - " bf_sys_std = np.std(bf_weak + bf_other)\n", - " bf_sys_std_arr.append(bf_sys_std)\n", - " \n", - " SNR_dB = 20 * np.log10(bf_weak_std / bf_other_std)\n", - " bf_SNR_dB_arr.append(SNR_dB)\n", - "\n", - "plt.figure(1)\n", - "plt.plot(S_arr, bf_weak_std_arr, 'g', S_arr, bf_other_std_arr, 'b', S_arr, bf_sys_std_arr, 'r')\n", - "plt.title(\"Beamformer\")\n", - "plt.xlabel(\"Number of signal inputs\")\n", - "plt.ylabel(\"BF std\")\n", - "plt.legend(['bf_weak', 'bf_other', 'bf_sys'])\n", - "plt.grid()\n", + "ampl_sub_50dBFS = ampl_50dBFS * G_subband # subband amplitude -50dBFS signal input sine\n", + "SST_50dBFS = ampl_sub_50dBFS**2 * N_int_sub\n", "\n", - "plt.figure(2)\n", - "plt.plot(S_arr, bf_SNR_dB_arr, 'r')\n", - "plt.title(\"Beamformer\")\n", - "plt.xlabel(\"Number of signal inputs\")\n", - "plt.ylabel(\"SNR [dB]\")\n", - "plt.grid()" - ] - }, - { - "cell_type": "markdown", - "id": "71aa6647", - "metadata": {}, - "source": [ - "**Conclusion:**\n", - "The beamformer improves the SNR of the weak signal by factor sqrt(S). For most very weak astronimical signals this is not enough to make them appear above the system noise, so then additional beamforming is needed or integration in time using a correlator." - ] - }, - { - "cell_type": "markdown", - "id": "84b8930c", - "metadata": {}, - "source": [ - "### 4.3 Correlation\n" + "ampl_si_16q = 16 # [q], so 16 q is 4 bits amplitude\n", + "ampl_sub_16q = ampl_si_16q * G_subband # subband amplitude for signal input sine with A = 16 q\n", + "SST_ampl_16q = ampl_sub_16q**2 * N_int_sub\n", + "\n", + "sigma_si_16q = 16 * np.sqrt(2) # [q], so A = 16 * sqrt(2) q for sigma = 16 q\n", + "sigma_sub_16q = sigma_si_16q * G_subband # subband sigma for arbitrary signal input with sigma = 16 q\n", + "SST_sigma_16q = sigma_sub_16q**2 * N_int_sub\n", + "\n", + "print(\"Signal input level --> Expected subband level and SST level:\")\n", + "print()\n", + "print(\" ampl_si ampl_sub #bits SST #bits\")\n", + "print(f\"{FS:8.1f} {ampl_sub_fs:10.1f} {np.log2(ampl_sub_fs):8.4f} {SST_fs:e} {np.log2(SST_fs):.1f}\")\n", + "print(f\"{ampl_50dBFS:8.1f} {ampl_sub_50dBFS:10.1f} {np.log2(ampl_sub_50dBFS):8.4f} {SST_50dBFS:e} {np.log2(SST_50dBFS):.1f}\")\n", + "print(f\"{ampl_si_16q:8.1f} {ampl_sub_16q:10.1f} {np.log2(ampl_sub_16q):8.4f} {SST_ampl_16q:e} {np.log2(SST_ampl_16q):.1f}\")\n", + "print()\n", + "print(\"sigma_si sigma_sub #bits SST #bits\")\n", + "print(f\"{sigma_si_16q:8.1f} {sigma_sub_16q:10.1f} {np.log2(sigma_sub_16q):8.4f} {SST_sigma_16q:e} {np.log2(SST_sigma_16q):.1f}\")" ] }, { "cell_type": "code", - "execution_count": 31, - "id": "470fd269", + "execution_count": null, + "id": "f0b09a83", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SNR input = -33.979 dB\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "# Signal inputs\n", - "N_steps = 1000\n", - "\n", - "N_min = 100\n", - "N_max = 100000\n", - "n_incr = (N_max / N_min)**(1 / N_steps)\n", - "N_arr = []\n", - "for s in range(N_steps + 1):\n", - " n = int(N_min * n_incr**s)\n", - " N_arr.append(n)\n", - "\n", - "sigma_weak = 0.01\n", - "sigma_other = 0.5\n", - "\n", - "SNR_dB = 20 * np.log10(sigma_weak / sigma_other)\n", - "print(f\"SNR input = {SNR_dB:.3f} dB\")\n", - "\n", - "# Correlator mean(A * B)\n", - "cor_weak_arr = []\n", - "cor_other_arr = []\n", - "cor_sys_arr = []\n", - "cor_SNR_dB_arr = []\n", - "for N in N_arr:\n", - " si_weak = np.random.randn(N)\n", - " si_weak *= sigma_weak / np.std(si_weak)\n", - "\n", - " # Signal input A\n", - " sA_other = np.random.randn(N)\n", - " sA_other *= sigma_other / np.std(sA_other)\n", - " sA_sys = sA_other + si_weak\n", - "\n", - " # Signal input B\n", - " sB_other = np.random.randn(N)\n", - " sB_other *= sigma_other / np.std(sB_other)\n", - " sB_sys = sB_other + si_weak\n", - " \n", - " # Correlate A and B\n", - " cor_weak = np.mean(si_weak * si_weak)\n", - " cor_weak_arr.append(cor_weak)\n", - " cor_other = np.mean(sA_other * sB_other)\n", - " cor_other_arr.append(cor_other)\n", - " cor_sys = np.mean(sA_sys * sB_sys)\n", - " cor_sys_arr.append(cor_sys)\n", - " #print(f\"{N}, {cor_weak:9.6f}, {cor_other:9.6f}, {cor_sys:9.6f}\")\n", - "\n", - " SNR_dB = 10 * np.log10(np.abs(cor_weak / cor_other))\n", - " cor_SNR_dB_arr.append(SNR_dB)\n", - " #print(f\"{N}, SNR output = {SNR_dB:.0f} dB\")\n", - "\n", - "plt.figure(1)\n", - "plt.plot(N_arr, cor_weak_arr, 'g', N_arr, cor_other_arr, 'b', N_arr, cor_sys_arr, 'r')\n", - "plt.title(\"Correlator\")\n", - "plt.xlabel(\"Number of samples\")\n", - "plt.ylabel(\"Cross power\")\n", - "plt.legend(['cor_weak', 'cor_other', 'cor_sys'])\n", - "plt.grid()\n", - "\n", - "plt.figure(2)\n", - "plt.plot(N_arr, cor_SNR_dB_arr, 'r')\n", - "plt.title(\"Correlator\")\n", - "plt.xlabel(\"Number of samples\")\n", - "plt.ylabel(\"SNR [dB]\")\n", - "plt.grid()" + "# Digital beamformer (BF)\n", + "# . is a coherent beamformer = voltage beamformer\n", + "# . uses BF weights to form beamlets from sum of weighted subbands\n" ] }, { diff --git a/applications/lofar2/model/signal_statistics.ipynb b/applications/lofar2/model/signal_statistics.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..c90858b30b427b8e2309e7caed3722bfa052b7ec --- /dev/null +++ b/applications/lofar2/model/signal_statistics.ipynb @@ -0,0 +1,424 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "82c10597", + "metadata": {}, + "source": [ + "# Signal statistics for beamformer and correlator\n", + "\n", + "Author: Eric Kooistra, 18 May 2022\n", + "\n", + "Purpose: Model the SNR of a beamformer and a correlator\n", + "\n", + "Status:\n", + "* coherent, voltage beamformer: I think I understand how it improves SNR by sqrt(N_ant)\n", + "* incoherent, power beamformer: TODO, but I do not understand yet how N_ant > 1 can improve SNR\n", + "* correlator: started, but I do not understand yet how N_int > 1 can improve SNR and what is the limit\n", + "\n", + "References:\n", + "\n", + "1. Understanding digital signal processing, R.G. Lyons" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "2b477516", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "4ddef2d8", + "metadata": {}, + "source": [ + "## 1 Statistics basics:\n", + "\n", + "* dc = mean # direct current\n", + "* sigma = std # standard deviation\n", + "* var = std**2 # variance\n", + "* mean power = var + mean**2\n", + "* rms = sqrt(mean power) = sqrt(var + mean**2)\n", + "\n", + "Coherent and incoherent signals. With S signals, the std of their sum:\n", + " \n", + "* increases by S for coherent signals\n", + "* increases by sqrt(S) for incoherent signals" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "9c55fb7b", + "metadata": {}, + "outputs": [], + "source": [ + "def rms(arr):\n", + " \"\"\"Root mean square of values in arr\n", + " \n", + " rms = sqrt(mean powers) = sqrt(std**2 + mean**2)\n", + " \n", + " The rms() also works for complex input thanks to using np.abs().\n", + " \"\"\"\n", + " return np.sqrt(np.mean(np.abs(arr)**2.0))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "74edfe32", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean(si) = -0.199151, expected -0.2\n", + "std(si) = 0.500000, expected 0.5\n", + "rms(si) = 0.538202, expected 0.538516\n" + ] + } + ], + "source": [ + "N_samples = 10000\n", + "sigma = 0.5\n", + "var = sigma**2\n", + "dc = -0.2\n", + "\n", + "# Signal input voltages\n", + "si = np.random.randn(N_samples)\n", + "si *= sigma / np.std(si) # apply requested sigma\n", + "si += dc # add offset\n", + "\n", + "print(f\"mean(si) = {np.mean(si):.6f}, expected {dc}\")\n", + "print(f\"std(si) = {np.std(si):.6f}, expected {sigma}\")\n", + "print(f\"rms(si) = {rms(si):.6f}, expected {np.sqrt(var + dc**2):.6f}\") " + ] + }, + { + "cell_type": "markdown", + "id": "17d333f1", + "metadata": {}, + "source": [ + "## 2 Beamforming\n", + "\n", + "Two types:\n", + "\n", + "1. Coherent, voltage beamformer (e.g. digital BF in LOFAR2 Station, TAB in ARTS)\n", + "2. Incoherent, power beamformer (e.g. IAB in ARTS)" + ] + }, + { + "cell_type": "markdown", + "id": "96de4cb4", + "metadata": {}, + "source": [ + "### 2.1 Coherent, voltages beamformer (BF)\n", + "\n", + "Two signal input types:\n", + " \n", + "1. Coherent signals, add up as voltages\n", + "2. Incoherent signal, add up as power\n", + "\n", + "In the voltage beamformer the weak signal in the beamlet adds coherently and the sky\n", + "signals from other directions add incoherently. Hence the SNR of the weak signal in\n", + "the BF output improves by factor S/sqrt(S) = sqrt(S)." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "89845ec3", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Signal inputs\n", + "# . Warning: do use not too high values for N_samples and S_max to avoid too long compute time.\n", + "N_samples = 1000\n", + "S_max = 200\n", + "S_arr = np.arange(1, S_max + 1)\n", + "\n", + "sigma_weak = 0.05\n", + "sigma_other = 0.5\n", + "\n", + "si_weak = np.random.randn(N_samples)\n", + "si_weak *= sigma_weak / np.std(si_weak)\n", + "\n", + "# Beamformer sum(S)\n", + "bf_weak_std_arr = []\n", + "bf_other_std_arr = []\n", + "bf_sys_std_arr = []\n", + "bf_SNR_dB_arr = []\n", + "for S in S_arr:\n", + " # The weak signal in the beamlet adds coherently for all signal inputs\n", + " bf_weak = S * si_weak\n", + " bf_weak_std = np.std(bf_weak)\n", + " bf_weak_std_arr.append(bf_weak_std)\n", + " \n", + " # The other signals from other directions add incoherently\n", + " bf_other = np.zeros(N_samples)\n", + " for si in range(1, S + 1):\n", + " si_other = np.random.randn(N_samples)\n", + " si_other *= sigma_other / np.std(si_other)\n", + " bf_other += si_other\n", + " bf_other_std = np.std(bf_other)\n", + " bf_other_std_arr.append(bf_other_std)\n", + " \n", + " # Total BF output\n", + " bf_sys_std = np.std(bf_weak + bf_other)\n", + " bf_sys_std_arr.append(bf_sys_std)\n", + " \n", + " SNR_dB = 20 * np.log10(bf_weak_std / bf_other_std)\n", + " bf_SNR_dB_arr.append(SNR_dB)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(S_arr, bf_weak_std_arr, 'g', S_arr, bf_other_std_arr, 'b', S_arr, bf_sys_std_arr, 'r')\n", + "plt.title(\"Beamformer\")\n", + "plt.xlabel(\"Number of signal inputs\")\n", + "plt.ylabel(\"BF std\")\n", + "plt.legend(['bf_weak', 'bf_other', 'bf_sys'])\n", + "plt.grid()\n", + "\n", + "plt.figure(2)\n", + "plt.plot(S_arr, bf_SNR_dB_arr, 'r')\n", + "plt.title(\"Beamformer\")\n", + "plt.xlabel(\"Number of signal inputs\")\n", + "plt.ylabel(\"SNR [dB]\")\n", + "plt.grid()" + ] + }, + { + "cell_type": "markdown", + "id": "71aa6647", + "metadata": {}, + "source": [ + "**Conclusion:**\n", + "The voltage beamformer improves the SNR of the weak signal by factor sqrt(S). For most very weak astronimical signals this is not enough to make them appear above the system noise, so then additional beamforming is needed or integration in time using a correlator." + ] + }, + { + "cell_type": "markdown", + "id": "9dafd903", + "metadata": {}, + "source": [ + "### 2.2 Incoherent, powers beamformer\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "499d7eb6", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO" + ] + }, + { + "cell_type": "markdown", + "id": "84b8930c", + "metadata": {}, + "source": [ + "## 3 Correlation\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "470fd269", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SNR input = -10.458 dB\n" + ] + }, + { + "data": { + "image/png": "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Dh1KZGQk/fr148knn+T888/noYceKuzMroiBAweSn58PuKaoG264gWOPPRaAiy66iDVr1nDkkUeiqrRu3ZoZM2YwYcIEfv/739OrVy9SU1M57LDDim2zSZMmfPjhh5x44ok0bdq0WP9FZYjrL244UlNTtbJ3uMN3aXsDOybBNIQLsSrKylw/LV++nMMPPzzk9HbBXdkCHUsRWaKqqYHSW9OTMcaYoKzpyRhjathLL73EE088UWzd4MGDmTJlSphyVDEWKIwxpoadf/75nH/++eHORqVZ05MxxpigLFAE8sEH4c6BMcbUGRYoAqniUDJjjGlILFAYY4wJygKFMcbUMWlpaXz55ZeFr88777zC+Z7CwQKFMcbUsIrej6JkoKgKVaWgoKBK27DhscaYeufqq2Hp0uBp8vPjqcDtKOjbFx5/vPx01Xk/ip07d3LBBRewatUqEhISmDp1KomJiTzzzDNERkby6quv8uSTTwIwb948Hn30UTZv3syDDz7IuHHjAHjooYd46623yM7OZtSoUdx///2sWbOGk046iYEDB7JkyRJmzZpF586dQz8YJVigMMaYEFX3/Shuu+02+vXrx4wZM/j888+ZOHEiS5cu5dJLL6Vp06Zcd911ALzwwgts2rSJBQsWsGLFCkaPHs24ceOYPXs26enpfP3116gqo0aNYt68eXTq1In09HSmTZvGoEGDqlxuCxTGmHonlF/+GRn76/z9KBYsWMC7774LuJlpd+zYwd69ewOmHTt2LBERERxxxBGF956YPXs2s2fPpl+/fgDs3buX9PR0OnXqROfOnaslSIAFCmOMqTHl3Y+iImJjYwuXfZO5qio33HADl1xyCVA0KeCaNWuqdd/WmW2MMSGq7vtRHHfccbz22muA68BOTk4mMTGRZs2akZGRUe7nTzrpJF588UUyMzMB+O2339i6dWtFi1Uuq1EYY0yIqvt+FLfffjsXXHABvXv3JiEhgWnTpgHw+9//nnHjxvH+++8XdmYHMnLkSJYvX87RRx8NQHx8PK+//nrQ5q7KsPtR+PPdjwIazT0pGsJ9CirKylw/2f0oymf3ozDGGBMWYQ0UInKyiKwUkV9EZHKQdGeIiIpIwGhnjDF12UsvvUTfvn2LPS6//PJwZytkYeujEJFIYApwIrABWCQiM1X1pxLpmgFXAV/Vfi6NMabq7H4UlTcA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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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6NKlS9DnrUoh6AZM9EQgGbhQRHJU9ZMqtMkwDCPsqDIhUNX8edREZAKuauiTSjQgLEoEhmEYpREyIRCR94AUIFlEtgAPA9EAqvpSqK4bNDYfgWEYBhDaXkPDyhD3ulDZUcJFK/2ShmEYqampxMTE0Lt3bwCuu+46LrroIoYOHVplNoWPi4ndu0lasqSqrTAMo5ZR1vkIUlNTmTNnToVcW1XJy8s75vOEj4uJGTPocuedBduzZsGAAVVnj2EYxXL33bB4cclxcnPjKUvv0c6dYezYkuNU5HwEe/fuZeTIkaxbt446deowfvx46tWrx0svvURkZCRvv/02zz//PAAzZ87kmWeeYfv27Tz55JP5pYOnnnqKSZMmkZWVxaWXXsro0aPZsGED5513Hj179mThwoVMnTqVli1bBn8jiiB8hCCQgQOtesgwjHwqej6Chx9+mC5duvDJJ58wffp0RowYweLFi7nllltISEhg9OjRALz66qts27aN2bNns2LFCgYPHszQoUOZNm0aq1evZt68eagqgwcP5ttvv6V9+/asXr2aN954g169elVI2sNXCAzDqLaU9uUOkJZ2uFrPRzB79mw++ugjwHk23bNnDwcPHiwy7iWXXEJERAQdOnTIn3tg2rRpTJs2LX88QHp6OmvXrqV9+/a0bNmywkQATAgMwzDKRWnzEZSF2NjY/HWftwdV5b777uPmm2/O35eWlsaePXsq9NoQTo3FhmEYJVDR8xH069ePd955B3ANxMnJydSrV4/ExETS0tJKPf68887jtddeIz09HYCtW7eya9eusiYrKMKmRPDLL9C0qo0wDKPaUtHzETzyyCOMHDmSjh07UqdOHd544w0ALr74YoYOHcqnn36a31hcFIMGDWL58uWcddZZACQkJPDSSy+RlJR0bAktgpA6nQsF3bp10wULFpT5uLcGf8C1/7mycGANS3t5qA0+aMqKpblmsnz5ck499dSg45uvoeIp6l6KSLFO58Kmakg09+jAr7+GhQsr3xjDMIxqRNhUDaXMf+rowHPPdb9hUDIwDCM01Ib5CMJGCBruW1PVJhiGUQu5/vrruf7666vajGMibKqGDMMwjKIxITAMwwhzTAgMwzDCHBMCwzCMMMeEwDAM4xgoqxvq6ogJgWEYhsebb75Jx44d6dSpE9deey0bNmxg4MCBdOzYkV/96lds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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Signal inputs\n", + "N_steps = 100\n", + "\n", + "N_min = 10\n", + "N_max = 10000\n", + "n_incr = (N_max / N_min)**(1 / N_steps)\n", + "N_arr = []\n", + "for s in range(N_steps + 1):\n", + " n = int(N_min * n_incr**s)\n", + " N_arr.append(n)\n", + "\n", + "sigma_weak = 0.3\n", + "sigma_other = 1.0\n", + "\n", + "SNR_dB = 20 * np.log10(sigma_weak / sigma_other)\n", + "print(f\"SNR input = {SNR_dB:.3f} dB\")\n", + "\n", + "# Correlator mean(A * B)\n", + "cor_weak_mean_arr = []\n", + "cor_weak_std_arr = []\n", + "cor_other_mean_arr = []\n", + "cor_other_std_arr = []\n", + "cor_sys_mean_arr = []\n", + "cor_sys_std_arr = []\n", + "cor_SNR_arr = []\n", + "cor_SNR_dB_arr = []\n", + "for N in N_arr:\n", + " si_weak = np.random.randn(N)\n", + " si_weak *= sigma_weak / np.std(si_weak)\n", + "\n", + " # Signal input A\n", + " sA_other = np.random.randn(N)\n", + " sA_other *= sigma_other / np.std(sA_other)\n", + " sA_sys = sA_other + si_weak\n", + "\n", + " # Signal input B\n", + " sB_other = np.random.randn(N)\n", + " sB_other *= sigma_other / np.std(sB_other)\n", + " sB_sys = sB_other + si_weak\n", + " \n", + " # Correlate A and B\n", + " cor_weak_mean = np.mean(si_weak * si_weak)\n", + " cor_weak_mean_arr.append(cor_weak_mean)\n", + " cor_weak_std = np.std(si_weak * si_weak)\n", + " cor_weak_std_arr.append(cor_weak_std)\n", + " cor_other_mean = np.mean(sA_other * sB_other)\n", + " cor_other_mean_arr.append(cor_other_mean)\n", + " cor_other_std = np.std(sA_other * sB_other)\n", + " cor_other_std_arr.append(cor_other_std)\n", + " cor_sys_mean = np.mean(sA_sys * sB_sys)\n", + " cor_sys_mean_arr.append(cor_sys_mean)\n", + " cor_sys_std = np.std(sA_sys * sB_sys)\n", + " cor_sys_std_arr.append(cor_sys_std)\n", + " #print(f\"{N}, {cor_weak_mean:9.6f}, {cor_other_mean:9.6f}, {cor_sys_mean:9.6f}\")\n", + " #print(f\"{N}, {cor_weak_std:9.6f}, {cor_other_std:9.6f}, {cor_sys_std:9.6f}\")\n", + "\n", + " SNR = np.abs(cor_weak_mean / cor_other_mean)\n", + " SNR_dB = 10 * np.log10(SNR)\n", + " cor_SNR_arr.append(SNR)\n", + " cor_SNR_dB_arr.append(SNR_dB)\n", + " #print(f\"{N}, SNR output = {SNR_dB:.0f} dB\")\n", + "\n", + "plt.figure(1)\n", + "plt.plot(N_arr, cor_weak_mean_arr, 'g', N_arr, cor_other_mean_arr, 'b', N_arr, cor_sys_mean_arr, 'r')\n", + "plt.title(\"Correlator mean\")\n", + "plt.xlabel(\"Number of samples\")\n", + "plt.ylabel(\"Cross power mean\")\n", + "plt.legend(['cor_weak', 'cor_other', 'cor_sys'])\n", + "plt.grid()\n", + "\n", + "plt.figure(2)\n", + "plt.plot(N_arr, cor_weak_std_arr, 'g', N_arr, cor_other_std_arr, 'b', N_arr, cor_sys_std_arr, 'r')\n", + "plt.title(\"Correlator std\")\n", + "plt.xlabel(\"Number of samples\")\n", + "plt.ylabel(\"Cross power std\")\n", + "plt.legend(['cor_weak', 'cor_other', 'cor_sys'])\n", + "plt.grid()\n", + "\n", + "plt.figure(3)\n", + "#plt.plot(N_arr, cor_SNR_arr, 'r')\n", + "plt.plot(N_arr, cor_SNR_dB_arr, 'r')\n", + "plt.title(\"Correlator\")\n", + "plt.xlabel(\"Number of samples\")\n", + "#plt.ylabel(\"SNR\")\n", + "plt.ylabel(\"SNR [dB]\")\n", + "plt.grid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8713e865", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/erko_howto_tools.txt b/doc/erko_howto_tools.txt index 3bd3a1be0d91ba3f973f5aedc3f7fe47fbd0b994..3870bca56c84bc88fde8a3a631250a269a1592df 100755 --- a/doc/erko_howto_tools.txt +++ b/doc/erko_howto_tools.txt @@ -4,12 +4,14 @@ * ARGS * GIT workflow * SVN +* SDP HW tests (SDPTR, upe_gear, tcpdump) * Confluence * Polarion * LaTeX * Markdown * Vi * Remote access +* Remote access using step * Regression test * License server * Screen to run a terminal session without ssh connection @@ -21,7 +23,8 @@ * Jupyter * Graphana * Zenodo DOI -* SDPTR +* Install OpenSCAD +* Drawio @@ -43,6 +46,9 @@ # Setup RadioHDL development environment for hdl/. The hdl/libraries, hdl/boards and hdl/applications are # developed simultaneously and therefor in one git hdl/ repository +> cd git + alias initsdp='cd $HOMEDATA/git/hdl;. ./init_hdl.sh;cd ../upe_gear;. ./init_upe.sh;cd ../sdptr;. ./init_sdptr.sh;cd ..' + > cd ~/git/hdl > . ./init_hdl.sh @@ -56,6 +62,7 @@ - cp ${RADIOHDL_WORK}/hdl_user_components.ipx $altera_dir/ip/altera/user_components.ipx * init_hdl.sh automatically also sources ../radiohdl/init_radiohdl.sh if necessary + * init_hdl.sh automatically also sources ../args/init_args.sh if necessary source also radiohdl tools @@ -98,13 +105,24 @@ during tb simulation load --> fixed by "sudo chmod a+w -R modelsim_altera_libs/1 > run_quartus unb1 & -# Run command line synthesis +# Run command line synthesis for dts +quartus_config unb2c run_qsys_pro unb2c lofar2_unb2c_sdp_station_full; gen_rom_mmap.py --avalon -d lofar2_unb2c_sdp_station -r lofar2_unb2c_sdp_station_full; run_reg unb2c lofar2_unb2c_sdp_station_full; run_qcomp unb2c lofar2_unb2c_sdp_station_full --clk=CLK; run_rbf unb2c lofar2_unb2c_sdp_station_full +# Run command line synthesis for sdp-arts +quartus_config unb2b +run_qsys_pro unb2b lofar2_unb2b_sdp_station_full_wg +gen_rom_mmap.py --avalon -d lofar2_unb2b_sdp_station -r lofar2_unb2b_sdp_station_full_wg +run_reg unb2b lofar2_unb2b_sdp_station_full_wg +run_qcomp unb2b lofar2_unb2b_sdp_station_full_wg --clk=CLK +run_rbf unb2b lofar2_unb2b_sdp_station_full_wg + +> quartus_config unb2b; run_qsys_pro unb2b lofar2_unb2b_sdp_station_full_wg; gen_rom_mmap.py --avalon -d lofar2_unb2b_sdp_station -r lofar2_unb2b_sdp_station_full_wg; run_reg unb2b lofar2_unb2b_sdp_station_full_wg; run_qcomp unb2b lofar2_unb2b_sdp_station_full_wg --clk=CLK; run_rbf unb2b lofar2_unb2b_sdp_station_full_wg + ******************************************************************************* * RadioHDL with SVN ******************************************************************************* @@ -384,6 +402,92 @@ small narrow icons. I can recover them by selecting the Figure icon and then choosing the expand button in the bar on top or below the Figure. Weird, but for me it is an ok workaround, + +******************************************************************************* +* SDP HW tests (SDPTR, upe_gear, tcpdump): +******************************************************************************* + +Remote access using step: + +> mystep + +then: + +> ping dop386.astron.nl +> ping 10.87.0.186 (= dop386) + +> ssh -X dop386.astron.nl +> ssh -X kooistra@10.87.0.186 # dop386 from ASTROM +> ssh -J bastion.astron.nl kooistra@10.87.0.186 # dop386 from home + +1) gitlab + Zorg er voor dat je de GIT repositories hebt op dop386 (10.87.0.186) + 10 git clone https://git.astron.nl/lofar2.0/sdptr + 12 git clone https://git.astron.nl/desp/hdl + 13 git clone https://git.astron.nl/desp/radiohdl + 14 git clone https://git.astron.nl/desp/args + 15 git clone https://git.astron.nl/desp/upe_gear + 37 initsdp + + scp ~/.gitconfig kooistra@dop386:/home/kooistra # for default git user name and user email + + +2) upe_gear + a) register map uitlezen: util_unb2.py --unb2 16:19 --pn2 0:3 --seq REGMAP + 25 util_system_info.py --unb2 16:19 --pn2 0:3 -n 99 + 35 more reginfo/register_info.py + b) PPS count: util_ppsh.py --unb2 16:19 --pn2 0:3 -n 1 + c) unb2b_minimal laden: util_epcs.py --unb2 16:19 --pn2 0:3 -n 9 + d) cd ~/git/hdl/applications/lofar2/images + e) image uitpakken: tar -xvzf lofar2_unb2b_sdp_station_full_wg-r241070441.tar.gz + f) image flashen: util_epcs.py --unb2 16:19 --pn2 0:3 -n 4 -s ./lofar2_unb2b_sdp_station_full_wg-r241070441.rbf + g) User image laden: util_epcs.py --unb2 16:19 --pn2 0:3 -n 8 + + +3) SDPTR RPi4: + host 10.99.0.250 + port 4840 for DTS-lab + port 4842 for sdp-arts + --ip dop386 --mac dop386 for statistics destination + + 50 stat_stream_xst.py --host 10.99.0.250 --port 4842 -h + 51 stat_stream_xst.py --host 10.99.0.250 --port 4842 --headers + 52 stat_stream_xst.py --host 10.99.0.250 --port 4842 --headers --stream ON + 57 stat_stream_xst.py --host 10.99.0.250 --port 4842 --setup --ip dop386 --mac dop386 + + 43 sdp_rw.py --host 10.99.0.250 --port 4842 -l + 44 sdp_rw.py --host 10.99.0.250 --port 4842 -l pps + 45 sdp_rw.py --host 10.99.0.250 --port 4842 -r pps_capture_cnt + + 114 sdp_rw.py --host 10.99.0.250 --port 4842 -r sdp_config_first_fpga_nr + 116 sdp_rw.py --host 10.99.0.250 --port 4842 -r sdp_config_nof_fpgas + + 92 sdp_rw.py --host 10.99.0.250 --port 4842 -w fpga_mask [True]*16 + 93 sdp_rw.py --host 10.99.0.250 --port 4842 -r fpga_mask + 99 sdp_rw.py --host 10.99.0.250 --port 4842 -r global_node_index + + 80 sdp_rw.py --host 10.99.0.250 --port 4842 -r scrap + 81 sdp_rw.py --host 10.99.0.250 --port 4842 -w scrap [1]*16 + 82 sdp_rw.py --host 10.99.0.250 --port 4842 -w scrap [1]*8192 + 83 sdp_rw.py --host 10.99.0.250 --port 4842 -r scrap + + 72 sdp_rw.py --host 10.99.0.250 --port 4842 -w processing_enable [False]*16 + 73 sdp_rw.py --host 10.99.0.250 --port 4842 -r processing_enable + + 66 vi test/py/base/statistics_stream_packet.py + + 58 sdp_rw.py --host 10.99.0.250 --port 4842 -r xst_offload_hdr_eth_destination_mac + 59 sdp_rw.py --host 10.99.0.250 --port 4842 -r xst_offload_hdr_eth_destination_ip + 64 sdp_rw.py --host 10.99.0.250 --port 4842 -r xst_integration_interval + 71 sdp_rw.py --host 10.99.0.250 --port 4842 -r signal_input_bsn + + +4) tcpdump + > ifconfig # to find ethernet port + > sudo tcpdump -vvXXSnelfi enp5s0 port 5001 # for UDP only + > sudo tcpdump -vvXXSnelfi enp5s0 port 5001 > tcpdump.txt (> is new file, >> is append) + + ******************************************************************************* * Polarion: ******************************************************************************* @@ -490,27 +594,45 @@ Host dop421 ProxyCommand ssh -q -A astron netcat 10.87.0.221 ******************************************************************************* -* Regression test +* Remote access using step: ******************************************************************************* -* Remote access to regression test machine dop349: +* Old way: Remote access to regression test machine dop349: ssh -X kooistra@portal.astron.nl -# Ipv via portal.astron.nl nu via bastion.astron.nl (195.169.155.27) mbv step client +# New way: Ipv via portal.astron.nl nu via bastion.astron.nl (195.169.155.27) mbv step client # zie: https://support.astron.nl/confluence/pages/viewpage.action?spaceKey=IN&title=SSH+access+to+the+ASTRON+network /home/kooistra/.ssh/config /home/kooistra/.step/ssh/config /home/kooistra/.step/ssh/known_hosts +ssh -J bastion.astron.nl kooistra@10.87.0.186 # = dop386 ssh -J bastion.astron.nl regtest@dop349.astron.nl You won't be asked for a (bastion) password. The certificate you've just generated will last for twelve hours. Once it's elapsed, the only step from the above you need to perform again is $ step ssh login kooistra@astron.nl --provisioner "keycloak" +alias mystep='step ssh login kooistra@astron.nl --provisioner "keycloak"' + Whereupon you'll be good for another twelve hours. The above command is a great candidate for a shell alias. +******************************************************************************* +* Regression test +******************************************************************************* + +Remote access using step: + +> mystep + +then: + +> ping dop349.astron.nl --> responses within ~20 ms +> ping 10.87.6.144 --> --> responses within ~20 ms, ip dop349 = 10.87.6.144 + +> ssh -X regtest@dop349.astron.nl + # On dop349 crontab -l # shows scheduled cron jobs crontab -e # edit schedule @@ -718,6 +840,9 @@ https://linuxize.com/ > passwd +# If login does not source .bashrc, then set bash as default shell and relogin +chsh -s /bin/bash + # Linux update via # - system updates available icon and notifications icon in toolbar # - of via command line: @@ -746,6 +871,8 @@ dop466_0 = HDD > zip -r apertif_matlab-v1.0.zip apertif_matlab > zipinfo apertif_matlab-v1.0.zip +> tar -xvzf lofar2_unb2b_sdp_station_full_wg-r241070441.tar.gz + > grep -rl 'search text in files' . # -r for recursive, -l for only list filename > find . -name *_thisfile.txt @@ -756,6 +883,7 @@ Start --> Administration --> Synaptic package manager > sudo -s # to become root > sudo pip install numpy # to run Python2 library installer as root > sudo pip3 install numpy # to run Python3 library installer as root +> sudo pip3 install matplotlib > sudo apt-get install python3-tk # worked, now I can do: python3 test_plot.py @@ -782,6 +910,8 @@ Start --> Administration --> Synaptic package manager # Add to .bashrc: export PATH="$HOME/.local/bin:$PATH" > jupyter-lab +WARNING: The scripts f2py, f2py3 and f2py3.8 are installed in '/home/kooistra/.local/bin' which is not on PATH. + # Markdown > sudo pip3 install markdown # zit al in Python3, maar kan alleen md --> html > sudo pip3 install mdutils # https://pypi.org/project/mdutils/ # kan md genereren @@ -954,9 +1084,9 @@ Gelukt ! ******************************************************************************* -* SDPTR +* Drawio ******************************************************************************* -:kooistra@dop466:/dop466_0/kooistra/git/sdptr/test/py/control$ ./sdp_rw.py --host dop421 -l -:kooistra@dop466:/dop466_0/kooistra/git/sdptr/test/py/control$ ./sdp_rw.py --host dop421 -r firmware_version - +Oude drawio uninstall mbv Administration/Software Manager +Nieuw heet nu diagrams.net 18.1.3 installed mbv Administration/Software Manager +Alt-F7 to move window on screen diff --git a/libraries/base/dp/dp.peripheral.yaml b/libraries/base/dp/dp.peripheral.yaml index 9cca7c30d99b6efd5ea8c17f1b7c3d549c246ff1..697f014501864ff93650e4ef28770ad95e7575f5 100644 --- a/libraries/base/dp/dp.peripheral.yaml +++ b/libraries/base/dp/dp.peripheral.yaml @@ -107,7 +107,7 @@ peripherals: - peripheral_name: dp_bsn_align_v2 # pi_dp_bsn_align_v2.py - peripheral_description: "Align frames from multiple input streams." + peripheral_description: "Align packets from multiple input streams." parameters: # Parameters of dp_bsn_align_v2.vhd - { name: g_nof_streams, value: 2 } @@ -120,12 +120,12 @@ peripherals: number_of_mm_ports: g_nof_streams fields: - - field_name: enable - field_description: "Stream enable per stream via bits g_nof_streams-1 : 0. Bit value 0 disables the stream, 1 enables the stream. Disabled streams are not aligned." + field_description: "Stream enable per stream. Value 0 disables the stream, 1 enables the stream. Disabled streams are not aligned." address_offset: 0 * MM_BUS_SIZE mm_width: 1 access_mode: RW - - field_name: replaced_pkt_cnt - field_description: "Count of packets that contain replacement data per sync interval." + field_description: "Count of packets per stream that contain replacement data per sync interval." address_offset: 1 * MM_BUS_SIZE access_mode: RO @@ -453,12 +453,12 @@ peripherals: mm_port_description: "" fields: - - field_name: err_count_index - field_description: "The total amount of discarded DP blocks per bit in the in_sosi.err field (g_nof_err_counts-1 DOWNTO 0)." + field_description: "Number of errors count per bit in the input sosi.err field (g_nof_err_counts-1 DOWNTO 0)." number_of_fields: g_nof_err_counts address_offset: 0 access_mode: RO - - field_name: total_discarded_blocks - field_description: "The total amount of discarded DP blocks." + field_description: "The total amount of discarded DP blocks. All input DP blocks with sosi.err /= 0 are discarded." address_offset: g_nof_err_counts * MM_BUS_SIZE # 8 * MM_BUS_SIZE access_mode: RO - - field_name: total_block_count diff --git a/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd index 839b6eee681665af5afb5b3a144169868fc309c5..fb32a58e02b98a023a4ddce8a75dfae4068bf0d0 100644 --- a/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd +++ b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd @@ -58,8 +58,9 @@ -- sync_in is not equal to start_pulse as start pulse indicates the start -- of a packet and not the start of a sync period. -- . For generating a bsn at out_sosi, the bsn_at_sync should contain the --- desired bsn at sync_in pulse. The bsn is increased in this component at --- every start_pulse. +-- desired bsn at sync_in pulse. If g_bsn_incr_enable then out_sosi.bsn is +-- incremented in this component at every start_pulse, else out_sosi.bsn +-- is kept at bsn_at_sync. -- -------------------------------------------------------------------------- LIBRARY IEEE,common_lib; @@ -78,16 +79,17 @@ ENTITY dp_block_from_mm IS g_word_w : NATURAL := c_word_w; g_mm_rd_latency : NATURAL := 1; -- default 1 from rd_en to rd_val, use 2 to ease timing closure g_reverse_word_order : BOOLEAN := FALSE; - g_bsn_w : NATURAL := 1 - ); + g_bsn_w : NATURAL := 1; + g_bsn_incr_enable : BOOLEAN := TRUE + ); PORT ( rst : IN STD_LOGIC; clk : IN STD_LOGIC; start_pulse : IN STD_LOGIC; - sync_in : IN STD_LOGIC := '0'; -- Must be syncronous with start_pulse. + sync_in : IN STD_LOGIC := '0'; -- Must be syncronous with start_pulse. bsn_at_sync : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS => '0'); start_address : IN NATURAL; - mm_done : OUT STD_LOGIC; + mm_done : OUT STD_LOGIC; -- = out_sosi.eop mm_mosi : OUT t_mem_mosi; mm_miso : IN t_mem_miso; out_sosi : OUT t_dp_sosi; @@ -158,7 +160,7 @@ BEGIN out_sosi.bsn <= RESIZE_DP_BSN(out_bsn); -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.bsn can be used for output bsn END PROCESS; - mm_done <= r.eop; + mm_done <= out_eop; p_reg : PROCESS(rst, clk) BEGIN @@ -219,7 +221,7 @@ BEGIN IF v.sync_in_detected = '1' THEN v.sync := '1'; v.sync_in_detected := '0'; - ELSE + ELSIF g_bsn_incr_enable = TRUE THEN v.bsn := INCR_UVEC(r.bsn, 1); END IF; END IF; diff --git a/libraries/base/dp/src/vhdl/dp_block_from_mm_dc.vhd b/libraries/base/dp/src/vhdl/dp_block_from_mm_dc.vhd index 86189e162cc1f7c9ccc80c94795eac7f32d9a7f4..b355ca2e1d552d078a634042fabe958c1372826c 100644 --- a/libraries/base/dp/src/vhdl/dp_block_from_mm_dc.vhd +++ b/libraries/base/dp/src/vhdl/dp_block_from_mm_dc.vhd @@ -21,10 +21,22 @@ -- . Pieter Donker -- Purpose: -- . Read a block of data from memory mapped (MM) location and stream it as a block of data, --- this is a dual-clock wrapper around dp_block_from_mm.vhd +-- this is a dual-clock wrapper around dp_block_from_mm.vhd. -- Description: -- . https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+filterbank -- . see dp_block_from_mm.vhd +-- . read block - output block synchronisation: +-- The start_pulse causes dp_block_from_mm to read a block from memory. The +-- mm_done = mm_fifo_sosi.eop signals that the last word was read from +-- memory and is about to enter the u_dp_fifo_fill_eop. The +-- u_dp_fifo_fill_eop can only output a new packet when it has got the eop, +-- so then the out_sop = dp_out_sosi.sop will appear some cycles later at the +-- u_dp_fifo_fill_eop output, due to the mm_clk - dp_clk domain crossing. +-- The out_sop thus indicates that the complete block available in the +-- u_dp_fifo_fill_eop and is being output. Now a new start_pulse can be +-- accepted by dp_block_from_mm_dc to read a next block. Thanks to this +-- handshake the start_pulse and out_sop always follow in pairs. +-- -- -------------------------------------------------------------------------- LIBRARY IEEE,common_lib; @@ -42,8 +54,9 @@ ENTITY dp_block_from_mm_dc IS g_nof_data : NATURAL; g_word_w : NATURAL := c_word_w; g_reverse_word_order : BOOLEAN := FALSE; - g_bsn_w : NATURAL := 1 - ); + g_bsn_w : NATURAL := 1; + g_bsn_incr_enable : BOOLEAN := TRUE + ); PORT ( -- mm_clk domain mm_rst : IN STD_LOGIC; @@ -54,10 +67,10 @@ ENTITY dp_block_from_mm_dc IS dp_rst : IN STD_LOGIC; dp_clk : IN STD_LOGIC; start_pulse : IN STD_LOGIC; - sync_in : IN STD_LOGIC := '0'; -- Must be syncronous with start_pulse. + sync_in : IN STD_LOGIC := '0'; -- Must be syncronous with start_pulse. bsn_at_sync : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS => '0'); start_address : IN NATURAL; - done : OUT STD_LOGIC; + out_sop : OUT STD_LOGIC; -- = out_sosi.sop out_sosi : OUT t_dp_sosi; out_siso : IN t_dp_siso ); @@ -69,61 +82,80 @@ ARCHITECTURE str OF dp_block_from_mm_dc IS -- Fit one packet in FIFO, and less than two, to avoid filling the FIFO with -- multiple packets in case writing FIFO (mm_clk) is faster than reading - -- FIFO (dp_clk). + -- FIFO (dp_clk). It also works if the FIFO can fit multiple packets, + -- because the handshake between out_sop and start_pulse takes care that a + -- new packet will only be input when the previous packet is being output. CONSTANT c_fifo_fill : NATURAL := c_packet_size; CONSTANT c_fifo_size : NATURAL := c_packet_size + c_packet_size/2; CONSTANT c_start_addr_w : NATURAL := c_natural_w; CONSTANT c_delay_len : NATURAL := c_meta_delay_len; + SIGNAL dp_out_sosi : t_dp_sosi := c_dp_sosi_rst; + SIGNAL dp_out_siso : t_dp_siso; SIGNAL mm_fifo_sosi : t_dp_sosi := c_dp_sosi_rst; SIGNAL mm_fifo_siso : t_dp_siso; - SIGNAL start_pulse_dly : STD_LOGIC_VECTOR(0 TO c_delay_len) := (OTHERS => '0'); - SIGNAL sync_dly : STD_LOGIC_VECTOR(0 TO c_delay_len) := (OTHERS => '0'); SIGNAL mm_start_pulse : STD_LOGIC := '0'; + SIGNAL mm_sync_hi : STD_LOGIC := '0'; + SIGNAL mm_sync_level : STD_LOGIC := '0'; SIGNAL mm_sync : STD_LOGIC := '0'; - SIGNAL mm_done : STD_LOGIC := '0'; + SIGNAL mm_done : STD_LOGIC := '0'; -- not used, instead use out_sop SIGNAL mm_bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS => '0'); SIGNAL start_address_slv : STD_LOGIC_VECTOR(c_start_addr_w-1 DOWNTO 0) := (OTHERS => '0'); SIGNAL mm_start_address_slv : STD_LOGIC_VECTOR(c_start_addr_w-1 DOWNTO 0) := (OTHERS => '0'); SIGNAL mm_start_address : NATURAL := 0; BEGIN - -- Use sync/start_pulse_dly to make sure mm_start_address_slv is stable before - -- mm_start_pulse, also when mm_clk is faster than dp_clk (e.g. in sim). - start_pulse_dly(0) <= start_pulse; - start_pulse_dly(1 TO c_delay_len) <= start_pulse_dly(0 TO c_delay_len-1) WHEN rising_edge(dp_clk); - sync_dly(0) <= sync_in; - sync_dly(1 TO c_delay_len) <= sync_dly(0 TO c_delay_len-1) WHEN rising_edge(dp_clk); + -- Use g_delay_len = c_meta_delay_len + 4 for start_pulse and g_delay_len = + -- c_meta_delay_len for the other signals. The + 4 ensures that the other + -- signals are already stable in the mm_clk domain, when the mm_start_pulse + -- occurs in the mm_clk domain. Use + 4 to still have 2 clock cycles margin + -- if mm_start_pulse arrive one clock cycle early and mm_sync_hi arrives one + -- clock cycle late. u_common_spulse_start_pulse : ENTITY common_lib.common_spulse + GENERIC MAP ( + g_delay_len => c_meta_delay_len + 4 + ) PORT MAP ( in_rst => dp_rst, in_clk => dp_clk, - in_pulse => start_pulse_dly(c_delay_len), + in_pulse => start_pulse, out_rst => mm_rst, out_clk => mm_clk, out_pulse => mm_start_pulse ); + -- The synchronous start_pulse and sync_in in the dp_clk domain cannot be + -- passed on via two separate common_spulse instances, because then they may + -- appear at different clock cycles in the mm_clk domain, due to that the + -- dp_clk and mm_clk are asynchronous on HW. Therefore use mm_sync_level to + -- pass on sync_in. u_common_spulse_sync : ENTITY common_lib.common_spulse + GENERIC MAP ( + g_delay_len => c_meta_delay_len + ) PORT MAP ( in_rst => dp_rst, in_clk => dp_clk, - in_pulse => sync_dly(c_delay_len), + in_pulse => sync_in, out_rst => mm_rst, out_clk => mm_clk, - out_pulse => mm_sync + out_pulse => mm_sync_hi ); - u_common_spulse_mm_done : ENTITY common_lib.common_spulse - PORT MAP ( - in_rst => mm_rst, - in_clk => mm_clk, - in_pulse => mm_done, - out_rst => dp_rst, - out_clk => dp_clk, - out_pulse => done - ); + p_mm_sync : PROCESS(mm_clk) + BEGIN + IF rising_edge(mm_clk) THEN + IF mm_sync_hi = '1' THEN + mm_sync_level <= '1'; + END IF; + IF mm_start_pulse = '1' THEN + mm_sync_level <= '0'; + END IF; + END IF; + END PROCESS; + + mm_sync <= mm_sync_level AND mm_start_pulse; -- synchronous with mm_start_pulse start_address_slv <= TO_UVEC(start_address, c_start_addr_w); mm_start_address <= TO_UINT(mm_start_address_slv); @@ -169,8 +201,8 @@ BEGIN snk_in => mm_fifo_sosi, snk_out => mm_fifo_siso, -- ST source - src_out => out_sosi, - src_in => out_siso + src_out => dp_out_sosi, + src_in => dp_out_siso ); u_dp_block_from_mm : ENTITY work.dp_block_from_mm @@ -181,7 +213,8 @@ BEGIN g_nof_data => g_nof_data, g_word_w => g_word_w, g_reverse_word_order => g_reverse_word_order, - g_bsn_w => g_bsn_w + g_bsn_w => g_bsn_w, + g_bsn_incr_enable => g_bsn_incr_enable ) PORT MAP ( clk => mm_clk, @@ -191,11 +224,18 @@ BEGIN sync_in => mm_sync, bsn_at_sync => mm_bsn_at_sync, start_address => mm_start_address, - mm_done => mm_done, + mm_done => mm_done, -- = mm_fifo_sosi.eop mm_mosi => mm_mosi, mm_miso => mm_miso, out_sosi => mm_fifo_sosi, out_siso => mm_fifo_siso ); + + -- Wire output + out_sop <= dp_out_sosi.sop; + + out_sosi <= dp_out_sosi; + dp_out_siso <= out_siso; + END str; diff --git a/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd index 66598b4d337c739710274cbe38b8ebebb8d85bf6..84c6953020fc5f8c44d5313a2f25398af3612de5 100644 --- a/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd +++ b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd @@ -29,9 +29,16 @@ -- sop and eop will be active. -- Alternatively, one can assert dp_on while dp_on_pps is high to -- start the data path on the next PPS. +-- The dp_on is asynchronous. The dp_bsn_source_v2 takes care that +-- src_out.valid starts with a src_out.sop and that src_out.valid can +-- only go low after a src_out.eop, to ensure that src_out only produces +-- complete sop-eop blocks that enter the subsequent processing. +-- The bs_start is active at the first src_out.sop after dp_on went high. -- Remarks: --- Starting the data path is only possible from the dp_off state, so one +-- . Starting the data path is only possible from the dp_off state, so one -- has to disable (dp_on='0') the data path before restarting it. +-- . Effectively dp_on_status = src_out.valid, because when the BSN source +-- is on, then src_out.valid = '1' at every clk cycle. -- -- author : P.Donker okt. 2020, added bsn_time_offset -- @@ -57,8 +64,8 @@ ENTITY dp_bsn_source_v2 IS dp_on : IN STD_LOGIC; dp_on_pps : IN STD_LOGIC; - dp_on_status : OUT STD_LOGIC; - bs_restart : OUT STD_LOGIC; + dp_on_status : OUT STD_LOGIC; -- = src_out.valid + bs_restart : OUT STD_LOGIC; -- = src_out.sop for first sop after dp_on went high nof_clk_per_sync : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(g_nof_clk_per_sync, c_word_w); bsn_init : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); diff --git a/libraries/technology/jesd204b/tech_jesd204b.peripheral.yaml b/libraries/technology/jesd204b/tech_jesd204b.peripheral.yaml index 39125f424499c9c9c3793f229d2711024798dfa6..4dcb02e027356ec88766d3e8a895db9af14e8584 100644 --- a/libraries/technology/jesd204b/tech_jesd204b.peripheral.yaml +++ b/libraries/technology/jesd204b/tech_jesd204b.peripheral.yaml @@ -21,8 +21,8 @@ peripherals: bit_offset: 31 mm_width: 1 access_mode: RW - - - field_name: enable - field_description: "Enable JESD signal input i by setting bit i = 1, disable by clearing bit i = 0." + - - field_name: disable + field_description: "Disable JESD signal input i by setting bit i = 1, enable by clearing bit i = 0." address_offset: 0x0 bit_offset: 0 mm_width: 31