From 04d35f90ecb23cbd0a6a87952eca502cf9270e40 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Thu, 8 Jan 2026 05:14:06 +0000 Subject: [PATCH] ue: simplify dlsch LLR functions Change layer_llr buffer from 2D to 3D with symbol as first dimenstion. Refactor layer demapping function. --- common/utils/utils.h | 11 ++ .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 158 +++++++----------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 1 - .../PHY/nr_phy_common/inc/nr_phy_common.h | 8 +- .../PHY/nr_phy_common/src/nr_phy_common.c | 10 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 4 +- 6 files changed, 86 insertions(+), 106 deletions(-) diff --git a/common/utils/utils.h b/common/utils/utils.h index 432e754875..752ba2264b 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -20,6 +20,17 @@ extern "C" { #define sizeofArray(a) (sizeof(a)/sizeof(*(a))) #define CHECK_INDEX(ARRAY, INDEX) assert((INDEX) < sizeofArray(ARRAY)) +#define GET_ARRAY_MAX(arr, size, max_val) \ + do { \ + DevAssert((size) > 0); \ + (max_val) = (arr)[0]; \ + for (size_t _i = 1; _i < (size); _i++) { \ + if ((arr)[_i] > (max_val)) { \ + (max_val) = (arr)[_i]; \ + } \ + } \ + } while (0) + // Prevent double evaluation in max macro #define cmax(a,b) ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 9e17c141f2..693cb028dd 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -868,79 +868,83 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, } } -static void nr_dlsch_layer_demapping(int16_t *llr_cw[2], - uint8_t Nl, - uint8_t mod_order, - uint32_t length, - int32_t codeword_TB0, - int32_t codeword_TB1, - uint sz, - int16_t llr_layers[][sz]) +static void nr_dlsch_layer_demapping(const uint8_t Nl, + const uint8_t mod_order, + const int llrLayerSize, + const int16_t llr_layers[NR_SYMBOLS_PER_SLOT][Nl][llrLayerSize], + const NR_UE_DLSCH_t *dlsch, + const uint32_t re_len[NR_SYMBOLS_PER_SLOT], + int16_t *llr) { + const int s0 = dlsch->dlsch_config.start_symbol; + const int s1 = dlsch->dlsch_config.number_symbols; + + int k = 0; switch (Nl) { case 1: - if (codeword_TB1 == -1) - memcpy(llr_cw[0], llr_layers[0], (length)*sizeof(int16_t)); - else if (codeword_TB0 == -1) - memcpy(llr_cw[1], llr_layers[0], (length)*sizeof(int16_t)); - - break; + for (int i = s0; i < (s0 + s1); i++) { + memcpy(llr + k, llr_layers[i][0], re_len[i] * mod_order * sizeof(int16_t)); + k += re_len[i] * mod_order; + } + break; case 2: case 3: case 4: - for (int i=0; i<(length/Nl/mod_order); i++){ - for (int l=0; l0 1 2 3 - else if (codeword_TB0 == -1) - llr_cw[1][Nl*mod_order*i+l*mod_order+m] = llr_layers[l][i*mod_order+m];//i:0 -->0 1 2 3 - //if (i<4) printf("length%d: llr_layers[l%d][m%d]=%d: \n",length,l,m,llr_layers[l][i*mod_order+m]); - } + for (int i = s0; i < (s0 + s1); i++) { + int m = 0; + for (int j = 0; j < re_len[i]; j++) { + for (int l = 0; l < Nl; l++) { + memcpy(llr + k, llr_layers[i][l] + m * mod_order, sizeof(int16_t) * mod_order); + k += mod_order; + // if (i<4) printf("length%d: llr_layers[l%d][m%d]=%d: \n",length,l,m,llr_layers[l][i*mod_order+m]); } + m++; } - break; + } + break; - default: - AssertFatal(0, "Not supported number of layers %d\n", Nl); + default: + AssertFatal(0, "Not supported number of layers %d\n", Nl); } } -static void nr_dlsch_llr(uint32_t rx_size_symbol, - int nbRx, - uint sz, - int nl, - int16_t layer_llr[][sz], - c16_t rxdataF_comp[][nl][nbRx][rx_size_symbol], - c16_t dl_ch_mag[rx_size_symbol], - c16_t dl_ch_magb[rx_size_symbol], - c16_t dl_ch_magr[rx_size_symbol], - NR_DL_UE_HARQ_t *dlsch1_harq, - unsigned char symbol, - uint32_t len, - NR_UE_DLSCH_t dlsch[2], - uint32_t llr_offset_symbol) +/* Computes LLRs from compensated PDSCH signal per OFDM symbol for all layers */ +static int nr_dlsch_llr(const NR_UE_DLSCH_t *dlsch, + const int len, + const int rx_size_symbol, + const c16_t dl_ch_mag[rx_size_symbol], + const c16_t dl_ch_magb[rx_size_symbol], + const c16_t dl_ch_magr[rx_size_symbol], + const int nb_antennas_rx, + const c16_t rxdataF_comp[dlsch->Nl][nb_antennas_rx][rx_size_symbol], + const int llrSize, + int16_t layer_llr[dlsch->Nl][llrSize]) { - switch (dlsch[0].dlsch_config.qamModOrder) { + switch (dlsch->dlsch_config.qamModOrder) { case 2 : - for(int l = 0; l < dlsch[0].Nl; l++) - nr_qpsk_llr(&rxdataF_comp[symbol][l][0][0], layer_llr[l] + llr_offset_symbol, len); + for (int l = 0; l < dlsch[0].Nl; l++) + nr_qpsk_llr(rxdataF_comp[l][0], layer_llr[l], len); break; case 4 : - for(int l = 0; l < dlsch[0].Nl; l++) - nr_16qam_llr(&rxdataF_comp[symbol][l][0][0], dl_ch_mag, layer_llr[l] + llr_offset_symbol, len); + for (int l = 0; l < dlsch[0].Nl; l++) + nr_16qam_llr(rxdataF_comp[l][0], dl_ch_mag, layer_llr[l], len); break; case 6 : for(int l=0; l < dlsch[0].Nl; l++) - nr_64qam_llr(&rxdataF_comp[symbol][l][0][0], dl_ch_mag, dl_ch_magb, layer_llr[l] + llr_offset_symbol, len); + nr_64qam_llr(rxdataF_comp[l][0], dl_ch_mag, dl_ch_magb, layer_llr[l], len); break; case 8: for(int l=0; l < dlsch[0].Nl; l++) - nr_256qam_llr(&rxdataF_comp[symbol][l][0][0], dl_ch_mag, dl_ch_magb, dl_ch_magr, layer_llr[l] + llr_offset_symbol, len); + nr_256qam_llr(rxdataF_comp[l][0], + dl_ch_mag, + dl_ch_magb, + dl_ch_magr, + layer_llr[l], + len); break; default: @@ -948,30 +952,7 @@ static void nr_dlsch_llr(uint32_t rx_size_symbol, break; } - //TODO: Revisited for Nl>4 - if (dlsch1_harq) { - switch (dlsch[1].dlsch_config.qamModOrder) { - case 2 : - nr_qpsk_llr(&rxdataF_comp[symbol][0][0][0], layer_llr[0] + llr_offset_symbol, len); - break; - - case 4: - nr_16qam_llr(&rxdataF_comp[symbol][0][0][0], dl_ch_mag, layer_llr[0] + llr_offset_symbol, len); - break; - - case 6 : - nr_64qam_llr(&rxdataF_comp[symbol][0][0][0], dl_ch_mag, dl_ch_magb, layer_llr[0] + llr_offset_symbol, len); - break; - - case 8 : - nr_256qam_llr(&rxdataF_comp[symbol][0][0][0], dl_ch_mag, dl_ch_magb, dl_ch_magr, layer_llr[0] + llr_offset_symbol, len); - break; - - default: - AssertFatal(false, "Unknown mod_order!!!!\n"); - break; - } - } + return 0; } //============================================================================================== @@ -988,7 +969,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, int16_t *llr[2], uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT], c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], - uint32_t llr_offset[NR_SYMBOLS_PER_SLOT], int32_t *log2_maxh, int rx_size_symbol, int nbRx, @@ -1376,39 +1356,31 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, dlsch); dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol]; } - if (symbol < startSymbIdx + nbSymb - 1) // up to the penultimate symbol - llr_offset[symbol + 1] = dl_valid_re[symbol] * dlsch_config->qamModOrder + llr_offset[symbol]; /* at last symbol in a slot calculate LLR's for whole slot */ if (symbol == (startSymbIdx + nbSymb - 1)) { - const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl; - - if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) { - LOG_E(PHY, "rx_llr_layer_size %d, G %d, Nl, %d, discarding this pdsch\n", rx_llr_layer_size, G, dlsch[0].Nl); - return -1; - } - __attribute__((aligned(32))) int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size]; + /* create LLR layer buffer */ + int max_symb_re = 0; + GET_ARRAY_MAX(dl_valid_re, NR_SYMBOLS_PER_SLOT, max_symb_re); + const int llr_per_symbol = max_symb_re * dlsch->dlsch_config.qamModOrder; + __attribute__((aligned(32))) int16_t layer_llr[NR_SYMBOLS_PER_SLOT][nl][llr_per_symbol]; // Generate LLR from PTRS compensated signal start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); for (int llr_sym = startSymbIdx; llr_sym < startSymbIdx + nbSymb; llr_sym++) { - nr_dlsch_llr(rx_size_symbol, - nbRx, - rx_llr_layer_size, - nl, - layer_llr, - rxdataF_comp, + nr_dlsch_llr(dlsch, + dl_valid_re[llr_sym], + rx_size_symbol, dl_ch_mag[llr_sym][0][0], dl_ch_magb[llr_sym][0][0], dl_ch_magr[llr_sym][0][0], - dlsch1_harq, - llr_sym, - dl_valid_re[llr_sym], - dlsch, - llr_offset[llr_sym]); + n_rx, + rxdataF_comp[llr_sym], + llr_per_symbol, + layer_llr[llr_sym]); } stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); - nr_dlsch_layer_demapping(llr, dlsch[0].Nl, dlsch_config->qamModOrder, G, codeword_TB0, codeword_TB1, rx_llr_layer_size, layer_llr); + nr_dlsch_layer_demapping(nl, dlsch_config->qamModOrder, llr_per_symbol, layer_llr, dlsch, dl_valid_re, llr[0]); stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); /* for (int i=0; i < 2; i++){ diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 4aeac61e1f..f0d8617a18 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -312,7 +312,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, int16_t *llr[2], uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT], c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], - uint32_t llr_offset[NR_SYMBOLS_PER_SLOT], int32_t *log2_maxh, int rx_size_symbol, int nbRx, diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 8baf8df8bb..f4e513cdb7 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -349,10 +349,10 @@ typedef struct { } csi_mapping_parms_t; csi_mapping_parms_t get_csi_mapping_parms(int row, int b, int l0, int l1); int get_cdm_group_size(int cdm_type); -void nr_qpsk_llr(c16_t *rxdataF_comp, int16_t *llr, uint32_t nb_re); -void nr_16qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re); -void nr_64qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, int16_t *llr, uint32_t nb_re); -void nr_256qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, c16_t *ch_mag3, int16_t *llr, uint32_t nb_re); +void nr_qpsk_llr(const c16_t *rxdataF_comp, int16_t *llr, uint32_t nb_re); +void nr_16qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re); +void nr_64qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag, const c16_t *ch_mag2, int16_t *llr, uint32_t nb_re); +void nr_256qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag, const c16_t *ch_mag2, const c16_t *ch_mag3, int16_t *llr, uint32_t nb_re); void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal); void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb); diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index 203c19814b..e61db67bbb 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -66,9 +66,9 @@ static inline c16_t saturating_sub(c16_t a, c16_t b) //---------------------------------------------------------------------------------------------- // QPSK //---------------------------------------------------------------------------------------------- -void nr_qpsk_llr(c16_t *rxdataF_comp, int16_t *llr, uint32_t nb_re) +void nr_qpsk_llr(const c16_t *rxdataF_comp, int16_t *llr, uint32_t nb_re) { - c16_t *rxF = rxdataF_comp; + const c16_t *rxF = rxdataF_comp; c16_t *llr32 = (c16_t *)llr; for (int i = 0; i < nb_re; i++) { llr32[i].r = rxF[i].r >> 4; @@ -80,7 +80,7 @@ void nr_qpsk_llr(c16_t *rxdataF_comp, int16_t *llr, uint32_t nb_re) // 16-QAM //---------------------------------------------------------------------------------------------- -void nr_16qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re) +void nr_16qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; simde__m256i *ch_mag256 = (simde__m256i *)ch_mag_in; @@ -148,7 +148,7 @@ void nr_16qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag_in, int16_t *llr, uint32_t // 64-QAM //---------------------------------------------------------------------------------------------- -void nr_64qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, int16_t *llr, uint32_t nb_re) +void nr_64qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag, const c16_t *ch_mag2, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF = (simde__m256i *)rxdataF_comp; @@ -251,7 +251,7 @@ void nr_64qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, int16_t *l } } -void nr_256qam_llr(c16_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, c16_t *ch_mag3, int16_t *llr, uint32_t nb_re) +void nr_256qam_llr(const c16_t *rxdataF_comp, const c16_t *ch_mag, const c16_t *ch_mag2, const c16_t *ch_mag3, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; simde__m256i *llr256 = (simde__m256i *)llr; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 347e259554..7f500b00a4 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -685,7 +685,6 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, } uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT] = {0}; - uint32_t llr_offset[NR_SYMBOLS_PER_SLOT] = {0}; int32_t log2_maxh = 0; @@ -752,7 +751,6 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, llr, dl_valid_re, rxdataF, - llr_offset, &log2_maxh, rx_size_symbol, ue->frame_parms.nb_antennas_rx, @@ -1319,7 +1317,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ unav_res, dlsch_config->qamModOrder, dlsch[0].Nl); - const uint32_t rx_llr_buf_sz = ((G + 15) / 16) * 16; + const uint32_t rx_llr_buf_sz = ALIGNARRAYSIZE(G, 32); // each LLR is 2 bytes hence 64 byte aligned const uint32_t nb_codewords = NR_MAX_NB_LAYERS > 4 ? 2 : 1; int16_t* llr[2]; for (int i = 0; i < nb_codewords; i++)