diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b2a3b41d9..1247d8219c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1152,6 +1152,10 @@ add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON}) add_library(PHY_NR ${PHY_NR_SRC}) target_link_libraries(PHY_NR nr_phy_common nr_common) +add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC}) +target_link_libraries(PHY_NR_NO_AVX_256 nr_phy_common nr_common) +target_compile_definitions(PHY_NR_NO_AVX_256 PUBLIC USE_128BIT) + add_library(PHY_NR_UE ${PHY_NR_UE_SRC}) target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common) diff --git a/ci-scripts/datalog_rt_stats.60.2x2.yaml b/ci-scripts/datalog_rt_stats.60.2x2.yaml index 6a5600a9d1..66ab367e7c 100644 --- a/ci-scripts/datalog_rt_stats.60.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.60.2x2.yaml @@ -14,7 +14,7 @@ Ref : L1 Tx processing : 400.0 DLSCH encoding : 177.0 L1 Rx processing : 345.0 - PUSCH inner-receiver : 210.0 + PUSCH inner-receiver : 200.0 Schedule Response : 3.0 DL & UL scheduling timing : 13.0 UL Indication : 3.0 diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index a309a0cb8f..205cd6072b 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -80,7 +80,6 @@ #define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" #define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" #define CONFIG_HLP_DISABLETIMECORR "disable UE timing correction\n" -#define CONFIG_HLP_RRC_CFG_PATH "path for RRC configuration\n" #define CONFIG_HLP_RE_CFG_FILE "filename for reconfig.raw in phy-test mode\n" #define CONFIG_HLP_RB_CFG_FILE "filename for rbconfig.raw in phy-test mode\n" #define CONFIG_HLP_UECAP_FILE "path for UE Capabilities file\n" diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 23eb70997a..bc5f4bc778 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -89,7 +89,7 @@ unsigned short config_frames[4] = {2,9,11,13}; extern const char *duplex_mode[]; THREAD_STRUCT thread_struct; -nrUE_params_t nrUE_params; +nrUE_params_t nrUE_params = {0}; // Thread variables pthread_cond_t nfapi_sync_cond; @@ -113,31 +113,12 @@ int oai_exit = 0; static int tx_max_power[MAX_NUM_CCs] = {0}; -int vcdflag = 0; - double rx_gain_off = 0.0; -char *usrp_args = NULL; -char *tx_subdev = NULL; -char *rx_subdev = NULL; -char *rrc_config_path = NULL; -char *reconfig_file = NULL; -char *rbconfig_file = NULL; -char *uecap_file = NULL; uint64_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; uint64_t sidelink_frequency[MAX_NUM_CCs][4]; -#if MAX_NUM_CCs == 1 -rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; -double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; -double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; -#else -rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; -double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; -double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; -#endif - // UE and OAI config variables openair0_config_t openair0_cfg[MAX_CARDS]; @@ -221,10 +202,7 @@ static void get_options(configmodule_interface_t *cfg) paramdef_t cmdline_params[] =CMDLINE_NRUEPARAMS_DESC ; int numparams = sizeofArray(cmdline_params); config_get(cfg, cmdline_params, numparams, NULL); - - AssertFatal(rrc_config_path == NULL, "the option \"rrc_config_path\" is deprecated. Please use --reconfig-file and --rbconfig-file separately to point to files reconfig.raw and rbconfig.raw\n"); - - if (vcdflag > 0) + if (nrUE_params.vcdflag > 0) ouput_vcd = 1; } @@ -232,15 +210,10 @@ static void get_options(configmodule_interface_t *cfg) void set_options(int CC_id, PHY_VARS_NR_UE *UE){ NR_DL_FRAME_PARMS *fp = &UE->frame_parms; - // Init power variables - tx_max_power[CC_id] = tx_max_power[0]; - rx_gain[0][CC_id] = rx_gain[0][0]; - tx_gain[0][CC_id] = tx_gain[0][0]; - // Set UE variables - UE->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; - UE->tx_total_gain_dB = (int)tx_gain[CC_id][0]; - UE->tx_power_max_dBm = tx_max_power[CC_id]; + UE->rx_total_gain_dB = (int)nrUE_params.rx_gain + rx_gain_off; + UE->tx_total_gain_dB = (int)nrUE_params.tx_gain; + UE->tx_power_max_dBm = nrUE_params.tx_max_power; UE->rf_map.card = 0; UE->rf_map.chain = CC_id + 0; UE->max_ldpc_iterations = nrUE_params.max_ldpc_iterations; @@ -317,9 +290,9 @@ void init_openair0() openair0_cfg[card].configFilename = get_softmodem_params()->rf_config_file; - if (usrp_args) openair0_cfg[card].sdr_addrs = usrp_args; - if (tx_subdev) openair0_cfg[card].tx_subdev = tx_subdev; - if (rx_subdev) openair0_cfg[card].rx_subdev = rx_subdev; + if (get_nrUE_params()->usrp_args) openair0_cfg[card].sdr_addrs = get_nrUE_params()->usrp_args; + if (get_nrUE_params()->tx_subdev) openair0_cfg[card].tx_subdev = get_nrUE_params()->tx_subdev; + if (get_nrUE_params()->rx_subdev) openair0_cfg[card].rx_subdev = get_nrUE_params()->rx_subdev; } } @@ -483,7 +456,7 @@ int main(int argc, char **argv) else init_pdcp(mode_offset + ue_id_g); - init_NR_UE(NB_UE_INST, uecap_file, reconfig_file, rbconfig_file); + init_NR_UE(NB_UE_INST, get_nrUE_params()->uecap_file, get_nrUE_params()->reconfig_file, get_nrUE_params()->rbconfig_file); if (get_softmodem_params()->emulate_l1) { RCconfig_nr_ue_macrlc(); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 204b16b109..08cafc8379 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -30,27 +30,26 @@ /*------------------------------------------------------------------------------------------------------------------------------------------*/ // clang-format off #define CMDLINE_NRUEPARAMS_DESC { \ - {"usrp-args", CONFIG_HLP_USRP_ARGS, 0, .strptr=&usrp_args, .defstrval="type=b200", TYPE_STRING, 0}, \ - {"tx_subdev", CONFIG_HLP_TX_SUBDEV, 0, .strptr=&tx_subdev, .defstrval=NULL, TYPE_STRING, 0}, \ - {"rx_subdev", CONFIG_HLP_RX_SUBDEV, 0, .strptr=&rx_subdev, .defstrval=NULL, TYPE_STRING, 0}, \ + {"usrp-args", CONFIG_HLP_USRP_ARGS, 0, .strptr=&nrUE_params.usrp_args, .defstrval="type=b200", TYPE_STRING, 0}, \ + {"tx_subdev", CONFIG_HLP_TX_SUBDEV, 0, .strptr=&nrUE_params.tx_subdev, .defstrval=NULL, TYPE_STRING, 0}, \ + {"rx_subdev", CONFIG_HLP_RX_SUBDEV, 0, .strptr=&nrUE_params.rx_subdev, .defstrval=NULL, TYPE_STRING, 0}, \ {"dlsch-parallel", CONFIG_HLP_DLSCH_PARA, 0, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ {"offset-divisor", CONFIG_HLP_OFFSET_DIV, 0, .uptr=&nrUE_params.ofdm_offset_divisor, .defuintval=8, TYPE_UINT32, 0}, \ {"max-ldpc-iterations", CONFIG_HLP_MAX_LDPC_ITERATIONS, 0, .iptr=&nrUE_params.max_ldpc_iterations, .defuintval=8, TYPE_UINT8, 0}, \ {"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&(nrUE_params.ldpc_offload_flag), .defintval=0, TYPE_INT, 0}, \ - {"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, .iptr=&vcdflag, .defintval=0, TYPE_INT, 0}, \ - {"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \ - {"rrc_config_path", CONFIG_HLP_RRC_CFG_PATH, 0, .strptr=&rrc_config_path, .defstrval=NULL, TYPE_STRING, 0}, \ - {"reconfig-file", CONFIG_HLP_RE_CFG_FILE, 0, .strptr=&reconfig_file, .defstrval="./reconfig.raw", TYPE_STRING, 0}, \ - {"rbconfig-file", CONFIG_HLP_RB_CFG_FILE, 0, .strptr=&rbconfig_file, .defstrval="./rbconfig.raw", TYPE_STRING, 0}, \ - {"ue-idx-standalone", NULL, 0, .u16ptr=&ue_idx_standalone, .defuintval=0xFFFF, TYPE_UINT16, 0}, \ - {"ue-rxgain", CONFIG_HLP_UERXG, 0, .dblptr=&(rx_gain[0][0]), .defdblval=110, TYPE_DOUBLE, 0}, \ - {"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, .dblptr=&rx_gain_off, .defdblval=0, TYPE_DOUBLE, 0}, \ - {"ue-txgain", CONFIG_HLP_UETXG, 0, .dblptr=&(tx_gain[0][0]), .defdblval=0, TYPE_DOUBLE, 0}, \ + {"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, .iptr=&nrUE_params.vcdflag, .defintval=0, TYPE_INT, 0}, \ + {"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&nrUE_params.uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \ + {"reconfig-file", CONFIG_HLP_RE_CFG_FILE, 0, .strptr=&nrUE_params.reconfig_file, .defstrval="./reconfig.raw", TYPE_STRING, 0}, \ + {"rbconfig-file", CONFIG_HLP_RB_CFG_FILE, 0, .strptr=&nrUE_params.rbconfig_file, .defstrval="./rbconfig.raw", TYPE_STRING, 0}, \ + {"ue-idx-standalone", NULL, 0, .u16ptr=&ue_idx_standalone, .defuintval=0xFFFF, TYPE_UINT16, 0}, \ + {"ue-rxgain", CONFIG_HLP_UERXG, 0, .dblptr=&nrUE_params.rx_gain, .defdblval=110, TYPE_DOUBLE, 0}, \ + {"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, .dblptr=&nrUE_params.rx_gain_off, .defdblval=0, TYPE_DOUBLE, 0}, \ + {"ue-txgain", CONFIG_HLP_UETXG, 0, .dblptr=&nrUE_params.tx_gain, .defdblval=0, TYPE_DOUBLE, 0}, \ {"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, .iptr=&(nrUE_params.nb_antennas_rx), .defuintval=1, TYPE_UINT8, 0}, \ {"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, .iptr=&(nrUE_params.nb_antennas_tx), .defuintval=1, TYPE_UINT8, 0}, \ {"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, .iptr=&(nrUE_params.UE_scan_carrier), .defintval=0, TYPE_INT, 0}, \ {"ue-fo-compensation", CONFIG_HLP_UEFO, PARAMFLAG_BOOL, .iptr=&(nrUE_params.UE_fo_compensation), .defintval=0, TYPE_INT, 0}, \ - {"ue-max-power", NULL, 0, .iptr=&(tx_max_power[0]), .defintval=90, TYPE_INT, 0}, \ + {"ue-max-power", NULL, 0, .iptr=&(nrUE_params.tx_max_power), .defintval=90, TYPE_INT, 0}, \ {"r" , CONFIG_HLP_PRB_SA, 0, .iptr=&(nrUE_params.N_RB_DL), .defintval=106, TYPE_UINT, 0}, \ {"ssb", CONFIG_HLP_SSC, 0, .iptr=&(nrUE_params.ssb_start_subcarrier), .defintval=516, TYPE_UINT16, 0}, \ {"if_freq" , CONFIG_HLP_IF_FREQ, 0, .u64ptr=&(nrUE_params.if_freq), .defuintval=0, TYPE_UINT64, 0}, \ @@ -67,25 +66,36 @@ // clang-format on typedef struct { - uint64_t optmask; //mask to store boolean config options - uint32_t ofdm_offset_divisor; // Divisor for sample offset computation for each OFDM symbol - int max_ldpc_iterations; // number of maximum LDPC iterations - tpool_t Tpool; // thread pool - int UE_scan_carrier; + uint64_t optmask; // mask to store boolean config options + uint32_t ofdm_offset_divisor; // Divisor for sample offset computation for each OFDM symbol + int max_ldpc_iterations; // number of maximum LDPC iterations + tpool_t Tpool; // thread pool + int UE_scan_carrier; int UE_fo_compensation; - uint64_t if_freq; - int if_freq_off; - int chest_freq; - int chest_time; - int no_timing_correction; - int nb_antennas_rx; + uint64_t if_freq; + int if_freq_off; + int chest_freq; + int chest_time; + int no_timing_correction; + int nb_antennas_rx; int nb_antennas_tx; - int N_RB_DL; - int ssb_start_subcarrier; + int N_RB_DL; + int ssb_start_subcarrier; int ldpc_offload_flag; - unsigned int ntn_koffset; - double ntn_ta_common; + unsigned int ntn_koffset; + double ntn_ta_common; int agc; + char *usrp_args; + char *tx_subdev; + char *rx_subdev; + char *reconfig_file; + char *rbconfig_file; + char *uecap_file; + double tx_gain; + double rx_gain; + double rx_gain_off; + int vcdflag; + int tx_max_power; } nrUE_params_t; extern uint64_t get_nrUE_optmask(void); extern uint64_t set_nrUE_optmask(uint64_t bitmask); diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 8a5b101ad4..1c0c596253 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -54,7 +54,7 @@ typedef struct { uint32_t rsrp; int rsrp_dBm; uint8_t rank_indicator; - uint8_t i1; + uint16_t i1; uint8_t i2; uint8_t cqi; rlm_t radiolink_monitoring; diff --git a/openair1/PHY/CMakeLists.txt b/openair1/PHY/CMakeLists.txt index b841d00601..8c055bf878 100644 --- a/openair1/PHY/CMakeLists.txt +++ b/openair1/PHY/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(nr_phy_common) add_subdirectory(TOOLS) +add_subdirectory(NR_TRANSPORT) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index d9f799ac37..fea6b930ac 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -30,7 +30,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" - +#include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include "executables/softmodem-common.h" #include "nr_phy_common.h" @@ -86,16 +86,15 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ul_id]; c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates; const int symbolSize = gNB->frame_parms.ofdm_symbol_size; - const int soffset = (Ns & 3) * gNB->frame_parms.symbols_per_slot*symbolSize; - const int nushift = (p >> 1) & 1; - int ch_offset = symbolSize*symbol; - const int symbol_offset = symbolSize*symbol; + const int slot_offset = (Ns & 3) * gNB->frame_parms.symbols_per_slot * symbolSize; + const int delta = get_delta(p, pusch_pdu->dmrs_config_type); + const int symbol_offset = symbolSize * symbol; const int k0 = bwp_start_subcarrier; const int nb_rb_pusch = pusch_pdu->rb_size; - LOG_D(PHY, "ch_offset %d, soffset %d, symbol_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n", - ch_offset, soffset, + LOG_D(PHY, "symbol_offset %d, slot_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n", symbol_offset, + slot_offset, symbolSize, Ns, k0, @@ -154,25 +153,27 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, memset(delay, 0, sizeof(*delay)); for (int aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { - c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset]; - c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset]; + c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset + slot_offset]; + c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset]; - memset(ul_ch,0,sizeof(*ul_ch)*symbolSize); + memset(ul_ch, 0, sizeof(*ul_ch) * symbolSize); #ifdef DEBUG_PUSCH - LOG_I(PHY, "In %s symbol_offset %d, nushift %d\n", __FUNCTION__, symbol_offset, nushift); - LOG_I(PHY, "In %s ch est pilot, N_RB_UL %d\n", __FUNCTION__, gNB->frame_parms.N_RB_UL); - LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch); - LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift); + LOG_I(PHY, "symbol_offset %d, delta %d\n", symbol_offset, delta); + LOG_I(PHY, "ch est pilot, N_RB_UL %d\n", gNB->frame_parms.N_RB_UL); + LOG_I(PHY, + "bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", + bwp_start_subcarrier, + k0, + gNB->frame_parms.first_carrier_offset, + nb_rb_pusch); + LOG_I(PHY, "ul_ch addr %p \n", ul_ch); #endif if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0) { c16_t *pil = pilot; int re_offset = k0; LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); - // For configuration type 1: k = 4*n + 2*k' + delta, - // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 int pilot_cnt = 0; - int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p); for (int n = 0; n < 3 * nb_rb_pusch; n++) { // LS estimation @@ -180,7 +181,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, for (int k_line = 0; k_line <= 1; k_line++) { re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % symbolSize; - ch = c32x16maddShift(*pil, rxdataF[soffset + re_offset], ch, 16); + ch = c32x16maddShift(*pil, rxdataF[re_offset], ch, 16); pil++; } @@ -212,9 +213,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, #ifdef DEBUG_PUSCH re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize; - c16_t *rxF = &rxdataF[soffset + re_offset]; + c16_t *rxF = &rxdataF[re_offset]; printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", - pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i); + pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch16.r, ch16.i); #endif if (pilot_cnt == 0) { @@ -236,7 +237,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // Revert delay pilot_cnt = 0; - ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset]; + ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset]; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *ul_inv_delay_table = gNB->frame_parms.delay_table[inv_delay_idx]; for (int n = 0; n < 3 * nb_rb_pusch; n++) { @@ -249,7 +250,6 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, #ifdef DEBUG_PUSCH re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize; - c16_t *rxF = &rxdataF[soffset + re_offset]; printf("ch -> (%4d,%4d), ch_inter -> (%4d,%4d)\n", ul_ls_est[k].r, ul_ls_est[k].i, ul_ch[k].r, ul_ch[k].i); #endif pilot_cnt++; @@ -260,7 +260,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d| LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n"); c16_t *pil = pilot; - c16_t *rx = &rxdataF[soffset + nushift]; + c16_t *rx = &rxdataF[delta]; for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n += 6) { c16_t ch0 = c16mulShift(*pil, rx[(k0 + n) % symbolSize], 15); pil++; @@ -284,16 +284,16 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } } - - else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB + // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB + else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { LOG_D(PHY,"PUSCH estimation DMRS type 1, no Freq-domain interpolation\n"); - c16_t *rxF = &rxdataF[soffset + nushift]; + c16_t *rxF = &rxdataF[delta]; int pil_offset = 0; int re_offset = k0; c16_t ch; // First PRB - ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6); + ch = c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6); #if NO_INTERP for (c16_t *end=ul_ch+12; ul_chframe_parms.nb_antennas_rx + aarx][ch_offset]; + ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset]; for (int idxP = 0; idxP < ceil((float)nb_rb_pusch * 12 / 8); idxP++) { for (int idxI = 0; idxI < 8; idxI++) { printf("%d\t%d\t", ul_ch[idxP * 8 + idxI].r, ul_ch[idxP * 8 + idxI].i); diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c index 377eb4d89b..4d5ed0fe63 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -299,7 +299,7 @@ uint16_t get_dmrs_freq_idx_ul(uint16_t n, uint8_t k_prime, uint8_t delta, uint8_ int8_t get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol) { for(uint8_t symbol = counter; symbol < end_symbol; symbol++) { - if((ul_dmrs_symb_pos >> symbol) & 0x01 ) { + if((ul_dmrs_symb_pos >> symbol) & 0x01) { return symbol; } } @@ -318,23 +318,23 @@ uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb, uint8 } /* return the position of valid dmrs symbol in a slot for channel compensation */ -int8_t get_valid_dmrs_idx_for_channel_est(uint16_t dmrs_symb_pos, uint8_t counter) +int8_t get_valid_dmrs_idx_for_channel_est(uint16_t dmrs_symb_pos, uint8_t counter) { int8_t symbIdx = -1; /* if current symbol is DMRS then return this index */ - if(is_dmrs_symbol(counter, dmrs_symb_pos ) ==1) { + if(is_dmrs_symbol(counter, dmrs_symb_pos) == 1) { return counter; } /* find previous DMRS symbol */ - for(int8_t symbol = counter;symbol >=0 ; symbol--) { - if((1< 0) { + for(int8_t symbol = counter; symbol >= 0 ; symbol--) { + if((1 << symbol & dmrs_symb_pos) > 0) { symbIdx = symbol; break; } } /* if there is no previous dmrs available then find the next possible*/ if(symbIdx == -1) { - symbIdx = get_next_dmrs_symbol_in_slot(dmrs_symb_pos,counter,15); + symbIdx = get_next_dmrs_symbol_in_slot(dmrs_symb_pos, counter, 15); } return symbIdx; } diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 0debd23295..1c217d8da0 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -41,10 +41,8 @@ #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" // Table 6.4.1.1.3-1/2 from TS 38.211 -static const int delta1[8] = {0, 0, 1, 1, 0, 0, 1, 1}; static const int wf1[8][2] = {{1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}}; static const int wt1[8][2] = {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, -1}, {1, -1}, {1, -1}, {1, -1}}; -static const int delta2[12] = {0, 0, 2, 2, 4, 4, 0, 0, 2, 2, 4, 4}; static const int wf2[12][2] = {{1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}, {1, 1}, {1, -1}}; static const int wt2[12][2] = @@ -56,14 +54,6 @@ static const c16_t nr_rx_mod_table[7] = static const c16_t nr_rx_nmod_table[7] = {{0, 0}, {-23170, 23170}, {23170, -23170}, {-23170, 23170}, {-23170, -23170}, {23170, 23170}, {23170, -23170}}; -int nr_pusch_dmrs_delta(uint8_t dmrs_config_type, unsigned short p) { - if (dmrs_config_type == pusch_dmrs_type1) { - return delta1[p]; - } else { - return delta2[p]; - } -} - int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned int Ns, const uint32_t *nr_gold_pusch, diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index 8636c9972a..cf93433db7 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -27,8 +27,6 @@ #include "PHY/defs_gNB.h" #include "openair1/PHY/NR_REFSIG/nr_refsig_common.h" -int nr_pusch_dmrs_delta(uint8_t dmrs_config_type, unsigned short p); - int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned int Ns, const uint32_t *nr_gold_pusch, diff --git a/openair1/PHY/NR_TRANSPORT/CMakeLists.txt b/openair1/PHY/NR_TRANSPORT/CMakeLists.txt new file mode 100644 index 0000000000..dc1a5e0301 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/CMakeLists.txt @@ -0,0 +1,3 @@ +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 2d33e0f55b..b8f88125ee 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -276,16 +276,16 @@ void nr_idft(int32_t *z, uint32_t Msc_PUSCH) } -static void nr_ulsch_extract_rbs (c16_t* const rxdataF, - c16_t* const chF, - c16_t *rxFext, - c16_t *chFext, - int rxoffset, - int choffset, - int aarx, - int is_dmrs_symbol, - nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_DL_FRAME_PARMS *frame_parms) +static void nr_ulsch_extract_rbs(c16_t* const rxdataF, + c16_t* const chF, + c16_t *rxFext, + c16_t *chFext, + int rxoffset, + int choffset, + int aarx, + int is_dmrs_symbol, + nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_DL_FRAME_PARMS *frame_parms) { uint8_t delta = 0; @@ -301,8 +301,7 @@ static void nr_ulsch_extract_rbs (c16_t* const rxdataF, if (is_dmrs_symbol == 0) { if (start_re + nb_re_pusch <= frame_parms->ofdm_symbol_size) memcpy(rxF_ext, &rxF[start_re], nb_re_pusch * sizeof(c16_t)); - else - { + else { int neg_length = frame_parms->ofdm_symbol_size - start_re; int pos_length = nb_re_pusch - neg_length; memcpy(rxF_ext, &rxF[start_re], neg_length * sizeof(c16_t)); @@ -310,57 +309,47 @@ static void nr_ulsch_extract_rbs (c16_t* const rxdataF, } memcpy(ul_ch0_ext, ul_ch0, nb_re_pusch * sizeof(c16_t)); } - else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) // 6 REs / PRB - { + else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // 6 REs / PRB AssertFatal(delta == 0 || delta == 1, "Illegal delta %d\n",delta); c16_t *rxF32 = &rxF[start_re]; if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { - for (int idx = 1 - delta; idx < nb_re_pusch; idx += 2) - { + for (int idx = 1 - delta; idx < nb_re_pusch; idx += 2) { *rxF_ext++ = rxF32[idx]; *ul_ch0_ext++ = ul_ch0[idx]; } } - else // handle the two pieces around DC - { + else { // handle the two pieces around DC int neg_length = frame_parms->ofdm_symbol_size - start_re; int pos_length = nb_re_pusch - neg_length; int idx, idx2; - for (idx = 1 - delta; idx < neg_length; idx += 2) - { + for (idx = 1 - delta; idx < neg_length; idx += 2) { *rxF_ext++ = rxF32[idx]; *ul_ch0_ext++= ul_ch0[idx]; } rxF32 = rxF; idx2 = idx; - for (idx = 1 - delta; idx < pos_length; idx += 2, idx2 += 2) - { + for (idx = 1 - delta; idx < pos_length; idx += 2, idx2 += 2) { *rxF_ext++ = rxF32[idx]; *ul_ch0_ext++ = ul_ch0[idx2]; } } } - else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2) // 8 REs / PRB - { + else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2) { // 8 REs / PRB AssertFatal(delta==0||delta==2||delta==4,"Illegal delta %d\n",delta); - if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) - { - for (int idx = 0; idx < nb_re_pusch; idx ++) - { + if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) { + for (int idx = 0; idx < nb_re_pusch; idx ++) { if (idx % 6 == 2 * delta || idx % 6 == 2 * delta + 1) continue; *rxF_ext++ = rxF[idx]; *ul_ch0_ext++ = ul_ch0[idx]; } } - else - { + else { int neg_length = frame_parms->ofdm_symbol_size - start_re; int pos_length = nb_re_pusch - neg_length; c16_t *rxF64 = &rxF[start_re]; int idx, idx2; - for (idx = 0; idx < neg_length; idx ++) - { + for (idx = 0; idx < neg_length; idx ++) { if (idx % 6 == 2 * delta || idx % 6 == 2 * delta + 1) continue; *rxF_ext++ = rxF64[idx]; @@ -368,8 +357,7 @@ static void nr_ulsch_extract_rbs (c16_t* const rxdataF, } rxF64 = rxF; idx2 = idx; - for (idx = 0; idx < pos_length; idx++, idx2++) - { + for (idx = 0; idx < pos_length; idx++, idx2++) { if (idx % 6 == 2 * delta || idx % 6 == 2 * delta + 1) continue; *rxF_ext++ = rxF64[idx]; @@ -1282,19 +1270,26 @@ static void inner_rx(PHY_VARS_gNB *gNB, memset(rxFext, 0, sizeof(c16_t) * nb_rx_ant * buffer_length); memset(chFext, 0, sizeof(c16_t) * nb_layer * nb_rx_ant* buffer_length); + int dmrs_symbol; + if (gNB->chest_time == 0) + dmrs_symbol = dmrs_symbol_flag ? symbol : get_valid_dmrs_idx_for_channel_est(rel15_ul->ul_dmrs_symb_pos, symbol); + else { // average of channel estimates stored in first symbol + int end_symbol = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols; + dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, end_symbol); + } for (int aarx = 0; aarx < nb_rx_ant; aarx++) { for (int aatx = 0; aatx < nb_layer; aatx++) { nr_ulsch_extract_rbs(rxF[aarx], - (c16_t *)pusch_vars->ul_ch_estimates[aatx * nb_rx_ant + aarx], - rxFext[aarx], - chFext[aatx][aarx], - soffset+(symbol * frame_parms->ofdm_symbol_size), - pusch_vars->dmrs_symbol * frame_parms->ofdm_symbol_size, - aarx, - dmrs_symbol_flag, - rel15_ul, - frame_parms); + (c16_t *)pusch_vars->ul_ch_estimates[aatx * nb_rx_ant + aarx], + rxFext[aarx], + chFext[aatx][aarx], + soffset+(symbol * frame_parms->ofdm_symbol_size), + dmrs_symbol * frame_parms->ofdm_symbol_size, + aarx, + dmrs_symbol_flag, + rel15_ul, + frame_parms); } } c16_t rho[nb_layer][nb_layer][buffer_length] __attribute__((aligned(32))); @@ -1362,10 +1357,10 @@ static void inner_rx(PHY_VARS_gNB *gNB, else { nr_ulsch_mmse_2layers(frame_parms, (int32_t **)pusch_vars->rxdataF_comp, - (int **)rxF_ch_maga, - (int **)rxF_ch_magb, - (int **)rxF_ch_magc, - (int **)chFext, + (int **)rxF_ch_maga, + (int **)rxF_ch_magb, + (int **)rxF_ch_magc, + (int **)chFext, rel15_ul->rb_size, frame_parms->nb_antennas_rx, rel15_ul->qam_mod_order, @@ -1412,15 +1407,7 @@ static void nr_pusch_symbol_processing(void *arg) int ulsch_id = rdata->ulsch_id; int slot = rdata->slot; NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id]; - for (int symbol = rdata->startSymbol; symbol < rdata->startSymbol+rdata->numSymbols; symbol++) { - int dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; - if (dmrs_symbol_flag == 1) - { - if ((rel15_ul->ul_dmrs_symb_pos >> ((symbol + 1) % frame_parms->symbols_per_slot)) & 0x01) - AssertFatal(1==0,"Double DMRS configuration is not yet supported\n"); - gNB->pusch_vars[ulsch_id].dmrs_symbol = symbol; - } - + for (int symbol = rdata->startSymbol; symbol < rdata->startSymbol + rdata->numSymbols; symbol++) { if (gNB->pusch_vars[ulsch_id].ul_valid_re_per_slot[symbol] == 0) continue; int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; @@ -1428,14 +1415,14 @@ static void nr_pusch_symbol_processing(void *arg) ulsch_id, slot, frame_parms, - pusch_vars, + pusch_vars, rel15_ul, - gNB->common_vars.rxdataF, - (c16_t**)gNB->pusch_vars[ulsch_id].ul_ch_estimates, + gNB->common_vars.rxdataF, + (c16_t**)gNB->pusch_vars[ulsch_id].ul_ch_estimates, rdata->llr_layers, soffset, gNB->pusch_vars[ulsch_id].ul_valid_re_per_slot[symbol], - symbol, + symbol, gNB->pusch_vars[ulsch_id].log2_maxh, rdata->nvar); @@ -1469,7 +1456,6 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, nfapi_nr_pusch_pdu_t *rel15_ul = &gNB->ulsch[ulsch_id].harq_process->ulsch_pdu; NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id]; - pusch_vars->dmrs_symbol = INVALID_VALUE; int nbSymb = 0; uint32_t bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start) * NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); @@ -1481,13 +1467,12 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, start_meas(&gNB->ulsch_channel_estimation_stats); int max_ch = 0; uint32_t nvar = 0; - for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { + int end_symbol = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols; + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol++) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag); if (dmrs_symbol_flag == 1) { - if (pusch_vars->dmrs_symbol == INVALID_VALUE) - pusch_vars->dmrs_symbol = symbol; for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++) { uint32_t nvar_tmp = 0; @@ -1505,9 +1490,9 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, } // measure the SNR from the channel estimation nr_gnb_measurements(gNB, - &gNB->ulsch[ulsch_id], - pusch_vars, - symbol, + &gNB->ulsch[ulsch_id], + pusch_vars, + symbol, rel15_ul->nrOfLayers); allocCast2D(n0_subband_power, unsigned int, @@ -1535,18 +1520,13 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, nvar /= (rel15_ul->nr_of_symbols * rel15_ul->nrOfLayers * frame_parms->nb_antennas_rx); // averaging time domain channel estimates - if (gNB->chest_time == 1) - { + if (gNB->chest_time == 1) nr_chest_time_domain_avg(frame_parms, pusch_vars->ul_ch_estimates, rel15_ul->nr_of_symbols, rel15_ul->start_symbol_index, rel15_ul->ul_dmrs_symb_pos, rel15_ul->rb_size); - pusch_vars->dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, - rel15_ul->start_symbol_index, - rel15_ul->nr_of_symbols); - } stop_meas(&gNB->ulsch_channel_estimation_stats); @@ -1554,7 +1534,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, // Scrambling initialization int number_dmrs_symbols = 0; - for (int l = rel15_ul->start_symbol_index; l < rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols; l++) + for (int l = rel15_ul->start_symbol_index; l < end_symbol; l++) number_dmrs_symbols += ((rel15_ul->ul_dmrs_symb_pos)>>l) & 0x01; int nb_re_dmrs; if (rel15_ul->dmrs_config_type == pusch_dmrs_type1) @@ -1593,32 +1573,38 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, // first the computation of channel levels int nb_re_pusch = 0, meas_symbol = -1; - for(meas_symbol = rel15_ul->start_symbol_index; - meas_symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); - meas_symbol++) - if ((nb_re_pusch = get_nb_re_pusch(frame_parms,rel15_ul,meas_symbol)) > 0) + for(meas_symbol = rel15_ul->start_symbol_index; meas_symbol < end_symbol; meas_symbol++) + if ((nb_re_pusch = get_nb_re_pusch(frame_parms, rel15_ul, meas_symbol)) > 0) break; - AssertFatal(nb_re_pusch>0 && meas_symbol>=0,"nb_re_pusch %d cannot be 0 or meas_symbol %d cannot be negative here\n",nb_re_pusch,meas_symbol); + AssertFatal(nb_re_pusch > 0 && meas_symbol >= 0, + "nb_re_pusch %d cannot be 0 or meas_symbol %d cannot be negative here\n", + nb_re_pusch, + meas_symbol); // extract the first dmrs for the channel level computation // extract the data in the OFDM frame, to the start of the array int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; nb_re_pusch = (nb_re_pusch + 15) & ~15; + int dmrs_symbol; + if (gNB->chest_time == 0) + dmrs_symbol = get_valid_dmrs_idx_for_channel_est(rel15_ul->ul_dmrs_symb_pos, meas_symbol); + else // average of channel estimates stored in first symbol + dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, end_symbol); for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) for (int aatx = 0; aatx < rel15_ul->nrOfLayers; aatx++) nr_ulsch_extract_rbs(gNB->common_vars.rxdataF[aarx], - (c16_t *)pusch_vars->ul_ch_estimates[aatx * frame_parms->nb_antennas_rx + aarx], - (c16_t*)&pusch_vars->rxdataF_ext[aarx][meas_symbol * nb_re_pusch], - (c16_t*)&pusch_vars->ul_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx+aarx][meas_symbol * nb_re_pusch], - soffset + meas_symbol * frame_parms->ofdm_symbol_size, - pusch_vars->dmrs_symbol * frame_parms->ofdm_symbol_size, - aarx, - (rel15_ul->ul_dmrs_symb_pos >> meas_symbol) & 0x01, - rel15_ul, - frame_parms); + (c16_t*)pusch_vars->ul_ch_estimates[aatx * frame_parms->nb_antennas_rx + aarx], + (c16_t*)&pusch_vars->rxdataF_ext[aarx][meas_symbol * nb_re_pusch], + (c16_t*)&pusch_vars->ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx+aarx][meas_symbol * nb_re_pusch], + soffset + meas_symbol * frame_parms->ofdm_symbol_size, + dmrs_symbol * frame_parms->ofdm_symbol_size, + aarx, + (rel15_ul->ul_dmrs_symb_pos >> meas_symbol) & 0x01, + rel15_ul, + frame_parms); int avgs = 0; int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers]; @@ -1662,12 +1648,9 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, start_meas(&gNB->rx_pusch_symbol_processing_stats); int numSymbols = gNB->num_pusch_symbols_per_thread; - for(uint8_t symbol = rel15_ul->start_symbol_index; - symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); - symbol += numSymbols) - { + for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol += numSymbols) { int total_res = 0; - for (int s = 0; s < numSymbols;s++) { + for (int s = 0; s < numSymbols; s++) { pusch_vars->ul_valid_re_per_slot[symbol+s] = get_nb_re_pusch(frame_parms,rel15_ul,symbol+s); pusch_vars->llr_offset[symbol+s] = ((symbol+s) == rel15_ul->start_symbol_index) ? 0 : diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index de5639a149..2529fdd38e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -39,6 +39,19 @@ #define USE_128BIT #endif +int16_t saturating_sub(int16_t a, int16_t b) +{ + int32_t result = (int32_t)a - (int32_t)b; + + if (result < INT16_MIN) { + return INT16_MIN; + } else if (result > INT16_MAX) { + return INT16_MAX; + } else { + return (int16_t)result; + } +} + //---------------------------------------------------------------------------------------------- // QPSK //---------------------------------------------------------------------------------------------- @@ -59,48 +72,27 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, // 16-QAM //---------------------------------------------------------------------------------------------- -void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol) { -#ifdef USE_128BIT - simde__m128i *rxF = (simde__m128i*)rxdataF_comp; - simde__m128i *ch_mag; - simde__m128i *ulsch_llr_128 = (simde__m128i*) ulsch_llr; - int i; - - ch_mag = (simde__m128i*)ul_ch_mag; - nb_re >>= 2; // length in quad words (4 REs) - nb_re += ((nb_re&3) == 0 ? 0 : 1); - - // Each iteration does 4 RE (gives 16 16bit-llrs) - for (i=0; i |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm_subs_epi16(ch_mag[i],xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - - ulsch_llr_128[0] = simde_mm_unpacklo_epi32(rxF[i],xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs - ulsch_llr_128[1] = simde_mm_unpackhi_epi32(rxF[i],xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs - ulsch_llr_128 += 2; - } -#else - simde__m256i *rxF_256 = (simde__m256i*)rxdataF_comp; - simde__m256i *ch_mag = (simde__m256i*)ul_ch_mag; - int64_t *llr_64 = (int64_t*)ulsch_llr; + simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; + simde__m256i *ch_mag = (simde__m256i *)ul_ch_mag; + int64_t *llr_64 = (int64_t *)ulsch_llr; +#ifndef USE_128BIT simde__m256i xmm0, xmm1, xmm2; - for (int i = 0; i < ((nb_re + 7) >> 3); i++) { - xmm0 = simde_mm256_abs_epi16(rxF_256[i]); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_subs_epi16(ch_mag[i], xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - - xmm1 = simde_mm256_unpacklo_epi32(rxF_256[i], xmm0); - xmm2 = simde_mm256_unpackhi_epi32(rxF_256[i], xmm0); + for (int i = 0; i < (nb_re >> 3); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm256_abs_epi16(*rxF_256); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm256_subs_epi16(*ch_mag, xmm0); + + xmm1 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); + xmm2 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // xmm1 |1st 2ed 3rd 4th 9th 10th 13rd 14th| // xmm2 |5th 6th 7th 8th 11st 12ed 15th 16th| - + *llr_64++ = simde_mm256_extract_epi64(xmm1, 0); *llr_64++ = simde_mm256_extract_epi64(xmm1, 1); *llr_64++ = simde_mm256_extract_epi64(xmm2, 0); @@ -109,9 +101,47 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, *llr_64++ = simde_mm256_extract_epi64(xmm1, 3); *llr_64++ = simde_mm256_extract_epi64(xmm2, 2); *llr_64++ = simde_mm256_extract_epi64(xmm2, 3); + rxF_256++; + ch_mag++; } + + nb_re &= 0x7; #endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF_256; + simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag; + simde__m128i *ulsch_llr_128 = (simde__m128i *)llr_64; + + // Each iteration does 4 RE (gives 16 16bit-llrs) + for (int i = 0; i < (nb_re >> 2); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + simde__m128i xmm0 = simde_mm_abs_epi16(*rxF_128); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm_subs_epi16(*ch_mag_128, xmm0); + + ulsch_llr_128[0] = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs + ulsch_llr_128[1] = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs + ulsch_llr_128 += 2; + rxF_128++; + ch_mag_128++; + } + simde_mm_empty(); + + nb_re &= 0x3; + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ul_ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *ulsch_llr_i16 = (int16_t *)ulsch_llr_128; + for (uint i = 0U; i < nb_re; i++) { + int16_t real = rxDataF_i16[2 * i]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + ulsch_llr_i16[4 * i] = real; + ulsch_llr_i16[4 * i + 1] = imag; + ulsch_llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); + ulsch_llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); + } } //---------------------------------------------------------------------------------------------- @@ -121,89 +151,116 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int32_t *ul_ch_magb, - int16_t *ulsch_llr, + int16_t *ulsch_llr, uint32_t nb_re, - uint8_t symbol) + uint8_t symbol) { -#ifdef USE_128BIT - simde__m128i *rxF = (simde__m128i*)rxdataF_comp; - simde__m128i *ch_mag = (simde__m128i*)ul_ch_mag; - simde__m128i *ch_magb = (simde__m128i*)ul_ch_magb; - int i; + simde__m256i *rxF = (simde__m256i *)rxdataF_comp; - nb_re = nb_re>>2; // length in 128-bit words (4 REs) - nb_re += ((nb_re&3) == 0 ? 0 : 1); - simde__m64 *llr64 = (simde__m64 *) ulsch_llr; - - // Each iteration does 4 RE (gives 24 16bit-llrs) - for (i=0; i> 3); i++) { - xmm0 = rxF[i]; - xmm1 = simde_mm256_abs_epi16(xmm0); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm1 = simde_mm256_subs_epi16(ch_maga[i], xmm1); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 +#ifndef USE_128BIT + simde__m256i xmm0, xmm1, xmm2; + for (int i = 0; i < (nb_re >> 3); i++) { + xmm0 = *rxF; + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm1 = simde_mm256_abs_epi16(xmm0); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm1 = simde_mm256_subs_epi16(*ch_maga, xmm1); xmm2 = simde_mm256_abs_epi16(xmm1); - xmm2 = simde_mm256_subs_epi16(ch_magb[i], xmm2); + xmm2 = simde_mm256_subs_epi16(*ch_magb, xmm2); // xmm0 |1st 4th 7th 10th 13th 16th 19th 22ed| // xmm1 |2ed 5th 8th 11th 14th 17th 20th 23rd| // xmm2 |3rd 6th 9th 12th 15th 18th 21st 24th| - *llr_32++ = simde_mm256_extract_epi32(xmm0,0); - *llr_32++ = simde_mm256_extract_epi32(xmm1,0); - *llr_32++ = simde_mm256_extract_epi32(xmm2,0); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 0); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 0); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 0); - *llr_32++ = simde_mm256_extract_epi32(xmm0,1); - *llr_32++ = simde_mm256_extract_epi32(xmm1,1); - *llr_32++ = simde_mm256_extract_epi32(xmm2,1); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 1); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 1); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 1); - *llr_32++ = simde_mm256_extract_epi32(xmm0,2); - *llr_32++ = simde_mm256_extract_epi32(xmm1,2); - *llr_32++ = simde_mm256_extract_epi32(xmm2,2); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 2); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 2); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 2); - *llr_32++ = simde_mm256_extract_epi32(xmm0,3); - *llr_32++ = simde_mm256_extract_epi32(xmm1,3); - *llr_32++ = simde_mm256_extract_epi32(xmm2,3); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 3); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 3); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 3); - *llr_32++ = simde_mm256_extract_epi32(xmm0,4); - *llr_32++ = simde_mm256_extract_epi32(xmm1,4); - *llr_32++ = simde_mm256_extract_epi32(xmm2,4); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 4); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 4); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 4); - *llr_32++ = simde_mm256_extract_epi32(xmm0,5); - *llr_32++ = simde_mm256_extract_epi32(xmm1,5); - *llr_32++ = simde_mm256_extract_epi32(xmm2,5); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 5); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 5); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 5); - *llr_32++ = simde_mm256_extract_epi32(xmm0,6); - *llr_32++ = simde_mm256_extract_epi32(xmm1,6); - *llr_32++ = simde_mm256_extract_epi32(xmm2,6); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 6); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 6); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 6); - *llr_32++ = simde_mm256_extract_epi32(xmm0,7); - *llr_32++ = simde_mm256_extract_epi32(xmm1,7); - *llr_32++ = simde_mm256_extract_epi32(xmm2,7); + *llr_32++ = simde_mm256_extract_epi32(xmm0, 7); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 7); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 7); + rxF++; + ch_maga++; + ch_magb++; } + + nb_re &= 0x7; #endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF; + simde__m128i *ch_mag_128 = (simde__m128i *)ch_maga; + simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; + + simde__m64 *llr64 = (simde__m64 *)llr_32; + + // Each iteration does 4 RE (gives 24 16bit-llrs) + for (int i = 0; i < (nb_re >> 2); i++) { + simde__m128i xmm0, xmm1, xmm2; + xmm0 = *rxF_128; + xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = simde_mm_subs_epi16(*ch_mag_128, xmm1); + xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = simde_mm_subs_epi16(*ch_magb_128, xmm2); + + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 0), simde_mm_extract_epi32(xmm0, 0)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 1), simde_mm_extract_epi32(xmm2, 0)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 1), simde_mm_extract_epi32(xmm1, 1)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 2), simde_mm_extract_epi32(xmm0, 2)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 3), simde_mm_extract_epi32(xmm2, 2)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 3), simde_mm_extract_epi32(xmm1, 3)); + rxF_128++; + ch_mag_128++; + ch_magb_128++; + } + + nb_re &= 0x3; + + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ul_ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *ul_ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *llr_i16 = (int16_t *)llr64; + for (int i = 0; i < nb_re; i++) { + int16_t real = rxDataF_i16[2 * i]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + llr_i16[6 * i] = real; + llr_i16[6 * i + 1] = imag; + llr_i16[6 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[6 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t mag_realb = ul_ch_magb_i16[2 * i]; + int16_t mag_imagb = ul_ch_magb_i16[2 * i + 1]; + llr_i16[6 * i + 4] = saturating_sub(mag_realb, abs(llr_i16[6 * i + 2])); + llr_i16[6 * i + 5] = saturating_sub(mag_imagb, abs(llr_i16[6 * i + 3])); + } simde_mm_empty(); } @@ -211,94 +268,37 @@ void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int32_t *ul_ch_magb, int32_t *ul_ch_magc, - int16_t *ulsch_llr, + int16_t *ulsch_llr, uint32_t nb_re, - uint8_t symbol) + uint8_t symbol) { -#ifdef USE_128BIT - simde__m128i *rxF = (simde__m128i*)rxdataF_comp; - simde__m128i *llr128=(simde__m128i*)ulsch_llr; + simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; + simde__m256i *llr256 = (simde__m256i *)ulsch_llr; - simde__m128i* ch_mag = (simde__m128i*)ul_ch_mag; - simde__m128i* ch_magb = (simde__m128i*)ul_ch_magb; - simde__m128i* ch_magc = (simde__m128i*)ul_ch_magc; - int len_mod4 = nb_re & 3; - int nb_re128 = nb_re >> 2; // length in 128-bit words (4 REs) + simde__m256i *ch_maga = (simde__m256i *)ul_ch_mag; + simde__m256i *ch_magb = (simde__m256i *)ul_ch_magb; + simde__m256i *ch_magc = (simde__m256i *)ul_ch_magc; +#ifndef USE_128BIT + simde__m256i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; - for (int i=0; i |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm_subs_epi16(ch_mag[i], xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm1 = simde_mm_abs_epi16(xmm0); - xmm1 = simde_mm_subs_epi16(ch_magb[i], xmm1); // contains 8 LLRs - xmm2 = simde_mm_abs_epi16(xmm1); - xmm2 = simde_mm_subs_epi16(ch_magc[i], xmm2); // contains 8 LLRs - // rxF[i] A0 A1 A2 A3 - // xmm0 B0 B1 B2 B3 - // xmm1 C0 C1 C2 C3 - // xmm2 D0 D1 D2 D3 - xmm3 = simde_mm_unpacklo_epi32(rxF[i], xmm0); // A0 B0 A1 B1 - xmm4 = simde_mm_unpackhi_epi32(rxF[i], xmm0); // A2 B2 A3 B3 - xmm5 = simde_mm_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 - xmm6 = simde_mm_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 - - llr128[0] = simde_mm_unpacklo_epi64(xmm3,xmm5); // A0 B0 C0 D0 - llr128[1] = simde_mm_unpackhi_epi64(xmm3,xmm5); // A1 B1 C1 D1 - llr128[2] = simde_mm_unpacklo_epi64(xmm4,xmm6); // A2 B2 C2 D2 - llr128[3] = simde_mm_unpackhi_epi64(xmm4,xmm6); // A3 B3 C3 D3 - llr128+=4; - } - - if (len_mod4) { - int last_2_re = (nb_re >> 1) - 1; - simde__m64 *llr64 = (simde__m64 *)llr128; - simde__m64 xmm0,xmm1,xmm2; - simde__m64 *rxF = (simde__m64*)rxdataF_comp; - simde__m64 *ch_mag = (simde__m64*)ul_ch_mag; - simde__m64 *ch_magb = (simde__m64*)ul_ch_magb; - simde__m64 *ch_magc = (simde__m64*)ul_ch_magc; - - xmm0 = simde_mm_abs_pi16(rxF[last_2_re]); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm_subs_pi16(ch_mag[last_2_re],xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - // xmmtmpD2 contains 4 LLRs - xmm1 = simde_mm_abs_pi16(xmm0); - xmm1 = simde_mm_subs_pi16(ch_magb[last_2_re],xmm1); // contains 4 LLRs - xmm2 = simde_mm_abs_pi16(xmm1); - xmm2 = simde_mm_subs_pi16(ch_magc[last_2_re],xmm2); // contains 4 LLRs - // rxF[i] A0 A1 - // xmm0 B0 B1 - // xmm1 C0 C1 - // xmm2 D0 D1 - llr64[0] = simde_mm_unpacklo_pi32(rxF[last_2_re],xmm0); // A0 B0 - llr64[2] = simde_mm_unpackhi_pi32(rxF[last_2_re],xmm0); // A1 B1 - llr64[1] = simde_mm_unpacklo_pi32(xmm1,xmm2); // C0 D0 - llr64[3] = simde_mm_unpackhi_pi32(xmm1,xmm2); // C1 D1 - } -#else - simde__m256i *rxF = (simde__m256i*)rxdataF_comp; - simde__m256i xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6; - simde__m256i *llr256=(simde__m256i*)ulsch_llr; - - simde__m256i* ch_maga = (simde__m256i*)ul_ch_mag; - simde__m256i* ch_magb = (simde__m256i*)ul_ch_magb; - simde__m256i* ch_magc = (simde__m256i*)ul_ch_magc; - - for (int i = 0; i < ((nb_re + 7) >> 3); i++) { - xmm0 = simde_mm256_abs_epi16(rxF[i]); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_subs_epi16(ch_maga[i], xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + for (int i = 0; i < (nb_re >> 3); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm256_abs_epi16(*rxF_256); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm256_subs_epi16(*ch_maga, xmm0); // xmmtmpD2 contains 16 LLRs xmm1 = simde_mm256_abs_epi16(xmm0); - xmm1 = simde_mm256_subs_epi16(ch_magb[i], xmm1); // contains 16 LLRs + xmm1 = simde_mm256_subs_epi16(*ch_magb, xmm1); // contains 16 LLRs xmm2 = simde_mm256_abs_epi16(xmm1); - xmm2 = simde_mm256_subs_epi16(ch_magc[i], xmm2); // contains 16 LLRs + xmm2 = simde_mm256_subs_epi16(*ch_magc, xmm2); // contains 16 LLRs // rxF[i] A0 A1 A2 A3 A4 A5 A6 A7 bits 7,6 // xmm0 B0 B1 B2 B3 B4 B5 B6 B7 bits 5,4 // xmm1 C0 C1 C2 C3 C4 C5 C6 C7 bits 3,2 // xmm2 D0 D1 D2 D3 D4 D5 D6 D7 bits 1,0 - xmm3 = simde_mm256_unpacklo_epi32(rxF[i], xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 - xmm4 = simde_mm256_unpackhi_epi32(rxF[i], xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 - xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 - xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 + xmm3 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 + xmm4 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 + xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 + xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 xmm0 = simde_mm256_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 A4 B4 C4 D4 xmm1 = simde_mm256_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 A5 B5 C5 D5 @@ -308,8 +308,77 @@ void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x20); // A2 B2 C2 D2 A3 B3 C3 D3 *llr256++ = simde_mm256_permute2x128_si256(xmm0, xmm1, 0x31); // A4 B4 C4 D4 A5 B5 C5 D5 *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x31); // A6 B6 C6 D6 A7 B7 C7 D7 + ch_magc++; + ch_magb++; + ch_maga++; + rxF_256++; } + + nb_re &= 0x7; #endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF_256; + simde__m128i *llr_128 = (simde__m128i *)llr256; + + simde__m128i *ch_maga_128 = (simde__m128i *)ch_maga; + simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; + simde__m128i *ch_magc_128 = (simde__m128i *)ch_magc; + + for (int i = 0; i < (nb_re >> 2); i++) { + simde__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm_abs_epi16(*rxF_128); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm_subs_epi16(*ch_maga_128, xmm0); + xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = simde_mm_subs_epi16(*ch_magb_128, xmm1); // contains 8 LLRs + xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = simde_mm_subs_epi16(*ch_magc_128, xmm2); // contains 8 LLRs + // rxF[i] A0 A1 A2 A3 + // xmm0 B0 B1 B2 B3 + // xmm1 C0 C1 C2 C3 + // xmm2 D0 D1 D2 D3 + xmm3 = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // A0 B0 A1 B1 + xmm4 = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // A2 B2 A3 B3 + xmm5 = simde_mm_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 + xmm6 = simde_mm_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 + + *llr_128++ = simde_mm_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 + *llr_128++ = simde_mm_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 + *llr_128++ = simde_mm_unpacklo_epi64(xmm4, xmm6); // A2 B2 C2 D2 + *llr_128++ = simde_mm_unpackhi_epi64(xmm4, xmm6); // A3 B3 C3 D3 + + rxF_128++; + ch_maga_128++; + ch_magb_128++; + ch_magc_128++; + } + + if (nb_re & 3) { + for (int i = 0; i < (nb_re & 0x3); i++) { + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ul_ch_mag_i16 = (int16_t *)ch_maga_128; + int16_t *ul_ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *ul_ch_magc_i16 = (int16_t *)ch_magc_128; + int16_t *ulsch_llr_i16 = (int16_t *)llr_128; + int16_t real = rxDataF_i16[2 * i + 0]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + ulsch_llr_i16[8 * i] = real; + ulsch_llr_i16[8 * i + 1] = imag; + ulsch_llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); + ulsch_llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t magb_real = ul_ch_magb_i16[2 * i]; + int16_t magb_imag = ul_ch_magb_i16[2 * i + 1]; + ulsch_llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(ulsch_llr_i16[8 * i + 2])); + ulsch_llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(ulsch_llr_i16[8 * i + 3])); + int16_t magc_real = ul_ch_magc_i16[2 * i]; + int16_t magc_imag = ul_ch_magc_i16[2 * i + 1]; + ulsch_llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(ulsch_llr_i16[8 * i + 4])); + ulsch_llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(ulsch_llr_i16[8 * i + 5])); + } + } simde_mm_empty(); } diff --git a/openair1/PHY/NR_TRANSPORT/tests/CMakeLists.txt b/openair1/PHY/NR_TRANSPORT/tests/CMakeLists.txt new file mode 100644 index 0000000000..1051824bf9 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(test_llr test_llr.cpp) +target_link_libraries(test_llr PRIVATE PHY_NR GTest::gtest minimal_lib) +add_dependencies(tests test_llr) +add_test(NAME test_llr + COMMAND ./test_llr) + +add_executable(test_llr_no_avx_256 test_llr.cpp) +target_link_libraries(test_llr_no_avx_256 PRIVATE PHY_NR_NO_AVX_256 GTest::gtest minimal_lib) +add_dependencies(tests test_llr_no_avx_256) +add_test(NAME test_llr_no_avx_256 + COMMAND ./test_llr_no_avx_256) diff --git a/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp new file mode 100644 index 0000000000..56a0943d03 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp @@ -0,0 +1,505 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "gtest/gtest.h" +#include +#include +#include +#include +extern "C" { +void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol); +void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol); +void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, + int32_t *ul_ch_magc, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol); +struct configmodule_interface_s; +struct configmodule_interface_s *uniqCfg = NULL; + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + if (assert) { + abort(); + } else { + exit(EXIT_SUCCESS); + } +} +#include "openair1/PHY/TOOLS/tools_defs.h" +} +#include +#include "common/utils/LOG/log.h" +#include +#include +#include + +constexpr bool is_power_of_two(uint64_t n) +{ + return n > 0 && (n & (n - 1)) == 0; +} + +size_t align_up(size_t a, size_t b) +{ + return (a + b - 1) / b * b; +} + +int16_t saturating_sub(int16_t a, int16_t b) +{ + int32_t result = (int32_t)a - (int32_t)b; + + if (result < INT16_MIN) { + return INT16_MIN; + } else if (result > INT16_MAX) { + return INT16_MAX; + } else { + return (int16_t)result; + } +} + +// Template adaptations for std::vector. This is needed because the avx functions expect 256 bit alignment. +template +class AlignedAllocator { + public: + static_assert(is_power_of_two(alignment), "Alignment should be power of 2"); + static_assert(alignment >= 8, "Alignment must be at least 8 bits"); + using value_type = T; + + AlignedAllocator() = default; + + AlignedAllocator(const AlignedAllocator &) = default; + + AlignedAllocator &operator=(const AlignedAllocator &) = default; + + template + struct rebind { + using other = AlignedAllocator; + }; + + T *allocate(size_t n) + { + size_t alignment_bytes = alignment / 8; + void *ptr = ::aligned_alloc(alignment_bytes, align_up(n * sizeof(T), alignment_bytes)); + return static_cast(ptr); + } + + void deallocate(T *p, size_t n) + { + ::free(p); + } +}; + +// Using 512-aligned vector in case some functions use avx-512 +template +using AlignedAllocator512 = AlignedAllocator; +template +using AlignedVector512 = std::vector>; + +void nr_ulsch_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol) +{ + int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; + for (auto i = 0U; i < nb_re; i++) { + int16_t real = rxdataF_comp[i].r; + int16_t imag = rxdataF_comp[i].i; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + ulsch_llr[4 * i] = real; + ulsch_llr[4 * i + 1] = imag; + ulsch_llr[4 * i + 2] = saturating_sub(mag_real, std::abs(real)); + ulsch_llr[4 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + } +} + +void nr_ulsch_64qam_llr_ref(c16_t *rxdataF_comp, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol) +{ + int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; + int16_t *ul_ch_magb_i16 = (int16_t *)ul_ch_magb; + for (auto i = 0U; i < nb_re; i++) { + int16_t real = rxdataF_comp[i].r; + int16_t imag = rxdataF_comp[i].i; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + ulsch_llr[6 * i] = real; + ulsch_llr[6 * i + 1] = imag; + ulsch_llr[6 * i + 2] = saturating_sub(mag_real, std::abs(real)); + ulsch_llr[6 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + int16_t mag_realb = ul_ch_magb_i16[2 * i]; + int16_t mag_imagb = ul_ch_magb_i16[2 * i + 1]; + ulsch_llr[6 * i + 4] = saturating_sub(mag_realb, std::abs(ulsch_llr[6 * i + 2])); + ulsch_llr[6 * i + 5] = saturating_sub(mag_imagb, std::abs(ulsch_llr[6 * i + 3])); + } +} + +void nr_ulsch_256qam_llr_ref(c16_t *rxdataF_comp, + int32_t *ul_ch_mag, + int32_t *ul_ch_magb, + int32_t *ul_ch_magc, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol) +{ + int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; + int16_t *ul_ch_magb_i16 = (int16_t *)ul_ch_magb; + int16_t *ul_ch_magc_i16 = (int16_t *)ul_ch_magc; + for (auto i = 0U; i < nb_re; i++) { + int16_t real = rxdataF_comp[i].r; + int16_t imag = rxdataF_comp[i].i; + int16_t mag_real = ul_ch_mag_i16[2 * i]; + int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + ulsch_llr[8 * i] = real; + ulsch_llr[8 * i + 1] = imag; + ulsch_llr[8 * i + 2] = saturating_sub(mag_real, std::abs(real)); + ulsch_llr[8 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + int16_t magb_real = ul_ch_magb_i16[2 * i]; + int16_t magb_imag = ul_ch_magb_i16[2 * i + 1]; + ulsch_llr[8 * i + 4] = saturating_sub(magb_real, std::abs(ulsch_llr[8 * i + 2])); + ulsch_llr[8 * i + 5] = saturating_sub(magb_imag, std::abs(ulsch_llr[8 * i + 3])); + int16_t magc_real = ul_ch_magc_i16[2 * i]; + int16_t magc_imag = ul_ch_magc_i16[2 * i + 1]; + ulsch_llr[8 * i + 6] = saturating_sub(magc_real, std::abs(ulsch_llr[8 * i + 4])); + ulsch_llr[8 * i + 7] = saturating_sub(magc_imag, std::abs(ulsch_llr[8 * i + 5])); + } +} + +AlignedVector512 generate_random_c16(size_t num) +{ + std::random_device rd; + std::mt19937 rng(rd()); + std::uniform_int_distribution dist(INT16_MIN, INT16_MAX); + AlignedVector512 vec; + vec.resize(num); + auto gen = [&]() { return (c16_t){dist(rng), dist(rng)}; }; + std::generate(vec.begin(), vec.end(), gen); + return vec; +} + +AlignedVector512 generate_random_uint16(size_t num) +{ + AlignedVector512 vec; + vec.resize(num); + auto gen = [&]() { return static_cast(std::rand()); }; + std::generate(vec.begin(), vec.end(), gen); + return vec; +} + +void test_function_16_qam(AlignedVector512 nb_res) +{ + for (auto i = 0U; i < nb_res.size(); i++) { + uint32_t nb_re = nb_res[i]; + auto rf_data = generate_random_c16(nb_re); + auto magnitude_data = generate_random_uint16(nb_re * 2); + AlignedVector512 ulsch_llr_ref; + ulsch_llr_ref.resize(nb_re); + std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); + nr_ulsch_16qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)ulsch_llr_ref.data(), nb_re, 0); + + AlignedVector512 ulsch_llr; + ulsch_llr.resize(nb_re); + std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); + nr_ulsch_16qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)ulsch_llr.data(), nb_re, 0); + + int num_errors = 0; + for (auto i = 0U; i < nb_re; i++) { + EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) + << "Mismatch 16qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; + if (ulsch_llr_ref[i] != ulsch_llr[i]) { + num_errors++; + } + } + EXPECT_EQ(num_errors, 0) << " Errors during testing 16qam llr " << num_errors << " nb res " << nb_re; + } +} + +void test_function_64_qam(AlignedVector512 nb_res) +{ + for (auto i = 0U; i < nb_res.size(); i++) { + uint32_t nb_re = nb_res[i]; + auto rf_data = generate_random_c16(nb_re); + auto magnitude_data = generate_random_uint16(nb_re * 2); + auto magnitude_b_data = generate_random_uint16(nb_re * 2); + AlignedVector512 ulsch_llr_ref; + ulsch_llr_ref.resize(nb_re * 3); + std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); + nr_ulsch_64qam_llr_ref((c16_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int16_t *)ulsch_llr_ref.data(), + nb_re, + 0); + + AlignedVector512 ulsch_llr; + ulsch_llr.resize(nb_re * 3); + std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); + nr_ulsch_64qam_llr((int32_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int16_t *)ulsch_llr.data(), + nb_re, + 0); + + int num_errors = 0; + for (auto i = 0U; i < nb_re * 3; i++) { + EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) + << "Mismatch 64qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; + if (ulsch_llr_ref[i] != ulsch_llr[i]) { + num_errors++; + } + } + EXPECT_EQ(num_errors, 0) << " Errors during testing 64qam llr " << num_errors << " nb res " << nb_re; + } +} + +void test_function_256_qam(AlignedVector512 nb_res) +{ + for (auto i = 0U; i < nb_res.size(); i++) { + uint32_t nb_re = nb_res[i]; + auto rf_data = generate_random_c16(nb_re); + auto magnitude_data = generate_random_uint16(nb_re * 2); + auto magnitude_b_data = generate_random_uint16(nb_re * 2); + auto magnitude_c_data = generate_random_uint16(nb_re * 2); + AlignedVector512 ulsch_llr_ref; + ulsch_llr_ref.resize(nb_re * 4); + std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); + nr_ulsch_256qam_llr_ref((c16_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int32_t *)magnitude_c_data.data(), + (int16_t *)ulsch_llr_ref.data(), + nb_re, + 0); + + AlignedVector512 ulsch_llr; + ulsch_llr.resize(nb_re * 4); + std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); + nr_ulsch_256qam_llr((int32_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int32_t *)magnitude_c_data.data(), + (int16_t *)ulsch_llr.data(), + nb_re, + 0); + + int num_errors = 0; + for (auto i = 0U; i < nb_re * 4; i++) { + EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) + << "Mismatch 256qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; + if (ulsch_llr_ref[i] != ulsch_llr[i]) { + num_errors++; + } + } + EXPECT_EQ(num_errors, 0) << " Errors during testing 256qam llr " << num_errors << " nb res " << nb_re; + } +} + +TEST(test_llr, verify_reference_implementation_16qam) +{ + test_function_16_qam({16, 32, 24, 40, 48, 8 * 300}); +} + +TEST(test_llr, test_8_res_16qam) +{ + test_function_16_qam({8}); +} + +TEST(test_llr, test_4_res_16qam) +{ + test_function_16_qam({4}); +} + +TEST(test_llr, test_5_res_16qam) +{ + test_function_16_qam({5}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_12_res_16qam) +{ + test_function_16_qam({12}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_36_res_16qam) +{ + test_function_16_qam({36}); +} + +// any number of REs should work +TEST(test_llr, no_segfault_any_number_of_re_16qam) +{ + for (uint32_t i = 0U; i < 1000U; i++) { + test_function_16_qam({i}); + } +} + +TEST(test_llr, verify_reference_implementation_64qam) +{ + test_function_64_qam({16, 24, 32, 80, 8 * 300}); +} + +TEST(test_llr, test_8_res_64qam) +{ + test_function_64_qam({8}); +} + +TEST(test_llr, test_4_res_64qam) +{ + test_function_64_qam({4}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_12_res_64qam) +{ + test_function_64_qam({12}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_36_res_64qam) +{ + test_function_64_qam({36}); +} + +// any number of REs should work +TEST(test_llr, no_segfault_any_number_of_re_64qam) +{ + for (uint32_t i = 0U; i < 1000U; i++) { + test_function_64_qam({i}); + } +} + +TEST(test_llr, verify_reference_implementation_256qam) +{ + test_function_256_qam({16, 24, 32, 80, 8 * 300}); +} + +TEST(test_llr, test_8_res_256qam) +{ + test_function_256_qam({8}); +} + +TEST(test_llr, test_4_res_256qam) +{ + test_function_256_qam({4}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_12_res_256qam) +{ + test_function_256_qam({12}); +} + +// This is a "normal" segfault because the function assumed extra buffer for reading non-existent REs +TEST(test_llr, no_segmentation_fault_at_36_res_256qam) +{ + test_function_256_qam({36}); +} + +// any number of REs should work +TEST(test_llr, no_segfault_any_number_of_re_256qam) +{ + for (uint32_t i = 0U; i < 1000U; i++) { + test_function_256_qam({i}); + } +} + +// It is possible to implement an AVX accelerated llr computation for multiples of 2REs. +// This testcase can be used to verify this implementation as it visualizes LLR data with printfs +TEST(test_llr, check_2_res_256_qam) +{ + AlignedVector512 rf_data = {{1, 1}, {2, 2}}; + AlignedVector512 magnitude_data = {1, 1, 1, 1}; + AlignedVector512 magnitude_b_data = {2, 2, 2, 2}; + AlignedVector512 magnitude_c_data = {3, 3, 3, 3}; + AlignedVector512 ulsch_llr_ref; + ulsch_llr_ref.resize(2 * 8); + std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); + nr_ulsch_256qam_llr_ref((c16_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int32_t *)magnitude_c_data.data(), + (int16_t *)ulsch_llr_ref.data(), + 2, + 0); + + AlignedVector512 ulsch_llr; + ulsch_llr.resize(2 * 8); + std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); + nr_ulsch_256qam_llr((int32_t *)rf_data.data(), + (int32_t *)magnitude_data.data(), + (int32_t *)magnitude_b_data.data(), + (int32_t *)magnitude_c_data.data(), + (int16_t *)ulsch_llr.data(), + 2, + 0); + + printf("\nDUT:\n"); + for (auto i = 0U; i < 2; i++) { + printf("%d %d %d %d %d %d %d %d\n", + ulsch_llr[i * 8], + ulsch_llr[i * 8 + 1], + ulsch_llr[i * 8 + 2], + ulsch_llr[i * 8 + 3], + ulsch_llr[i * 8 + 4], + ulsch_llr[i * 8 + 5], + ulsch_llr[i * 8 + 6], + ulsch_llr[i * 8 + 7]); + } + + printf("\nREF:\n"); + for (auto i = 0U; i < 2; i++) { + printf("%d %d %d %d %d %d %d %d\n", + ulsch_llr_ref[i * 8], + ulsch_llr_ref[i * 8 + 1], + ulsch_llr_ref[i * 8 + 2], + ulsch_llr_ref[i * 8 + 3], + ulsch_llr_ref[i * 8 + 4], + ulsch_llr_ref[i * 8 + 5], + ulsch_llr_ref[i * 8 + 6], + ulsch_llr_ref[i * 8 + 7]); + } + + int num_errors = 0; + for (auto i = 0U; i < 2 * 8; i++) { + EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) + << "Mismatch 256qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; + if (ulsch_llr_ref[i] != ulsch_llr[i]) { + num_errors++; + } + } + EXPECT_EQ(num_errors, 0) << " Errors during testing 256qam llr " << num_errors << " nb res " << 2; +} + +int main(int argc, char **argv) +{ + logInit(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 47bb945b9b..d10f5b5b42 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1402,6 +1402,7 @@ void NFAPI_NR_DMRS_TYPE2_average_prb(NR_DL_FRAME_PARMS *frame_parms, c16multaddVectRealComplex(filt8_avlip6, &ch, dl_ch, 8); #endif } + int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, int nl, diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 180c91f06f..e75f22cab7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -877,7 +877,7 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss); #endif - if(csirs_config_pdu->measurement_bitmap == 0) { + if(csirs_config_pdu->csi_type == 0) { LOG_E(NR_PHY, "Handling of CSI-RS for tracking not handled yet at PHY\n"); return; } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 1cb7d256fd..abab53fb4b 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -357,8 +357,6 @@ typedef struct { /// - first index: ? [0..3] (hard coded) /// - first index: ? [0..1179743] (hard coded) int16_t **llr_layers; - /// DMRS symbol index, to be updated every DMRS symbol within a slot. - uint8_t dmrs_symbol; // PTRS symbol index, to be updated every PTRS symbol within a slot. uint8_t ptrs_symbol_index; /// bit mask of PT-RS ofdm symbol indicies diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 49afffcdc6..250dcc2f95 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -51,10 +51,12 @@ * *********************************************************************/ -int set_tdd_config_nr( nfapi_nr_config_request_scf_t *cfg, - int mu, - int nrofDownlinkSlots, int nrofDownlinkSymbols, - int nrofUplinkSlots, int nrofUplinkSymbols) +int set_tdd_config_nr(nfapi_nr_config_request_scf_t *cfg, + int mu, + int nrofDownlinkSlots, + int nrofDownlinkSymbols, + int nrofUplinkSlots, + int nrofUplinkSymbols) { int slot_number = 0; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 80e4643e14..0a4dc1b44b 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -153,6 +153,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, /* CC_id = */ 0, sched_ctrl->aggregation_level, nr_of_candidates, + 0, &sched_ctrl->sched_pdcch, sched_ctrl->coreset, Y); diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index b3f9711ed4..b9b62ec39f 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -72,6 +72,9 @@ #define CONFIG_STRING_MACRLC_MIN_GRANT_PRB "min_grant_prb" #define CONFIG_STRING_MACRLC_MIN_GRANT_MCS "min_grant_mcs" #define CONFIG_STRING_MACRLC_IDENTITY_PM "identity_precoding_matrix" +#define CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING "set_analog_beamforming" +#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration" +#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period" #define HLP_MACRLC_UL_PRBBLACK "SNR threshold to decide whether a PRB will be blacklisted or not" #define HLP_MACRLC_DL_BLER_UP "Upper threshold of BLER to decrease DL MCS" @@ -85,6 +88,9 @@ #define HLP_MACRLC_MIN_GRANT_PRB "Minimal Periodic ULSCH Grant PRBs" #define HLP_MACRLC_MIN_GRANT_MCS "Minimal Periodic ULSCH Grant MCS" #define HLP_MACRLC_IDENTITY_PM "Flag to use only identity matrix in DL precoding" +#define HLP_MACRLC_AB "Flag to enable analog beamforming" +#define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams" +#define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -127,6 +133,9 @@ {CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS_F1U, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_SHM_PREFIX, NULL, 0, .strptr=NULL, .defstrval="nvipc", TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_POLL_CORE, NULL, 0, .i8ptr=NULL, .defintval=-1, TYPE_INT8, 0}, \ + {CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, PARAMFLAG_BOOL, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ } // clang-format off @@ -165,6 +174,9 @@ #define MACRLC_LOCAL_N_ADDRESS_F1U_IDX 32 #define MACRLC_TRANSPORT_S_SHM_PREFIX 33 #define MACRLC_TRANSPORT_S_POLL_CORE 34 +#define MACRLC_ANALOG_BEAMFORMING_IDX 35 +#define MACRLC_ANALOG_BEAM_DURATION_IDX 36 +#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 37 #define MACRLCPARAMS_CHECK { \ { .s5 = { NULL } }, \ @@ -202,6 +214,9 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s2 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d4eb1f0895..0dfe99e3cb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1405,6 +1405,15 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) RC.nrmac[j]->identity_pm = *(MacRLC_ParamList.paramarray[j][MACRLC_IDENTITY_PM_IDX].u8ptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; memcpy(RC.nrmac[j]->ulprbbl, prbbl, 275 * sizeof(prbbl[0])); + bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; + if (ab) { + NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; + int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr; + beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *)); + beam_info->beam_duration = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAM_DURATION_IDX].u8ptr; + beam_info->beams_per_period = beams_per_period; + beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration + } } // for (j=0;j> (mu-2); // in table slots are numbered wrt 60kHz + if ((frame % x) == y || (frame % x) == y2) { + slot_60khz = slot >> (mu - 2); // in table slots are numbered wrt 60kHz s_map = table_6_3_3_2_4_prachConfig_Index[index][5]; - if ((s_map >> slot_60khz) & 0x01 ) { + if ((s_map >> slot_60khz) & 0x01) { for(int i = 0; i <= slot_60khz ;i++) { - if ( (s_map >> i) & 0x01) { + if ((s_map >> i) & 0x01) { (*RA_sfn_index)++; } } } - if ( ((s_map>>slot_60khz)&0x01) ) { + if (((s_map >> slot_60khz) & 0x01)) { *N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; // Number of RACH slots within a subframe if (mu == 3) { - if ( (*N_RA_slot == 1) && (slot%2 == 0) ) + if ((*N_RA_slot == 1) && (slot % 2 == 0) ) return 0; // no prach in even slots @ 120kHz for 1 prach per 60khz slot } if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ @@ -1850,23 +1850,23 @@ int get_nr_prach_info_from_index(uint8_t index, if (unpaired) { x = table_6_3_3_2_3_prachConfig_Index[index][2]; y = table_6_3_3_2_3_prachConfig_Index[index][3]; - if ( (frame%x)==y ) { + if ((frame % x) == y) { subframe = slot >> mu; s_map = table_6_3_3_2_3_prachConfig_Index[index][4]; - if ((s_map >> subframe) & 0x01 ) { + if ((s_map >> subframe) & 0x01) { for(int i = 0; i <= subframe ;i++) { - if ( (s_map >> i) & 0x01) { + if ((s_map >> i) & 0x01) { (*RA_sfn_index)++; } } } - if ( (s_map>>subframe)&0x01 ) { + if ((s_map >> subframe) & 0x01 ) { *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe if (mu == 1 && index >= 67) { - if ( (*N_RA_slot <= 1) && (slot%2 == 0) ) + if ((*N_RA_slot <= 1) && (slot % 2 == 0)) return 0; // no prach in even slots @ 30kHz for 1 prach per subframe } - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ + if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL) { *config_period = x; *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5]; *N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7]; @@ -1874,17 +1874,19 @@ int get_nr_prach_info_from_index(uint8_t index, if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1) format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1]; *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d (col 6 %lu) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u \n", frame, - slot, - index, table_6_3_3_2_3_prachConfig_Index[index][6], - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur, - *N_RA_slot, - *RA_sfn_index); + LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d (col 6 %lu) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u \n", + frame, + slot, + index, + table_6_3_3_2_3_prachConfig_Index[index][6], + pointa, + mu, + unpaired, + *start_symbol, + *N_t_slot, + *N_dur, + *N_RA_slot, + *RA_sfn_index); } return 1; } @@ -1897,10 +1899,10 @@ int get_nr_prach_info_from_index(uint8_t index, else { // FDD x = table_6_3_3_2_2_prachConfig_Index[index][2]; y = table_6_3_3_2_2_prachConfig_Index[index][3]; - if ( (frame%x)==y ) { + if ((frame % x) == y) { subframe = slot >> mu; s_map = table_6_3_3_2_2_prachConfig_Index[index][4]; - if ( (s_map>>subframe)&0x01 ) { + if ((s_map>>subframe) & 0x01) { *N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6]; // Number of RACH slots within a subframe if (mu == 1) { if ((*N_RA_slot <= 1) && (slot % 2 == 0)){ @@ -1908,7 +1910,7 @@ int get_nr_prach_info_from_index(uint8_t index, } } for(int i = 0; i <= subframe ; i++) { - if ( (s_map >> i) & 0x01) { + if ((s_map >> i) & 0x01) { (*RA_sfn_index)++; } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 6646e607bc..557a393ce2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2628,7 +2628,7 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) uint16_t bwp_size = current_DL_BWP->BWPSize; uint16_t bwp_start = current_DL_BWP->BWPStart; - for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){ + for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++) { NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; int period, offset; csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset); @@ -2644,7 +2644,10 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) csirs_config_pdu->subcarrier_spacing = mu; csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0; - csirs_config_pdu->csi_type = 1; // NZP-CSI-RS + if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations) + csirs_config_pdu->csi_type = 0; // TRS + else + csirs_config_pdu->csi_type = 1; // NZP-CSI-RS csirs_config_pdu->scramb_id = nzpcsi->scramblingID; csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 3cb650aac6..389304dd87 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -587,20 +587,31 @@ static void config_common(gNB_MAC_INST *nrmac, nr_pdsch_AntennaPorts_t pdsch_Ant scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols); AssertFatal(periods_per_frame > 0, "TDD configuration cannot be configured\n"); - if (frequency_range == FR2) { - LOG_I(NR_MAC, "Configuring TDD beam association to default\n"); - nrmac->tdd_beam_association = malloc16(periods_per_frame * sizeof(int16_t)); - for (int i = 0; i < periods_per_frame; ++i) - nrmac->tdd_beam_association[i] = -1; /* default: beams not configured */ - } else { - nrmac->tdd_beam_association = NULL; /* default: no beams */ - } } // precoding matrix configuration (to be improved) cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); } +static void initialize_beam_information(NR_beam_info_t *beam_info, int mu, int slots_per_frame) +{ + if(!beam_info->beam_allocation) + return; + + int size = mu == 0 ? slots_per_frame << 1 : slots_per_frame; + // slots in beam duration gives the number of consecutive slots tied the the same beam + AssertFatal(size % beam_info->beam_duration == 0, + "Beam duration %d should be divider of number of slots per frame %d\n", + beam_info->beam_duration, + slots_per_frame); + beam_info->beam_allocation_size = size / beam_info->beam_duration; + for (int i = 0; i < beam_info->beams_per_period; i++) { + beam_info->beam_allocation[i] = malloc16(beam_info->beam_allocation_size * sizeof(int)); + for (int j = 0; j < beam_info->beam_allocation_size; j++) + beam_info->beam_allocation[i][j] = -1; + } +} + void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config) { DevAssert(nrmac != NULL); @@ -614,16 +625,23 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c const int NTN_gNB_Koffset = get_NTN_Koffset(scc); const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const int size = n << (int)ceil(log2((NTN_gNB_Koffset + 13) / n + 1)); // 13 is upper limit for max_fb_time - nrmac->vrb_map_UL_size = size; - nrmac->common_channels[0].vrb_map_UL = calloc(size * MAX_BWP_SIZE, sizeof(uint16_t)); - AssertFatal(nrmac->common_channels[0].vrb_map_UL, - "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n"); + + int num_beams = 1; + if(nrmac->beam_info.beam_allocation) + num_beams = nrmac->beam_info.beams_per_period; + for (int i = 0; i < num_beams; i++) { + nrmac->common_channels[0].vrb_map_UL[i] = calloc(size * MAX_BWP_SIZE, sizeof(uint16_t)); + AssertFatal(nrmac->common_channels[0].vrb_map_UL[i], + "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL[%d]\n", i); + } nrmac->UL_tti_req_ahead_size = size; nrmac->UL_tti_req_ahead[0] = calloc(size, sizeof(nfapi_nr_ul_tti_request_t)); AssertFatal(nrmac->UL_tti_req_ahead[0], "could not allocate memory for nrmac->UL_tti_req_ahead[0]\n"); + initialize_beam_information(&nrmac->beam_info, *scc->ssbSubcarrierSpacing, n); + LOG_I(NR_MAC, "Configuring common parameters from NR ServingCellConfig\n"); config_common(nrmac, config->pdsch_AntennaPorts, config->pusch_AntennaPorts, scc); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index dbd64f524e..ad18ead1f4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -146,6 +146,24 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB, TX_req[CC_idP].Number_of_PDUs = 0; } +void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slot, int mu) +{ + // for now we use the same logic of UL_tti_req_ahead + // reset after 1 frame with the exception of 15kHz + if(!beam_info->beam_allocation) + return; + // initialization done only once + const int slots_per_frame = nr_slots_per_frame[mu]; + AssertFatal(beam_info->beam_allocation_size >= 0, "Beam information not initialized\n"); + int idx_to_clear = (frame * slots_per_frame + slot) / beam_info->beam_duration; + idx_to_clear = (idx_to_clear + beam_info->beam_allocation_size - 1) % beam_info->beam_allocation_size; + if (slot % beam_info->beam_duration == 0) { + // resetting previous period allocation + for (int i = 0; i < beam_info->beams_per_period; i++) + beam_info->beam_allocation[i][idx_to_clear] = -1; + } +} + bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) { return (bitmap >> (slot % 64)) & 0x01; } @@ -195,19 +213,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_ gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = gNB->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SCHED_LOCK(&gNB->sched_lock); - if (slot==0 && (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]>=257)) { - //FR2 - const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - AssertFatal(tdd,"Dynamic TDD not handled yet\n"); - const int nb_periods_per_frame = get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - // re-initialization of tdd_beam_association at beginning of frame - for (int i=0; itdd_beam_association[i] = -1; - } + clear_beam_information(&gNB->beam_info, frame, slot, *scc->ssbSubcarrierSpacing); gNB->frame = frame; start_meas(&gNB->eNB_scheduler); @@ -224,17 +234,20 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_ } for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //mbsfn_status[CC_id] = 0; - + int num_beams = 1; + if(gNB->beam_info.beam_allocation) + num_beams = gNB->beam_info.beams_per_period; // clear vrb_maps - memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * MAX_BWP_SIZE); + for (int i = 0; i < num_beams; i++) + memset(cc[CC_id].vrb_map[i], 0, sizeof(uint16_t) * MAX_BWP_SIZE); // clear last scheduled slot's content (only)! const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const int size = gNB->vrb_map_UL_size; const int prev_slot = frame * num_slots + slot + size - 1; - uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL; - memcpy(&vrb_map_UL[prev_slot % size * MAX_BWP_SIZE], &gNB->ulprbbl, sizeof(uint16_t) * MAX_BWP_SIZE); - + for (int i = 0; i < num_beams; i++) { + uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL[i]; + memcpy(&vrb_map_UL[prev_slot % size * MAX_BWP_SIZE], &gNB->ulprbbl, sizeof(uint16_t) * MAX_BWP_SIZE); + } clear_nr_nfapi_information(gNB, CC_id, frame, slot, &sched_info->DL_req, &sched_info->TX_req, &sched_info->UL_dci_req); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d1a0bae0dc..d8f6690818 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -81,13 +81,13 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, NR_COMMON_channels_t *cc = &gNB->common_channels[0]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0]; - - uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex; + NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; + uint8_t config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; uint8_t total_RApreambles = MAX_NUM_NR_PRACH_PREAMBLES; - if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL) - total_RApreambles = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles; + if (rach_ConfigCommon->totalNumberOfRA_Preambles != NULL) + total_RApreambles = *rach_ConfigCommon->totalNumberOfRA_Preambles; float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; uint16_t start_symbol_index = 0; @@ -97,8 +97,8 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, uint16_t prach_occasion_id = -1; uint8_t num_active_ssb = cc->num_active_ssb; - if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing) - mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing; + if (rach_ConfigCommon->msg1_SubcarrierSpacing) + mu = *rach_ConfigCommon->msg1_SubcarrierSpacing; else mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; @@ -115,13 +115,13 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, &RA_sfn_index, &N_RA_slot, &config_period); - uint8_t index = 0,slot_index = 0; - for (slot_index = 0;slot_index < N_RA_slot; slot_index++) { + uint8_t index = 0, slot_index = 0; + for (slot_index = 0; slot_index < N_RA_slot; slot_index++) { if (N_RA_slot <= 1) { //1 PRACH slot in a subframe if((mu == 1) || (mu == 3)) slot_index = 1; //For scs = 30khz and 120khz } - for (int i=0; i< N_t_slot; i++) { + for (int i = 0; i < N_t_slot; i++) { temp_start_symbol = (start_symbol + i * N_dur + 14 * slot_index) % 14; if(symbol == temp_start_symbol) { start_symbol_index = i; @@ -134,18 +134,18 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, slot_index = 0; //For scs = 30khz and 120khz } - // prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; - prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) + - (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; + // prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; + prach_occasion_id = (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period) + + (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; - //one RO is shared by one or more SSB - if(num_ssb_per_RO <= 1 ) - index = (int) (prach_occasion_id / (int)(1/num_ssb_per_RO)) % num_active_ssb; //one SSB have more than one continuous RO - else if ( num_ssb_per_RO > 1) { - index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ; - for(int j = 0;j < num_ssb_per_RO;j++) { - if(preamble_index < (((j+1) * total_RApreambles) / num_ssb_per_RO)) + if(num_ssb_per_RO <= 1) + index = (int) (prach_occasion_id / (int)(1 / num_ssb_per_RO)) % num_active_ssb; + //one RO is shared by one or more SSB + else if (num_ssb_per_RO > 1) { + index = (prach_occasion_id * (int)num_ssb_per_RO) % num_active_ssb; + for(int j = 0; j < num_ssb_per_RO; j++) { + if(preamble_index < ((j + 1) * cc->cb_preambles_per_ssb)) index = index + j; } } @@ -165,14 +165,14 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0]; - - uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex; + NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; + uint8_t config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; uint8_t mu,N_dur=0,N_t_slot=0,start_symbol=0,N_RA_slot = 0; uint16_t format,N_RA_sfn = 0,unused_RA_occasion,repetition = 0; uint8_t num_active_ssb = 0; uint8_t max_association_period = 1; - struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *ssb_perRACH_OccasionAndCB_PreamblesPerSSB = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB; + struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *ssb_perRACH_OccasionAndCB_PreamblesPerSSB = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB; switch (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present){ case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth: @@ -204,8 +204,8 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) break; } - if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing) - mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing; + if (rach_ConfigCommon->msg1_SubcarrierSpacing) + mu = *rach_ConfigCommon->msg1_SubcarrierSpacing; else mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; @@ -227,24 +227,24 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value)<<32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value ; uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm; - for(int i = 0;i < 64;i++) { - if ((L_ssb >> (63-i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1 - cc->ssb_index[num_active_ssb] = i; + for(int i = 0; i < 64; i++) { + if ((L_ssb >> (63 - i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1 + cc->ssb_index[num_active_ssb] = i; num_active_ssb++; } } cc->total_prach_occasions_per_config_period = total_RA_occasions; - for(int i=1; (1 << (i-1)) <= max_association_period; i++) { - cc->max_association_period = (1 <<(i-1)); + for(int i = 1; (1 << (i-1)) <= max_association_period; i++) { + cc->max_association_period = (1 << (i - 1)); total_RA_occasions = total_RA_occasions * cc->max_association_period; - if(total_RA_occasions >= (int) (num_active_ssb/num_ssb_per_RO)) { - repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO )/num_active_ssb); + if(total_RA_occasions >= (int) (num_active_ssb / num_ssb_per_RO)) { + repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO) / num_active_ssb); break; } } - unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition)/num_ssb_per_RO); + unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition) / num_ssb_per_RO); cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion; cc->num_active_ssb = num_active_ssb; @@ -308,24 +308,41 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP uint16_t format1 = (format >> 8) & 0xff; // second column of format from table if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe - if (slotP%2 == 1) + if (slotP % 2 == 1) slot_index = 1; else slot_index = 0; - }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe + } else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe slot_index = 0; } UL_tti_req->SFN = frameP; UL_tti_req->Slot = slotP; UL_tti_req->rach_present = 1; - for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion - for (int td_index=0; td_indexmax_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index; - if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){ + if (prach_occasion_id >= cc->total_prach_occasions) // to be confirmed: unused occasion? + continue; + + float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; + if(num_ssb_per_RO <= 1) { + int ssb_index = (int) (prach_occasion_id / (int)(1 / num_ssb_per_RO)) % cc->num_active_ssb; + beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, ssb_index, nr_slots_per_frame[mu]); + AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", ssb_index); + } + else { + int first_ssb_index = (prach_occasion_id * (int)num_ssb_per_RO) % cc->num_active_ssb; + for(int j = first_ssb_index; j < first_ssb_index + num_ssb_per_RO; j++) { + beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, j, nr_slots_per_frame[mu]); + AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", j); + } + } + if(td_index == 0) { AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus); @@ -414,11 +431,10 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP } // block resources in vrb_map_UL - const uint8_t mu_pusch = - scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; + const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); index = ul_buffer_index(frameP, slotP, mu, gNB->vrb_map_UL_size); - uint16_t *vrb_map_UL = &cc->vrb_map_UL[index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &cc->vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; for (int i = 0; i < n_ra_rb * fdm; ++i) vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] |= SL_to_bitmap(start_symbol, N_t_slot * N_dur); } @@ -551,20 +567,6 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont ra->contention_resolution_timer); } -static bool beam_is_active(const NR_TDD_UL_DL_Pattern_t *tdd, int mu, const int16_t *tdd_beam_association, int slot, int16_t ra_beam) -{ - if (tdd_beam_association == NULL) // no beams configured - return true; - DevAssert(tdd != NULL); - - const int n_slots_frame = nr_slots_per_frame[mu]; - uint8_t tdd_period_slot = n_slots_frame/get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - int num_tdd_period = slot / tdd_period_slot; - int16_t current_beam = tdd_beam_association[num_tdd_period]; - return current_beam == -1 /* no beams */ - || current_beam == ra_beam; -} - static void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t frame, @@ -585,14 +587,19 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) { - // beam association for FR2 - if (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0] >= 257) { - // FR2 - const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - if (!beam_is_active(tdd, mu, nr_mac->tdd_beam_association, sched_slot, ra->beam_id)) - return; + const int n_slots_frame = nr_slots_per_frame[mu]; + NR_beam_alloc_t beam_ul = beam_allocation_procedure(&nr_mac->beam_info, + sched_frame, + sched_slot, + ra->beam_id, + n_slots_frame); + if (beam_ul.idx < 0) + return; + NR_beam_alloc_t beam_dci = beam_allocation_procedure(&nr_mac->beam_info, frame, slot, ra->beam_id, n_slots_frame); + if (beam_dci.idx < 0) { + reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, ra->beam_id, n_slots_frame, beam_ul.new_beam); + return; } - int fh = 0; int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int StartSymbolIndex, NrOfSymbols; @@ -600,7 +607,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, int mappingtype = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; int buffer_index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[beam_ul.idx][buffer_index * MAX_BWP_SIZE]; const int BWPSize = sc_info->initial_ul_BWPSize; const int BWPStart = sc_info->initial_ul_BWPStart; @@ -674,6 +681,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, int CCEIndex = get_cce_index(nr_mac, CC_id, slot, 0, &aggregation_level, + beam_dci.idx, ss, coreset, &ra->sched_pdcch, @@ -724,7 +732,8 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, CC_id, &ra->sched_pdcch, CCEIndex, - aggregation_level); + aggregation_level, + beam_dci.idx); for (int rb = 0; rb < ra->msg3_nb_rb; rb++) { vrb_map_UL[rbStart + BWPStart + rb] |= SL_to_bitmap(StartSymbolIndex, NrOfSymbols); @@ -746,37 +755,38 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, } } -static int get_feasible_msg3_tda(frame_type_t frame_type, - const NR_ServingCellConfigCommon_t *scc, - int mu_delta, - uint64_t ulsch_slot_bitmap[3], - const NR_PUSCH_TimeDomainResourceAllocationList_t *tda_list, - int slots_per_frame, - int slot, - const NR_TDD_UL_DL_Pattern_t *tdd) +static bool get_feasible_msg3_tda(frame_type_t frame_type, + const NR_ServingCellConfigCommon_t *scc, + int mu_delta, + uint64_t ulsch_slot_bitmap[3], + const NR_PUSCH_TimeDomainResourceAllocationList_t *tda_list, + int slots_per_frame, + int frame, + int slot, + NR_RA_t *ra, + NR_beam_info_t *beam_info, + const NR_TDD_UL_DL_Pattern_t *tdd) { DevAssert(tda_list != NULL); - if (frame_type == FDD) { - int tda = 0; // the first occasion is good enough - return tda; - } - const int NTN_gNB_Koffset = get_NTN_Koffset(scc); - // TDD - DevAssert(tdd != NULL); - uint8_t tdd_period_slot = slots_per_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); + int tdd_period_slot = tdd ? slots_per_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : slots_per_frame; for (int i = 0; i < tda_list->list.count; i++) { // check if it is UL long k2 = *tda_list->list.array[i]->k2 + NTN_gNB_Koffset; - int temp_slot = (slot + k2 + mu_delta) % slots_per_frame; // msg3 slot according to 8.3 in 38.213 - if (!is_xlsch_in_slot(ulsch_slot_bitmap[temp_slot / 64], temp_slot)) + int abs_slot = slot + k2 + mu_delta; + int temp_frame = (frame + (abs_slot / slots_per_frame)) & 1023; + int temp_slot = abs_slot % slots_per_frame; // msg3 slot according to 8.3 in 38.213 + if ((frame_type == TDD) && !is_xlsch_in_slot(ulsch_slot_bitmap[temp_slot / 64], temp_slot)) continue; // check if enough symbols in case of mixed slot - bool has_mixed = tdd->nrofUplinkSymbols != 0 || tdd->nrofDownlinkSymbols != 0; - bool is_mixed = has_mixed && ((temp_slot % tdd_period_slot) == tdd->nrofDownlinkSlots); + bool is_mixed = false; + if (frame_type == TDD) { + bool has_mixed = tdd->nrofUplinkSymbols != 0 || tdd->nrofDownlinkSymbols != 0; + is_mixed = has_mixed && ((temp_slot % tdd_period_slot) == tdd->nrofDownlinkSlots); + } // if the mixed slot has not enough symbols, skip if (is_mixed && tdd->nrofUplinkSymbols < 3) continue; @@ -791,12 +801,20 @@ static int get_feasible_msg3_tda(frame_type_t frame_type, if ((slot_mask & msg3_mask) != msg3_mask) continue; + // check if it is possible to allocate MSG3 in a beam in this slot + NR_beam_alloc_t beam = beam_allocation_procedure(beam_info, temp_frame, temp_slot, ra->beam_id, slots_per_frame); + if (beam.idx < 0) + continue; + // is in mixed slot with more or equal than 3 symbols, or UL slot - int tda = i; - return tda; + ra->Msg3_frame = temp_frame; + ra->Msg3_slot = temp_slot; + ra->Msg3_tda_id = i; + ra->Msg3_beam = beam; + return true; } - return -1; // invalid + return false; } static void nr_get_Msg3alloc(module_id_t module_id, @@ -804,8 +822,7 @@ static void nr_get_Msg3alloc(module_id_t module_id, NR_ServingCellConfigCommon_t *scc, sub_frame_t current_slot, frame_t current_frame, - NR_RA_t *ra, - int16_t *tdd_beam_association) + NR_RA_t *ra) { // msg3 is scheduled in mixed slot in the following TDD period DevAssert(ra->Msg3_tda_id >= 0 && ra->Msg3_tda_id < 16); @@ -818,27 +835,20 @@ static void nr_get_Msg3alloc(module_id_t module_id, const NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList_Common; int mu = ul_bwp->scs; - const int n_slots_frame = nr_slots_per_frame[mu]; int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ra->msg3_startsymb, &ra->msg3_nbSymb); - long k2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc); - int abs_slot = current_slot + k2 + DELTA[mu]; - ra->Msg3_slot = abs_slot % n_slots_frame; - ra->Msg3_frame = (current_frame + (abs_slot / n_slots_frame)) % MAX_FRAME_NUMBER; - LOG_I(NR_MAC, - "UE %04x: Msg3 scheduled at %d.%d (%d.%d k2 %ld TDA %u)\n", + "UE %04x: Msg3 scheduled at %d.%d (%d.%d TDA %u)\n", ra->rnti, ra->Msg3_frame, ra->Msg3_slot, current_frame, current_slot, - k2, ra->Msg3_tda_id); const int buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, mu, mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE]; int bwpSize = sc_info->initial_ul_BWPSize; int bwpStart = sc_info->initial_ul_BWPStart; @@ -993,7 +1003,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_f const int scs = ul_bwp->scs; const uint16_t mask = SL_to_bitmap(ra->msg3_startsymb, ra->msg3_nbSymb); int buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, scs, mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE]; for (int i = 0; i < ra->msg3_nb_rb; ++i) { AssertFatal(!(vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start] & mask), "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n", @@ -1219,23 +1229,28 @@ static void nr_generate_Msg2(module_id_t module_idP, LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: Msg2 not monitored by UE\n", ra->RA_rnti, ra->rnti); return; } + + const int n_slots_frame = nr_slots_per_frame[dl_bwp->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + if (beam.idx < 0) + return; + const NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - if (!beam_is_active(tdd, ul_bwp->scs, nr_mac->tdd_beam_association, slotP, ra->beam_id)) { - LOG_I(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: beam %d inactive\n", ra->RA_rnti, ra->rnti, ra->beam_id); - return; - } - - ra->Msg3_tda_id = get_feasible_msg3_tda(cc->frame_type, - scc, - DELTA[ul_bwp->scs], - nr_mac->ulsch_slot_bitmap, - ul_bwp->tdaList_Common, - nr_slots_per_frame[ul_bwp->scs], - slotP, - tdd); - if (ra->Msg3_tda_id < 0 || ra->Msg3_tda_id > 15) { + bool ret = get_feasible_msg3_tda(cc->frame_type, + scc, + DELTA[ul_bwp->scs], + nr_mac->ulsch_slot_bitmap, + ul_bwp->tdaList_Common, + nr_slots_per_frame[ul_bwp->scs], + frameP, + slotP, + ra, + &nr_mac->beam_info, + tdd); + if (!ret || ra->Msg3_tda_id > 15) { LOG_D(NR_MAC, "UE RNTI %04x %d.%d: infeasible Msg3 TDA\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1274,7 +1289,7 @@ static void nr_generate_Msg2(module_id_t module_idP, if (!tda_info.valid_tda) return; - uint16_t *vrb_map = cc[CC_id].vrb_map; + uint16_t *vrb_map = cc[CC_id].vrb_map[beam.idx]; for (int i = 0; (i < rbSize) && (rbStart <= (BWPSize - rbSize)); i++) { if (vrb_map[BWPStart + rbStart + i] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) { rbStart += i; @@ -1283,7 +1298,9 @@ static void nr_generate_Msg2(module_id_t module_idP, } if (rbStart > (BWPSize - rbSize)) { - LOG_W(NR_MAC, "%s(): cannot find free vrb_map for RA RNTI %04x!\n", __func__, ra->RA_rnti); + LOG_W(NR_MAC, "Cannot find free vrb_map for RA RNTI %04x!\n", ra->RA_rnti); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1291,14 +1308,18 @@ static void nr_generate_Msg2(module_id_t module_idP, nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { LOG_W(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } uint8_t aggregation_level; - int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, ss, coreset, &ra->sched_pdcch, true); + int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &ra->sched_pdcch, true); if (CCEIndex < 0) { LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1462,7 +1483,7 @@ static void nr_generate_Msg2(module_id_t module_idP, nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[TX_req->Number_of_PDUs]; // Program UL processing for Msg3 - nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra, nr_mac->tdd_beam_association); + nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *)&tx_req->TLVs[0].value.direct[0]); // Start RA contention resolution timer in Msg3 transmission slot (current slot + K2) @@ -1512,7 +1533,7 @@ static void nr_generate_Msg2(module_id_t module_idP, TX_req->Slot = slotP; // Mark the corresponding symbols RBs as used - fill_pdcch_vrb_map(nr_mac, CC_id, &ra->sched_pdcch, CCEIndex, aggregation_level); + fill_pdcch_vrb_map(nr_mac, CC_id, &ra->sched_pdcch, CCEIndex, aggregation_level, beam.idx); for (int rb = 0; rb < rbSize; rb++) { vrb_map[BWPStart + rb + rbStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); } @@ -1762,6 +1783,11 @@ static void nr_generate_Msg4(module_id_t module_idP, mac_sdu_length = srb_status.bytes_in_buffer; } + const int n_slots_frame = nr_slots_per_frame[dl_bwp->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + if (beam.idx < 0) + return; + long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; @@ -1779,13 +1805,15 @@ static void nr_generate_Msg4(module_id_t module_idP, int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, + beam.idx, ss, coreset, &ra->sched_pdcch, true); if (CCEIndex < 0) { - LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI 0x%04x!\n", __func__, ra->rnti); + LOG_E(NR_MAC, "Cannot find free CCE for RA RNTI 0x%04x!\n", ra->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1793,6 +1821,7 @@ static void nr_generate_Msg4(module_id_t module_idP, nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { LOG_I(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1809,10 +1838,7 @@ static void nr_generate_Msg4(module_id_t module_idP, if (!msg4_tda.valid_tda) return; - NR_pdsch_dmrs_t dmrs_info = get_dl_dmrs_params(scc, - dl_bwp, - &msg4_tda, - 1); + NR_pdsch_dmrs_t dmrs_info = get_dl_dmrs_params(scc, dl_bwp, &msg4_tda, 1); uint8_t mcsTableIdx = dl_bwp->mcsTableIdx; uint8_t mcsIndex = 0; @@ -1846,7 +1872,7 @@ static void nr_generate_Msg4(module_id_t module_idP, AssertFatal(tb_size >= pdu_length,"Cannot allocate Msg4\n"); int i = 0; - uint16_t *vrb_map = cc[CC_id].vrb_map; + uint16_t *vrb_map = cc[CC_id].vrb_map[beam.idx]; while ((i < rbSize) && (rbStart + rbSize <= BWPSize)) { if (vrb_map[BWPStart + rbStart + i]&SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols)) { rbStart += i+1; @@ -1857,7 +1883,8 @@ static void nr_generate_Msg4(module_id_t module_idP, } if (rbStart > (BWPSize - rbSize)) { - LOG_E(NR_MAC, "%s(): cannot find free vrb_map for RNTI %04x!\n", __func__, ra->rnti); + LOG_E(NR_MAC, "Cannot find free vrb_map for RNTI %04x!\n", ra->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1877,9 +1904,10 @@ static void nr_generate_Msg4(module_id_t module_idP, LOG_D(NR_MAC, "Msg4 r_pucch %d (CCEIndex %d, delta_PRI %d)\n", r_pucch, CCEIndex, delta_PRI); - alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, r_pucch, 1); + alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, ra->beam_id, r_pucch, 1); if (alloc < 0) { - LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n",frameP,slotP); + LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n", frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } } @@ -1972,7 +2000,8 @@ static void nr_generate_Msg4(module_id_t module_idP, CC_id, &ra->sched_pdcch, CCEIndex, - aggregation_level); + aggregation_level, + beam.idx); for (int rb = 0; rb < rbSize; rb++) { vrb_map[BWPStart + rb + rbStart] |= SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 95ebf5eb5a..4e3133aff3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -89,13 +89,18 @@ static void schedule_ssb(frame_t frame, LOG_D(MAC,"Scheduling ssb %d at frame %d and slot %d\n",i_ssb,frame,slot); } -static void fill_ssb_vrb_map(NR_COMMON_channels_t *cc, int rbStart, int ssb_subcarrier_offset, uint16_t symStart, int CC_id) +static void fill_ssb_vrb_map(NR_COMMON_channels_t *cc, + int rbStart, + int ssb_subcarrier_offset, + uint16_t symStart, + int CC_id, + int beam) { AssertFatal(*cc->ServingCellConfigCommon->ssbSubcarrierSpacing != NR_SubcarrierSpacing_kHz240, "240kHZ subcarrier won't work with current VRB map because a single SSB might be across 2 slots\n"); - uint16_t *vrb_map = cc[CC_id].vrb_map; + uint16_t *vrb_map = cc[CC_id].vrb_map[beam]; const int extra_prb = ssb_subcarrier_offset > 0; for (int rb = 0; rb < 20 + extra_prb; rb++) vrb_map[rbStart + rb] = SL_to_bitmap(symStart % NR_NUMBER_OF_SYMBOLS_PER_SLOT, 4); @@ -115,10 +120,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, gNB_MAC_INST *gNB = RC.nrmac[module_idP]; /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ nfapi_nr_dl_tti_request_body_t *dl_req; - uint8_t num_tdd_period,num_ssb; - int CC_id; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { NR_COMMON_channels_t *cc= &gNB->common_channels[CC_id]; const NR_MIB_t *mib = cc->mib->message.choice.mib; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; @@ -169,18 +172,21 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, const BIT_STRING_t *longBitmap = &scc->ssb_PositionsInBurst->choice.longBitmap; uint16_t ssb_start_symbol; + const int n_slots_frame = nr_slots_per_frame[scs]; switch (scc->ssb_PositionsInBurst->present) { case 1: // short bitmap (<3GHz) max 4 SSBs - for (int i_ssb=0; i_ssb<4; i_ssb++) { - if ((shortBitmap->buf[0]>>(7-i_ssb))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 4; i_ssb++) { + if ((shortBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -202,14 +208,16 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, break; case 2: // medium bitmap (<6GHz) max 8 SSBs - for (int i_ssb=0; i_ssb<8; i_ssb++) { - if ((mediumBitmap->buf[0]>>(7-i_ssb))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 8; i_ssb++) { + if ((mediumBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -231,23 +239,16 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, break; case 3: // long bitmap FR2 max 64 SSBs - num_ssb = 0; - for (int i_ssb=0; i_ssb<64; i_ssb++) { - if ((longBitmap->buf[i_ssb/8]>>(7-(i_ssb%8)))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 64; i_ssb++) { + if ((longBitmap->buf[i_ssb / 8] >> (7 - (i_ssb % 8))) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset >> (scs - 2), ssb_start_symbol, CC_id); - const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - // FR2 is only TDD, to be fixed for flexible TDD - const int nr_slots_period = tdd ? n_slots_frame/get_nb_periods_per_frame(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity) : n_slots_frame; - num_tdd_period = rel_slot/nr_slots_period; - gNB->tdd_beam_association[num_tdd_period]=i_ssb; - num_ssb++; - AssertFatal(num_ssb<2,"beamforming currently not supported for more than one SSB per slot\n"); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset >> (scs - 2), ssb_start_symbol, CC_id, beam.idx); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -282,12 +283,13 @@ static uint32_t schedule_control_sib1(module_id_t module_id, NR_pdsch_dmrs_t *dmrs_parms, NR_tda_info_t *tda_info, uint8_t candidate_idx, + int beam, uint16_t num_total_bytes) { gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - uint16_t *vrb_map = cc->vrb_map; + uint16_t *vrb_map = cc->vrb_map[beam]; if (gNB_mac->sched_ctrlCommon == NULL){ LOG_D(NR_MAC,"schedule_control_common: Filling nr_mac->sched_ctrlCommon\n"); @@ -326,6 +328,7 @@ static uint32_t schedule_control_sib1(module_id_t module_id, CC_id, gNB_mac->sched_ctrlCommon->aggregation_level, nr_of_candidates, + beam, &gNB_mac->sched_ctrlCommon->sched_pdcch, gNB_mac->sched_ctrlCommon->coreset, 0); @@ -387,7 +390,8 @@ static uint32_t schedule_control_sib1(module_id_t module_id, CC_id, &gNB_mac->sched_ctrlCommon->sched_pdcch, gNB_mac->sched_ctrlCommon->cce_index, - gNB_mac->sched_ctrlCommon->aggregation_level); + gNB_mac->sched_ctrlCommon->aggregation_level, + beam); for (int rb = 0; rb < pdsch->rbSize; rb++) { vrb_map[rb + rbStart] |= SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); } @@ -571,15 +575,18 @@ void schedule_nr_sib1(module_id_t module_idP, scc->ssb_PositionsInBurst->present); } - for (int i=0; itype0_PDCCH_CSS_config[i]; - if((frameP%2 == type0_PDCCH_CSS_config->sfn_c) && + if((frameP % 2 == type0_PDCCH_CSS_config->sfn_c) && (slotP == type0_PDCCH_CSS_config->n_0) && (type0_PDCCH_CSS_config->num_rbs > 0) && (type0_PDCCH_CSS_config->active == true)) { + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB_mac->beam_info, frameP, slotP, i, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SIB1 corresponding to SSB %d in any available beam\n", i); LOG_D(NR_MAC,"(%d.%d) SIB1 transmission: ssb_index %d\n", frameP, slotP, type0_PDCCH_CSS_config->ssb_index); default_table_type_t table_type = get_default_table_type(type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern); @@ -602,6 +609,7 @@ void schedule_nr_sib1(module_id_t module_idP, &dmrs_parms, &tda_info, candidate_idx, + beam.idx, cc->sib1_bcch_length); nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index dc412cdf78..334c263501 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -543,10 +543,14 @@ static bool allocate_dl_retransmission(module_id_t module_id, retInfo->tda_info = temp_tda; } + // TODO properly set the beam index (currently only done for RA) + int beam = 0; + /* Find a free CCE */ int CCEIndex = get_cce_index(nr_mac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, + beam, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -565,8 +569,8 @@ static bool allocate_dl_retransmission(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, current_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, r_pucch, 0); - if (alloc<0) { + alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, beam, r_pucch, 0); + if (alloc < 0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, @@ -580,7 +584,8 @@ static bool allocate_dl_retransmission(module_id_t module_id, /* CC_id = */ 0, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + beam); /* just reuse from previous scheduling opportunity, set new start RB */ sched_ctrl->sched_pdsch = *retInfo; sched_ctrl->sched_pdsch.rbStart = rbStart; @@ -736,9 +741,13 @@ static void pf_dl(module_id_t module_id, NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head; + // TODO properly set the beam index (currently only done for RA) + int beam = 0; + int CCEIndex = get_cce_index(mac, CC_id, slot, iterator->UE->rnti, &sched_ctrl->aggregation_level, + beam, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -758,8 +767,8 @@ static void pf_dl(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, r_pucch, 0); - if (alloc<0) { + alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, beam, r_pucch, 0); + if (alloc < 0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI\n", rnti, frame, @@ -774,7 +783,8 @@ static void pf_dl(module_id_t module_id, /* CC_id = */ 0, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + beam); /* MCS has been set above */ sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot); @@ -874,7 +884,8 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ const uint16_t BWPStart = current_BWP->BWPStart; const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols); - uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; + // TODO improve handling of beam in vrb_map (for now just using 0) + uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map[0]; uint16_t rballoc_mask[bwpSize]; int n_rb_sched = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index c02691e82c..26cffef6ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -85,11 +85,14 @@ void nr_preprocessor_phytest(module_id_t module_id, const int bwpSize = dl_bwp->BWPSize; const int BWPStart = dl_bwp->BWPStart; + // TODO implement beam procedures for phy-test mode + int beam = 0; + int rbStart = 0; int rbSize = 0; if (target_dl_bw>bwpSize) target_dl_bw = bwpSize; - uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; + uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map[beam]; /* loop ensures that we allocate exactly target_dl_bw, or return */ while (true) { /* advance to first free RB */ @@ -133,6 +136,7 @@ void nr_preprocessor_phytest(module_id_t module_id, int CCEIndex = get_cce_index(RC.nrmac[module_id], CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, + beam, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -149,11 +153,10 @@ void nr_preprocessor_phytest(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(RC.nrmac[module_id], UE, frame, slot, r_pucch, 0); + alloc = nr_acknack_scheduling(RC.nrmac[module_id], UE, frame, slot, 0, r_pucch, 0); if (alloc < 0) { LOG_D(MAC, - "%s(): could not find PUCCH for UE %04x@%d.%d\n", - __func__, + "Could not find PUCCH for UE %04x@%d.%d\n", rnti, frame, slot); @@ -167,7 +170,8 @@ void nr_preprocessor_phytest(module_id_t module_id, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + beam); //AssertFatal(alloc, // "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n", @@ -283,8 +287,12 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ return false; sched_ctrl->sched_pusch.tda_info = tda_info; sched_ctrl->sched_pusch.time_domain_allocation = tda; + + // TODO implement beam procedures for phy-test mode + int beam = 0; + const int buffer_index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[beam][buffer_index * MAX_BWP_SIZE]; for (int i = rbStart; i < rbStart + rbSize; ++i) { if ((vrb_map_UL[i+BWPStart] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) != 0) { LOG_E(MAC, "%4d.%2d RB %d is already reserved, cannot schedule UE\n", frame, slot, i); @@ -298,6 +306,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ int CCEIndex = get_cce_index(nr_mac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, + beam, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -349,7 +358,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ CC_id, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + beam); for (int rb = rbStart; rb < rbStart + rbSize; rb++) vrb_map_UL[rb+BWPStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5769efe4f2..5bc2a97fd7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -501,11 +501,12 @@ int find_pdcch_candidate(const gNB_MAC_INST *mac, int cc_id, int aggregation, int nr_of_candidates, + int beam_idx, const NR_sched_pdcch_t *pdcch, const NR_ControlResourceSet_t *coreset, uint32_t Y) { - const uint16_t *vrb_map = mac->common_channels[cc_id].vrb_map; + const uint16_t *vrb_map = mac->common_channels[cc_id].vrb_map[beam_idx]; const int N_ci = 0; const int N_rb = pdcch->n_rb; // nb of rbs of coreset per symbol @@ -546,6 +547,7 @@ int get_cce_index(const gNB_MAC_INST *nrmac, const int slot, const rnti_t rnti, uint8_t *aggregation_level, + int beam_idx, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, NR_sched_pdcch_t *sched_pdcch, @@ -567,6 +569,7 @@ int get_cce_index(const gNB_MAC_INST *nrmac, CC_id, *aggregation_level, nr_of_candidates, + beam_idx, sched_pdcch, coreset, Y); @@ -577,9 +580,10 @@ void fill_pdcch_vrb_map(gNB_MAC_INST *mac, int CC_id, NR_sched_pdcch_t *pdcch, int first_cce, - int aggregation){ - - uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map; + int aggregation, + int beam) +{ + uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam]; int N_rb = pdcch->n_rb; // nb of rbs of coreset per symbol int L = pdcch->RegBundleSize; @@ -2725,7 +2729,9 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo NR_SCHED_ENSURE_LOCKED(&gNB_mac->sched_lock); - uint16_t *vrb_map = gNB_mac->common_channels[CC_id].vrb_map; + // TODO implement beam procedures + int beam = 0; + uint16_t *vrb_map = gNB_mac->common_channels[CC_id].vrb_map[beam]; UE_info->sched_csirs = 0; @@ -3110,6 +3116,43 @@ void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t } } +static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +{ + return ((frame * slots_per_frame + slot) / beam_info->beam_duration) % beam_info->beam_allocation_size; +} + +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +{ + // if no beam allocation for analog beamforming we always return beam index 0 (no multiple beams) + if (!beam_info->beam_allocation) + return (NR_beam_alloc_t) {.new_beam = false, .idx = 0}; + + const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + for (int i = 0; i < beam_info->beams_per_period; i++) { + NR_beam_alloc_t beam_struct = {.new_beam = false, .idx = i}; + int *beam = &beam_info->beam_allocation[i][index]; + if (*beam == -1) { + beam_struct.new_beam = true; + *beam = beam_index; + } + if (*beam == beam_index) + return beam_struct; + } + + return (NR_beam_alloc_t) {.new_beam = false, .idx = -1}; +} + +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam) +{ + if(!new_beam) // need to reset only if the beam was allocated specifically for this instance + return; + const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + for (int i = 0; i < beam_info->beams_per_period; i++) { + if (beam_info->beam_allocation[i][index] == beam_index) + beam_info->beam_allocation[i][index] = -1; + } +} + void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data) { gNB_MAC_INST *mac = RC.nrmac[0]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index b4492ffa44..20bf3c0cf2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -470,7 +470,8 @@ static void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, srs_pdu->beamforming.prg_size = 1; } - uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; + // TODO properly use beam allocation + uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[0][buffer_index * MAX_BWP_SIZE]; uint64_t mask = SL_to_bitmap(13 - srs_pdu->time_start_position, srs_pdu->num_symbols); for (int i = 0; i < srs_pdu->bwp_size; ++i) vrb_map_UL[i + srs_pdu->bwp_start] |= mask; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 3de5c1ea7a..d7fb5611ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -279,8 +279,9 @@ void nr_csi_meas_reporting(int Mod_idP, int bwp_start = ul_bwp->BWPStart; // going through the list of PUCCH resources to find the one indexed by resource_id + int beam_idx = 0; // TODO proper beam allocation const int index = ul_buffer_index(sched_frame, sched_slot, ul_bwp->scs, nrmac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[beam_idx][index * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; for (int j = 0; j < m; j++) { NR_PUCCH_Resource_t *pucchres = pucch_Config->resourceToAddModList->list.array[j]; @@ -1239,6 +1240,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot, + int beam_index, int r_pucch, int is_common) { @@ -1328,15 +1330,27 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, else { // unoccupied occasion // checking if in ul_slot the resources potentially to be assigned to this PUCCH are available set_pucch_allocation(ul_bwp, r_pucch, bwp_size, curr_pucch); + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, pucch_frame, pucch_slot, beam_index, n_slots_frame); + if (beam.idx < 0) { + LOG_D(NR_MAC, + "DL %4d.%2d, UL_ACK %4d.%2d beam resources for this occasion are already occupied, move to the following occasion\n", + frame, + slot, + pucch_frame, + pucch_slot); + continue; + } const int index = ul_buffer_index(pucch_frame, pucch_slot, ul_bwp->scs, mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[index * MAX_BWP_SIZE]; - bool ret = test_pucch0_vrb_occupation(curr_pucch, - vrb_map_UL, - bwp_start, - bwp_size); + uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; + bool ret = test_pucch0_vrb_occupation(curr_pucch, vrb_map_UL, bwp_start, bwp_size); if(!ret) { - LOG_D(NR_MAC, "DL %4d.%2d, UL_ACK %4d.%2d PRB resources for this occasion are already occupied, move to the following occasion\n", - frame, slot, pucch_frame, pucch_slot); + LOG_D(NR_MAC, + "DL %4d.%2d, UL_ACK %4d.%2d PRB resources for this occasion are already occupied, move to the following occasion\n", + frame, + slot, + pucch_frame, + pucch_slot); + reset_beam_status(&mac->beam_info, pucch_frame, pucch_slot, beam_index, n_slots_frame, beam.new_beam); continue; } // allocating a new PUCCH structure for this occasion @@ -1428,8 +1442,9 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) continue; } else { + int beam_idx = 0; // TODO proper beam allocation const int index = ul_buffer_index(SFN, slot, ul_bwp->scs, nrmac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam_idx][index * MAX_BWP_SIZE]; const int bwp_start = ul_bwp->BWPStart; const int bwp_size = ul_bwp->BWPSize; set_pucch_allocation(ul_bwp, -1, bwp_size, curr_pucch); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 144d7ef1b4..d0b36a4603 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1708,6 +1708,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, int CCEIndex = get_cce_index(nrmac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, + 0, // TODO use beam index sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -1725,7 +1726,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + 0); // TODO use beam index when implemented /* frame/slot in sched_pusch has been set previously. In the following, we * overwrite the information in the retransmission information before storing @@ -1866,6 +1868,7 @@ static void pf_ul(module_id_t module_id, int CCEIndex = get_cce_index(nrmac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, + 0, // TODO use beam index sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -1912,7 +1915,8 @@ static void pf_ul(module_id_t module_id, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + 0); // TODO use beam index); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); @@ -1983,6 +1987,7 @@ static void pf_ul(module_id_t module_id, int CCEIndex = get_cce_index(nrmac, CC_id, slot, iterator->UE->rnti, &sched_ctrl->aggregation_level, + 0, // TODO use beam index sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -2089,7 +2094,8 @@ static void pf_ul(module_id_t module_id, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, - sched_ctrl->aggregation_level); + sched_ctrl->aggregation_level, + 0); // TODO use beam index); n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) @@ -2155,7 +2161,8 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_ * vrb_map_UL) overlap with the "default" tda and exclude those RBs. * Calculate largest contiguous RBs */ const int index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[index * MAX_BWP_SIZE]; + // TODO improve handling of beam in vrb_map (for now just using 0) + uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; const uint16_t bwpSize = current_BWP->BWPSize; const uint16_t bwpStart = current_BWP->BWPStart; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 82fc2ceee1..9011e13f75 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -175,6 +175,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frameP, sub_frame_t slotP, + int beam_index, int r_pucch, int do_common); @@ -214,6 +215,7 @@ int find_pdcch_candidate(const gNB_MAC_INST *mac, int cc_id, int aggregation, int nr_of_candidates, + int beam_idx, const NR_sched_pdcch_t *pdcch, const NR_ControlResourceSet_t *coreset, uint32_t Y); @@ -222,7 +224,8 @@ void fill_pdcch_vrb_map(gNB_MAC_INST *mac, int CC_id, NR_sched_pdcch_t *pdcch, int first_cce, - int aggregation); + int aggregation, + int beam); void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, const NR_UE_DL_BWP_t *current_DL_BWP, @@ -396,6 +399,7 @@ int get_cce_index(const gNB_MAC_INST *nrmac, const int slot, const rnti_t rnti, uint8_t *aggregation_level, + int beam_idx, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, NR_sched_pdcch_t *sched_pdcch, @@ -420,9 +424,11 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, frame_t frame); int ul_buffer_index(int frame, int slot, int scs, int size); - void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam); + void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP); size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 7792b70f6d..ea696faa71 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -100,6 +100,7 @@ #define MAX_NUM_OF_SSB 64 #define MAX_NUM_NR_PRACH_PREAMBLES 64 #define MIN_NUM_PRBS_TO_SCHEDULE 5 +#define MAX_NUM_BEAM_PERIODS 4 extern const uint8_t nr_rv_round_map[4]; @@ -120,8 +121,15 @@ typedef enum { nrRA_Msg4 = 4, nrRA_WAIT_Msg4_ACK = 5, } RA_gNB_state_t; + static const char *const nrra_text[] = {"IDLE", "Msg2", "WAIT_Msg3", "Msg3_retransmission", "Msg3_dcch_dtch", "Msg4", "WAIT_Msg4_ACK"}; + +typedef struct { + int idx; + bool new_beam; +} NR_beam_alloc_t; + typedef struct nr_pdsch_AntennaPorts_t { int N1; int N2; @@ -203,6 +211,8 @@ typedef struct { frame_t Msg3_frame; /// Msg3 time domain allocation index int Msg3_tda_id; + /// Msg3 beam matrix index + NR_beam_alloc_t Msg3_beam; /// harq_pid used for Msg4 transmission uint8_t harq_pid; /// UE RNTI allocated during RAR @@ -261,10 +271,10 @@ typedef struct { /// Template for RA computations NR_RA_t ra[NR_NB_RA_PROC_MAX]; /// VRB map for common channels - uint16_t vrb_map[275]; + uint16_t vrb_map[MAX_NUM_BEAM_PERIODS][275]; /// VRB map for common channels and PUSCH, dynamically allocated because /// length depends on number of slots and RBs - uint16_t *vrb_map_UL; + uint16_t *vrb_map_UL[MAX_NUM_BEAM_PERIODS]; ///Number of active SSBs int num_active_ssb; //Total available prach occasions per configuration period @@ -742,6 +752,14 @@ typedef struct { uid_allocator_t uid_allocator; } NR_UEs_t; +typedef struct { + /// list of allocated beams per period + int **beam_allocation; + int beam_duration; // in slots + int beams_per_period; + int beam_allocation_size; +} NR_beam_info_t; + #define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++))) typedef void (*nr_pp_impl_dl)(module_id_t mod_id, @@ -841,8 +859,8 @@ typedef struct gNB_MAC_INST_s { time_stats_t rx_ulsch_sdu; // include rlc_data_ind /// processing time of eNB PCH scheduler time_stats_t schedule_pch; - /// list of allocated beams per period - int16_t *tdd_beam_association; + + NR_beam_info_t beam_info; /// bitmap of DLSCH slots, can hold up to 160 slots uint64_t dlsch_slot_bitmap[3]; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 91985393cb..d50f816072 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -1765,9 +1765,7 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, /* log SDUs rejected, at most once per second */ if (entity->sdu_rejected != 0 && entity->t_current > entity->t_log_buffer_full + 1000) { - LOG_E(RLC, "%s:%d:%s: warning: %d SDU rejected, SDU buffer full\n", - __FILE__, __LINE__, __FUNCTION__, - entity->sdu_rejected); + LOG_E(RLC, "%d SDU rejected, SDU buffer full\n", entity->sdu_rejected); entity->sdu_rejected = 0; entity->t_log_buffer_full = entity->t_current; } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index afad2d23a2..7b541c02ff 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -136,9 +136,16 @@ void nr_rlc_entity_tm_recv_sdu(nr_rlc_entity_t *_entity, exit(1); } + /* log SDUs rejected, at most once per second */ + if (entity->sdu_rejected != 0 + && entity->t_current > entity->t_log_buffer_full + 1000) { + LOG_E(RLC, "%d SDU rejected, SDU buffer full\n", entity->sdu_rejected); + entity->sdu_rejected = 0; + entity->t_log_buffer_full = entity->t_current; + } + if (entity->tx_size + size > entity->tx_maxsize) { - LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", - __FILE__, __LINE__, __FUNCTION__); + entity->sdu_rejected++; entity->common.stats.rxsdu_dd_pkts++; entity->common.stats.rxsdu_dd_bytes += size; @@ -181,6 +188,11 @@ void nr_rlc_entity_tm_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id) static void clear_entity(nr_rlc_entity_tm_t *entity) { + entity->t_current = 0; + + entity->t_log_buffer_full = 0; + entity->sdu_rejected = 0; + nr_rlc_free_sdu_segment_list(entity->tx_list); entity->tx_list = NULL; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h index 7918703799..716b35d14d 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h @@ -31,6 +31,10 @@ typedef struct { /* set to the latest know time by the user of the module. Unit: ms */ uint64_t t_current; + /* deal with logging of buffer full */ + uint64_t t_log_buffer_full; + int sdu_rejected; + /* tx management */ nr_rlc_sdu_segment_t *tx_list; nr_rlc_sdu_segment_t *tx_end; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index 4a9a67e40c..75e407328b 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -575,9 +575,16 @@ void nr_rlc_entity_um_recv_sdu(nr_rlc_entity_t *_entity, exit(1); } + /* log SDUs rejected, at most once per second */ + if (entity->sdu_rejected != 0 + && entity->t_current > entity->t_log_buffer_full + 1000) { + LOG_E(RLC, "%d SDU rejected, SDU buffer full\n", entity->sdu_rejected); + entity->sdu_rejected = 0; + entity->t_log_buffer_full = entity->t_current; + } + if (entity->tx_size + size > entity->tx_maxsize) { - LOG_W(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", - __FILE__, __LINE__, __FUNCTION__); + entity->sdu_rejected++; entity->common.stats.rxsdu_dd_pkts++; entity->common.stats.rxsdu_dd_bytes += size; @@ -712,11 +719,13 @@ static void clear_entity(nr_rlc_entity_um_t *entity) entity->rx_next_reassembly = 0; entity->rx_timer_trigger = 0; - entity->tx_next = 0; entity->t_current = 0; + entity->t_log_buffer_full = 0; + entity->sdu_rejected = 0; + entity->t_reassembly_start = 0; cur_rx = entity->rx_list; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h index c40e72ada1..6395bfd47e 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h @@ -47,6 +47,10 @@ typedef struct { /* set to the latest know time by the user of the module. Unit: ms */ uint64_t t_current; + /* deal with logging of buffer full */ + uint64_t t_log_buffer_full; + int sdu_rejected; + /* timers (stores the TTI of activation, 0 means not active) */ uint64_t t_reassembly_start;