diff --git a/src/constants.h b/src/constants.h index 35b5e4f81ad006202d37482cc0e08002ce38f520..c520fb4ec5bcb9de9a554294b673ab028647fb6a 100644 --- a/src/constants.h +++ b/src/constants.h @@ -49,6 +49,7 @@ #define C_N_step 1 #define C_N_crosslets_max 7 #define C_N_scrap 512 // Number of 32 bit words in FPGA scrap memory. +#define C_N_fft 1024 // The FFT size defines the number of samples per block. #define C_N_pol 2 // Number of antenna polarizations, X and Y. #define C_A_pn 6 // Number of dual polarization antennas per Processing Node (PN) FPGA. // #define C_N_beamlets 976 // Number of beamlets per antenna band 488, 976 diff --git a/src/fpga.cpp b/src/fpga.cpp index 53ba9e9739a4ec99ed2ffd99e0196dddf354fbc1..4f5ece24f4f558a95528f9954cc488ecb6278cf9 100644 --- a/src/fpga.cpp +++ b/src/fpga.cpp @@ -89,12 +89,16 @@ Fpga::Fpga(list<class Node*>& nodelist, const int32_t n_beamsets): pointMap->add_register("FPGA_xst_processing_enable_RW", "fpga/xst_processing_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN); pointMap->add_register("FPGA_xst_offload_enable_R", "fpga/xst_offload_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN); pointMap->add_register("FPGA_xst_offload_enable_RW", "fpga/xst_offload_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN); + pointMap->add_register("FPGA_xst_offload_nof_crosslets_R", "fpga/xst_offload_nof_crosslets", nodes.size(), 1, "RO", REG_FORMAT_UINT32); + pointMap->add_register("FPGA_xst_offload_nof_crosslets_RW", "fpga/xst_offload_nof_crosslets", nodes.size(), 1, "RW", REG_FORMAT_UINT32); pointMap->add_register("FPGA_xst_offload_hdr_eth_destination_mac_R", "fpga/xst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RO", REG_FORMAT_STRING); pointMap->add_register("FPGA_xst_offload_hdr_eth_destination_mac_RW", "fpga/xst_offload_hdr_eth_destination_mac", nodes.size(), 1, "RW", REG_FORMAT_STRING); pointMap->add_register("FPGA_xst_offload_hdr_ip_destination_address_R", "fpga/xst_offload_hdr_ip_destination_address", nodes.size(), 1, "RO", REG_FORMAT_STRING); pointMap->add_register("FPGA_xst_offload_hdr_ip_destination_address_RW", "fpga/xst_offload_hdr_ip_destination_address", nodes.size(), 1, "RW", REG_FORMAT_STRING); pointMap->add_register("FPGA_xst_offload_hdr_udp_destination_port_R", "fpga/xst_offload_hdr_udp_destination_port", nodes.size(), 1, "RO", REG_FORMAT_UINT16); pointMap->add_register("FPGA_xst_offload_hdr_udp_destination_port_RW", "fpga/xst_offload_hdr_udp_destination_port", nodes.size(), 1, "RW", REG_FORMAT_UINT16); + pointMap->add_register("FPGA_xst_input_bsn_at_sync_R", "fpga/xst_input_sync_at_bsn", nodes.size(), 1, "RO", REG_FORMAT_INT64); + pointMap->add_register("FPGA_xst_output_sync_bsn_R", "fpga/xst_output_sync_bsn", nodes.size(), 1, "RO", REG_FORMAT_INT64); pointMap->add_register("FPGA_processing_enable_R", "fpga/processing_enable", nodes.size(), 1, "RO", REG_FORMAT_BOOLEAN); pointMap->add_register("FPGA_processing_enable_RW", "fpga/processing_enable", nodes.size(), 1, "RW", REG_FORMAT_BOOLEAN); diff --git a/src/periph/fpga.cpp b/src/periph/fpga.cpp index cfdc546d306a718675d90de44f6b6facf630fdf4..c6037d4ef4512c9aaa9eb3c07b70ef7b163eb9d6 100644 --- a/src/periph/fpga.cpp +++ b/src/periph/fpga.cpp @@ -68,6 +68,8 @@ Periph_fpga::Periph_fpga(uint global_nr, string ipaddr, uint n_beamsets): my_current_fw_version("-.-"), my_bsn_input_sync_timeout(false), my_bsn_input_bsn(0), + my_xst_input_bsn_at_sync(0), + my_xst_output_sync_bsn(0), my_bsn_input_nof_packets(0), my_bsn_input_nof_valid(0), my_bsn_input_nof_err(0), @@ -75,7 +77,6 @@ Periph_fpga::Periph_fpga(uint global_nr, string ipaddr, uint n_beamsets): my_jesd_csr_dev_syncn {0}, my_jesd_rx_err0 {0}, my_jesd_rx_err1 {0}, - my_xst_processing_enable(false), my_pps_offset_cnt(0), my_signal_input_mean {0.0}, my_signal_input_rms {0.0} @@ -210,6 +211,9 @@ bool Periph_fpga::read(TermOutput& termout, const string addr, else if (addr == "fpga/xst_offload_enable") { retval = read_mm_port(termout, "REG_STAT_ENABLE_XST", "enable", format); } + else if (addr == "fpga/xst_offload_nof_crosslets") { + retval = read_mm_port(termout, "REG_NOF_CROSSLETS", "nof_crosslets", format); + } else if (addr == "fpga/xst_offload_hdr_eth_destination_mac") { retval = read_xst_offload_hdr_eth_destination_mac(termout, format); } @@ -228,6 +232,12 @@ bool Periph_fpga::read(TermOutput& termout, const string addr, else if (addr == "fpga/xst_subband_select") { retval = read_xst_subband_select(termout, format); } + else if (addr == "fpga/xst_input_sync_at_bsn") { + retval = read_xst_input_sync_at_bsn(termout, format, R_MEM); + } + else if (addr == "fpga/xst_output_sync_bsn") { + retval = read_xst_output_sync_bsn(termout, format, R_MEM); + } else if (addr == "fpga/processing_enable") { retval = read_mm_port(termout, "REG_BSN_SOURCE_V2", "dp_on", format); } @@ -414,6 +424,9 @@ bool Periph_fpga::write(TermOutput& termout, const string addr, const string typ else if (addr == "fpga/xst_offload_enable") { retval = write_xst_offload_enable(data); } + else if (addr == "fpga/xst_offload_nof_crosslets") { + retval = write_xst_offload_nof_crosslets(data); + } else if (addr == "fpga/xst_offload_hdr_eth_destination_mac") { retval = write_xst_offload_hdr_eth_destination_mac(data); } @@ -483,6 +496,8 @@ bool Periph_fpga::monitor(TermOutput& termout) read_time_since_last_pps(termout, REG_FORMAT_INT64, R_UCP); read_bsn_monitor_input_sync_timeout(termout, REG_FORMAT_INT64, R_UCP); read_bsn_monitor_input_bsn(termout, REG_FORMAT_INT64, R_UCP); + read_xst_input_sync_at_bsn(termout, REG_FORMAT_INT64, R_UCP); + read_xst_output_sync_bsn(termout, REG_FORMAT_INT64, R_UCP); read_bsn_monitor_input_nof_packets(termout, REG_FORMAT_INT32, R_UCP); read_bsn_monitor_input_nof_valid(termout, REG_FORMAT_INT32, R_UCP); read_bsn_monitor_input_nof_err(termout, REG_FORMAT_INT32, R_UCP); @@ -1292,6 +1307,11 @@ bool Periph_fpga::write_xst_offload_enable(const char *data) return Write("mm/0/REG_STAT_ENABLE_XST/0/enable", _data); } +bool Periph_fpga::write_xst_offload_nof_crosslets(const char *data) +{ + uint32_t *_ptr = (uint32_t *)data; + return Write("mm/0/REG_NOF_CROSSLETS/0/nof_crosslets", _ptr); +} bool Periph_fpga::read_xst_offload_hdr_eth_destination_mac(TermOutput& termout, int format) { @@ -1398,13 +1418,12 @@ bool Periph_fpga::read_xst_processing_enable(TermOutput& termout, int format) { bool retval = true; - // uint32_t data[20]; - // memset((void *)data, 0, sizeof(data)); - // retval = Read("mm/0/REG_BSN_SCHEDULER_XSUB/0/enable", data); - // bool processing_enable = (bool)data[0]; + uint32_t data[1]; + memset((void *)data, 0, sizeof(data)); + retval = Read("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/mon_output_enable", data); bool *_ptr = (bool *)termout.val; - *_ptr = my_xst_processing_enable; + *_ptr = (bool)data[0];; termout.nof_vals = 1; termout.datatype = format; return retval; @@ -1415,38 +1434,41 @@ bool Periph_fpga::write_xst_processing_enable(const char *data) bool retval = true; uint32_t *reg = new uint32_t[2]; bool processing_enable = (bool)data[0]; - uint64_t scheduled_bsn; + uint64_t start_bsn; if (processing_enable == true) { // get bsn and add latency - retval &= Read("mm/0/REG_BSN_SCHEDULER_XSUB/0/scheduled_bsn", reg); + retval &= Read("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/mon_input_bsn_at_sync", reg); if (retval == true) { - scheduled_bsn = (((uint64_t)reg[1] << 32) + reg[0]); - cout << "bsn=" << to_string(scheduled_bsn) << endl; - scheduled_bsn += C_BSN_LATENCY; - cout << "new bsn=" << to_string(scheduled_bsn) << endl; - reg[0] = (uint32_t)(scheduled_bsn & 0xffffffff); - reg[1] = (uint32_t)((scheduled_bsn >> 32) & 0xffffffff); + start_bsn = (((uint64_t)reg[1] << 32) + reg[0]); + cout << "bsn=" << to_string(start_bsn) << endl; + start_bsn = start_bsn + 2 * C_F_adc / C_N_fft; + cout << "new bsn=" << to_string(start_bsn) << endl; + reg[0] = (uint32_t)(start_bsn & 0xffffffff); + reg[1] = (uint32_t)((start_bsn >> 32) & 0xffffffff); // write sheduled bsn - retval &= Write("mm/0/REG_BSN_SCHEDULER_XSUB/0/scheduled_bsn", reg); - if (retval == true) { - my_xst_processing_enable = processing_enable; - } + retval &= Write("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/start_bsn", reg); + reg[0] = 1; + // write ctrl_enable = 1 + retval &= Write("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/ctrl_enable", reg); } } + else { + reg[0] = 0; + // write ctrl_enable = 0 + retval &= Write("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/ctrl_enable", reg); + } return retval; } bool Periph_fpga::read_xst_integration_interval(TermOutput& termout, int format) { - // TODO, fill in if supported in FW bool retval = true; - // uint32_t data[20]; - // memset((void *)data, 0, sizeof(data)); - // retval = Read("mm/0/REG_STAT_HDR_DAT_XST/0/??", data); - // double interval = ??; + uint32_t data[20]; + memset((void *)data, 0, sizeof(data)); + retval = Read("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/ctrl_interval_size", data); + double interval = (double)data[0] / C_F_adc; - double interval = 1.0; double *_ptr = (double *)termout.val; *_ptr = interval; termout.nof_vals = 1; @@ -1456,10 +1478,10 @@ bool Periph_fpga::read_xst_integration_interval(TermOutput& termout, int format) bool Periph_fpga::write_xst_integration_interval(const char *data) { - // uint32_t *_ptr = (uint32_t *)data; - // TODO, fill in if supported in FW - // return Write("mm/0/REG_STAT_HDR_DAT_XST/0/??", data); - return true; + double *_ptr = (double *)data; + uint32_t *reg = new uint32_t[1]; + reg[0] = (uint32_t)round(_ptr[0] * C_F_adc); + return Write("mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/ctrl_interval_size", reg); } bool Periph_fpga::read_xst_subband_select(TermOutput& termout, int format) @@ -1481,6 +1503,44 @@ bool Periph_fpga::read_xst_subband_select(TermOutput& termout, int format) return retval; } +bool Periph_fpga::read_xst_input_sync_at_bsn(TermOutput& termout, int format, int mode) { + bool retval = true; + int64_t bsn = my_xst_input_bsn_at_sync; + if (mode == R_UCP) { + uint32_t data[20]; + memset((void *)data, 0, sizeof(data)); + string regname; + regname = "mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/mon_input_bsn_at_sync"; + retval = Read(regname, data); + bsn = (((int64_t)data[1] << 32) + data[0]); + } + int64_t *_ptr = (int64_t *)termout.val; + *_ptr = bsn; + termout.nof_vals = 1; + termout.datatype = format; + my_xst_input_bsn_at_sync = bsn; + return retval; +} + +bool Periph_fpga::read_xst_output_sync_bsn(TermOutput& termout, int format, int mode) { + bool retval = true; + int64_t bsn = my_xst_output_sync_bsn; + if (mode == R_UCP) { + uint32_t data[20]; + memset((void *)data, 0, sizeof(data)); + string regname; + regname = "mm/0/REG_BSN_SYNC_SCHEDULER_XSUB/0/mon_output_sync_bsn"; + retval = Read(regname, data); + bsn = (((int64_t)data[1] << 32) + data[0]); + } + int64_t *_ptr = (int64_t *)termout.val; + *_ptr = bsn; + termout.nof_vals = 1; + termout.datatype = format; + my_xst_output_sync_bsn = bsn; + return retval; +} + bool Periph_fpga::write_xst_subband_select(const char *data) { uint32_t *_ptr = (uint32_t *)data; @@ -1579,10 +1639,10 @@ When FPGA_wg_enable_RW is set True, then enable the WG via mode = c_mode_calc = WG starts or restarts when it gets a trigger from the BSN scheduler. The trigger has to occur at the same BSN for all WG that are enabled, to ensure that they start synchronously. Any WG that are not enabled will ignore the trigger. The exact BSN at which the WG start is don't care. The trigger is -scheduled via scheduled_bsn in REG_BSN_SCHEDULER. The current BSN can be read from the REG_BSN_SCHEDULER -on one of the FPGAs. Assume the communication to write the scheduled_bsn in all FPGAs will take +scheduled via start_bsn in REG_BSN_SCHEDULER. The current BSN can be read from the REG_BSN_SCHEDULER +on one of the FPGAs. Assume the communication to write the start_bsn in all FPGAs will take less than 1 ms, then a margin of 10 - 100 ms is sufficient. The BSN period corresponds to 5.12 μs, so -a c_bsn_latency = 20000 (≈ 100 ms) is sufficient for scheduled_bsn = current_bsn + c_bsn_latency. +a c_bsn_latency = 20000 (≈ 100 ms) is sufficient for start_bsn = current_bsn + c_bsn_latency. The MP reports False when mode = c_mode_off = 0, else True. Note: The nof_samples field and mode field share an address in REG_DIAG_WG. The nof_samples = 2**W_wg_buf = 1024. @@ -1592,7 +1652,7 @@ bool Periph_fpga::write_wg_enable(const char *data) { bool *_ptr = (bool *)data; bool retval = true; uint32_t *reg = new uint32_t[4]; - uint64_t scheduled_bsn; + uint64_t start_bsn; bool wg_enable; string regname1; @@ -1621,20 +1681,20 @@ bool Periph_fpga::write_wg_enable(const char *data) { // get bsn and add latency wg_enable = _ptr[0]; if (wg_enable == true) { - regname1 = "mm/0/REG_BSN_SCHEDULER/0/scheduled_bsn"; + regname1 = "mm/0/REG_BSN_SCHEDULER/0/start_bsn"; retval = Read(regname1, reg); - scheduled_bsn = (((uint64_t)reg[1] << 32) + reg[0]); - cout << "bsn=" << to_string(scheduled_bsn) << endl; - scheduled_bsn += C_BSN_LATENCY; - cout << "new bsn=" << to_string(scheduled_bsn) << endl; - reg[0] = (uint32_t)(scheduled_bsn & 0xffffffff); - reg[1] = (uint32_t)((scheduled_bsn >> 32) & 0xffffffff); + start_bsn = (((uint64_t)reg[1] << 32) + reg[0]); + cout << "bsn=" << to_string(start_bsn) << endl; + start_bsn += C_BSN_LATENCY; + cout << "new bsn=" << to_string(start_bsn) << endl; + reg[0] = (uint32_t)(start_bsn & 0xffffffff); + reg[1] = (uint32_t)((start_bsn >> 32) & 0xffffffff); } // write sheduled bsn for (uint i=0; i< C_S_pn; i++) { wg_enable = _ptr[i]; if (wg_enable == true) { - regname1 = "mm/0/REG_BSN_SCHEDULER/" + to_string(i) + "/scheduled_bsn"; + regname1 = "mm/0/REG_BSN_SCHEDULER/" + to_string(i) + "/start_bsn"; retval = Write(regname1, reg); } } diff --git a/src/periph/fpga.h b/src/periph/fpga.h index a537008216f50593c5d9dd7c431e8b2ec099cffd..6fd292664b3ebe9e1db014f254c93d8d6598e465 100644 --- a/src/periph/fpga.h +++ b/src/periph/fpga.h @@ -61,6 +61,8 @@ private: bool my_bsn_input_sync_timeout; int64_t my_bsn_input_bsn; + int64_t my_xst_input_bsn_at_sync; + int64_t my_xst_output_sync_bsn; int32_t my_bsn_input_nof_packets; int32_t my_bsn_input_nof_valid; int32_t my_bsn_input_nof_err; @@ -128,11 +130,14 @@ private: bool read_xst_subband_select(TermOutput& termout, int format); bool write_xst_subband_select(const char *data); + bool read_xst_input_sync_at_bsn(TermOutput& termout, int format, int mode); + bool read_xst_output_sync_bsn(TermOutput& termout, int format, int mode); bool read_xst_integration_interval(TermOutput& termout, int format); bool write_xst_integration_interval(const char *data); bool read_xst_processing_enable(TermOutput& termout, int format); bool write_xst_processing_enable(const char *data); bool write_xst_offload_enable(const char *data); + bool write_xst_offload_nof_crosslets(const char *data); bool read_xst_offload_hdr_eth_destination_mac(TermOutput& termout, int format); bool write_xst_offload_hdr_eth_destination_mac(const char *data); bool read_xst_offload_hdr_ip_destination_address(TermOutput& termout, int format);