From f9fb02b1d72c6f2fcbfc3fb9b33ba48f51b3c3d7 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sun, 7 Dec 2025 05:29:58 +0000 Subject: [PATCH] clean-up: minimize code repetition harmonize ACK and CSI mapping into a single function. --- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 281 ++++++++------------- 1 file changed, 105 insertions(+), 176 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 57f26e3624..6708cef338 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -548,66 +548,18 @@ static double get_beta_offset_csi(const uint8_t beta_offset_idx) return beta_offset_values[beta_offset_idx]; } -/* - * This function maps the CSI part 1 bits - */ -static void map_csi(uci_on_pusch_bit_type_t *template, - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - const bool is_csi1, - uint16_t G_csi, - uint8_t l1_c, - const uint32_t *m_uci_current, - const uint32_t *m_ulsch_initial) +static uint32_t get_d_factor_re(const uint32_t a, const uint32_t b) { - const uint8_t n_symbols = pusch_pdu->nr_of_symbols; - const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; - - uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {0}; - for (uint8_t s = 1; s < n_symbols; s++) { - symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); - } - - uint32_t total_placed = 0; - for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_csi; sym++) { - const uint32_t uci_re_on_sym = m_uci_current[sym]; - - if (uci_re_on_sym <= 0) { - continue; - } - - const uint32_t remaining_to_place = G_csi - total_placed; - uint32_t d_factor_re; - const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm); - - if (num_re_to_select >= uci_re_on_sym) { + uint32_t d_factor_re; + if (a >= b) { + d_factor_re = 1; + } else { + d_factor_re = floor((double)b / a); + if (d_factor_re == 0) { d_factor_re = 1; - } else { - d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); - if (d_factor_re == 0) { - d_factor_re = 1; - } - } - - uint32_t re_offset = 0; - while (re_offset < uci_re_on_sym && total_placed < G_csi) { - if (template[symbol_start_bit_idx[sym] + (re_offset * nlqm)] != BIT_TYPE_ULSCH) { - re_offset++; - continue; // if RE already allocated to UCI or reserved for ACK - } - for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { - if (total_placed >= G_csi) { - break; - } - - uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; - uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; - template[cw_idx] = is_csi1 ? BIT_TYPE_CSI1 : BIT_TYPE_CSI2; - - total_placed++; - } - re_offset += d_factor_re; } } + return d_factor_re; } // Function to lookup beta offset value from Table 9.3-1 in TS 38.213 @@ -861,115 +813,93 @@ static void get_first_uci_symbol(const uint8_t start_symbol, *dmrs_p1 -= start_symbol; } -/* - * This function builds the initial template by reserving positions for HARQ-ACK. - */ -static void build_template_reserve_ack(uci_on_pusch_bit_type_t *template, - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint32_t G_ack_rvd, - uint8_t l1_c, - const uint32_t *m_uci_current, - const uint32_t *m_ulsch_initial, - uint32_t positions_by_sym[][MAX_UCI_CODED_BITS], - uint32_t *count_by_sym) +static inline bool skip_mapping_current_uci(const uci_on_pusch_bit_type_t template, const uci_on_pusch_bit_type_t uci_type_to_map) { - const uint8_t n_symbols = pusch_pdu->nr_of_symbols; - const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; + bool ret = false; + switch (uci_type_to_map) { + case BIT_TYPE_ACK_RESERVED: + case BIT_TYPE_ACK: + // ACK bits get the highest priority. Don't skip + ret = false; + break; - memset(count_by_sym, 0, n_symbols * sizeof(uint32_t)); + case BIT_TYPE_CSI1: + // Skip if already occupied by ACK and reserved ACK. Template is initialized with ULSCH + ret = (template != BIT_TYPE_ULSCH); + break; - uint32_t symbol_start_bit_idx[14] = {0}; - for (uint8_t s = 1; s < n_symbols; s++) { - symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); - } + case BIT_TYPE_CSI2: + // Skip if already occupied by ACK but not reserved ACK + ret = (template != BIT_TYPE_ACK_RESERVED && template != BIT_TYPE_ULSCH); + break; - // Reserve Positions using RE-level D-Factor Distribution - uint32_t total_reserved = 0; - - for (uint8_t sym = l1_c; sym < n_symbols && total_reserved < G_ack_rvd; sym++) { - const uint32_t uci_re_on_sym = m_uci_current[sym]; - - if (uci_re_on_sym > 0) { - const uint32_t remaining_to_reserve = G_ack_rvd - total_reserved; - uint32_t d_factor_re; - const uint32_t num_re_to_select = ceil((double)remaining_to_reserve / nlqm); - if (num_re_to_select >= uci_re_on_sym) { - d_factor_re = 1; - } else { - d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); - if (d_factor_re == 0) { - d_factor_re = 1; - } - } - - for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_reserved < G_ack_rvd; re_offset += d_factor_re) { - for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { - if (total_reserved >= G_ack_rvd) { - break; - } - - uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; - uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; - template[cw_idx] = BIT_TYPE_ACK_RESERVED; - positions_by_sym[sym][count_by_sym[sym]] = cw_idx; - count_by_sym[sym]++; - - total_reserved++; - } - } - } + default: + AssertFatal(0, "Mapping called with incorrect UCI type\n"); } + return ret; } -/* - * This function maps the HARQ-ACK bits when O_ACK > 2 - */ -static void map_non_overlapped_ack(uci_on_pusch_bit_type_t *template, - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint16_t G_ack, - uint8_t l1_c, - const uint32_t *m_uci_current, - const uint32_t *m_ulsch_initial) -{ - const uint8_t n_symbols = pusch_pdu->nr_of_symbols; - const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; +struct map_uci_common_arg { + uci_on_pusch_bit_type_t *template; + uci_on_pusch_bit_type_t uci_type_to_map; + uint32_t n_symbols; + uint32_t nlqm; + uint16_t G_uci; + uint8_t l1_c; + uint32_t *m_uci_current; + uint32_t *m_ulsch_initial; + uint32_t (*resv_ack_pos_symb)[MAX_UCI_CODED_BITS]; + uint32_t *resv_ack_count_symb; +}; - uint32_t symbol_start_bit_idx[14] = {0}; - for (uint8_t s = 1; s < n_symbols; s++) { - symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); +static void map_uci_common(struct map_uci_common_arg p) +{ + DevAssert((p.resv_ack_count_symb && p.resv_ack_pos_symb && (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED)) + || (!p.resv_ack_count_symb && !p.resv_ack_pos_symb && (p.uci_type_to_map != BIT_TYPE_ACK_RESERVED))); + + uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {0}; + for (uint8_t s = 1; s < p.n_symbols; s++) { + symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (p.m_ulsch_initial[s - 1] * p.nlqm); } + if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED) + memset(p.resv_ack_count_symb, 0, sizeof(*p.resv_ack_count_symb) * NR_SYMBOLS_PER_SLOT); + uint32_t total_placed = 0; - for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_ack; sym++) { - const uint32_t uci_re_on_sym = m_uci_current[sym]; + for (uint8_t sym = p.l1_c; sym < p.n_symbols && total_placed < p.G_uci; sym++) { + const uint32_t uci_re_on_sym = p.m_uci_current[sym]; - if (uci_re_on_sym > 0) { - const uint32_t remaining_to_place = G_ack - total_placed; - uint32_t d_factor_re; - const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm); + if (uci_re_on_sym <= 0) { + continue; + } - if (num_re_to_select >= uci_re_on_sym) { - d_factor_re = 1; - } else { - d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); - if (d_factor_re == 0) { - d_factor_re = 1; - } + const uint32_t remaining_to_place = p.G_uci - total_placed; + const uint32_t num_re_to_select = ceil((double)remaining_to_place / p.nlqm); + + uint32_t d_factor_re = get_d_factor_re(num_re_to_select, uci_re_on_sym); + uint32_t re_offset = 0; + uint32_t *cur_sym_resv_ack_pos = p.resv_ack_pos_symb[sym]; + while (re_offset < uci_re_on_sym && total_placed < p.G_uci) { + uci_on_pusch_bit_type_t cur_template = p.template[symbol_start_bit_idx[sym] + (re_offset * p.nlqm)]; + if (skip_mapping_current_uci(cur_template, p.uci_type_to_map)) { + re_offset++; + continue; // if RE already allocated to UCI or reserved for ACK } - - for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_placed < G_ack; re_offset += d_factor_re) { - for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { - if (total_placed >= G_ack) { - break; - } - - uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; - uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; - template[cw_idx] = BIT_TYPE_ACK; - - total_placed++; + for (uint32_t bit_in_re = 0; bit_in_re < p.nlqm; bit_in_re++) { + if (total_placed >= p.G_uci) { + break; } + + uint32_t bit_offset_in_sym = (re_offset * p.nlqm) + bit_in_re; + uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; + p.template[cw_idx] = p.uci_type_to_map; + if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED) { + cur_sym_resv_ack_pos[p.resv_ack_count_symb[sym]++] = cw_idx; + } + + total_placed++; } + re_offset += d_factor_re; } } } @@ -991,21 +921,13 @@ static void map_overlapped_ack(uci_on_pusch_bit_type_t *template, if (num_reserved_bits_on_sym > 0) { const uint32_t num_ack_remaining = G_ack - ack_bits_marked; - uint32_t d_factor; // This d-factor is calculated for stepping through the list of *reserved bits*. - if (num_ack_remaining >= num_reserved_bits_on_sym) { - d_factor = 1; - } else { - d_factor = floor((double)num_reserved_bits_on_sym / num_ack_remaining); - if (d_factor == 0) { - d_factor = 1; - } - } + const uint32_t d_factor_re = get_d_factor_re(num_ack_remaining, num_reserved_bits_on_sym); const uint32_t *reserved_indices_on_this_sym = positions_by_sym[sym_iter]; - for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor) { + for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor_re) { uint32_t pos_to_mark = reserved_indices_on_this_sym[i]; template[pos_to_mark] = BIT_TYPE_ACK_ULSCH; @@ -1131,23 +1053,34 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_ uint32_t positions_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT][MAX_UCI_CODED_BITS] = {0}; uint32_t count_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; + struct map_uci_common_arg map_arg = {.template = template, + .n_symbols = pusch_pdu->nr_of_symbols, + .nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers, + .l1_c = l1_c, + .m_uci_current = m_uci_current, + .m_ulsch_initial = m_ulsch_initial}; if (G_ack_rvd > 0) { - build_template_reserve_ack(template, - pusch_pdu, - G_ack_rvd, - l1_c, - m_uci_current, - m_ulsch_initial, - positions_by_sym, - count_by_sym); + map_arg.uci_type_to_map = BIT_TYPE_ACK_RESERVED; + map_arg.G_uci = G_ack_rvd; + map_arg.resv_ack_pos_symb = positions_by_sym; + map_arg.resv_ack_count_symb = count_by_sym; + map_uci_common(map_arg); } else if (G_ack > 0) { - map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial); + map_arg.uci_type_to_map = BIT_TYPE_ACK; + map_arg.G_uci = G_ack; + map_uci_common(map_arg); } // CSI part 1 - map_csi(template, pusch_pdu, true, G_csi1, first_non_dmrs_sym, m_uci_current, m_ulsch_initial); + map_arg.uci_type_to_map = BIT_TYPE_CSI1; + map_arg.G_uci = G_csi1; + map_arg.resv_ack_pos_symb = NULL; + map_arg.resv_ack_count_symb = NULL; + map_uci_common(map_arg); // CSI part 2 - map_csi(template, pusch_pdu, false, G_csi2, first_non_dmrs_sym, m_uci_current, m_ulsch_initial); + map_arg.uci_type_to_map = BIT_TYPE_CSI2; + map_arg.G_uci = G_csi2; + map_uci_common(map_arg); if (G_ack > 0 && G_ack_rvd > 0) { map_overlapped_ack(template, G_ack, l1_c, n_symbols, positions_by_sym, count_by_sym); @@ -1296,7 +1229,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, rm_info.E_uci_ACK, rm_info.E_uci_ACK_rvd, G_initial_total_pusch_bits); - uci_present |= true; } uint64_t b_csi1[16] = {0}; // limit to 1024-bit encoded length @@ -1310,8 +1242,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, mod_order, &b_csi1[0]); - uci_present |= true; - // Process CSI Part 2 if any if (pusch_pdu->pusch_uci.csi_payload.p2_bits > 0) nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part2_payload, @@ -1376,9 +1306,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH scrambling///////////////////////// uint32_t available_bits; - bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0 || pusch_pdu->pusch_uci.csi_payload.p1_bits != 0); - if (is_uci_on_pusch) { + if (uci_present) { // UCI on PUSCH is present, so available bits are the total codeword length available_bits = G_initial_total_pusch_bits; } else { @@ -1395,7 +1324,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, available_bits, pusch_pdu->data_scrambling_id, rnti, - is_uci_on_pusch, + uci_present, uci_mapping_template, scrambled_output); if (UE->phy_sim_test_buf) {