diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index fc113ffa46..948c9f8301 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -16,7 +16,7 @@ add_subdirectory(nr) add_subdirectory(LOG) add_subdirectory(threadPool) add_subdirectory(time_manager) -add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c reverse_bits.c fsn.c) +add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c bits.c fsn.c) target_include_directories(utils PUBLIC .) target_link_libraries(utils PRIVATE ${T_LIB}) add_subdirectory(barrier) diff --git a/common/utils/reverse_bits.c b/common/utils/bits.c similarity index 99% rename from common/utils/reverse_bits.c rename to common/utils/bits.c index 7fc1d27254..d329660821 100644 --- a/common/utils/reverse_bits.c +++ b/common/utils/bits.c @@ -2,7 +2,7 @@ * SPDX-License-Identifier: LicenseRef-CSSL-1.0 */ -#include "reverse_bits.h" +#include "bits.h" // we avoid assertions.h as it necessitates othe dependencies (e.g., exit_function) #include #include diff --git a/common/utils/bits.h b/common/utils/bits.h new file mode 100644 index 0000000000..88ca05edd2 --- /dev/null +++ b/common/utils/bits.h @@ -0,0 +1,76 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#ifndef BITS_H_ +#define BITS_H_ + +#include +#include +#include +#include "assertions.h" + +uint64_t reverse_bits(uint64_t in, int n_bits); +void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out); + +static inline int get_last_bit_index(const uint32_t *arr, int sz) +{ + AssertFatal(sz > 0, "Invalid size %d to get the first bit of array\n", sz); + for (int i = sz - 1; i >= 0; i--) { + if (arr[i] != 0) { + // 31 - clz gives the index of the highest bit (0-31) + return (i * 32) + (31 - __builtin_clz(arr[i])); + } + } + return -1; +} + +static uint32_t bit_mask(int from_bit, int num_bits) +{ + int total = from_bit + num_bits; + uint32_t right_mask = total < 32 ? (0xFFFFFFFF >> (32 - total)) : 0xFFFFFFFF; + return (0xFFFFFFFF << from_bit) & right_mask; +} + +static inline int get_first_bit_index_mask(const uint32_t *arr, int sz, int from_bit, int num_bits) +{ + // start i from first_bit + int i = from_bit / 32; + from_bit %= 32; + for (; i < sz && num_bits > 0; i++) { + uint32_t a = arr[i] & bit_mask(from_bit, num_bits); + if (a != 0) { + // Find the first set bit in this 32-bit word + return (i * 32) + __builtin_ctz(a); + } + num_bits -= 32 - from_bit; + from_bit = 0; + } + return -1; +} + +static inline int get_first_bit_index(const uint32_t *arr, int sz) +{ + return get_first_bit_index_mask(arr, sz, 0, sz * 32); +} + +static inline int count_bits(const uint32_t *arr, int sz) +{ + int ret = 0; + // sz is the number of uint32_t elements + for (int i = 0; i < sz; i++) + ret += __builtin_popcount(arr[i]); + return ret; +} + +static __attribute__((always_inline)) inline int count_bits64(uint64_t v) +{ + return __builtin_popcountll(v); +} + +static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t v, int start, int num) +{ + uint64_t mask = ((1LL << num) - 1) << start; + return count_bits64(v & mask); +} +#endif /* BITS_H_ */ diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 228e51feb2..078da2158c 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -262,28 +262,7 @@ static inline int get_num_dmrs(uint16_t dmrs_mask ) return(num_dmrs); } -static inline int count_bits(uint8_t *arr, int sz) -{ - AssertFatal(sz % sizeof(int) == 0, "to implement if needed\n"); - int ret = 0; - for (uint *ptr = (uint *)arr; (uint8_t *)ptr < arr + sz; ptr++) - ret += __builtin_popcount(*ptr); - return ret; -} - -static __attribute__((always_inline)) inline int count_bits64(uint64_t v) -{ - return __builtin_popcountll(v); -} - -static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t v, int start, int num) -{ - uint64_t mask = ((1LL << num) - 1) << start; - return count_bits64(v & mask); -} - void warn_higher_threequarter_fs(const int n_rb, const int mu); - uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t dl_nrarfcn); uint32_t to_nrarfcn(uint64_t dl_CarrierFreq); uint8_t set_ssb_case(int scs, int nr_band); diff --git a/common/utils/reverse_bits.h b/common/utils/reverse_bits.h deleted file mode 100644 index 697ed61052..0000000000 --- a/common/utils/reverse_bits.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: LicenseRef-CSSL-1.0 - */ - -#ifndef REVERSE_BITS_H_ -#define REVERSE_BITS_H_ - -#include -#include - -uint64_t reverse_bits(uint64_t in, int n_bits); -void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out); - -#endif /* REVERSE_BITS_H_ */ diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c index 534d103929..e4ceb359c1 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c @@ -5,7 +5,7 @@ #include "../nrLDPC_coding_interface.h" #include "nrLDPC_coding_aal.h" #include "PHY/sse_intrin.h" -#include "reverse_bits.h" +#include "bits.h" #include #include "common/config/config_paramdesc.h" #include "common/config/config_userapi.h" diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c index 9379a507e2..4db0e876b9 100644 --- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c +++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c @@ -3,7 +3,7 @@ */ #include "PHY/CODING/nrPolar_tools/nr_polar_defs.h" -#include "reverse_bits.h" +#include "bits.h" #include #include #include diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c index 0e8246cce1..2f04026a70 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -17,6 +17,7 @@ #include "PHY/NR_REFSIG/dmrs_nr.h" #include "log.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" +#include "bits.h" uint8_t allowed_xlsch_re_in_dmrs_symbol(uint16_t k, uint16_t start_sc, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 8f1bb827be..7edf19dec5 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -25,8 +25,13 @@ static void nr_pdsch_codeword_scrambling(uint8_t *in, uint32_t size, uint8_t q, nr_codeword_scrambling(in, size, q, Nid, n_RNTI, out); } +static uint32_t get_block_start_sc(int block_start, int bwp_start, int symbol_sz) +{ + return (block_start + bwp_start) * NR_NB_SC_PER_RB; +} + static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, - int start_sc, + const freq_alloc_bitmap_t *freq_alloc, int symbol_sz, c16_t *txF, c16_t *tx_layer, @@ -34,21 +39,30 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, c16_t *mod_ptrs) { int ptrs_idx = 0; - int k = start_sc; c16_t *in = tx_layer; - for (int i = 0; i < rel15->rbSize * NR_NB_SC_PER_RB; i++) { - /* check for PTRS symbol and set flag for PTRS RE */ - bool is_ptrs_re = - is_ptrs_subcarrier(k, rel15->rnti, rel15->PTRSFreqDensity, rel15->rbSize, rel15->PTRSReOffset, start_sc, symbol_sz); - if (is_ptrs_re) { - /* check if cuurent RE is PTRS RE*/ - uint16_t beta_ptrs = 1; - txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15); - ptrs_idx++; + int last_rb = freq_alloc->last_rb; + int first_rb = freq_alloc->first_rb; + uint32_t start_sc = get_block_start_sc(freq_alloc->first_rb, rel15->BWPStart, symbol_sz); + int k = start_sc; + for (int j = first_rb; j <= last_rb; j++) { + if (check_rb_in_bitmap(freq_alloc, j)) { + for (int i = 0; i < NR_NB_SC_PER_RB; i++) { + /* check for PTRS symbol and set flag for PTRS RE */ + bool is_ptrs_re = + is_ptrs_subcarrier(k, rel15->rnti, rel15->PTRSFreqDensity, freq_alloc->num_rbs, rel15->PTRSReOffset, start_sc, symbol_sz); + if (is_ptrs_re) { + /* check if cuurent RE is PTRS RE*/ + uint16_t beta_ptrs = 1; + txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15); + ptrs_idx++; + } else { + txF[k] = c16mulRealShift(*in++, amp, 15); + } + k++; + } } else { - txF[k] = c16mulRealShift(*in++, amp, 15); + k += NR_NB_SC_PER_RB; } - k++; } return in - tx_layer; } @@ -210,15 +224,14 @@ static inline int interleave_signals(c16_t *output, c16_t *signal1, const int am static inline int dmrs_case00(c16_t *output, c16_t *txl, c16_t *mod_dmrs, + const freq_alloc_bitmap_t *freq_alloc, const int16_t amp_dmrs, const int amp, - int sz, - int start_sc, int dmrs_port, const int dmrs_Type, int symbol_sz, int l_prime, - uint8_t numDmrsCdmGrpsNoData) + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15) { // DMRS params for this dmrs port int Wt[2], Wf[2]; @@ -226,27 +239,37 @@ static inline int dmrs_case00(c16_t *output, get_Wf(Wf, dmrs_port, dmrs_Type); const int8_t delta = get_delta(dmrs_port, dmrs_Type); int dmrs_idx = 0; + uint32_t start_sc = get_block_start_sc(freq_alloc->first_rb, rel15->BWPStart, symbol_sz); int k = start_sc; c16_t *in = txl; uint8_t k_prime = 0; uint16_t n = 0; - for (int i = 0; i < sz; i++) { - if (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (symbol_sz))) { - output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15); - dmrs_idx++; - k_prime = (k_prime + 1) & 1; - n += (k_prime ? 0 : 1); + int pos = freq_alloc->first_rb; + int last_processed_rb = freq_alloc->first_rb; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) { + // Mute skipped RBs + int skipped_sc = (block_start - last_processed_rb) * NR_NB_SC_PER_RB; + memset(output + k, 0, skipped_sc * sizeof(c16_t)); + k += skipped_sc; + for (int j = block_start; j <= block_end; j++) { + for (int i = 0; i < NR_NB_SC_PER_RB; i++) { + if (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (symbol_sz))) { + output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15); + dmrs_idx++; + k_prime = (k_prime + 1) & 1; + n += (k_prime ? 0 : 1); + } else if (allowed_xlsch_re_in_dmrs_symbol(k, start_sc, symbol_sz, rel15->numDmrsCdmGrpsNoData, dmrs_Type)) { + /* Map PTRS Symbol */ + /* Map DATA Symbol */ + output[k] = c16mulRealShift(*in++, amp, 15); + } else { + output[k] = (c16_t){0}; + } + k++; + } } - /* Map PTRS Symbol */ - /* Map DATA Symbol */ - else if (allowed_xlsch_re_in_dmrs_symbol(k, start_sc, symbol_sz, numDmrsCdmGrpsNoData, dmrs_Type)) { - output[k] = c16mulRealShift(*in++, amp, 15); - } - /* mute RE */ - else { - output[k] = (c16_t){0}; - } - k++; + last_processed_rb = block_end + 1; } // RE loop return in - txl; } @@ -291,10 +314,10 @@ static inline void neg_dmrs(c16_t *in, c16_t *out, int sz) static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms, int slot, const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, + const freq_alloc_bitmap_t *freq_alloc, int layer, c16_t *output, c16_t *txl_start, - int start_sc, int symbol_sz, int l_symbol, uint16_t dlPtrsSymPos, @@ -306,7 +329,6 @@ static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms, c16_t *dmrs_start) { c16_t *txl = txl_start; - const uint sz = rel15->rbSize * NR_NB_SC_PER_RB; /* calculate if current symbol is PTRS symbols */ int ptrs_symbol = 0; @@ -322,68 +344,83 @@ static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms, const uint32_t *gold = nr_gold_pdsch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol); nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs); - txl += do_ptrs_symbol(rel15, start_sc, symbol_sz, output, txl, amp, mod_ptrs); + txl += do_ptrs_symbol(rel15, freq_alloc, symbol_sz, output, txl, amp, mod_ptrs); } else if (rel15->dlDmrsSymbPos & (1 << l_symbol)) { /* Map DMRS Symbol */ int dmrs_port = get_dmrs_port(layer, rel15->dmrsPorts); if (l_prime == 0 && dmrs_Type == NFAPI_NR_DMRS_TYPE1) { - if (rel15->numDmrsCdmGrpsNoData == 2) { - switch (dmrs_port & 3) { - case 0: - 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, sz); - } break; - case 2: - 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, 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, 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, sz); - } break; - case 2: - 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, sz); - } break; - } - } else - AssertFatal(false, "rel15->numDmrsCdmGrpsNoData is %d\n", rel15->numDmrsCdmGrpsNoData); + int pos = 0; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) { + int start_rb = block_start; + int nb_rb = block_end - block_start + 1; + int start_sc = get_block_start_sc(start_rb, rel15->BWPStart, symbol_sz); + const int sz = nb_rb * NR_NB_SC_PER_RB; + if (rel15->numDmrsCdmGrpsNoData == 2) { + switch (dmrs_port & 3) { + case 0: + 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, sz); + } break; + case 2: + 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, 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, 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, sz); + } break; + case 2: + 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, sz); + } break; + } + } else + AssertFatal(false, "rel15->numDmrsCdmGrpsNoData is %d\n", rel15->numDmrsCdmGrpsNoData); + } } else { txl += dmrs_case00(output, txl, dmrs_start, + freq_alloc, amp_dmrs, amp, - sz, - start_sc, dmrs_port, dmrs_Type, symbol_sz, l_prime, - rel15->numDmrsCdmGrpsNoData); + rel15); } // generic DMRS case } else { // no PTRS or DMRS in this symbol - txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, sz); + int pos = 0; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) { + int start_rb = block_start; + int nb_rb = block_end - block_start + 1; + int start_sc = get_block_start_sc(start_rb, rel15->BWPStart, symbol_sz); + const int sz = nb_rb * NR_NB_SC_PER_RB; + txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, sz); + } } // no DMRS/PTRS in symbol return; } @@ -394,24 +431,25 @@ static inline void do_txdataF(c16_t **txdataF, PHY_VARS_gNB *gNB, const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, int ant, - int start_sc, + int rb_start, + int rb_size, int txdataF_offset_per_symbol) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int rb = 0; - uint16_t subCarrier = start_sc; + uint16_t subCarrier = get_block_start_sc(rb_start, rel15->BWPStart, symbol_sz); const nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; - while (rb < rel15->rbSize) { + while (rb < rb_size) { // get pmi info const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0; - const int pmi2 = (rb < (rel15->rbSize - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 1) / pb->prg_size].pm_idx) : -1; - const int pmi3 = (rb < (rel15->rbSize - 2) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 2) / pb->prg_size].pm_idx) : -1; - const int pmi4 = (rb < (rel15->rbSize - 3) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 3) / pb->prg_size].pm_idx) : -1; + const int pmi2 = (rb < (rb_size - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 1) / pb->prg_size].pm_idx) : -1; + const int pmi3 = (rb < (rb_size - 2) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 2) / pb->prg_size].pm_idx) : -1; + const int pmi4 = (rb < (rb_size - 3) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 3) / pb->prg_size].pm_idx) : -1; // If pmi of next RB and pmi of current RB are the same, we do 2 RB in a row - // if pmi differs, or current rb is the end (rel15->rbSize - 1), than we do 1 RB in a row + // if pmi differs, or current rb is the end (rb_size - 1), than we do 1 RB in a row int rb_step0 = pmi == pmi2 ? 2 : 1; - const int rb_step = rb_step0==2 && pmi3==pmi && pmi4==pmi ? 4 : rb_step0; + 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 (ant < rel15->nrOfLayers) @@ -446,13 +484,14 @@ static inline void do_txdataF(c16_t **txdataF, } // else { // non-unitary Precoding rb += rb_step; - } // RB loop: while(rb < rel15->rbSize) + } // RB loop: while(rb < rb_size) } typedef struct pdschSymbolProc_s { PHY_VARS_gNB *gNB; NR_DL_FRAME_PARMS *frame_parms; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15; + freq_alloc_bitmap_t *freq_alloc; unsigned int slot; unsigned int startSymbol; unsigned int numSymbols; @@ -478,14 +517,14 @@ static void nr_pdsch_symbol_processing(void *arg) c16_t *tx_layers[rel15->nrOfLayers]; for (int l = 0; l < rel15->nrOfLayers; l++) tx_layers[l] = rdata->tx_layers[l]; + freq_alloc_bitmap_t *freq_alloc = rdata->freq_alloc; const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4); - const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs; + const int n_dmrs = (rel15->BWPStart + freq_alloc->last_rb + 1) * nb_re_dmrs; // Loop Over OFDM symbols: c16_t mod_dmrs[(n_dmrs + 63) & ~63] __attribute__((aligned(64))); const int symbol_sz = frame_parms->ofdm_symbol_size; c16_t **txdataF = gNB->common_vars.txdataF[rdata->beam_nb]; - uint16_t start_sc = (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB; for (int l_symbol = rdata->startSymbol; l_symbol < rdata->startSymbol + rdata->numSymbols; l_symbol++) { start_meas(&rdata->dlsch_resource_mapping_stats); @@ -513,7 +552,7 @@ static void nr_pdsch_symbol_processing(void *arg) nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs); } - uint32_t dmrs_idx = rel15->rbStart; + uint32_t dmrs_idx = freq_alloc->first_rb; if (rel15->refPoint == 0) dmrs_idx += rel15->BWPStart; dmrs_idx *= rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4; @@ -522,10 +561,10 @@ static void nr_pdsch_symbol_processing(void *arg) do_onelayer(frame_parms, slot, rel15, + freq_alloc, layer, txdataF_precoding[layer], tx_layers[layer] + rdata->re_beginning_of_symbol[l_symbol], - start_sc, symbol_sz, l_symbol, rdata->dlPtrsSymPos, @@ -539,9 +578,22 @@ static void nr_pdsch_symbol_processing(void *arg) stop_meas(&rdata->dlsch_resource_mapping_stats); start_meas(&rdata->dlsch_precoding_stats); + const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz; for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) { - const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz; - do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol); + int pos = 0; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) { + do_txdataF(txdataF, + symbol_sz, + txdataF_precoding, + gNB, + rel15, + ant, + block_start, + block_end - block_start + 1, + txdataF_offset_per_symbol); + + } } stop_meas(&rdata->dlsch_precoding_stats); } @@ -555,20 +607,15 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats; time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats; + freq_alloc_bitmap_t *freq_alloc = &dlsch->freq_alloc; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; const int layerSz = frame_parms->N_RB_DL * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB; const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4); - LOG_D(PHY, - "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", - rel15->BWPStart, - rel15->BWPSize, - rel15->rbStart, - rel15->rbSize); - const int n_dmrs = rel15->rbSize * nb_re_dmrs; + const int n_dmrs = freq_alloc->num_rbs * nb_re_dmrs; const int xOverhead = 0; const int nb_re = - (12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * rel15->rbSize * rel15->nrOfLayers; + (12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * freq_alloc->num_rbs * rel15->nrOfLayers; const int Qm = rel15->qamModOrder[0]; const int encoded_length = nb_re * Qm; @@ -581,7 +628,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC rel15->StartSymbolIndex, 1 << rel15->PTRSTimeDensity, rel15->dlDmrsSymbPos); - n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; + n_ptrs = (freq_alloc->num_rbs + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; } #ifdef DEBUG_DLSCH @@ -692,6 +739,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC rdata->gNB = gNB; rdata->frame_parms = frame_parms; + rdata->freq_alloc = freq_alloc; rdata->rel15 = rel15; rdata->slot = slot; rdata->startSymbol = l_symbol; @@ -706,7 +754,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC rdata->beam_nb = beam_nb; for (int s = l_symbol; s < l_symbol + rdata->numSymbols; s++) { rdata->re_beginning_of_symbol[s] = re_beginning_of_symbol; - re_beginning_of_symbol += rel15->rbSize * NR_NB_SC_PER_RB; + re_beginning_of_symbol += freq_alloc->num_rbs * NR_NB_SC_PER_RB; if (n_ptrs > 0 && is_ptrs_symbol(s, dlPtrsSymPos)) { re_beginning_of_symbol -= n_ptrs; } else if (rel15->dlDmrsSymbPos & (1 << s)) { @@ -733,7 +781,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * should remain a multiple of 8 * 64 with enough offset to fit each dlsch */ - uint32_t size_output_tb = rel15->rbSize * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; + uint32_t size_output_tb = freq_alloc->num_rbs * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; return ((size_output_tb + 511) >> 9) << 6; } @@ -754,12 +802,19 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; + if (rel15->resourceAlloc == 0) { + int alloc_size = (rel15->BWPSize / 8) + (rel15->BWPSize % 8 > 0); + dlsch->freq_alloc = set_start_end_from_bitmap(rel15->BWPSize, alloc_size, rel15->rbBitmap); + } else { + dlsch->freq_alloc = set_bitmap_from_start_size(rel15->rbStart, rel15->rbSize); + } LOG_D(PHY, - "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", + "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbEnd %d rbsize %d\n", rel15->BWPStart, rel15->BWPSize, - rel15->rbStart, - rel15->rbSize); + dlsch->freq_alloc.first_rb, + dlsch->freq_alloc.last_rb, + dlsch->freq_alloc.num_rbs); const int Qm = rel15->qamModOrder[0]; @@ -773,7 +828,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr rel15->StartSymbolIndex, 1 << rel15->PTRSTimeDensity, rel15->dlDmrsSymbPos); - n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; + n_ptrs = (dlsch->freq_alloc.num_rbs + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols); } dlsch->unav_res = ptrsSymbPerSlot * n_ptrs; @@ -784,7 +839,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * => size_output is a sum of parts sizes rounded up to a multiple of 8 * 64 */ - size_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; + size_t size_output_tb = dlsch->freq_alloc.num_rbs * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; size_output += ceil_mod(size_output_tb, 8 * 64); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index bf63e1cbce..bfe912dac8 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -209,7 +209,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, } #endif - TB_parameters->nb_rb = rel15->rbSize; + int rbsize = dlsch->freq_alloc.num_rbs; + TB_parameters->nb_rb = rbsize; TB_parameters->Qm = rel15->qamModOrder[0]; TB_parameters->mcs = rel15->mcsIndex[0]; TB_parameters->nb_layers = rel15->nrOfLayers; @@ -217,7 +218,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, int nb_re_dmrs = (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData); - TB_parameters->G = nr_get_G(rel15->rbSize, + TB_parameters->G = nr_get_G(rbsize, rel15->NrOfSymbols, nb_re_dmrs, get_num_dmrs(rel15->dlDmrsSymbPos), @@ -226,7 +227,6 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, rel15->nrOfLayers); TB_parameters->tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; - TB_parameters->output = &output[dlsch_offset >> 3]; TB_parameters->segments = &segments[segments_offset]; @@ -245,7 +245,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * => dlsch_offset should remain a multiple of 8 * 64 with enough offset to fit each dlsch */ - const size_t dlsch_size = rel15->rbSize * gNB->frame_parms.symbols_per_slot * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers; + const size_t dlsch_size = rbsize * gNB->frame_parms.symbols_per_slot * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers; dlsch_offset += ceil_mod(dlsch_size, 8 * 64); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_TRANSPORT/nr_pbch.c index 70d43ed8aa..ccc4eb0405 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pbch.c @@ -10,7 +10,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/sse_intrin.h" #include "executables/softmodem-common.h" -#include "reverse_bits.h" +#include "bits.h" #include "openair1/PHY/NR_REFSIG/nr_refsig.h" #include "openair1/PHY/NR_REFSIG/nr_mod_table.h" #include "openair1/PHY/TOOLS/tools_defs.h" diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 9cb6e22c03..f907362ad9 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -19,6 +19,7 @@ #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "SCHED_NR/sched_nr.h" #include "defs.h" +#include "bits.h" #include "common/utils/LOG/log.h" #include // #define DEBUG_ULSCH_DECODING diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index fd6bd8ea42..0063ac9fda 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -25,7 +25,7 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "nfapi/oai_integration/vendor_ext.h" #include "SCHED_NR/sched_nr.h" -#include "reverse_bits.h" +#include "bits.h" #include "T.h" #include "nr_phy_common.h" 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 b9fba62a27..a8ea145c60 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -900,25 +900,30 @@ void nr_pdcch_channel_estimation(const PHY_VARS_NR_UE *ue, } } -void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, - c16_t *rxF, - c16_t *pil, - c16_t *dl_ch, - unsigned short bwp_start_subcarrier, - int rb_offset, - int nb_rb_pdsch, - const uint8_t bitmap[36], - delay_t *delay, - uint32_t *nvar) +static void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, + c16_t *rxF, + c16_t *pil, + c16_t *dl_ch, + unsigned short bwp_start_subcarrier, + const freq_alloc_bitmap_t *freq_alloc, + int nb_rb_pdsch, + int bwpsize, + delay_t *delay, + uint32_t *nvar) { c16_t *dl_ch0 = dl_ch; int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); int idx = 0; - for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) { - bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01; - if (allocated_rb) { + int pos = freq_alloc->first_rb; + int last_processed_rb = freq_alloc->first_rb; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, bwpsize, &pos, &block_start, &block_end)) { + int skipped_rbs = block_start - last_processed_rb; + pil += skipped_rbs * 6; + re_offset = (re_offset + skipped_rbs * 12) % frame_parms->ofdm_symbol_size; + for (int rb = block_start; rb <= block_end; rb++) { for (int pilot_cnt = 0; pilot_cnt < 6; pilot_cnt += 2) { c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH @@ -938,10 +943,8 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, idx++; } } - } else { - pil += 6; - re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } + last_processed_rb = block_end + 1; } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay); @@ -1071,9 +1074,9 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *pil, c16_t *dl_ch, unsigned short bwp_start_subcarrier, - int rb_offset, + const freq_alloc_bitmap_t *freq_alloc, int nb_rb_pdsch, - const uint8_t bitmap[36], + int bwpsize, delay_t *delay, uint32_t *nvar) { @@ -1082,9 +1085,14 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); int idx = 0; - for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) { - bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01; - if (allocated_rb) { + int pos = freq_alloc->first_rb; + int last_processed_rb = freq_alloc->first_rb; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, bwpsize, &pos, &block_start, &block_end)) { + int skipped_rbs = block_start - last_processed_rb; + pil += skipped_rbs * 4; + re_offset = (re_offset + skipped_rbs * 12) % frame_parms->ofdm_symbol_size; + for (int rb = block_start; rb <= block_end; rb++) { for (int pilot_cnt = 0; pilot_cnt < 4; pilot_cnt += 2) { c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH @@ -1104,10 +1112,8 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, idx++; } } - } else { - pil += 4; - re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } + last_processed_rb = block_end + 1; } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); @@ -1251,7 +1257,7 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *fp = &ue->frame_parms; const int ch_offset = fp->ofdm_symbol_size * symbol; const int symbol_offset = fp->ofdm_symbol_size * symbol; - int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->start[0]) * 12; + int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->first_rb) * 12; #ifdef DEBUG_PDSCH printf( @@ -1268,8 +1274,8 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, // generate pilot for gNB port number 1000+p int config_type = dlsch->dmrsConfigType; - int rb_offset = freq_alloc->start[0] + (dlsch->refPoint ? 0 : dlsch->BWPStart); - int nb_rb_pdsch = freq_alloc->end[freq_alloc->num_blocks - 1] - freq_alloc->start[0] + 1; + int rb_offset = freq_alloc->first_rb + (dlsch->refPoint ? 0 : dlsch->BWPStart); + int nb_rb_pdsch = freq_alloc->last_rb - freq_alloc->first_rb + 1; int8_t delta = get_delta(p, config_type); c16_t pilot[3280] __attribute__((aligned(16))); // Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS @@ -1297,9 +1303,9 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, &pilot[6 * rb_offset], dl_ch, bwp_start_subcarrier, - freq_alloc->start[0], + freq_alloc, nb_rb_pdsch, - freq_alloc->bitmap, + dlsch->BWPSize, &delay, nvar); @@ -1309,9 +1315,9 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, &pilot[4 * rb_offset], dl_ch, bwp_start_subcarrier, - freq_alloc->start[0], + freq_alloc, nb_rb_pdsch, - freq_alloc->bitmap, + dlsch->BWPSize, &delay, nvar); @@ -1372,6 +1378,7 @@ void nr_pdsch_ptrs_processing(int nbRx, NR_DL_UE_HARQ_t *dlsch1_harq, uint8_t nr_slot_rx, unsigned char symbol, + int nb_rb, uint16_t rnti, NR_UE_DLSCH_t dlsch[2]) { @@ -1388,7 +1395,6 @@ void nr_pdsch_ptrs_processing(int nbRx, uint16_t *ptrsSymbPos = NULL; uint8_t *ptrsSymbIdx = NULL; uint8_t *ptrsReOffset = NULL; - uint16_t *nb_rb = NULL; int nscid = 0; if(dlsch0_harq->status == NR_ACTIVE) { @@ -1399,7 +1405,6 @@ void nr_pdsch_ptrs_processing(int nbRx, K_ptrs = &dlsch[0].dlsch_config.PTRSFreqDensity; dmrsSymbPos = &dlsch[0].dlsch_config.dlDmrsSymbPos; ptrsReOffset = &dlsch[0].dlsch_config.PTRSReOffset; - nb_rb = &dlsch[0].dlsch_config.number_rbs; ptrsSymbPos = &dlsch[0].ptrs_symbols; ptrsSymbIdx = &dlsch[0].ptrs_symbol_index; nscid = dlsch[0].dlsch_config.nscid; @@ -1412,7 +1417,6 @@ void nr_pdsch_ptrs_processing(int nbRx, K_ptrs = &dlsch[1].dlsch_config.PTRSFreqDensity; dmrsSymbPos = &dlsch[1].dlsch_config.dlDmrsSymbPos; ptrsReOffset = &dlsch[1].dlsch_config.PTRSReOffset; - nb_rb = &dlsch[1].dlsch_config.number_rbs; ptrsSymbPos = &dlsch[1].ptrs_symbols; ptrsSymbIdx = &dlsch[1].ptrs_symbol_index; nscid = dlsch[1].dlsch_config.nscid; @@ -1456,7 +1460,7 @@ void nr_pdsch_ptrs_processing(int nbRx, nr_gold_pdsch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, frame_parms->Nid_cell, nscid, nr_slot_rx, symbol); nr_ptrs_cpe_estimation(*K_ptrs, *ptrsReOffset, - *nb_rb, + nb_rb, rnti, frame_parms->ofdm_symbol_size, rxdataF_comp[symbol][0][aarx], @@ -1492,11 +1496,7 @@ void nr_pdsch_ptrs_processing(int nbRx, #ifdef DEBUG_DL_PTRS printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i); #endif - rotate_cpx_vector(rxdataF_comp[i][0][aarx], - &phase_per_symbol[i], - rxdataF_comp[i][0][aarx], - ((*nb_rb) * NR_NB_SC_PER_RB), - 15); + rotate_cpx_vector(rxdataF_comp[i][0][aarx], &phase_per_symbol[i], rxdataF_comp[i][0][aarx], nb_rb * NR_NB_SC_PER_RB, 15); }// if not DMRS Symbol }// symbol loop }// last symbol check diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 6c5b049634..474debc2f7 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -5,7 +5,7 @@ #ifndef __NR_ESTIMATION_DEFS__H__ #define __NR_ESTIMATION_DEFS__H__ - +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "PHY/defs_nr_UE.h" /** @addtogroup _PHY_PARAMETER_ESTIMATION_BLOCKS_ @@ -130,6 +130,7 @@ void nr_pdsch_ptrs_processing(int nbRx, NR_DL_UE_HARQ_t *dlsch1_harq, uint8_t nr_slot_rx, unsigned char symbol, + int nb_rb, uint16_t rnti, NR_UE_DLSCH_t dlsch[2]); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 90e66cfb19..7ccc366dfa 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -47,6 +47,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, uint8_t **b, int *G, int nb_dlsch, + int number_rbs, uint8_t *DLSCH_ids) { nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch]; @@ -95,7 +96,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, // ------------------------------------------------------------------ TB_parameters->G = G[DLSCH_id]; - TB_parameters->nb_rb = dlsch_config->number_rbs; + TB_parameters->nb_rb = number_rbs; TB_parameters->Qm = dlsch_config->qamModOrder; TB_parameters->mcs = dlsch_config->mcs; TB_parameters->nb_layers = dlsch[DLSCH_id].Nl; @@ -256,7 +257,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, kpiStructure.nb_total++; kpiStructure.blockSize = dlsch_config->TBS; kpiStructure.dl_mcs = dlsch_config->mcs; - kpiStructure.nofRBs = dlsch_config->number_rbs; + kpiStructure.nofRBs = number_rbs; harq_process->decodeResult = harq_process->processedSegments == harq_process->C; @@ -327,7 +328,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, dlsch->dlsch_config.mcs, dlsch->Nl, dlsch_config->number_symbols, - dlsch_config->number_rbs, + number_rbs, dlsch_config->qamModOrder, Coderate); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 53a6cbc19f..6dea229ef5 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -12,6 +12,7 @@ #include "nr_transport_proto_ue.h" #include "PHY/sse_intrin.h" #include "T.h" +#include "bits.h" #include "openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h" #include "PHY/NR_REFSIG/nr_refsig.h" #include "PHY/NR_REFSIG/dmrs_nr.h" @@ -276,21 +277,26 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, int32_t dl_ch_estimates_ext[][rx_size_symbol], unsigned char symbol, uint8_t pilots, - uint8_t config_type, - int startBWP, + const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config, const freq_alloc_bitmap_t *freq_alloc, - uint8_t n_dmrs_cdm_groups, uint8_t Nl, NR_DL_FRAME_PARMS *fp, - uint16_t dlDmrsSymbPos, uint32_t csi_res_bitmap, int chest_time_type) { + int config_type = dlsch_config->dmrsConfigType; + int n_dmrs_cdm_groups = dlsch_config->n_dmrs_cdm_groups; if (config_type == NFAPI_NR_DMRS_TYPE1) - AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2, "n_dmrs_cdm_groups %d is illegal\n", n_dmrs_cdm_groups); + AssertFatal(n_dmrs_cdm_groups == 1 + || n_dmrs_cdm_groups == 2, + "n_dmrs_cdm_groups %d is illegal\n", + n_dmrs_cdm_groups); else - AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2 || n_dmrs_cdm_groups == 3, - "n_dmrs_cdm_groups %d is illegal\n",n_dmrs_cdm_groups); + AssertFatal(n_dmrs_cdm_groups == 1 + || n_dmrs_cdm_groups == 2 + || n_dmrs_cdm_groups == 3, + "n_dmrs_cdm_groups %d is illegal\n", + n_dmrs_cdm_groups); uint32_t dmrs_rb_bitmap = 0; if (pilots) { @@ -312,13 +318,15 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, uint32_t dmrs_csi_overlap_odd = csi_res_odd + dmrs_rb_bitmap; int8_t validDmrsEst; if (chest_time_type == 0) - validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos, symbol); + validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlsch_config->dlDmrsSymbPos, symbol); else - validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos, 0, 14); // get first dmrs symbol index + validDmrsEst = get_next_dmrs_symbol_in_slot(dlsch_config->dlDmrsSymbPos, 0, 14); // get first dmrs symbol index - for (int b = 0; b < freq_alloc->num_blocks; b++) { - int start_rb = freq_alloc->start[b] + startBWP; - int nb_rb = freq_alloc->end[b] - freq_alloc->start[b] + 1; + int pos = 0; + int block_start, block_end; + while (find_next_rb_block(freq_alloc->bitmap, dlsch_config->BWPSize, &pos, &block_start, &block_end)) { + int start_rb = block_start + dlsch_config->BWPStart; + int nb_rb = block_end - block_start + 1; const int start_re = (fp->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size; for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) { c16_t *rxF_ext = rxdataF_ext[aarx]; @@ -1076,13 +1084,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, dl_ch_estimates_ext, symbol, pilots, - config_type, - dlsch_config->BWPStart, + dlsch_config, freq_alloc, - dlsch_config->n_dmrs_cdm_groups, nl, fp, - dlsch_config->dlDmrsSymbPos, csi_res_bitmap, ue->chest_time); stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS); @@ -1112,13 +1117,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, uint32_t csi_re_count = 0; uint32_t csi_res_even = csi_res_bitmap & 0xfff; uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff; - int start = freq_alloc->start[0] + dlsch_config->BWPStart; - int end = freq_alloc->end[freq_alloc->num_blocks - 1] + 1; + uint32_t count_even = count_bits(&csi_res_even, 1); + uint32_t count_odd = count_bits(&csi_res_odd, 1); + int start = freq_alloc->first_rb + dlsch_config->BWPStart; + int end = freq_alloc->last_rb + 1; for (int rb = start; rb < end; rb++) { - if ((freq_alloc->bitmap[rb / 8] >> (rb % 8)) & 0x01) { - uint32_t rb_csi_pattern = (rb % 2 == 0) ? csi_res_even : csi_res_odd; - csi_re_count += __builtin_popcount(rb_csi_pattern); - } + if ((freq_alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01) + csi_re_count += (rb % 2 == 0) ? count_even : count_odd; } nb_re_pdsch = (nb_re_pdsch > csi_re_count) ? (nb_re_pdsch - csi_re_count) : 0; if (csi_re_count > 0) { @@ -1326,6 +1331,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, dlsch1_harq, nr_slot_rx, symbol, + freq_alloc->num_rbs, dlsch[0].rnti, dlsch); dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol]; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index 7e1d6ccb92..89f868b210 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -14,7 +14,7 @@ #include #include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "openair1/PHY/NR_REFSIG/nr_refsig.h" -#include "reverse_bits.h" +#include "bits.h" #include "instrumentation.h" //#define DEBUG_PBCH //#define DEBUG_PBCH_ENCODING 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 7de87cc2ee..ed269cd1de 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -11,6 +11,7 @@ #include "SCHED_NR_UE/defs.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1 #define NR_PUSCH_y 3 // UCI placeholder bit @@ -70,6 +71,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, uint8_t **b, int *G, int nb_dlsch, + int number_rbs, uint8_t *DLSCH_ids); int nr_ulsch_pre_encoding(PHY_VARS_NR_UE *ue, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index c57d0c74ce..f269b2694d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -12,15 +12,6 @@ #include "nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h" #include "../NR_TRANSPORT/nr_transport_common_proto.h" -#define MAX_FA_BLOCKS 10 -typedef struct { - int start[MAX_FA_BLOCKS]; - int end[MAX_FA_BLOCKS]; - int num_rbs; - int num_blocks; - uint8_t bitmap[36]; -} freq_alloc_bitmap_t; - typedef struct { /// Index of current HARQ round for this ULSCH uint8_t round; diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index 7ae1a04dbf..ad0c29de1e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -15,7 +15,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include #include "common/utils/LOG/log.h" -#include "reverse_bits.h" +#include "bits.h" #include "openair1/PHY/NR_REFSIG/nr_refsig.h" #include "T.h" diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 3e627c38cd..1ca19deda0 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -11,6 +11,7 @@ #include "common/platform_constants.h" #include "defs_nr_common.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" #include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" @@ -101,6 +102,8 @@ typedef struct { typedef struct { /// Nfapi DLSCH PDU const nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu; + /// freq allocation information + freq_alloc_bitmap_t freq_alloc; /// pointer to pdu from MAC interface (this is "a" in 36.212) uint8_t *pdu; /// Pointer to the payload 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 9f2ac727fb..74beb9e02b 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -377,4 +377,14 @@ int nr_get_ssb_start_sc(int scs, int ssb_sco, frequency_range_t freq_range); +bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end); +typedef struct { + int first_rb; + int last_rb; + int num_rbs; + uint32_t bitmap[9]; +} freq_alloc_bitmap_t; +bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb); +freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]); +freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size); #endif 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 5e71d0b285..5239aa2c00 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -3,6 +3,7 @@ */ #include "nr_phy_common.h" +#include "bits.h" #include #ifdef __aarch64__ #define USE_128BIT @@ -427,6 +428,79 @@ void nr_scale_channel(int size, int ch_estimates_ext[][size], int symb, uint32_t } } +freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) +{ + freq_alloc_bitmap_t alloc = {0}; + int num_words = (size + 31) / 32; + AssertFatal(num_words <= sizeofArray(alloc.bitmap), + "freq_alloc_bitmap.bitmap %lu words < %d\n", + sizeofArray(alloc.bitmap), + num_words); + memcpy(alloc.bitmap, bitmap, alloc_size); + alloc.num_rbs = count_bits(alloc.bitmap, num_words); + alloc.first_rb = get_first_bit_index(alloc.bitmap, num_words); + alloc.last_rb = get_last_bit_index(alloc.bitmap, num_words); + AssertFatal(alloc.first_rb >= 0 && alloc.last_rb >=0 , "No valid RB set, no bit set in bitmap\n"); + return alloc; +} + +freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) +{ + freq_alloc_bitmap_t alloc = { + .num_rbs = size, + .first_rb = start, + .last_rb = start + size - 1 + }; + memset(alloc.bitmap, 0, sizeof(alloc.bitmap)); + for (int i = start; i < size + start; i++) + alloc.bitmap[i / 32] |= (1U << (i % 32)); + return alloc; +} + +bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb) +{ + return (alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01; +} + +/** + * Finds the next contiguous block of set bits. + * @param bitmap The bit buffer + * @param size Total bits in the buffer + * @param pos Pointer to current bit index (updated by function) + * @param start Output: Start index of the found block + * @param end Output: End index of the found block + * @return true if a block was found, false if no more bits are set + */ +bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end) +{ + AssertFatal(*pos >= 0 && *pos <= size, "Invalid combination of bit index %d and size %d\n", *pos, size); + const int words = (size + 31) / 32; + + // Find start of next block + int idx = get_first_bit_index_mask(bitmap, words, *pos, size - *pos); + if (idx < 0) + return false; + *start = idx; + + // Find end of block: first zero bit after idx + // Reuse get_first_bit_index_from on the inverted bitmap + idx++; + int word_idx = idx / 32; + int n = words - word_idx; + uint32_t inv[n]; + for (int i = 0; i < n; i++) + inv[i] = ~bitmap[word_idx + i]; + if (size % 32 != 0) + inv[n - 1] &= (1u << (size % 32)) - 1; + + int end_off = get_first_bit_index_mask(inv, n, idx - word_idx * 32, size - idx); + idx = (end_off < 0) ? size : word_idx * 32 + end_off; + + *end = (idx > size) ? size - 1 : idx - 1; + *pos = idx; // Update position for the next call + return true; +} + void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size) { const double phase_inc = -fo_Hz / (samples_per_ms * 1000); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index e32023452d..2d09377b5b 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -486,57 +486,13 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue, return ret; } -static freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) -{ - freq_alloc_bitmap_t alloc = { - .num_rbs = 0, - .num_blocks = 0 - }; - - bool pos_bit = false; - for (int i = 0; i < size; i++) { - if ((bitmap[i / 8] >> i % 8) & 0x1) { - if (!pos_bit) { - pos_bit = true; - alloc.start[alloc.num_blocks] = i; - AssertFatal(alloc.num_blocks < MAX_FA_BLOCKS, "Number of type0 PDSCH RBG exceeting %d\n", MAX_FA_BLOCKS); - alloc.num_blocks++; - } - alloc.num_rbs++; - } else { - if (pos_bit) { - pos_bit = false; - alloc.end[alloc.num_blocks - 1] = i - 1; - } - } - } - if (pos_bit) - alloc.end[alloc.num_blocks - 1] = size - 1; - AssertFatal(alloc.num_blocks > 0, "Frequency allocation bitmap empty\n"); - memcpy(alloc.bitmap, bitmap, alloc_size * sizeof(uint8_t)); - return alloc; -} - -static freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) -{ - freq_alloc_bitmap_t alloc = { - .num_rbs = size, - .num_blocks = 1, - .start[0] = start, - .end[0] = start + size - 1 - }; - memset(alloc.bitmap, 0, 36 * sizeof(uint8_t)); - for (int i = start; i < size + start; i++) - alloc.bitmap[i / 8] += 1 << (i % 8); - return alloc; -} - static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], int16_t *llr[2], c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], - int G) + int G, + freq_alloc_bitmap_t *freq_alloc) { int frame_rx = proc->frame_rx; int nr_slot_rx = proc->nr_slot_rx; @@ -552,13 +508,6 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, // dlsch0_harq contains the previous transmissions data for this harq pid NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid]; - freq_alloc_bitmap_t freq_alloc = {0}; - if (dlschCfg->resource_alloc == 0) { - int alloc_size = (dlschCfg->BWPSize / 8) + (dlschCfg->BWPSize % 8 > 0); - freq_alloc = set_start_end_from_bitmap(dlschCfg->BWPSize, alloc_size, dlschCfg->rb_bitmap); - } else - freq_alloc = set_bitmap_from_start_size(dlschCfg->start_rb, dlschCfg->number_rbs); - LOG_D(PHY, "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, start RB %d, end RB %d, symbol_start %d, nb_symbols " "%d, DMRS mask " @@ -569,8 +518,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, harq_pid, dlsch0_harq->status, dlschCfg->BWPStart, - freq_alloc.start[0], - freq_alloc.end[freq_alloc.num_blocks - 1], + freq_alloc->first_rb, + freq_alloc->last_rb, dlschCfg->start_symbol, dlschCfg->number_symbols, dlschCfg->dlDmrsSymbPos, @@ -586,7 +535,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, int32_t ptrs_re_per_slot[ue->frame_parms.nb_antennas_rx][NR_SYMBOLS_PER_SLOT]; memset(ptrs_re_per_slot, 0, sizeof(ptrs_re_per_slot)); - const uint32_t rx_size_symbol = (freq_alloc.num_rbs * NR_NB_SC_PER_RB + 15) & ~15; + const uint32_t rx_size_symbol = (freq_alloc->num_rbs * NR_NB_SC_PER_RB + 15) & ~15; fourDimArray_t *toFree2 = NULL; allocCast4D(rxdataF_comp, c16_t, @@ -608,7 +557,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, nr_pdsch_channel_estimation(ue, proc, dlschCfg, - &freq_alloc, + freq_alloc, nl, get_dmrs_port(nl, dlschCfg->dmrs_ports), m, @@ -632,7 +581,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, } stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS); nvar /= (dlschCfg->number_symbols * dlsch0->Nl * ue->frame_parms.nb_antennas_rx); - nr_ue_measurement_procedures(2, ue, proc, freq_alloc.num_rbs, pdsch_est_size, pdsch_dl_ch_estimates); + nr_ue_measurement_procedures(2, ue, proc, freq_alloc->num_rbs, pdsch_est_size, pdsch_dl_ch_estimates); if (ue->chest_time == 1) { // averaging time domain channel estimates nr_chest_time_domain_avg(&ue->frame_parms, @@ -640,7 +589,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, dlschCfg->number_symbols, dlschCfg->start_symbol, dlschCfg->dlDmrsSymbPos, - freq_alloc.num_rbs); + freq_alloc->num_rbs); } uint16_t first_symbol_with_data = dlschCfg->start_symbol; @@ -667,13 +616,13 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, pdschChanEstimates, sizeof(c16_t), 1, - freq_alloc.num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + freq_alloc->num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, &mt); scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue, pdschRxdataF, sizeof(c16_t), 1, - freq_alloc.num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + freq_alloc->num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, &mt); } fourDimArray_t *toFree3 = NULL; @@ -713,7 +662,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, if (nr_rx_pdsch(ue, proc, dlsch, - &freq_alloc, + freq_alloc, m, first_symbol_flag, harq_pid, @@ -812,7 +761,10 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], - int16_t *llr[2]) { + int16_t *llr[2], + int G[2], + freq_alloc_bitmap_t *freq_alloc) +{ if (dlsch[0].active == false) { LOG_E(PHY, "DLSCH should be active when calling this function\n"); return; @@ -823,7 +775,6 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, int nr_slot_rx = proc->nr_slot_rx; NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid]; NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid]; - uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos); nr_downlink_indication_t dl_indication; fapi_nr_rx_indication_t rx_ind = {0}; uint16_t number_pdus = 1; @@ -833,15 +784,6 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, int nb_dlsch = 0; nb_dlsch += (is_cw0_active == NR_ACTIVE) ? 1 : 0; nb_dlsch += (is_cw1_active == NR_ACTIVE) ? 1 : 0; - uint16_t nb_symb_sch = dlsch[0].dlsch_config.number_symbols; - uint8_t dmrs_type = dlsch[0].dlsch_config.dmrsConfigType; - - uint8_t nb_re_dmrs; - if (dmrs_type == NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6 * dlsch[0].dlsch_config.n_dmrs_cdm_groups; - } else { - nb_re_dmrs = 4 * dlsch[0].dlsch_config.n_dmrs_cdm_groups; - } LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw0_active); LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw1_active); @@ -858,27 +800,15 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, return; } - int G[2]; uint8_t DLSCH_ids[nb_dlsch]; int pdsch_id = 0; uint8_t *p_b[2] = {NULL}; for (uint8_t DLSCH_id = 0; DLSCH_id < 2; DLSCH_id++) { NR_DL_UE_HARQ_t *dl_harq = &ue->dl_harq_processes[DLSCH_id][harq_pid]; - if (dl_harq->status != NR_ACTIVE) continue; + if (dl_harq->status != NR_ACTIVE) + continue; DLSCH_ids[pdsch_id++] = DLSCH_id; - fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; - uint32_t unav_res = 0; - if (dlsch_config->pduBitmap & 0x1) { - uint16_t ptrsSymbPos = 0; - set_ptrs_symb_idx(&ptrsSymbPos, dlsch_config->number_symbols, dlsch_config->start_symbol, 1 << dlsch_config->PTRSTimeDensity, - dlsch_config->dlDmrsSymbPos); - int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity; - int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols); - unav_res = n_ptrs * ptrsSymbPerSlot; - } - unav_res += compute_csi_rm_unav_res(dlsch_config); - G[DLSCH_id] = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[DLSCH_id].Nl); start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); nr_dlsch_unscrambling(llr[DLSCH_id], G[DLSCH_id], 0, dlsch[DLSCH_id].dlsch_config.dlDataScramblingId, dlsch[DLSCH_id].rnti); @@ -888,7 +818,7 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids); + nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, freq_alloc->num_rbs, DLSCH_ids); stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); int ind_type = -1; @@ -938,9 +868,8 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * NR_MAX_NB_LAYERS; // number of segments to be allocated - int num_rb = dlsch[0].dlsch_config.number_rbs; - if (num_rb != 273) { - a_segments = a_segments * num_rb; + if (freq_alloc->num_rbs != 273) { + a_segments = a_segments * freq_alloc->num_rbs; a_segments = (a_segments / 273) + 1; } uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment @@ -1253,6 +1182,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ nr_ue_csi_rs_procedures(ue, proc, rxdataF, &phy_data->csirs_vars.csirs_config_pdu); } + int G[2] = {0}; if (dlsch[0].active) { fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[0].dlsch_config; uint16_t nb_symb_sch = dlsch_config->number_symbols; @@ -1267,6 +1197,13 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ } } + freq_alloc_bitmap_t freq_alloc = {0}; + if (dlsch_config->resource_alloc == 0) { + int alloc_size = (dlsch_config->BWPSize / 8) + (dlsch_config->BWPSize % 8 > 0); + freq_alloc = set_start_end_from_bitmap(dlsch_config->BWPSize, alloc_size, dlsch_config->rb_bitmap); + } else + freq_alloc = set_bitmap_from_start_size(dlsch_config->start_rb, dlsch_config->number_rbs); + const uint8_t nb_re_dmrs = get_num_dmrs_re_per_rb(dlsch_config->dmrsConfigType, dlsch_config->n_dmrs_cdm_groups); uint16_t dmrs_len = get_num_dmrs(dlsch_config->dlDmrsSymbPos); uint32_t unav_res = 0; @@ -1277,35 +1214,35 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ dlsch_config->start_symbol, 1 << dlsch_config->PTRSTimeDensity, dlsch_config->dlDmrsSymbPos); - int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity; + int n_ptrs = (freq_alloc.num_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity; int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols); unav_res = n_ptrs * ptrsSymbPerSlot; } unav_res += compute_csi_rm_unav_res(dlsch_config); - int G = nr_get_G(dlsch_config->number_rbs, - dlsch_config->number_symbols, - nb_re_dmrs, - dmrs_len, - unav_res, - dlsch_config->qamModOrder, - dlsch[0].Nl); - const uint32_t rx_llr_buf_sz = ALIGNARRAYSIZE(G, 32); // each LLR is 2 bytes hence 64 byte aligned + G[0] = nr_get_G(freq_alloc.num_rbs, + dlsch_config->number_symbols, + nb_re_dmrs, + dmrs_len, + unav_res, + dlsch_config->qamModOrder, + dlsch[0].Nl); + const uint32_t rx_llr_buf_sz = ALIGNARRAYSIZE(G[0], 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++) llr[i] = (int16_t *)malloc16_clear(rx_llr_buf_sz * sizeof(int16_t)); // it returns -1 in case of internal failure, or 0 in case of normal result - int ret_pdsch = nr_ue_pdsch_procedures(ue, proc, dlsch, llr, rxdataF, G); + int ret_pdsch = nr_ue_pdsch_procedures(ue, proc, dlsch, llr, rxdataF, G[0], &freq_alloc); TracyCPlot("pdsch mcs", dlsch->dlsch_config.mcs); - UEscopeCopy(ue, pdschLlr, llr[0], sizeof(int16_t), 1, G, 0); + UEscopeCopy(ue, pdschLlr, llr[0], sizeof(int16_t), 1, G[0], 0); LOG_D(PHY, "DLSCH data reception at nr_slot_rx: %d\n", nr_slot_rx); start_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS); if (ret_pdsch >= 0) { - nr_ue_dlsch_procedures(ue, proc, dlsch, llr); + nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G, &freq_alloc); } else { LOG_E(NR_PHY, "Demodulation impossible, internal error\n"); diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index c06a5529c9..ccddc9be63 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -410,8 +410,9 @@ int main(int argc, char **argv) dlsch_ue[0].rnti = n_rnti; nr_init_dl_harq_processes(UE->dl_harq_processes, 8, nb_rb); - unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; + unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; NR_gNB_DLSCH_t *dlsch = &gNB->dlsch[0]; + dlsch->freq_alloc = set_bitmap_from_start_size(0, nb_rb); //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; uint8_t nb_re_dmrs = 6; // No data in dmrs symbol @@ -554,6 +555,7 @@ int main(int argc, char **argv) &p_b, available_bits_array, 1, + num_rb, DLSCH_ids); if (dlsch0_ue->last_iteration_cnt > dlsch0_ue->max_ldpc_iterations) diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index c5b8723908..1eef6fda51 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -31,6 +31,7 @@ #include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h" #include "executables/nr-uesoftmodem.h" #include "nfapi/oai_integration/vendor_ext.h" +#include "bits.h" //#define DEBUG_NR_ULSCHSIM diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 7e74f26f56..eac4290f77 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -53,6 +53,7 @@ #include "common/openairinterface5g_limits.h" #include "common/ran_context.h" #include "common/utils/LOG/log.h" +#include "common/utils/bits.h" #include "common/utils/T/T.h" #include "common/utils/nr/nr_common.h" #include "common/utils/threadPool/thread-pool.h" diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index d65b080176..6003693126 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -5,7 +5,7 @@ #include #include "nr_mac.h" #include "nr_mac_common.h" -#include "common/utils/nr/nr_common.h" +#include "common/utils/bits.h" #include #include diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index f7b239ab38..f269d11f51 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -27,7 +27,7 @@ /* utils */ #include "assertions.h" -#include "reverse_bits.h" +#include "bits.h" #include "oai_asn1.h" #include "common/utils/LOG/log.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" @@ -380,14 +380,14 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p currentBit += writeBit(rb_bitmap, currentBit, bit_rbg, P); } - // write last bit - int last_bit_rbg = frequency_domain_assignment.val & 0x01; - const int tmp=(start_DLBWP + n_RB_DLBWP) % P; - int last_RBG = tmp ? tmp : P; - writeBit(rb_bitmap, currentBit, last_bit_rbg, last_RBG); - } - else if (pdsch_Config && - pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_dynamicSwitch) + // write last bit (only if more than 1 RBG) + if (n_RBG > 1) { + int last_bit_rbg = frequency_domain_assignment.val & 0x01; + const int tmp = (start_DLBWP + n_RB_DLBWP) % P; + int last_RBG = tmp ? tmp : P; + writeBit(rb_bitmap, currentBit, last_bit_rbg, last_RBG); + } + } else if (pdsch_Config && pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_dynamicSwitch) AssertFatal(false, "DLSCH dynamic switch allocation not yet supported\n"); else { // TS 38.214 subclause 5.1.2.2.2 Downlink resource allocation type 1 @@ -408,7 +408,7 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p LOG_D(MAC,"DLSCH start_rb = %i\n", dlsch_config_pdu->start_rb); } } - if(pusch_config_pdu != NULL){ + if(pusch_config_pdu != NULL) { /* * TS 38.214 subclause 6.1.2.2 Resource allocation in frequency domain (uplink) */ @@ -428,10 +428,6 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p LOG_W(MAC, "Frequency domain assignment values are invalid! #RBs: %d, Start RB: %d, n_RB_ULBWP: %d \n",pusch_config_pdu->rb_size, pusch_config_pdu->rb_start, n_RB_ULBWP); return -1; } - LOG_D(MAC,"ULSCH riv = %i\n", riv); - LOG_D(MAC,"ULSCH n_RB_DLBWP = %i\n", n_RB_ULBWP); - LOG_D(MAC,"ULSCH number_rbs = %i\n", pusch_config_pdu->rb_size); - LOG_D(MAC,"ULSCH start_rb = %i\n", pusch_config_pdu->rb_start); } return 0; } @@ -1376,12 +1372,20 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, nb_rb_oh = 0; int nb_re_dmrs = ((dmrs_type == NULL) ? 6 : 4) * dlsch_pdu->n_dmrs_cdm_groups; + int number_rbs; + if (dlsch_pdu->resource_alloc == 1) { + number_rbs = dlsch_pdu->number_rbs; + } else { + uint32_t temp_bitmap[9]; + memcpy(temp_bitmap, dlsch_pdu->rb_bitmap, 36); + number_rbs = count_bits(temp_bitmap, 9); + } int R = nr_get_code_rate_dl(dlsch_pdu->mcs, dlsch_pdu->mcs_table); if (R > 0) { dlsch_pdu->targetCodeRate = R; dlsch_pdu->TBS = nr_compute_tbs(dlsch_pdu->qamModOrder, R, - dlsch_pdu->number_rbs, + number_rbs, dlsch_pdu->number_symbols, nb_re_dmrs * get_num_dmrs(dlsch_pdu->dlDmrsSymbPos), nb_rb_oh, @@ -1422,7 +1426,7 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, if (dl_dmrs_config->phaseTrackingRS != NULL) { bool valid_ptrs_setup = set_dl_ptrs_values(dl_dmrs_config->phaseTrackingRS->choice.setup, - dlsch_pdu->number_rbs, + number_rbs, dlsch_pdu->mcs, dlsch_pdu->mcs_table, &dlsch_pdu->PTRSFreqDensity, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 15c59716be..47ee80a529 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -23,7 +23,7 @@ #include "oai_asn1.h" #include "SIMULATION/TOOLS/sim.h" // for taus #include "utils.h" - +#include "bits.h" #include #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "RRC/NR_UE/L2_interface_ue.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 3341455e45..a1220c9df7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -15,7 +15,7 @@ /* Utils */ #include "common/utils/LOG/log.h" -#include "common/utils/nr/nr_common.h" +#include "common/utils/bits.h" #include "UTIL/OPT/opt.h" /* rlc */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 6e2e4970a0..3dc39f9612 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -11,8 +11,8 @@ #include "NR_MAC_gNB/nr_mac_gNB.h" #include "NR_MAC_gNB/mac_proto.h" +#include "common/utils/bits.h" #include "common/utils/LOG/log.h" -#include "common/utils/nr/nr_common.h" #include "UTIL/OPT/opt.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index ad3b4997dc..9f8f9b7314 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -24,7 +24,7 @@ #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair3/UTILS/conversions.h" #include "LAYER2/nr_rlc/nr_rlc_asn1_utils.h" -#include "reverse_bits.h" +#include "bits.h" #include "NR_MeasurementTimingConfiguration.h" #include "uper_decoder.h" diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 21e95164e7..f00eebf321 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -11,7 +11,7 @@ #include "NR_MAC_UE/mac_proto.h" #include "assertions.h" #include "SCHED_NR_UE/fapi_nr_ue_l1.h" -#include "reverse_bits.h" +#include "bits.h" #include "openair2/RRC/NR_UE/L2_interface_ue.h" #define MAX_IF_MODULES 100 diff --git a/openair2/RRC/NR_UE/verify_RRC.c b/openair2/RRC/NR_UE/verify_RRC.c index 42d3204d27..07017639c5 100644 --- a/openair2/RRC/NR_UE/verify_RRC.c +++ b/openair2/RRC/NR_UE/verify_RRC.c @@ -2,7 +2,8 @@ * SPDX-License-Identifier: LicenseRef-CSSL-1.0 */ - #include "rrc_proto.h" +#include "rrc_proto.h" +#include "common/utils/bits.h" static bool check_resourcesForInterference(const NR_CSI_MeasConfig_t *meas, NR_CSI_ResourceConfigId_t res_id, bool is_CSIIM) { @@ -119,8 +120,9 @@ static bool check_csi_resourceMapping_consistency(NR_CSI_RS_ResourceMapping_t re valid = false; break; case NR_CSI_RS_ResourceMapping__nrofPorts_p8: { - uint8_t freq = BIT_STRING_to_uint8(&resourceMapping.frequencyDomainAllocation.choice.other); - if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2 || count_bits(&freq, 1) != 4) { + uint32_t freq32 = 0; + freq32 = (uint32_t)BIT_STRING_to_uint8(&resourceMapping.frequencyDomainAllocation.choice.other); + if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2 || count_bits(&freq32, 1) != 4) { // row 7 and 8 -> l0+1 if (resourceMapping.firstOFDMSymbolInTimeDomain == 13) valid = false;