From 044ca835d621ae24c1bef084629bc1af440bcd03 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Tue, 23 Sep 2025 04:21:38 +0000 Subject: [PATCH] phy: use fftshift'ed buffer for txdataF So far txdataF buffer has DC RE as the first element. This was prefered most likely to avoid memcpy before iFFT but comes with a small complexity in RE mapping functions. Instead, we use a flat buffer that holds freq domain data starting from first negative SC. After resource mapping is done on all channels, each OFDM symbol is shifted before iFFT so that the buffer start with DC RE. This reduces complexity in mapping functions and later on when passing beam IDs to 7.2 split RU especially when a beam is associated to interleaved RB and/or REs. There is already a memcpy in place to copy txdataF from gNB stuct to RU struct. So this change does not introduce new memcpy. --- openair1/PHY/INIT/nr_init_ru.c | 3 +- openair1/PHY/MODULATION/nr_modulation.h | 9 ++ openair1/PHY/MODULATION/ofdm_mod.c | 48 +++++--- openair1/PHY/NR_TRANSPORT/nr_dci.c | 9 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 108 +++++------------- openair1/PHY/NR_TRANSPORT/nr_pbch.c | 37 +----- openair1/PHY/NR_TRANSPORT/nr_prs.c | 11 +- openair1/PHY/NR_TRANSPORT/nr_pss.c | 6 +- openair1/PHY/NR_TRANSPORT/nr_sss.c | 5 +- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 9 +- .../nr_phy_common/src/nr_phy_common_csirs.c | 4 +- openair1/SCHED_NR/nr_ru_procedures.c | 18 +-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + openair1/SIMULATION/NR_PHY/dlsim.c | 21 +++- openair1/SIMULATION/NR_PHY/pbchsim.c | 32 +++++- radio/fhi_72/oaioran.c | 81 ++++++------- 16 files changed, 185 insertions(+), 217 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 21b564d3c2..1092545705 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -103,7 +103,8 @@ void nr_phy_init_RU(RU_t *ru) ru->common.txdataF_BF = (int32_t **)malloc16(nb_tx_streams * sizeof(int32_t*)); LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, nb_tx_streams * sizeof(int32_t *)); for (int i = 0; i < nb_tx_streams; i++) { - ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t)); + ru->common.txdataF_BF[i] = + (int32_t *)malloc16_clear(fp->samples_per_slot_wCP * sizeof(int32_t)); LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx); } // allocate FFT output buffers (RX) diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index 9e8ac3ba3c..fda32fa86f 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -105,6 +105,7 @@ void nr_beam_precoding(c16_t **txdataF, void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp, c16_t *txdataF, + bool is_flat_buff, const c16_t *symbol_rotation, int slot, int nb_rb, @@ -161,4 +162,12 @@ void nr_layer_precoder_simd(const int n_layers, const int sc_offset, const int re_cnt, c16_t *txdataF_precoded); + +void fft_shift(const c16_t *in, + uint32_t in_symb_sz, + uint16_t num_prb, + c16_t *out, + uint16_t fft_size_out, + uint16_t start_symb, + uint16_t num_symb); #endif diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index c3311fb78a..8a31648605 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -288,6 +288,7 @@ void do_OFDM_mod(c16_t **txdataF, c16_t **txdata, uint32_t frame,uint16_t next_s void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp, c16_t *txdataF, + bool is_flat_buff, const c16_t *symbol_rotation, int slot, int nb_rb, @@ -309,20 +310,39 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp, this_rotation->r, this_rotation->i); - if (nb_rb & 1) { - rotate_cpx_vector(this_symbol, this_rotation, this_symbol, - (nb_rb + 1) * 6, 15); - rotate_cpx_vector(this_symbol + fp->first_carrier_offset - 6, - this_rotation, - this_symbol + fp->first_carrier_offset - 6, - (nb_rb + 1) * 6, 15); - } else { - rotate_cpx_vector(this_symbol, this_rotation, this_symbol, - nb_rb * 6, 15); - rotate_cpx_vector(this_symbol + fp->first_carrier_offset, - this_rotation, - this_symbol + fp->first_carrier_offset, - nb_rb * 6, 15); + if (is_flat_buff) + rotate_cpx_vector(this_symbol, this_rotation, this_symbol, nb_rb * NR_NB_SC_PER_RB, 15); + else { + c16_t *this_symbol_neg = this_symbol + fp->first_carrier_offset; + if (nb_rb & 1) { + this_symbol_neg -= 6; + nb_rb += 1; + } + rotate_cpx_vector(this_symbol, this_rotation, this_symbol, nb_rb * 6, 15); + rotate_cpx_vector(this_symbol_neg, this_rotation, this_symbol_neg, nb_rb * 6, 15); } } } + +/* Do FFT-shift for symbols in the provided in buffer and writes to out buffer. */ +void fft_shift(const c16_t *in, + uint32_t in_symb_sz, + uint16_t num_prb, + c16_t *out, + uint16_t fft_size_out, + uint16_t start_symb, + uint16_t num_symb) +{ + const int num_samp_half = num_prb * NR_NB_SC_PER_RB / 2; + const int first_carrier_offset = fft_size_out - num_samp_half; + for (int s = start_symb; s < start_symb + num_symb; s++) { + // Copy negative freq component + uint16_t out_offset = s * fft_size_out + first_carrier_offset; + uint16_t in_offset = s * in_symb_sz; + memcpy(out + out_offset, in + in_offset, num_samp_half * sizeof(int32_t)); + // Copy positive freq component + out_offset = s * fft_size_out; + in_offset = s * in_symb_sz + num_samp_half; + memcpy(out + out_offset, in + in_offset, num_samp_half * sizeof(int32_t)); + } +} diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index edb296e8a4..a4f5c80989 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -67,7 +67,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, if (pdcch_pdu_rel15->CoreSetType == 1) additional_offset = (pdcch_pdu_rel15->BWPStart + 5) / 6 * 6 - pdcch_pdu_rel15->BWPStart; int rb_offset = cset_start + additional_offset; - uint16_t cset_start_sc = frame_parms->first_carrier_offset + (pdcch_pdu_rel15->BWPStart + rb_offset) * NR_NB_SC_PER_RB; + uint16_t cset_start_sc = (pdcch_pdu_rel15->BWPStart + rb_offset) * NR_NB_SC_PER_RB; int idx1 = pdcch_pdu_rel15->StartSymbolIndex+pdcch_pdu_rel15->DurationSymbols; int idx2 = (((n_rb + rb_offset + pdcch_pdu_rel15->BWPStart) * 3) + 15) & ~15; c16_t mod_dmrs[idx1][idx2] __attribute__((aligned(16))); @@ -179,8 +179,6 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, /// Resource mapping uint16_t amp = gNB->TX_AMP; c16_t *txdataF = gNB->common_vars.txdataF[beam_nb][0]; - if (cset_start_sc >= frame_parms->ofdm_symbol_size) - cset_start_sc -= frame_parms->ofdm_symbol_size; int num_regs = dci_pdu->AggregationLevel * NR_NB_REG_PER_CCE / pdcch_pdu_rel15->DurationSymbols; /*Mapping the encoded DCI along with the DMRS */ @@ -189,8 +187,6 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, for (int reg_count = 0; reg_count < num_regs; reg_count++) { int k = cset_start_sc + reg_list[d][reg_count] * NR_NB_SC_PER_RB; LOG_D(NR_PHY_DCI, "REG %d k %d\n", reg_list[d][reg_count], k); - if (k >= frame_parms->ofdm_symbol_size) - k -= frame_parms->ofdm_symbol_size; int l = cset_start_symb + symbol_idx; @@ -226,9 +222,6 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, } k++; - - if (k >= frame_parms->ofdm_symbol_size) - k -= frame_parms->ofdm_symbol_size; } // m } // reg_count } // symbol_idx diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index b09f816c7d..1edb590a58 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -86,8 +86,7 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, printf("k %d \t txdataF: %d %d\n", k, txF[k].r, txF[k].i); #endif } - if (++k >= symbol_sz) - k -= symbol_sz; + k++; } return in - tx_layer; } @@ -294,7 +293,7 @@ static inline int dmrs_case00(c16_t *output, else { output[k] = (c16_t){0}; } - k = (k + 1) % symbol_sz; + k++; } // RE loop return in - txl; } @@ -355,12 +354,6 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms, { c16_t *txl = txl_start; const uint sz = rel15->rbSize * NR_NB_SC_PER_RB; - int upper_limit = sz; - int remaining_re = 0; - if (start_sc + upper_limit > symbol_sz) { - upper_limit = symbol_sz - start_sc; - remaining_re = sz - upper_limit; - } /* calculate if current symbol is PTRS symbols */ int ptrs_symbol = 0; @@ -385,47 +378,39 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms, if (rel15->numDmrsCdmGrpsNoData == 2) { switch (dmrs_port & 3) { case 0: - txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, upper_limit); - txl += interleave_with_0_signal_first(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, sz); break; case 1: { c16_t dmrs[sz / 2]; neg_dmrs(dmrs_start, dmrs, sz / 2); - txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, upper_limit); - txl += interleave_with_0_signal_first(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, sz); } break; case 2: - txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, upper_limit); - txl += interleave_with_0_start_with_0(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, sz); break; case 3: { c16_t dmrs[sz / 2]; neg_dmrs(dmrs_start, dmrs, sz / 2); - txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, upper_limit); - txl += interleave_with_0_start_with_0(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, sz); } break; } } else if (rel15->numDmrsCdmGrpsNoData == 1) { switch (dmrs_port & 3) { case 0: - txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, upper_limit); - txl += interleave_signals(output, txl, amp, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, sz); break; case 1: { c16_t dmrs[sz / 2]; neg_dmrs(dmrs_start, dmrs, sz / 2); - txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, upper_limit); - txl += interleave_signals(output, txl, amp, dmrs + upper_limit / 2, amp_dmrs, remaining_re); + txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, sz); } break; case 2: - txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, upper_limit); - txl += interleave_signals(output, dmrs_start + upper_limit / 2, amp_dmrs, txl, amp, remaining_re); + txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, sz); break; case 3: { c16_t dmrs[sz / 2]; neg_dmrs(dmrs_start, dmrs, sz / 2); - txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, upper_limit); - txl += interleave_signals(output, dmrs + upper_limit / 2, amp_dmrs, txl, amp, remaining_re); + txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, sz); } break; } } else @@ -445,8 +430,7 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms, rel15->numDmrsCdmGrpsNoData); } // generic DMRS case } else { // no PTRS or DMRS in this symbol - txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, upper_limit); - txl += no_ptrs_dmrs_case(output, txl, amp, remaining_re); + txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, sz); } // no DMRS/PTRS in symbol return txl - txl_start; } @@ -477,30 +461,13 @@ static inline void do_txdataF(c16_t **txdataF, const int rb_step = rb_step0==2 && pmi3==pmi && pmi4==pmi ? 4 : rb_step0; const int re_cnt = NR_NB_SC_PER_RB * rb_step; if (pmi == 0) { // unitary Precoding - if (subCarrier + re_cnt <= symbol_sz) { // RB does not cross DC - if (ant < rel15->nrOfLayers) - memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], - &txdataF_precoding[ant][subCarrier], - re_cnt * sizeof(**txdataF)); - else - memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, re_cnt * sizeof(**txdataF)); - } else { // RB does cross DC - const int neg_length = symbol_sz - subCarrier; - const int pos_length = re_cnt - neg_length; - if (ant < rel15->nrOfLayers) { - memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], - &txdataF_precoding[ant][subCarrier], - neg_length * sizeof(**txdataF)); - memcpy(&txdataF[ant][txdataF_offset_per_symbol], &txdataF_precoding[ant], pos_length * sizeof(**txdataF)); - } else { - memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, neg_length * sizeof(**txdataF)); - memset(&txdataF[ant][txdataF_offset_per_symbol], 0, pos_length * sizeof(**txdataF)); - } - } + if (ant < rel15->nrOfLayers) + memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], + &txdataF_precoding[ant][subCarrier], + re_cnt * sizeof(**txdataF)); + else + memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, re_cnt * sizeof(**txdataF)); subCarrier += re_cnt; - if (subCarrier >= symbol_sz) { - subCarrier -= symbol_sz; - } } else { // non-unitary Precoding AssertFatal(frame_parms->nb_antennas_tx > 1, "No precoding can be done with a single antenna port\n"); // get the precoding matrix weights: @@ -514,38 +481,21 @@ static inline void do_txdataF(c16_t **txdataF, "Number of layers %d doesn't match to the one in precoding matrix %d\n", rel15->nrOfLayers, pmi_pdu->numLayers); - if ((subCarrier + re_cnt) < symbol_sz) { // within ofdm_symbol_size, use SIMDe - nr_layer_precoder_simd(rel15->nrOfLayers, - symbol_sz, - txdataF_precoding, - ant, - pmi_pdu, - subCarrier, - re_cnt, - &txdataF[ant][txdataF_offset_per_symbol]); - subCarrier += re_cnt; - } else { // crossing ofdm_symbol_size, use simple arithmetic operations - for (int i = 0; i < re_cnt; i++) { - txdataF[ant][txdataF_offset_per_symbol + subCarrier] = - nr_layer_precoder_cm(rel15->nrOfLayers, symbol_sz, txdataF_precoding, ant, pmi_pdu, subCarrier); -#ifdef DEBUG_DLSCH_MAPPING - printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n", - ant, - l_symbol, - subCarrier, - txdataF[ant][l_symbol * symbol_sz + subCarrier + txdataF_offset].r, - txdataF[ant][l_symbol * symbol_sz + subCarrier + txdataF_offset].i); -#endif - if (++subCarrier >= symbol_sz) { - subCarrier -= symbol_sz; - } - } - } // else{ // crossing ofdm_symbol_size, use simple arithmetic operations + nr_layer_precoder_simd(rel15->nrOfLayers, + symbol_sz, + txdataF_precoding, + ant, + pmi_pdu, + subCarrier, + re_cnt, + &txdataF[ant][txdataF_offset_per_symbol]); + subCarrier += re_cnt; } // else { // non-unitary Precoding rb += rb_step; } // RB loop: while(rb < rel15->rbSize) } + static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch, int slot) { const int16_t amp = gNB->TX_AMP; @@ -641,9 +591,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC start_meas(&gNB->dlsch_pdsch_generation_stats); /// Resource mapping // Non interleaved VRB to PRB mapping - uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB; - if (start_sc >= symbol_sz) - start_sc -= symbol_sz; + uint16_t start_sc = (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB; #ifdef DEBUG_DLSCH_MAPPING printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n", diff --git a/openair1/PHY/NR_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_TRANSPORT/nr_pbch.c index 159e040d11..4acda03b91 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pbch.c @@ -71,7 +71,7 @@ void nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, /// Resource mapping // PBCH DMRS are mapped within the SSB block on every fourth subcarrier starting from nushift of symbols 1, 2, 3 ///symbol 1 [0+nushift:4:236+nushift] -- 60 mod symbols - k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier + nushift; + k = frame_parms->ssb_start_subcarrier + nushift; l = ssb_start_symbol + 1; for (int m = 0; m < 60; m++) { @@ -80,13 +80,10 @@ void nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, #endif txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dmrs[m], amp, 15); k+=4; - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } ///symbol 2 [0+u:4:44+nushift ; 192+nu:4:236+nushift] -- 24 mod symbols - k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier + nushift; + k = frame_parms->ssb_start_subcarrier + nushift; l++; for (int m = 60; m < 84; m++) { @@ -100,13 +97,10 @@ void nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1)+1]); #endif k+=(m==71)?148:4; // Jump from 44+nu to 192+nu - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } ///symbol 3 [0+nushift:4:236+nushift] -- 60 mod symbols - k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier + nushift; + k = frame_parms->ssb_start_subcarrier + nushift; l++; for (int m = 84; m < NR_PBCH_DMRS_LENGTH; m++) { @@ -115,9 +109,6 @@ void nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, #endif txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dmrs[m], amp, 15); k+=4; - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } #ifdef DEBUG_PBCH_DMRS @@ -334,7 +325,7 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, nushift = config->cell_config.phy_cell_id.value &3; // PBCH modulated symbols are mapped within the SSB block on symbols 1, 2, 3 excluding the subcarriers used for the PBCH DMRS ///symbol 1 [0:239] -- 180 mod symbols - int k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + int k = frame_parms->ssb_start_subcarrier; int l = ssb_start_symbol + 1; int m = 0; int16_t amp = gNB->TX_AMP; @@ -351,13 +342,10 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, k++; m++; } - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } ///symbol 2 [0:47 ; 192:239] -- 72 mod symbols - k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + k = frame_parms->ssb_start_subcarrier; l++; m=180; @@ -373,16 +361,10 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, k++; m++; } - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } k += 144; - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; - m=216; for (int ssb_sc_idx = 192; ssb_sc_idx < 240; ssb_sc_idx++) { @@ -397,13 +379,10 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, k++; m++; } - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } ///symbol 3 [0:239] -- 180 mod symbols - k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + k = frame_parms->ssb_start_subcarrier; l++; m=252; @@ -419,9 +398,5 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, k++; m++; } - - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prs.c b/openair1/PHY/NR_TRANSPORT/nr_prs.c index 207a94447d..87edffdc7d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prs.c @@ -51,9 +51,9 @@ int nr_generate_prs(int slot, c16_t *txdataF, int16_t amp, prs_config_t *prs_cfg else if (prs_cfg->CombSize == 12){ k_prime = k_prime_table[3][symInd]; } - - k = (prs_cfg->REOffset+k_prime) % prs_cfg->CombSize + prs_cfg->RBOffset*12 + frame_parms->first_carrier_offset; - + + k = (prs_cfg->REOffset + k_prime) % prs_cfg->CombSize + prs_cfg->RBOffset * 12; + // QPSK modulation uint32_t *gold = nr_gold_prs(prs_cfg->NPRSID, slot, l); for (int m = 0; m < (12/prs_cfg->CombSize) * prs_cfg->NumRB; m++) { @@ -66,10 +66,7 @@ int nr_generate_prs(int slot, c16_t *txdataF, int16_t amp, prs_config_t *prs_cfg txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_prs[m], amp, 15); k = k + prs_cfg->CombSize; - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; - } + } } #ifdef DEBUG_PRS_MAP LOG_M("nr_prs.m", "prs",(int16_t *)&txdataF[prs_cfg->SymbolStart*frame_parms->ofdm_symbol_size],prs_cfg->NumPRSSymbols*frame_parms->ofdm_symbol_size, 1, 1); diff --git a/openair1/PHY/NR_TRANSPORT/nr_pss.c b/openair1/PHY/NR_TRANSPORT/nr_pss.c index 965ac51c21..6b219dba90 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pss.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pss.c @@ -49,8 +49,7 @@ int nr_generate_pss( c16_t *txdataF, /// Resource mapping // PSS occupies a predefined position (subcarriers 56-182, symbol 0) within the SSB block starting from - int k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier + 56; //and - if (k>= frame_parms->ofdm_symbol_size) k-=frame_parms->ofdm_symbol_size; + int k = frame_parms->ssb_start_subcarrier + 56; int l = ssb_start_symbol; @@ -61,9 +60,6 @@ int nr_generate_pss( c16_t *txdataF, // printf("pss: writing position k %d / %d\n",k,frame_parms->ofdm_symbol_size); ((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_pss) >> 15; k++; - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } #ifdef NR_PSS_DEBUG diff --git a/openair1/PHY/NR_TRANSPORT/nr_sss.c b/openair1/PHY/NR_TRANSPORT/nr_sss.c index 45835f8206..71bae9a065 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_sss.c +++ b/openair1/PHY/NR_TRANSPORT/nr_sss.c @@ -59,16 +59,13 @@ int nr_generate_sss( c16_t *txdataF, /// Resource mapping // SSS occupies a predefined position (subcarriers 56-182, symbol 2) within the SSB block starting from - int k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier + 56; //and + int k = frame_parms->ssb_start_subcarrier + 56; int l = ssb_start_symbol + 2; for (int i = 0; i < NR_SSS_LENGTH; i++) { int16_t d_sss = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 23170; ((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_sss) >> 15; k++; - - if (k >= frame_parms->ofdm_symbol_size) - k-=frame_parms->ofdm_symbol_size; } #ifdef NR_SSS_DEBUG // write_output("sss_0.m", "sss_0", (void*)txdataF[0][l*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 881ce016bc..e24166a5b6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -1619,7 +1619,14 @@ uint8_t nr_tx_rotation_and_ofdm_mod(const uint8_t slot, if (was_symbol_used[i] == false) continue; for (int ap = 0; ap < n_antenna_ports; ap++) { - apply_nr_rotation_TX(frame_parms, txdataF[ap], frame_parms->symbol_rotation[linktype], slot, N_RB, i, 1); + apply_nr_rotation_TX(frame_parms, + txdataF[ap], + false, + frame_parms->symbol_rotation[linktype], + slot, + N_RB, + i, + 1); } } } diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common_csirs.c b/openair1/PHY/nr_phy_common/src/nr_phy_common_csirs.c index 7cc14b385f..a0db67e50d 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common_csirs.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_csirs.c @@ -25,7 +25,6 @@ static void csi_rs_resource_mapping(c16_t **dataF, int csi_rs_length, int16_t mod_csi[][csi_rs_length >> 1], int ofdm_symbol_size, - int start_sc, const csi_mapping_parms_t *mapping_parms, int start_rb, int nb_rbs, @@ -43,7 +42,7 @@ static void csi_rs_resource_mapping(c16_t **dataF, int p = s + mapping_parms->j[ji] * gs; // port index for (int kp = 0; kp <= mapping_parms->kprime; kp++) { // loop over frequency resource elements within a group // frequency index of current resource element - int k = (start_sc + (n * NR_NB_SC_PER_RB) + mapping_parms->koverline[ji] + kp) % (ofdm_symbol_size); + int k = ((n * NR_NB_SC_PER_RB) + mapping_parms->koverline[ji] + kp); // wf according to tables 7.4.5.3-2 to 7.4.5.3-5 int wf = kp == 0 ? 1 : (-2 * (s % 2) + 1); int na = n * alpha; @@ -625,7 +624,6 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, frame_parms->N_RB_DL << 4, mod_csi, frame_parms->ofdm_symbol_size, - frame_parms->first_carrier_offset, phy_csi_parms, start_rb, nr_of_rbs, diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 01b6fe7389..20ca99f0c4 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -217,8 +217,6 @@ void nr_feptx(void *arg) int startSymbol = feptx->startSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int numSymbols = feptx->numSymbols; - int numSamples = feptx->numSymbols * fp->ofdm_symbol_size; - int txdataF_offset = startSymbol * fp->ofdm_symbol_size; int tx_idx = aa + bb * ru->nb_tx; @@ -232,11 +230,17 @@ void nr_feptx(void *arg) } // If there is no digital beamforming we just need to copy the data to RU - if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) - memcpy((void *)&ru->common.txdataF_BF[tx_idx][txdataF_offset], - (void *)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset], - numSamples * sizeof(int32_t)); - else { + if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) { + // FFT shift + const NR_DL_FRAME_PARMS *fp = &ru->gNB_list[0]->frame_parms; + fft_shift(ru->gNB_list[0]->common_vars.txdataF[bb][aa], + fp->ofdm_symbol_size, + fp->N_RB_DL, + (c16_t *)ru->common.txdataF_BF[tx_idx], + fp->ofdm_symbol_size, + startSymbol, + numSymbols); + } else { AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 80f96e1f43..629d9cc406 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -320,6 +320,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, if (gNB->phase_comp) { apply_nr_rotation_TX(fp, gNB->common_vars.txdataF[i][aa], + true, fp->symbol_rotation[0], slot, fp->N_RB_DL, diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index aa9ebccde8..2cdaa4143e 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1141,9 +1141,17 @@ int main(int argc, char **argv) //TODO: loop over slots for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { - + c16_t fft_in_buff[frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot] __attribute__((aligned(64))); + memset(fft_in_buff, 0, sizeof(fft_in_buff)); if (cyclic_prefix_type == 1) { - PHY_ofdm_mod((int *)gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[0][aa], + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + fft_in_buff, + frame_parms->ofdm_symbol_size, + 0, + 12); + PHY_ofdm_mod((int *)fft_in_buff, (int *)&txdata[aa][slot_offset], frame_parms->ofdm_symbol_size, 12, @@ -1154,7 +1162,14 @@ int main(int argc, char **argv) for (int i = 0; i < 14; i++) { was_symbol_used[i] = true; } - nr_normal_prefix_mod(gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[0][aa], + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + fft_in_buff, + frame_parms->ofdm_symbol_size, + 0, + 14); + nr_normal_prefix_mod(fft_in_buff, &txdata[aa][slot_offset], 14, frame_parms, diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index cad3012400..a828db184d 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -525,17 +525,28 @@ int main(int argc, char **argv) nr_common_signal_procedures (gNB,frame,slot, &ssb_pdu[i]); int samp = get_samples_slot_timestamp(frame_parms, slot); - for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { + for (aa = 0; aa < gNB->frame_parms.nb_antennas_tx; aa++) { + c16_t fft_in_buff[frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot] __attribute__((aligned(64))); + memset(fft_in_buff, 0, sizeof(fft_in_buff)); if (cyclic_prefix_type == 1) { apply_nr_rotation_TX(frame_parms, gNB->common_vars.txdataF[0][aa], + true, frame_parms->symbol_rotation[0], slot, frame_parms->N_RB_DL, 0, 12); - PHY_ofdm_mod((int *)gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[0][aa], + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + fft_in_buff, + frame_parms->ofdm_symbol_size, + 0, + 12); + + PHY_ofdm_mod((int *)fft_in_buff, (int *)&txdata[aa][samp], frame_parms->ofdm_symbol_size, 12, @@ -544,21 +555,30 @@ int main(int argc, char **argv) } else { apply_nr_rotation_TX(frame_parms, gNB->common_vars.txdataF[0][aa], + true, frame_parms->symbol_rotation[0], slot, frame_parms->N_RB_DL, 0, 14); - PHY_ofdm_mod((int *)gNB->common_vars.txdataF[0][aa], - (int*)&txdata[aa][samp], + fft_shift(gNB->common_vars.txdataF[0][aa], + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + fft_in_buff, + frame_parms->ofdm_symbol_size, + 0, + 14); + + PHY_ofdm_mod((int *)fft_in_buff, + (int *)&txdata[aa][samp], frame_parms->ofdm_symbol_size, 1, frame_parms->nb_prefix_samples0, CYCLIC_PREFIX); - PHY_ofdm_mod((int *)&gNB->common_vars.txdataF[0][aa][frame_parms->ofdm_symbol_size], - (int*)&txdata[aa][samp + frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size], + PHY_ofdm_mod((int *)fft_in_buff + frame_parms->ofdm_symbol_size, + (int *)&txdata[aa][samp + frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 13, frame_parms->nb_prefix_samples, diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 7f858219ac..d7b39b307b 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -612,21 +612,6 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) int num_totalRB = p_prbMapElm->nRBSize; int start_totalRB = p_prbMapElm->nRBStart; - int pos_len = 0; - int neg_len = 0; - - if (start_totalRB < (num_totalRB >> 1)) // there are PRBs left of DC - neg_len = min((num_totalRB * 6) - (start_totalRB * 12), num_totalRB * N_SC_PER_PRB); - pos_len = (num_totalRB * N_SC_PER_PRB) - neg_len; - // Calculation of the pointer for the section in the buffer. - // start of positive frequency component - uint16_t *src1 = (uint16_t *)&pos[(neg_len == 0) ? ((start_totalRB * N_SC_PER_PRB) - (num_totalRB * 6)) : 0]; - // start of negative frequency component - uint16_t *src2 = (uint16_t *)&pos[(start_totalRB * N_SC_PER_PRB) + fftsize - (num_totalRB * 6)]; - - uint32_t local_src[num_totalRB * N_SC_PER_PRB] __attribute__((aligned(64))); - memcpy((void *)local_src, (void *)src2, neg_len * 4); - memcpy((void *)&local_src[neg_len], (void *)src1, pos_len * 4); if (ptr && pos) { u8dptr = (uint8_t *)ptr; int16_t payload_len = 0; @@ -662,26 +647,33 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) } uint16_t *dst16 = (uint16_t *)dst; + // Start of this section + int32_t *pos_start = pos + (start_totalRB + startRB) * N_SC_PER_PRB; + if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_NONE) { payload_len = numRB * N_SC_PER_PRB * 4L; /* convert to Network order */ // NOTE: ggc 11 knows how to generate AVX2 for this! for (idx = 0; idx < (numRB * N_SC_PER_PRB) * 2; idx++) - ((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx + startRB * N_SC_PER_PRB * 2]); + ((uint16_t *)dst16)[idx] = htons(((uint16_t *)pos_start)[idx]); } else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { payload_len = (3 * p_prbMapElm->iqWidth + 1) * numRB; + /* Although arm intrinsics natively handle unaligned memory + access, we use a 64 byte aligned input here for maximum + performance. So the src_compr buffer is used for both x86 and arm. + */ + uint32_t src_compr[num_totalRB * N_SC_PER_PRB] __attribute__((aligned(64))); + + /* Copy from txdataF with current symbol's PRB start (nRBStart) + + current section's PRB start (UP_nPRBStart) */ + memcpy(src_compr, pos_start, (numRB * N_SC_PER_PRB) * sizeof(*pos_start)); + #if defined(__i386__) || defined(__x86_64__) struct xranlib_compress_request bfp_com_req = {}; struct xranlib_compress_response bfp_com_rsp = {}; - uint32_t src_compr[num_totalRB * N_SC_PER_PRB] __attribute__((aligned(64))); - if (numRB == num_totalRB) { - bfp_com_req.data_in = (int16_t *)local_src; - } else { - memcpy(src_compr, local_src + (startRB * N_SC_PER_PRB), (numRB * N_SC_PER_PRB) * sizeof(*local_src)); - bfp_com_req.data_in = (int16_t *)src_compr; - } + bfp_com_req.data_in = (int16_t *)src_compr; bfp_com_req.numRBs = numRB; bfp_com_req.len = payload_len; @@ -693,7 +685,7 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp); #elif defined(__arm__) || defined(__aarch64__) - armral_bfp_compression(p_prbMapElm->iqWidth, numRB, (int16_t *)(local_src + startRB * N_SC_PER_PRB), (int8_t *)dst); + armral_bfp_compression(p_prbMapElm->iqWidth, numRB, (int16_t *)src_compr, (int8_t *)dst); #else AssertFatal(1 == 0, "BFP compression not supported on this architecture"); #endif @@ -950,7 +942,6 @@ int xran_fh_tx_send_slot_BySymbol(ru_info_t *ru, int frame, int slot, uint64_t t const struct xran_fh_init *fh_init = get_xran_fh_init(); const struct xran_fh_config *fh_cfg = get_xran_fh_config(0); - int nPRBs = fh_cfg->nDLRBs; int fftsize = 1 << fh_cfg->nDLFftSize; int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports; int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; @@ -1105,36 +1096,32 @@ int xran_fh_tx_send_slot_BySymbol(ru_info_t *ru, int frame, int slot, uint64_t t } uint16_t *dst16 = (uint16_t *)dst; - int pos_len = 0; - int neg_len = 0; - - if (p_prbMapElm->UP_nRBStart < (nPRBs >> 1)) // there are PRBs left of DC - neg_len = min((nPRBs * 6) - (p_prbMapElm->UP_nRBStart * 12), p_prbMapElm->UP_nRBSize * N_SC_PER_PRB); - pos_len = (p_prbMapElm->UP_nRBSize * N_SC_PER_PRB) - neg_len; - // Calculation of the pointer for the section in the buffer. - // start of positive frequency component - uint16_t *src1 = (uint16_t *)&pos[(neg_len == 0) ? ((p_prbMapElm->UP_nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0]; - // start of negative frequency component - uint16_t *src2 = (uint16_t *)&pos[(p_prbMapElm->UP_nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6)]; - - uint32_t local_src[p_prbMapElm->UP_nRBSize * N_SC_PER_PRB] __attribute__((aligned(64))); - memcpy((void *)local_src, (void *)src2, neg_len * 4); - memcpy((void *)&local_src[neg_len], (void *)src1, pos_len * 4); + int32_t *pos_start = pos + p_prbMapElm->UP_nRBStart * N_SC_PER_PRB; + uint32_t numPrb = p_prbMapElm->UP_nRBSize; if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_NONE) { - payload_len = p_prbMapElm->UP_nRBSize * N_SC_PER_PRB * 4L; + payload_len = numPrb * N_SC_PER_PRB * 4L; /* convert to Network order */ // NOTE: ggc 11 knows how to generate AVX2 for this! - for (idx = 0; idx < (pos_len + neg_len) * 2; idx++) - ((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]); + for (idx = 0; idx < numPrb * N_SC_PER_PRB * 2; idx++) + ((uint16_t *)dst16)[idx] = htons(((uint16_t *)pos_start)[idx]); } else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { - payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->UP_nRBSize; + payload_len = (3 * p_prbMapElm->iqWidth + 1) * numPrb; + /* Although arm intrinsics natively handle unaligned memory + access, we use a 64 byte aligned input here for maximum + performance. So the src_compr buffer is used for both x86 and arm. + */ + uint32_t src_compr[numPrb * N_SC_PER_PRB] __attribute__((aligned(64))); + + /* Copy from txdataF with current symbol's PRB start (nRBStart) + + current section's PRB start (UP_nPRBStart) */ + memcpy(src_compr, pos_start, (numPrb * N_SC_PER_PRB) * sizeof(*pos_start)); #if defined(__i386__) || defined(__x86_64__) struct xranlib_compress_request bfp_com_req = {}; struct xranlib_compress_response bfp_com_rsp = {}; - bfp_com_req.data_in = (int16_t *)local_src; - bfp_com_req.numRBs = p_prbMapElm->UP_nRBSize; + bfp_com_req.data_in = (int16_t *)src_compr; + bfp_com_req.numRBs = numPrb; bfp_com_req.len = payload_len; bfp_com_req.compMethod = p_prbMapElm->compMethod; bfp_com_req.iqWidth = p_prbMapElm->iqWidth; @@ -1144,7 +1131,7 @@ int xran_fh_tx_send_slot_BySymbol(ru_info_t *ru, int frame, int slot, uint64_t t xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp); #elif defined(__arm__) || defined(__aarch64__) - armral_bfp_compression(p_prbMapElm->iqWidth, p_prbMapElm->UP_nRBSize, (int16_t *)local_src, (int8_t *)dst); + armral_bfp_compression(p_prbMapElm->iqWidth, numPrb, (int16_t *)src_compr, (int8_t *)dst); #else AssertFatal(1 == 0, "BFP compression not supported on this architecture"); #endif