TX optimizations for gNB.

- phase compensation in symbol processing to allow for thread-pool parallelization
- some aarch64 optimizations for precoding and layer mapping
This commit is contained in:
Raymond Knopp
2026-05-04 20:59:41 +02:00
parent ba9b9b217a
commit 66253f2289
11 changed files with 685 additions and 136 deletions

View File

@@ -215,6 +215,174 @@ void nr_modulation(const uint32_t *in, uint32_t length, uint16_t mod_order, int1
AssertFatal(false, "Invalid or unsupported modulation order %d\n", mod_order);
}
static inline uint8_t get_packed_symbol(const uint8_t *in_bytes, uint32_t length, uint16_t mod_order, uint32_t symbol_idx)
{
const uint32_t bit_offset = symbol_idx * mod_order;
const uint32_t byte_offset = bit_offset >> 3;
const uint32_t bit_shift = bit_offset & 0x7;
const uint32_t num_bytes = (length + 7) >> 3;
uint16_t packed = in_bytes[byte_offset];
if (bit_shift > 8 - mod_order && byte_offset + 1 < num_bytes)
packed |= (uint16_t)in_bytes[byte_offset + 1] << 8;
return (packed >> bit_shift) & ((1U << mod_order) - 1);
}
static inline uint64_t get_packed_bits(const uint8_t *in_bytes, uint32_t length, uint32_t bit_offset, uint8_t width)
{
const uint32_t byte_offset = bit_offset >> 3;
const uint32_t bit_shift = bit_offset & 0x7;
const uint32_t num_bytes = (length + 7) >> 3;
const uint32_t bytes_needed = (bit_shift + width + 7) >> 3;
uint64_t packed = 0;
for (uint32_t i = 0; i < bytes_needed && byte_offset + i < num_bytes; i++)
packed |= (uint64_t)in_bytes[byte_offset + i] << (i << 3);
return (packed >> bit_shift) & ((UINT64_C(1) << width) - 1);
}
bool nr_modulation_layer_mapping(const uint32_t *in,
uint32_t length,
uint16_t mod_order,
uint8_t n_layers,
int layerSz,
c16_t tx_layers[][layerSz])
{
if (n_layers < 1 || n_layers > 4)
return false;
const uint32_t n_symbs = length / mod_order;
if ((n_symbs % n_layers) != 0)
return false;
const uint8_t *in_bytes = (const uint8_t *)in;
switch (mod_order) {
case 2: {
const c16_t *nr_mod_table = nr_qpsk_mod_table;
if (n_layers == 1) {
nr_modulation(in, length, mod_order, (int16_t *)tx_layers[0]);
return true;
}
for (uint32_t sym = 0, layer_sym = 0; sym < n_symbs; sym += n_layers, layer_sym++) {
for (uint8_t layer = 0; layer < n_layers; layer++) {
const uint8_t idx = get_packed_symbol(in_bytes, length, mod_order, sym + layer);
tx_layers[layer][layer_sym] = nr_mod_table[idx];
}
}
return true;
}
case 4: {
const int32_t *nr_mod_table = nr_16qam_mod_table;
if (n_layers == 1) {
nr_modulation(in, length, mod_order, (int16_t *)tx_layers[0]);
return true;
}
for (uint32_t sym = 0, layer_sym = 0; sym < n_symbs; sym += n_layers, layer_sym++) {
for (uint8_t layer = 0; layer < n_layers; layer++) {
const uint8_t idx = get_packed_symbol(in_bytes, length, mod_order, sym + layer);
((int32_t *)tx_layers[layer])[layer_sym] = nr_mod_table[idx];
}
}
return true;
}
case 6: {
const c16_t *nr_mod_table = (const c16_t *)nr_64qam_mod_table;
if (n_layers == 1) {
c16_t *tx0 = tx_layers[0];
uint32_t sym = 0;
for (; sym + 2 <= n_symbs; sym += 2) {
const uint16_t idx = get_packed_bits(in_bytes, length, sym * mod_order, 12);
tx0[sym] = nr_mod_table[idx * 2];
tx0[sym + 1] = nr_mod_table[idx * 2 + 1];
}
if (sym < n_symbs) {
const uint8_t idx = get_packed_symbol(in_bytes, length, mod_order, sym);
tx0[sym] = nr_mod_table[idx * 2];
}
return true;
}
if (n_layers == 2) {
c16_t *tx0 = tx_layers[0];
c16_t *tx1 = tx_layers[1];
for (uint32_t sym = 0, layer_sym = 0; sym < n_symbs; sym += 2, layer_sym++) {
const uint16_t idx = get_packed_bits(in_bytes, length, sym * mod_order, 12);
tx0[layer_sym] = nr_mod_table[idx * 2];
tx1[layer_sym] = nr_mod_table[idx * 2 + 1];
}
return true;
}
if (n_layers == 3) {
c16_t *tx0 = tx_layers[0];
c16_t *tx1 = tx_layers[1];
c16_t *tx2 = tx_layers[2];
uint32_t sym = 0;
uint32_t layer_sym = 0;
for (; sym + 6 <= n_symbs; sym += 6, layer_sym += 2) {
const uint64_t bits = get_packed_bits(in_bytes, length, sym * mod_order, 36);
const uint16_t idx0 = bits & 0xfff;
const uint16_t idx1 = (bits >> 12) & 0xfff;
const uint16_t idx2 = (bits >> 24) & 0xfff;
tx0[layer_sym] = nr_mod_table[idx0 * 2];
tx1[layer_sym] = nr_mod_table[idx0 * 2 + 1];
tx2[layer_sym] = nr_mod_table[idx1 * 2];
tx0[layer_sym + 1] = nr_mod_table[idx1 * 2 + 1];
tx1[layer_sym + 1] = nr_mod_table[idx2 * 2];
tx2[layer_sym + 1] = nr_mod_table[idx2 * 2 + 1];
}
if (sym < n_symbs) {
for (uint8_t layer = 0; layer < 3; layer++) {
const uint8_t idx = get_packed_symbol(in_bytes, length, mod_order, sym + layer);
tx_layers[layer][layer_sym] = nr_mod_table[idx * 2];
}
}
return true;
}
if (n_layers == 4) {
c16_t *tx0 = tx_layers[0];
c16_t *tx1 = tx_layers[1];
c16_t *tx2 = tx_layers[2];
c16_t *tx3 = tx_layers[3];
for (uint32_t sym = 0, layer_sym = 0; sym < n_symbs; sym += 4, layer_sym++) {
const uint32_t bits = get_packed_bits(in_bytes, length, sym * mod_order, 24);
const uint16_t idx0 = bits & 0xfff;
const uint16_t idx1 = (bits >> 12) & 0xfff;
tx0[layer_sym] = nr_mod_table[idx0 * 2];
tx1[layer_sym] = nr_mod_table[idx0 * 2 + 1];
tx2[layer_sym] = nr_mod_table[idx1 * 2];
tx3[layer_sym] = nr_mod_table[idx1 * 2 + 1];
}
return true;
}
return false;
}
case 8: {
const int32_t *nr_mod_table = nr_256qam_mod_table;
if (n_layers == 1) {
nr_modulation(in, length, mod_order, (int16_t *)tx_layers[0]);
return true;
}
for (uint32_t sym = 0, layer_sym = 0; sym < n_symbs; sym += n_layers, layer_sym++) {
for (uint8_t layer = 0; layer < n_layers; layer++) {
const uint8_t idx = get_packed_symbol(in_bytes, length, mod_order, sym + layer);
((int32_t *)tx_layers[layer])[layer_sym] = nr_mod_table[idx];
}
}
return true;
}
default:
return false;
}
}
void nr_layer_mapping(int nbCodes,
int encoded_len,
c16_t mod_symbs[nbCodes][encoded_len],
@@ -257,16 +425,12 @@ void nr_layer_mapping(int nbCodes,
}
#endif
#if defined(__aarch64__) && defined(USE_NEON)
// SIMDe doesn't handle this properly, gcc up to 14.2 neither
uint8_t const perm0[16] = {0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15};
uint8x16_t perm = vld1q_u8(perm0);
uint8x16_t d;
for (; i < (n_symbs & (~3)); i += 4) {
d = vqtbl1q_u8(*(uint8x16_t *)(mod + i), perm);
*(int64_t *)tx0 = vgetq_lane_u64((uint64x2_t)d, 0);
*(int64_t *)tx1 = vgetq_lane_u64((uint64x2_t)d, 1);
tx0 += 2;
tx1 += 2;
for (; i < (n_symbs & ~7); i += 8) {
uint32x4x2_t d = vld2q_u32((const uint32_t *)(mod + i));
vst1q_u32((uint32_t *)tx0, d.val[0]);
vst1q_u32((uint32_t *)tx1, d.val[1]);
tx0 += 4;
tx1 += 4;
}
#endif
for (; i < n_symbs; i += 2) {
@@ -375,6 +539,17 @@ void nr_layer_mapping(int nbCodes,
tx2 += 8;
}
}
#endif
#if defined(__aarch64__) && defined(USE_NEON)
for (; i < (n_symbs & ~11); i += 12) {
uint32x4x3_t d = vld3q_u32((const uint32_t *)(mod + i));
vst1q_u32((uint32_t *)tx0, d.val[0]);
vst1q_u32((uint32_t *)tx1, d.val[1]);
vst1q_u32((uint32_t *)tx2, d.val[2]);
tx0 += 4;
tx1 += 4;
tx2 += 4;
}
#endif
for (; i < n_symbs; i += 3) {
*tx0++ = mod[i];
@@ -448,17 +623,16 @@ void nr_layer_mapping(int nbCodes,
}
#endif
#if defined(__aarch64__) && defined(USE_NEON)
// SIMDe doesn't handle this properly, gcc up to 14.2 neither
for (; i < (n_symbs & ~3); i += 4) {
uint32x4_t d4 = *(uint32x4_t *)(mod + i);
*(uint32_t *)tx0 = vgetq_lane_u32(d4, 0);
tx0++;
*(uint32_t *)tx1 = vgetq_lane_u32(d4, 1);
tx1++;
*(uint32_t *)tx2 = vgetq_lane_u32(d4, 2);
tx2++;
*(uint32_t *)tx3 = vgetq_lane_u32(d4, 3);
tx3++;
for (; i < (n_symbs & ~15); i += 16) {
uint32x4x4_t d = vld4q_u32((const uint32_t *)(mod + i));
vst1q_u32((uint32_t *)tx0, d.val[0]);
vst1q_u32((uint32_t *)tx1, d.val[1]);
vst1q_u32((uint32_t *)tx2, d.val[2]);
vst1q_u32((uint32_t *)tx3, d.val[3]);
tx0 += 4;
tx1 += 4;
tx2 += 4;
tx3 += 4;
}
#endif
for (; i < n_symbs; i += 4) {
@@ -740,21 +914,47 @@ static inline __attribute__((always_inline)) __m256i cmac_prec256(__m256i y, __m
}
#endif
#ifdef __aarch64__
#ifdef NEWOPTIM
static inline __attribute__((always_inline)) int16x4x2_t cmac0_prec4(int16x8_t x, int16x4_t wr, int16x4_t wi) {
const int16x4_t x_lo = vget_low_s16(x);
const int16x4_t x_hi = vget_high_s16(x);
const int16x4_t xr = vuzp1_s16(x_lo, x_hi);
const int16x4_t xi = vuzp2_s16(x_lo, x_hi);
#else
static inline __attribute__((always_inline)) int16x8_t cmac0_prec128(int16x8_t x, int16x8_t wr, int16x8_t wi) {
//
int16x8_t xr = vuzp1q_s16(x, x); // even lanes
int16x8_t xi = vuzp2q_s16(x, x); // odd lanes
#endif
#ifdef __ARM_FEATURE_QRDMX
// ARMv8.1-A: Use RDM instructions
#ifdef NEWOPTIM
// real = ar*br - ai*bi (Q15 scaling via high-half doubling muls)
int16x4_t real = vqdmulh_s16(xr, wr); // ≈ round((2*xr*wr)/2^16)
real = vqrdmlsh_s16(real, xi, wi); // real -= round((2*xi*wi)/2^16)
// imag = ar*bi + ai*br
int16x4_t imag = vqdmulh_s16(xr, wi);
imag = vqrdmlah_s16(imag, xi, wr); // imag += round((2*xi*wr)/2^16)
#else
// real = ar*br - ai*bi (Q15 scaling via high-half doubling muls)
int16x8_t real = vqdmulhq_s16(xr, wr); // ≈ round((2*xr*wr)/2^16)
real = vqrdmlshq_s16(real, xi, wi); // real -= round((2*xi*wi)/2^16)
//
// imag = ar*bi + ai*br
int16x8_t imag = vqdmulhq_s16(xr, wi);
imag = vqrdmlahq_s16(imag, xi, wr); // imag += round((2*xi*wr)/2^16)
#endif
#else
// ARMv8.0-A fallback: Use standard 32-bit multiply
#ifdef NEWOPTIM
int32x4_t real_prod = vmull_s16(xr, wr);
real_prod = vmlsl_s16(real_prod, xi, wi);
int32x4_t imag_prod = vmull_s16(xr, wi);
imag_prod = vmlal_s16(imag_prod, xi, wr);
int16x4_t real = vqrshrn_n_s32(real_prod, 15);
int16x4_t imag = vqrshrn_n_s32(imag_prod, 15);
#else
int32x4_t real_lo = vmull_s16(vget_low_s16(xr), vget_low_s16(wr));
int32x4_t real_hi = vmull_s16(vget_high_s16(xr), vget_high_s16(wr));
real_lo = vmlsl_s16(real_lo, vget_low_s16(xi), vget_low_s16(wi));
@@ -768,15 +968,33 @@ static inline __attribute__((always_inline)) int16x8_t cmac0_prec128(int16x8_t x
int16x8_t real = vcombine_s16(vqrshrn_n_s32(real_lo, 15), vqrshrn_n_s32(real_hi, 15));
int16x8_t imag = vcombine_s16(vqrshrn_n_s32(imag_lo, 15), vqrshrn_n_s32(imag_hi, 15));
#endif
#endif
#ifdef NEWOPTIM
int16x4x2_t produ;
produ.val[0] = real;
produ.val[1] = imag;
return produ;
#else
// Re-interleave [real, imag]
int16x8x2_t produ = vzipq_s16(real, imag);
return produ.val[0];
return produ.val[0];
#endif
}
#ifdef NEWOPTIM
static inline __attribute__((always_inline)) int16x4x2_t cmac_prec4(int16x4x2_t y, int16x8_t x, int16x4_t wr, int16x4_t wi) {
const int16x4x2_t produ = cmac0_prec4(x, wr, wi);
y.val[0] = vadd_s16(y.val[0], produ.val[0]);
y.val[1] = vadd_s16(y.val[1], produ.val[1]);
return y;
}
#else
static inline __attribute__((always_inline)) int16x8_t cmac_prec128(int16x8_t y, int16x8_t x, int16x8_t wr, int16x8_t wi) {
int16x8_t produ = cmac0_prec128(x, wr, wi);
return vaddq_s16(y, produ);
}
#else
#endif
#else // __x86 128-bit
static inline __attribute__((always_inline)) simde__m128i cmac0_prec128(simde__m128i x, simde__m128i w_c, simde__m128i w_s)
{
// Multiplication and shift
@@ -807,6 +1025,12 @@ static inline __attribute__((always_inline)) __m128i cmac_prec128(__m128i y, __m
const Type w_c##Rank = Instruct(c16toI32(c16conj(weights[Rank][ant]))); \
const Type w_s##Rank = Instruct(c16toI32(c16swap(weights[Rank][ant]))); \
const Type *in##Rank = (Type *)(txdataF_res_mapped[Rank] + sc_offset + (out-beginning));
#if defined(NEWOPTIM) && defined(__aarch64__)
#define load_consts_arm(Rank) \
const int16x4_t wr##Rank = vdup_n_s16(weights[Rank][ant].r); \
const int16x4_t wi##Rank = vdup_n_s16(weights[Rank][ant].i); \
const int16x8_t *in##Rank = (const int16x8_t *)(txdataF_res_mapped[Rank] + sc_offset + (out - beginning));
#endif
void nr_layer_precoder_simd(const int n_layers,
const int symSz,
@@ -943,19 +1167,37 @@ void nr_layer_precoder_simd(const int n_layers,
}
#endif
#ifdef __aarch64__
load_consts(int16x8_t, vdupq_n_s16, 0);
#ifdef NEWOPTIM
load_consts_arm(0);
#else
load_consts(int16x8_t, vdupq_n_s16, 0);
#endif
if (n_layers == 1) {
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
#ifdef NEWOPTIM
const int16x4x2_t y = cmac0_prec4(vld1q_s16((const int16_t *)in0++), wr0, wi0);
vst2_s16((int16_t *)out, y);
#else
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
// Accumulate the product
int16x8_t y = cmac0_prec128(x0, w_c0, w_s0);
// Store the result to txdataF
*(int16x8_t *)out = y;
#endif
}
}
if (n_layers == 2) {
load_consts(int16x8_t, vdupq_n_s16, 1);
#ifdef NEWOPTIM
load_consts_arm(1);
#else
load_consts(int16x8_t, vdupq_n_s16, 1);
#endif
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
#ifdef NEWOPTIM
int16x4x2_t y = cmac0_prec4(vld1q_s16((const int16_t *)in0++), wr0, wi0);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in1++), wr1, wi1);
vst2_s16((int16_t *)out, y);
#else
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
const int16x8_t x1 = vld1q_s16((const int16_t *)in1++);
// Accumulate the product
@@ -963,41 +1205,66 @@ void nr_layer_precoder_simd(const int n_layers,
y = cmac_prec128(y, x1, w_c1, w_s1);
// Store the result to txdataF
*(int16x8_t *)out = y;
#endif
}
}
if (n_layers == 3) {
#ifdef NEWOPTIM
load_consts_arm(1);
load_consts_arm(2);
#else
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
#endif
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
#ifdef NEWOPTIM
int16x4x2_t y = cmac0_prec4(vld1q_s16((const int16_t *)in0++), wr0, wi0);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in1++), wr1, wi1);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in2++), wr2, wi2);
vst2_s16((int16_t *)out, y);
#else
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
const int16x8_t x1 = vld1q_s16((const int16_t *)in1++);
const int16x8_t x2 = vld1q_s16((const int16_t *)in2++);
// Accumulate the product
int16x8_t y = cmac0_prec128(x0, w_c0, w_s0);
;
y = cmac_prec128(y, x1, w_c1, w_s1);
y = cmac_prec128(y, x2, w_c2, w_s2);
// Store the result to txdataF
*(int16x8_t *)out = y;
#endif
}
}
if (n_layers == 4) {
#ifdef NEWOPTIM
load_consts_arm(1);
load_consts_arm(2);
load_consts_arm(3);
#else
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
load_consts(int16x8_t, vdupq_n_s16, 3);
#endif
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
#ifdef NEWOPTIM
int16x4x2_t y = cmac0_prec4(vld1q_s16((const int16_t *)in0++), wr0, wi0);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in1++), wr1, wi1);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in2++), wr2, wi2);
y = cmac_prec4(y, vld1q_s16((const int16_t *)in3++), wr3, wi3);
vst2_s16((int16_t *)out, y);
#else
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
const int16x8_t x1 = vld1q_s16((const int16_t *)in1++);
const int16x8_t x2 = vld1q_s16((const int16_t *)in2++);
const int16x8_t x3 = vld1q_s16((const int16_t *)in3++);
// Accumulate the product
int16x8_t y = cmac0_prec128(x0, w_c0, w_s0);
;
y = cmac_prec128(y, x1, w_c1, w_s1);
y = cmac_prec128(y, x2, w_c2, w_s2);
y = cmac_prec128(y, x3, w_c3, w_s3);
// Store the result to txdataF
*(int16x8_t *)out = y;
*(int16x8_t *)out = y;
#endif
}
}
#else

View File

@@ -28,6 +28,13 @@ void nr_modulation(const uint32_t *in,
uint16_t mod_order,
int16_t *out);
bool nr_modulation_layer_mapping(const uint32_t *in,
uint32_t length,
uint16_t mod_order,
uint8_t n_layers,
int layerSz,
c16_t tx_layers[][layerSz]);
/*! \brief Perform NR layer mapping. TS 38.211 V15.4.0 subclause 7.3.1.3
@param[in] mod_symbs, double Pointer to modulated symbols for each codeword
@param[in] n_layers, number of layers

View File

@@ -40,11 +40,26 @@ static inline uint16_t get_dci_ant_port_index(const nfapi_v4_pdcch_pdu_parameter
return dci_ant_idx;
}
static inline void mark_prb(uint64_t *prb_mask, int prb_mask_words, int symbol, int prb)
{
uint64_t *symbol_mask = prb_mask + symbol * prb_mask_words;
symbol_mask[prb >> 6] |= UINT64_C(1) << (prb & 63);
}
static inline bool prb_marked(const uint64_t *prb_mask, int prb)
{
return (prb_mask[prb >> 6] >> (prb & 63)) & 0x1;
}
void nr_generate_dci(PHY_VARS_gNB *gNB,
const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
NR_DL_FRAME_PARMS *frame_parms,
int slot)
int slot,
uint64_t *phase_comp_prb_mask,
int prb_mask_words)
{
uint64_t local_phase_comp_prb_mask[frame_parms->symbols_per_slot][prb_mask_words];
memset(local_phase_comp_prb_mask, 0, sizeof(local_phase_comp_prb_mask));
// fill reg list per symbol
int reg_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE];
nr_fill_reg_list(reg_list, pdcch_pdu_rel15);
@@ -193,6 +208,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
dmrs_idx = (reg_list[d][reg_count] + pdcch_pdu_rel15->BWPStart + rb_offset) * 3;
else
dmrs_idx = (reg_list[d][reg_count] + rb_offset) * 3;
const int reg_prb = pdcch_pdu_rel15->BWPStart + reg_list[d][reg_count] + rb_offset;
int k_prime = 0;
@@ -220,6 +236,8 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
k++;
} // m
if (gNB->phase_comp)
mark_prb(&local_phase_comp_prb_mask[0][0], prb_mask_words, l, reg_prb);
} // reg_count
} // symbol_idx
@@ -228,4 +246,31 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
dci_pdu->PayloadSizeBits,
*(unsigned long long *)dci_pdu->Payload);
} // for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++)
if (!gNB->phase_comp)
return;
const int symb_offset = (slot % frame_parms->slots_per_subframe) * frame_parms->symbols_per_slot;
c16_t *txdataF = gNB->common_vars.txdataF[0];
for (int symbol = pdcch_pdu_rel15->StartSymbolIndex;
symbol < pdcch_pdu_rel15->StartSymbolIndex + pdcch_pdu_rel15->DurationSymbols;
symbol++) {
uint64_t *local_symbol_mask = &local_phase_comp_prb_mask[symbol][0];
int prb = 0;
while (prb < frame_parms->N_RB_DL) {
while (prb < frame_parms->N_RB_DL && !prb_marked(local_symbol_mask, prb))
prb++;
const int start_prb = prb;
while (prb < frame_parms->N_RB_DL && prb_marked(local_symbol_mask, prb))
prb++;
if (prb > start_prb) {
c16_t *this_symbol = txdataF + symbol * frame_parms->ofdm_symbol_size + start_prb * NR_NB_SC_PER_RB;
const c16_t *rot = &frame_parms->symbol_rotation[0][symb_offset + symbol];
rotate_cpx_vector(this_symbol, rot, this_symbol, (prb - start_prb) * NR_NB_SC_PER_RB, 15);
uint64_t *global_symbol_mask = phase_comp_prb_mask;
for (int rr = start_prb; rr < prb; rr++)
global_symbol_mask[rr >> 6] |= UINT64_C(1) << (rr & 63);
}
}
}
}

View File

@@ -12,7 +12,9 @@
void nr_generate_dci(PHY_VARS_gNB *gNB,
const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
NR_DL_FRAME_PARMS *frame_parms,
int slot);
int slot,
uint64_t *phase_comp_prb_mask,
int prb_mask_words);
void nr_fill_dci(PHY_VARS_gNB *gNB,
int frame,

View File

@@ -500,12 +500,21 @@ typedef struct pdschSymbolProc_s {
unsigned int dlPtrsSymPos;
unsigned int n_ptrs;
uint16_t *ant_to_map;
uint64_t *pdsch_phase_comp_prb_mask;
int prb_mask_words;
unsigned int re_beginning_of_symbol[14];
c16_t *tx_layers[4];
time_stats_t dlsch_resource_mapping_stats;
time_stats_t dlsch_precoding_stats;
} pdschSymbolProc_t;
static inline void mark_prb_range(uint64_t *prb_mask, int prb_mask_words, int symbol, int start_prb, int nb_prb)
{
uint64_t *symbol_mask = prb_mask + symbol * prb_mask_words;
for (int prb = start_prb; prb < start_prb + nb_prb; prb++)
symbol_mask[prb >> 6] |= UINT64_C(1) << (prb & 63);
}
static void nr_pdsch_symbol_processing(void *arg)
{
pdschSymbolProc_t *rdata = (pdschSymbolProc_t *)arg;
@@ -525,6 +534,7 @@ static void nr_pdsch_symbol_processing(void *arg)
const int symbol_sz = frame_parms->ofdm_symbol_size;
c16_t **txdataF = gNB->common_vars.txdataF;
const int symb_offset = (slot % frame_parms->slots_per_subframe) * frame_parms->symbols_per_slot;
for (int l_symbol = rdata->startSymbol; l_symbol < rdata->startSymbol + rdata->numSymbols; l_symbol++) {
start_meas(&rdata->dlsch_resource_mapping_stats);
@@ -595,6 +605,12 @@ static void nr_pdsch_symbol_processing(void *arg)
block_end - block_start + 1,
txdataF_offset_per_symbol);
if (gNB->phase_comp) {
c16_t *pdsch_sc = &txdataF[ant][txdataF_offset_per_symbol + block_start];
const c16_t *rot = &frame_parms->symbol_rotation[0][symb_offset + l_symbol];
rotate_cpx_vector(pdsch_sc, rot, pdsch_sc,(block_end - block_start + 1)*NR_NB_SC_PER_RB, 15);
mark_prb_range(rdata->pdsch_phase_comp_prb_mask, rdata->prb_mask_words, l_symbol, block_start, block_end - block_start + 1);
}
}
}
stop_meas(&rdata->dlsch_precoding_stats);
@@ -603,7 +619,12 @@ static void nr_pdsch_symbol_processing(void *arg)
completed_task_ans(rdata->ans);
}
static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch, int slot)
static int do_one_dlsch(unsigned char *input_ptr,
PHY_VARS_gNB *gNB,
NR_gNB_DLSCH_t *dlsch,
int slot,
uint64_t *pdsch_phase_comp_prb_mask,
int prb_mask_words)
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
@@ -652,51 +673,67 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
if (IS_SOFTMODEM_DLSIM)
memcpy(dlsch->f, input_ptr, (encoded_length + 7) >> 3);
c16_t mod_symbs[rel15->NrOfCodewords][encoded_length] __attribute__((aligned(64)));
for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
/// scrambling
start_meas(dlsch_scrambling_stats);
uint32_t scrambled_output[(encoded_length >> 5) + 4]; // modulator acces by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
nr_pdsch_codeword_scrambling(input_ptr, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
#ifdef DEBUG_DLSCH
printf("PDSCH scrambling:\n");
for (int i = 0; i < encoded_length >> 8; i++) {
for (int j = 0; j < 8; j++)
printf("0x%08x\t", scrambled_output[(i << 3) + j]);
printf("\n");
}
#endif
stop_meas(dlsch_scrambling_stats);
/// Modulation
start_meas(dlsch_modulation_stats);
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
stop_meas(dlsch_modulation_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
for (int i = 0; i < nb_re; i += 8) {
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_symbs[codeWord][i + j].r, mod_symbs[codeWord][i + j].i);
}
printf("\n");
}
#endif
}
start_meas(&gNB->dlsch_pdsch_generation_stats);
/// Resource mapping
// Non interleaved VRB to PRB mapping
AssertFatal(n_dmrs, "n_dmrs can't be 0\n");
// make a large enough tail to process all re with SIMD regardless a garbadge filler
start_meas(&gNB->dlsch_layer_mapping_stats);
int layerSz2 = (layerSz + 63) & ~63;
c16_t tx_layers[rel15->nrOfLayers][layerSz2] __attribute__((aligned(64)));
memset(tx_layers, 0, sizeof(tx_layers));
nr_layer_mapping(rel15->NrOfCodewords, encoded_length, mod_symbs, rel15->nrOfLayers, layerSz2, nb_re, tx_layers);
const bool use_fused_mod_layer =
rel15->NrOfCodewords == 1 && (rel15->nrOfLayers == 3 || rel15->nrOfLayers == 4) && (Qm == 2 || Qm == 4 || Qm == 6 || Qm == 8);
if (use_fused_mod_layer) {
start_meas(dlsch_scrambling_stats);
uint32_t scrambled_output[(encoded_length >> 5) + 4]; // modulator access by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
start_meas(dlsch_modulation_stats);
nr_pdsch_codeword_scrambling(input_ptr, encoded_length, 0, rel15->dataScramblingId, rel15->rnti, scrambled_output);
stop_meas(dlsch_scrambling_stats);
const bool fused_ok =
nr_modulation_layer_mapping(scrambled_output, encoded_length, Qm, rel15->nrOfLayers, layerSz2, tx_layers);
AssertFatal(fused_ok,
"Unsupported fused modulation/layer mapping for Qm %d, %d layers, %d codewords\n",
Qm,
rel15->nrOfLayers,
rel15->NrOfCodewords);
stop_meas(dlsch_modulation_stats);
} else {
c16_t mod_symbs[rel15->NrOfCodewords][encoded_length] __attribute__((aligned(64)));
for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
/// scrambling
start_meas(dlsch_scrambling_stats);
uint32_t scrambled_output[(encoded_length >> 5) + 4]; // modulator acces by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
nr_pdsch_codeword_scrambling(input_ptr, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
#ifdef DEBUG_DLSCH
printf("PDSCH scrambling:\n");
for (int i = 0; i < encoded_length >> 8; i++) {
for (int j = 0; j < 8; j++)
printf("0x%08x\t", scrambled_output[(i << 3) + j]);
printf("\n");
}
#endif
stop_meas(dlsch_scrambling_stats);
/// Modulation
start_meas(dlsch_modulation_stats);
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
stop_meas(dlsch_modulation_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
for (int i = 0; i < nb_re; i += 8) {
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_symbs[codeWord][i + j].r, mod_symbs[codeWord][i + j].i);
}
printf("\n");
}
#endif
}
start_meas(&gNB->dlsch_layer_mapping_stats);
nr_layer_mapping(rel15->NrOfCodewords, encoded_length, mod_symbs, rel15->nrOfLayers, layerSz2, nb_re, tx_layers);
stop_meas(&gNB->dlsch_layer_mapping_stats);
}
/// Layer Precoding and Antenna port mapping
// tx_layers 1-8 are mapped on antenna ports 1000-1007
@@ -765,6 +802,8 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
rdata->dlPtrsSymPos = dlPtrsSymPos;
rdata->n_ptrs = n_ptrs;
rdata->ant_to_map = ant_to_map;
rdata->pdsch_phase_comp_prb_mask = pdsch_phase_comp_prb_mask;
rdata->prb_mask_words = prb_mask_words;
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 += freq_alloc->num_rbs * NR_NB_SC_PER_RB;
@@ -798,7 +837,13 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
return ((size_output_tb + 511) >> 9) << 6;
}
void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_array, int frame, int slot)
void nr_generate_pdsch(PHY_VARS_gNB *gNB,
int n_dlsch,
NR_gNB_DLSCH_t *dlsch_array,
int frame,
int slot,
uint64_t *pdsch_phase_comp_prb_mask,
int prb_mask_words)
{
time_stats_t *dlsch_encoding_stats = &gNB->dlsch_encoding_stats;
time_stats_t *tinput = &gNB->tinput;
@@ -884,7 +929,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
unsigned char *output_ptr = output;
for (int i = 0; i < n_dlsch; i++) {
output_ptr += do_one_dlsch(output_ptr, gNB, &dlsch_array[i], slot);
output_ptr += do_one_dlsch(output_ptr, gNB, &dlsch_array[i], slot, pdsch_phase_comp_prb_mask, prb_mask_words);
}
}

View File

@@ -11,7 +11,13 @@
#include "PHY/defs_gNB.h"
void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_array, int frame, int slot);
void nr_generate_pdsch(PHY_VARS_gNB *gNB,
int n_dlsch,
NR_gNB_DLSCH_t *dlsch_array,
int frame,
int slot,
uint64_t *pdsch_phase_comp_prb_mask,
int prb_mask_words);
int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
int n_dlsch,

View File

@@ -16,11 +16,11 @@ void nr_codeword_scrambling(uint8_t *in,
const int roundedSz = (size + 31) / 32;
uint32_t *seq = gold_cache((n_RNTI << 15) + (q << 14) + Nid, roundedSz);
unsigned int i_32 = 0;
#if defined(__AVX512F__) && defined(__AVX512VL__)
#ifdef __AVX2__
for (; i_32 < ((roundedSz >> 3) << 3); i_32 += 8) {
__m256i in_256 = _mm256_load_epi32(&((uint32_t *)in)[i_32]);
__m256i seq_256 = _mm256_load_epi32(&seq[i_32]);
_mm256_storeu_epi32(&out[i_32], _mm256_xor_si256(in_256, seq_256));
__m256i in_256 = _mm256_loadu_si256((void*)&((uint32_t *)in)[i_32]);
__m256i seq_256 = _mm256_loadu_si256((void*)&seq[i_32]);
_mm256_storeu_si256((void*)&out[i_32], _mm256_xor_si256(in_256, seq_256));
}
#endif
#if defined(__aarch64__)

View File

@@ -14,6 +14,7 @@
#include "common/utils/LOG/log.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/MODULATION/nr_modulation.h"
#include "PHY/NR_REFSIG/ss_pbch_nr.h"
#include "T.h"
#include "T_messages_creator.h"
#include "executables/nr-softmodem.h"
@@ -39,6 +40,90 @@ static void nr_fill_indication(const PHY_VARS_gNB *gNB,
nfapi_nr_crc_t *crc,
nfapi_nr_rx_data_pdu_t *pdu);
static inline bool prb_is_rotated(const uint64_t *prb_mask, int prb)
{
return (prb_mask[prb >> 6] >> (prb & 63)) & 0x1;
}
static inline void mark_prb(uint64_t *prb_mask, int prb_mask_words, int symbol, int prb)
{
uint64_t *symbol_mask = prb_mask + symbol * prb_mask_words;
symbol_mask[prb >> 6] |= UINT64_C(1) << (prb & 63);
}
static inline void mark_prb_range(uint64_t *prb_mask, int prb_mask_words, int symbol, int first_prb, int nb_prb)
{
for (int prb = first_prb; prb < first_prb + nb_prb; prb++)
mark_prb(prb_mask, prb_mask_words, symbol, prb);
}
static inline void apply_nr_rotation_TX_segment(const NR_DL_FRAME_PARMS *fp,
c16_t *txdataF,
const c16_t *symbol_rotation,
int slot,
int symbol,
int first_prb,
int nb_prb)
{
const int symb_offset = (slot % fp->slots_per_subframe) * fp->symbols_per_slot;
const c16_t *rot = &symbol_rotation[symb_offset + symbol];
c16_t *this_symbol = txdataF + symbol * fp->ofdm_symbol_size + first_prb * NR_NB_SC_PER_RB;
rotate_cpx_vector(this_symbol, rot, this_symbol, nb_prb * NR_NB_SC_PER_RB, 15);
}
static void merge_prb_mask(const NR_DL_FRAME_PARMS *fp,
const uint64_t *local_prb_mask,
uint64_t *global_prb_mask,
int prb_mask_words)
{
for (int symbol = 0; symbol < fp->symbols_per_slot; symbol++) {
const uint64_t *local_symbol_mask = local_prb_mask + symbol * prb_mask_words;
uint64_t *global_symbol_mask = global_prb_mask + symbol * prb_mask_words;
int prb = 0;
while (prb < fp->N_RB_DL) {
while (prb < fp->N_RB_DL && !prb_is_rotated(local_symbol_mask, prb))
prb++;
const int start_prb = prb;
while (prb < fp->N_RB_DL && prb_is_rotated(local_symbol_mask, prb))
prb++;
if (prb > start_prb) {
for (int rr = start_prb; rr < prb; rr++)
global_symbol_mask[rr >> 6] |= UINT64_C(1) << (rr & 63);
}
}
}
}
static void apply_nr_rotation_TX_masked(const NR_DL_FRAME_PARMS *fp,
c16_t **txdataF,
int num_tx_buffers,
const c16_t *symbol_rotation,
int slot,
const uint64_t *local_prb_mask,
uint64_t *global_prb_mask,
int prb_mask_words)
{
for (int aa = 0; aa < num_tx_buffers; aa++) {
if (!txdataF[aa])
continue;
for (int symbol = 0; symbol < fp->symbols_per_slot; symbol++) {
const uint64_t *local_symbol_mask = local_prb_mask + symbol * prb_mask_words;
int prb = 0;
while (prb < fp->N_RB_DL) {
while (prb < fp->N_RB_DL && !prb_is_rotated(local_symbol_mask, prb))
prb++;
const int start_prb = prb;
while (prb < fp->N_RB_DL && prb_is_rotated(local_symbol_mask, prb))
prb++;
if (prb > start_prb)
apply_nr_rotation_TX_segment(fp, txdataF[aa], symbol_rotation, slot, symbol, start_prb, prb - start_prb);
}
}
}
merge_prb_mask(fp, local_prb_mask, global_prb_mask, prb_mask_words);
}
void beam_index_allocation(uint16_t fapi_beam_index,
int ant,
int num_ports,
@@ -70,7 +155,12 @@ uint16_t get_first_ant_idx(bool das, uint16_t num_ports_beams, uint16_t beam_id,
return ((das) ? (beam_id & 0x7fff) * num_ports_beams : fapi_start_port);
}
void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu)
void nr_common_signal_procedures(PHY_VARS_gNB *gNB,
int frame,
int slot,
const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu,
uint64_t *phase_comp_prb_mask,
int prb_mask_words)
{
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
const nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &ssb_pdu->ssb_pdu_rel15;
@@ -149,6 +239,26 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n
#endif
nr_generate_pbch(gNB, ssb_pdu, txdataF[ant_port], ssb_start_symbol, n_hf, frame, cfg, fp);
if (!gNB->phase_comp)
return;
uint64_t local_phase_comp_prb_mask[fp->symbols_per_slot][prb_mask_words];
memset(local_phase_comp_prb_mask, 0, sizeof(local_phase_comp_prb_mask));
const int ssb_start_prb = fp->ssb_start_subcarrier / NR_NB_SC_PER_RB;
const int ssb_nb_prb = (fp->ssb_start_subcarrier % NR_NB_SC_PER_RB + 240 + NR_NB_SC_PER_RB - 1) / NR_NB_SC_PER_RB;
for (int symbol = ssb_start_symbol; symbol < ssb_start_symbol + NR_N_SYMBOLS_SSB; symbol++)
mark_prb_range(&local_phase_comp_prb_mask[0][0], prb_mask_words, symbol, ssb_start_prb, ssb_nb_prb);
c16_t *ssb_txdataF[] = {txdataF[0]};
apply_nr_rotation_TX_masked(fp,
ssb_txdataF,
1,
fp->symbol_rotation[0],
slot,
&local_phase_comp_prb_mask[0][0],
phase_comp_prb_mask,
prb_mask_words);
}
// clearing beam information to be provided to RU for all slots (DL and UL)
@@ -163,7 +273,11 @@ void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot)
}
}
static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, int slot, const nfapi_nr_dl_tti_csi_rs_pdu *csi_rs_pdu)
static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB,
int slot,
const nfapi_nr_dl_tti_csi_rs_pdu *csi_rs_pdu,
uint64_t *phase_comp_prb_mask,
int prb_mask_words)
{
const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csi_rs_pdu->csi_rs_pdu_rel15;
if (csi_params->csi_type == 2) // ZP-CSI
@@ -213,6 +327,60 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, int slot, const nfapi_nr_d
csi_params->power_control_offset_ss,
csi_params->cdm_type,
gNB->common_vars.txdataF + ant_port_offset);
if (!gNB->phase_comp)
return;
uint64_t local_phase_comp_prb_mask[gNB->frame_parms.symbols_per_slot][prb_mask_words];
memset(local_phase_comp_prb_mask, 0, sizeof(local_phase_comp_prb_mask));
for (int rb = csi_params->start_rb; rb < csi_params->start_rb + csi_params->nr_of_rbs; rb++) {
if ((csi_params->freq_density <= 1) && (csi_params->freq_density != (rb % 2)))
continue;
for (int j = 0; j < mapping_parms.size; j++) {
for (int lp = 0; lp <= mapping_parms.lprime; lp++) {
const int symbol = mapping_parms.loverline[j] + lp;
mark_prb(&local_phase_comp_prb_mask[0][0], prb_mask_words, symbol, rb);
}
}
}
apply_nr_rotation_TX_masked(&gNB->frame_parms,
gNB->common_vars.txdataF,
min(mapping_parms.ports, gNB->gNB_config.carrier_config.num_tx_ant.value),
gNB->frame_parms.symbol_rotation[0],
slot,
&local_phase_comp_prb_mask[0][0],
phase_comp_prb_mask,
prb_mask_words);
}
static void nr_generate_prs_gNB(PHY_VARS_gNB *gNB,
int slot,
int slot_prs,
prs_config_t *prs_config,
uint64_t *phase_comp_prb_mask,
int prb_mask_words)
{
const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
nr_generate_prs(slot_prs, gNB->common_vars.txdataF[0], AMP, prs_config, fp);
if (!gNB->phase_comp)
return;
uint64_t local_phase_comp_prb_mask[fp->symbols_per_slot][prb_mask_words];
memset(local_phase_comp_prb_mask, 0, sizeof(local_phase_comp_prb_mask));
for (int symbol = prs_config->SymbolStart; symbol < prs_config->SymbolStart + prs_config->NumPRSSymbols; symbol++)
mark_prb_range(&local_phase_comp_prb_mask[0][0], prb_mask_words, symbol, prs_config->RBOffset, prs_config->NumRB);
c16_t *prs_txdataF[] = {gNB->common_vars.txdataF[0]};
apply_nr_rotation_TX_masked(fp,
prs_txdataF,
1,
fp->symbol_rotation[0],
slot,
&local_phase_comp_prb_mask[0][0],
phase_comp_prb_mask,
prb_mask_words);
}
void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
@@ -228,6 +396,10 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
if ((cfg->cell_config.frame_duplex_type.value == TDD) && (nr_slot_select(cfg,frame,slot) == NR_UPLINK_SLOT))
return;
const int prb_mask_words = (fp->N_RB_DL + 63) >> 6;
uint64_t phase_comp_prb_mask[gNB->common_vars.num_beams_period][fp->symbols_per_slot][prb_mask_words];
memset(phase_comp_prb_mask, 0, sizeof(phase_comp_prb_mask));
// clear the transmit data array and beam index for the current slot
for (int aa = 0; aa < fp->nb_antennas_tx; aa++) {
memset(gNB->common_vars.txdataF[aa], 0, fp->samples_per_slot_wCP * sizeof(**gNB->common_vars.txdataF));
@@ -243,26 +415,41 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
{
int slot_prs = (slot - i * prs_config->PRSResourceTimeGap + fp->slots_per_frame) % fp->slots_per_frame;
LOG_D(PHY,"gNB_TX: frame %d, slot %d, slot_prs %d, PRS Resource ID %d\n",frame, slot, slot_prs, rsc_id);
nr_generate_prs(slot_prs, gNB->common_vars.txdataF[0], AMP, prs_config, fp);
nr_generate_prs_gNB(gNB, slot, slot_prs, prs_config, &phase_comp_prb_mask[0][0][0], prb_mask_words);
}
}
}
for (int i = 0; i < UL_dci_req->numPdus; ++i)
nr_generate_dci(gNB, &UL_dci_req->ul_dci_pdu_list[i].pdcch_pdu.pdcch_pdu_rel15, &gNB->frame_parms, slot);
nr_generate_dci(gNB,
&UL_dci_req->ul_dci_pdu_list[i].pdcch_pdu.pdcch_pdu_rel15,
&gNB->frame_parms,
slot,
&phase_comp_prb_mask[0][0][0],
prb_mask_words);
int num_pdsch = 0;
for (int i = 0; i < DL_req->dl_tti_request_body.nPDUs; ++i) {
const nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu = &DL_req->dl_tti_request_body.dl_tti_pdu_list[i];
switch (dl_tti_pdu->PDUType) {
case NFAPI_NR_DL_TTI_SSB_PDU_TYPE:
nr_common_signal_procedures(gNB, frame, slot, &dl_tti_pdu->ssb_pdu);
nr_common_signal_procedures(gNB,
frame,
slot,
&dl_tti_pdu->ssb_pdu,
&phase_comp_prb_mask[0][0][0],
prb_mask_words);
break;
case NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE:
nr_generate_dci(gNB, &dl_tti_pdu->pdcch_pdu.pdcch_pdu_rel15, &gNB->frame_parms, slot);
nr_generate_dci(gNB,
&dl_tti_pdu->pdcch_pdu.pdcch_pdu_rel15,
&gNB->frame_parms,
slot,
&phase_comp_prb_mask[0][0][0],
prb_mask_words);
break;
case NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE:
nr_generate_csi_rs_gNB(gNB, slot, &dl_tti_pdu->csi_rs_pdu);
nr_generate_csi_rs_gNB(gNB, slot, &dl_tti_pdu->csi_rs_pdu, &phase_comp_prb_mask[0][0][0], prb_mask_words);
break;
case NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE: {
int tx_data_idx = dl_tti_pdu->pdsch_pdu.pdsch_pdu_rel15.pduIndex;
@@ -287,28 +474,17 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
if (num_pdsch > 0) {
LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", num_pdsch, frame, slot);
nr_generate_pdsch(gNB, num_pdsch, gNB->dlsch, frame, slot);
nr_generate_pdsch(gNB, num_pdsch, gNB->dlsch, frame, slot, &phase_comp_prb_mask[0][0][0], prb_mask_words);
}
//apply the OFDM symbol rotation here
start_meas(&gNB->phase_comp_stats);
for (int aa = 0; aa < fp->nb_antennas_tx; aa++) {
if (gNB->phase_comp) {
apply_nr_rotation_TX(fp,
gNB->common_vars.txdataF[aa],
true,
fp->symbol_rotation[0],
slot,
fp->N_RB_DL,
0,
fp->Ncp == NR_EXTENDED ? 12 : 14);
}
T(T_GNB_PHY_DL_OUTPUT_SIGNAL,
T_INT(0),
T_INT(frame),
T_INT(slot),
T_INT(aa),
T_BUFFER(gNB->common_vars.txdataF[aa], fp->samples_per_slot_wCP * sizeof(int32_t)));
for (int aa = 0; aa < cfg->carrier_config.num_tx_ant.value; aa++) {
T(T_GNB_PHY_DL_OUTPUT_SIGNAL,
T_INT(0),
T_INT(frame),
T_INT(slot),
T_INT(aa),
T_BUFFER(gNB->common_vars.txdataF[aa], fp->samples_per_slot_wCP * sizeof(int32_t)));
}
stop_meas(&gNB->phase_comp_stats);
}

View File

@@ -19,7 +19,12 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req);
int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO);
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, prach_item_t *prach_id, nfapi_nr_rach_indication_t *rach_ind);
void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu);
void nr_common_signal_procedures(PHY_VARS_gNB *gNB,
int frame,
int slot,
const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu,
uint64_t *phase_comp_prb_mask,
int prb_mask_words);
void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx);
void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa);
void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx);

View File

@@ -745,7 +745,6 @@ int main(int argc, char **argv)
AssertFatal((gNB->if_inst = NR_IF_Module_init(0)) != NULL, "Cannot register interface");
gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
gNB->num_pdsch_symbols_per_thread = num_pdsch_symbols_per_thread;
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));;
prepare_scc(scc);
@@ -849,6 +848,7 @@ int main(int argc, char **argv)
// nr_mac_config_scc()
gNB_mac->pre_processor_dl = nr_dlsim_preprocessor;
phy_init_nr_gNB(gNB);
gNB->num_pdsch_symbols_per_thread = num_pdsch_symbols_per_thread;
N_RB_DL = gNB->frame_parms.N_RB_DL;
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.connected_ue_list[0];
@@ -1447,16 +1447,21 @@ int main(int argc, char **argv)
printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time");
printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Matching time");
printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time");
printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time");
printStatIndent2(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time");
printStatIndent2(&gNB->dlsch_pdsch_generation_stats,"DLSCH PDSCH Generation time");
printStatIndent3(&gNB->dlsch_layer_mapping_stats,"DLSCH Layer Mapping time");
gNB->dlsch_resource_mapping_stats.trials = gNB->dlsch_layer_mapping_stats.trials;
printStatIndent3(&gNB->dlsch_resource_mapping_stats,"DLSCH Resource Mapping time");
gNB->dlsch_precoding_stats.trials = gNB->dlsch_layer_mapping_stats.trials;
printStatIndent3(&gNB->dlsch_precoding_stats,"DLSCH Precoding time");
if (gNB->phase_comp)
printStatIndent2(&gNB->phase_comp_stats, "Phase Compensation");
printStatIndent3(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time");
if (gNB->dlsch_layer_mapping_stats.trials > 0) {
printStatIndent3(&gNB->dlsch_modulation_stats,"DLSCH modulation time");
printStatIndent3(&gNB->dlsch_layer_mapping_stats,"DLSCH Layer Mapping time");
}
else {
printStatIndent3(&gNB->dlsch_modulation_stats,"DLSCH mod/lm time");
}
if (num_pdsch_symbols_per_thread == 0) {
gNB->dlsch_resource_mapping_stats.trials = gNB->dlsch_modulation_stats.trials;
if (gNB->dlsch_precoding_stats.trials > 0) printStatIndent3(&gNB->dlsch_resource_mapping_stats,"DLSCH Resource Mapping time");
gNB->dlsch_precoding_stats.trials = gNB->dlsch_modulation_stats.trials;
if (gNB->dlsch_precoding_stats.trials > 0) printStatIndent3(&gNB->dlsch_precoding_stats,"DLSCH Precoding time");
}
if (use_cuda) {
printStatIndent(&pipeline_stats, "GPU Channel Pipeline");

View File

@@ -396,6 +396,7 @@ int main(int argc, char **argv)
RC.gNB[0] = malloc16_clear(sizeof(*(RC.gNB[0])));
gNB = RC.gNB[0];
gNB->ofdm_offset_divisor = UINT_MAX;
gNB->phase_comp = true;
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
frame_parms->nb_antennas_tx = n_tx;
frame_parms->nb_antennas_rx = n_rx;
@@ -489,6 +490,9 @@ int main(int argc, char **argv)
__attribute__ ((aligned(32))) c16_t rxdataF[UE->frame_parms.nb_antennas_rx][rxdataF_sz];
nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64] = {0};
if (input_fd==NULL) {
const int prb_mask_words = (frame_parms->N_RB_DL + 63) / 64;
uint64_t phase_comp_prb_mask[gNB->common_vars.num_beams_period][frame_parms->symbols_per_slot][prb_mask_words];
memset(phase_comp_prb_mask, 0, sizeof(phase_comp_prb_mask));
for (i=0; i<frame_parms->Lmax; i++) {
if((SSB_positions >> i) & 0x01) {
@@ -506,22 +510,18 @@ int main(int argc, char **argv)
for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++)
memset(gNB->common_vars.txdataF[aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t));
nr_common_signal_procedures (gNB,frame,slot, &ssb_pdu[i]);
nr_common_signal_procedures(gNB,
frame,
slot,
&ssb_pdu[i],
&phase_comp_prb_mask[0][0][0],
prb_mask_words);
int samp = get_samples_slot_timestamp(frame_parms, slot);
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[aa],
true,
frame_parms->symbol_rotation[0],
slot,
frame_parms->N_RB_DL,
0,
12);
fft_shift(gNB->common_vars.txdataF[aa],
frame_parms->ofdm_symbol_size,
frame_parms->N_RB_DL,
@@ -537,15 +537,6 @@ int main(int argc, char **argv)
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
} else {
apply_nr_rotation_TX(frame_parms,
gNB->common_vars.txdataF[aa],
true,
frame_parms->symbol_rotation[0],
slot,
frame_parms->N_RB_DL,
0,
14);
fft_shift(gNB->common_vars.txdataF[aa],
frame_parms->ofdm_symbol_size,
frame_parms->N_RB_DL,