clean-up: minimize code repetition

harmonize ACK and CSI mapping into a single function.
This commit is contained in:
Sakthivel Velumani
2026-01-26 10:02:30 +01:00
committed by francescomani
parent 36a5dbdfff
commit f9fb02b1d7
+105 -176
View File
@@ -548,66 +548,18 @@ static double get_beta_offset_csi(const uint8_t beta_offset_idx)
return beta_offset_values[beta_offset_idx]; return beta_offset_values[beta_offset_idx];
} }
/* static uint32_t get_d_factor_re(const uint32_t a, const uint32_t b)
* 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)
{ {
const uint8_t n_symbols = pusch_pdu->nr_of_symbols; uint32_t d_factor_re;
const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; if (a >= b) {
d_factor_re = 1;
uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {0}; } else {
for (uint8_t s = 1; s < n_symbols; s++) { d_factor_re = floor((double)b / a);
symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); if (d_factor_re == 0) {
}
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) {
d_factor_re = 1; 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 // 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; *dmrs_p1 -= start_symbol;
} }
/* 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)
* 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)
{ {
const uint8_t n_symbols = pusch_pdu->nr_of_symbols; bool ret = false;
const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; 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}; case BIT_TYPE_CSI2:
for (uint8_t s = 1; s < n_symbols; s++) { // Skip if already occupied by ACK but not reserved ACK
symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); ret = (template != BIT_TYPE_ACK_RESERVED && template != BIT_TYPE_ULSCH);
} break;
// Reserve Positions using RE-level D-Factor Distribution default:
uint32_t total_reserved = 0; AssertFatal(0, "Mapping called with incorrect UCI type\n");
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++;
}
}
}
} }
return ret;
} }
/* struct map_uci_common_arg {
* This function maps the HARQ-ACK bits when O_ACK > 2 uci_on_pusch_bit_type_t *template;
*/ uci_on_pusch_bit_type_t uci_type_to_map;
static void map_non_overlapped_ack(uci_on_pusch_bit_type_t *template, uint32_t n_symbols;
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, uint32_t nlqm;
uint16_t G_ack, uint16_t G_uci;
uint8_t l1_c, uint8_t l1_c;
const uint32_t *m_uci_current, uint32_t *m_uci_current;
const uint32_t *m_ulsch_initial) uint32_t *m_ulsch_initial;
{ uint32_t (*resv_ack_pos_symb)[MAX_UCI_CODED_BITS];
const uint8_t n_symbols = pusch_pdu->nr_of_symbols; uint32_t *resv_ack_count_symb;
const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; };
uint32_t symbol_start_bit_idx[14] = {0}; static void map_uci_common(struct map_uci_common_arg p)
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); 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; uint32_t total_placed = 0;
for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_ack; 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 = m_uci_current[sym]; const uint32_t uci_re_on_sym = p.m_uci_current[sym];
if (uci_re_on_sym > 0) { if (uci_re_on_sym <= 0) {
const uint32_t remaining_to_place = G_ack - total_placed; continue;
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) { const uint32_t remaining_to_place = p.G_uci - total_placed;
d_factor_re = 1; const uint32_t num_re_to_select = ceil((double)remaining_to_place / p.nlqm);
} else {
d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); uint32_t d_factor_re = get_d_factor_re(num_re_to_select, uci_re_on_sym);
if (d_factor_re == 0) { uint32_t re_offset = 0;
d_factor_re = 1; 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 bit_in_re = 0; bit_in_re < p.nlqm; bit_in_re++) {
for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_placed < G_ack; re_offset += d_factor_re) { if (total_placed >= p.G_uci) {
for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { break;
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++;
} }
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) { if (num_reserved_bits_on_sym > 0) {
const uint32_t num_ack_remaining = G_ack - ack_bits_marked; 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*. // This d-factor is calculated for stepping through the list of *reserved bits*.
if (num_ack_remaining >= num_reserved_bits_on_sym) { const uint32_t d_factor_re = get_d_factor_re(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 *reserved_indices_on_this_sym = positions_by_sym[sym_iter]; 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]; uint32_t pos_to_mark = reserved_indices_on_this_sym[i];
template[pos_to_mark] = BIT_TYPE_ACK_ULSCH; 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 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}; 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) { if (G_ack_rvd > 0) {
build_template_reserve_ack(template, map_arg.uci_type_to_map = BIT_TYPE_ACK_RESERVED;
pusch_pdu, map_arg.G_uci = G_ack_rvd;
G_ack_rvd, map_arg.resv_ack_pos_symb = positions_by_sym;
l1_c, map_arg.resv_ack_count_symb = count_by_sym;
m_uci_current, map_uci_common(map_arg);
m_ulsch_initial,
positions_by_sym,
count_by_sym);
} else if (G_ack > 0) { } 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 // 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 // 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) { if (G_ack > 0 && G_ack_rvd > 0) {
map_overlapped_ack(template, G_ack, l1_c, n_symbols, positions_by_sym, count_by_sym); 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,
rm_info.E_uci_ACK_rvd, rm_info.E_uci_ACK_rvd,
G_initial_total_pusch_bits); G_initial_total_pusch_bits);
uci_present |= true;
} }
uint64_t b_csi1[16] = {0}; // limit to 1024-bit encoded length 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, mod_order,
&b_csi1[0]); &b_csi1[0]);
uci_present |= true;
// Process CSI Part 2 if any // Process CSI Part 2 if any
if (pusch_pdu->pusch_uci.csi_payload.p2_bits > 0) if (pusch_pdu->pusch_uci.csi_payload.p2_bits > 0)
nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part2_payload, 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///////////////////////// /////////////////////////ULSCH scrambling/////////////////////////
uint32_t available_bits; 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 // UCI on PUSCH is present, so available bits are the total codeword length
available_bits = G_initial_total_pusch_bits; available_bits = G_initial_total_pusch_bits;
} else { } else {
@@ -1395,7 +1324,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
available_bits, available_bits,
pusch_pdu->data_scrambling_id, pusch_pdu->data_scrambling_id,
rnti, rnti,
is_uci_on_pusch, uci_present,
uci_mapping_template, uci_mapping_template,
scrambled_output); scrambled_output);
if (UE->phy_sim_test_buf) { if (UE->phy_sim_test_buf) {