mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-18 15:10:29 +00:00
Compare commits
6 Commits
develop
...
gNB_TX_opt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b7b75a8e2 | ||
|
|
2f2a3c1f71 | ||
|
|
ee22b6e83a | ||
|
|
f668d2e527 | ||
|
|
3ff24df579 | ||
|
|
66253f2289 |
@@ -202,6 +202,8 @@ elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=neoverse-n1 -lgcc -lrt")
|
||||
elseif (CPUPART MATCHES "0xd49") # Neoverse-N2
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=neoverse-n2 -ftree-vectorize -lgcc -lrt")
|
||||
elseif (CPUPART MATCHES "0xd08") # Cortex-A72 (e.g. NXP LS2160A)
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=cortex-a72 -lgcc -lrt")
|
||||
elseif (CPUPART MATCHES "0xd03") # Cortex-A53
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -gdwarf-2 -mcpu=cortex-a53 -lgcc -lrt")
|
||||
else ()
|
||||
@@ -212,8 +214,11 @@ else()
|
||||
endif()
|
||||
|
||||
if (NOT CROSS_COMPILE)
|
||||
if (CPUPART MATCHES "0xd03")
|
||||
# Cortex-A53 does not support ARMv8.2-A extensions
|
||||
if (CPUPART MATCHES "0xd08")
|
||||
# Cortex-A72 is ARMv8.0-A only (no ARMv8.2-A); hardware includes crypto (aes, pmull, sha1, sha2)
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a+simd+crypto")
|
||||
elseif (CPUPART MATCHES "0xd03")
|
||||
# Cortex-A53 is ARMv8.0-A only; crypto extension is optional and not assumed present
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a+simd")
|
||||
else()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native")
|
||||
|
||||
@@ -280,6 +280,10 @@ one_measurement_t test_ldpc(short max_iterations,
|
||||
stop_meas(&time);
|
||||
|
||||
impp.n_segments = n_segments;
|
||||
impp.tinput = &tinput;
|
||||
impp.tparity = &tparity;
|
||||
impp.toutput = &toutput;
|
||||
impp.tinput_memcpy = &tprep;
|
||||
start_meas(&ret.time_optim);
|
||||
impp.first_seg = 0;
|
||||
ldpc_toCompare.LDPCencoder(test_input, channel_input_optim, &impp);
|
||||
|
||||
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc176_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc176_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc192_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc192_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc208_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc208_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc224_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc224_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc240_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc240_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc256_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc256_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc288_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc288_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc320_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc320_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc352_alignr_byte_128.c
Normal file
151
openair1/PHY/CODING/nrLDPC_encoder/ldpc352_alignr_byte_128.c
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -23,32 +23,40 @@
|
||||
// high-throughput cases. The version with "permutex2var" instruction uses less memory (i.e. 1/64th of the memory to store the
|
||||
// input), but uses more reads instead of creating 64 shifts of the input with memcpy
|
||||
#include "ldpc384_simd512_permutex_byte.c"
|
||||
#else
|
||||
#else
|
||||
#include "ldpc384_simd512_byte.c"
|
||||
#endif
|
||||
#else
|
||||
#include "ldpc384_byte.c"
|
||||
#endif
|
||||
#ifdef USE_ALIGNR
|
||||
#include "ldpc384_alignr_byte_128.c"
|
||||
#include "ldpc352_alignr_byte_128.c"
|
||||
#include "ldpc320_alignr_byte_128.c"
|
||||
#include "ldpc288_alignr_byte_128.c"
|
||||
#include "ldpc256_alignr_byte_128.c"
|
||||
#include "ldpc240_alignr_byte_128.c"
|
||||
#include "ldpc224_alignr_byte_128.c"
|
||||
#include "ldpc208_alignr_byte_128.c"
|
||||
#include "ldpc192_alignr_byte_128.c"
|
||||
#include "ldpc176_alignr_byte_128.c"
|
||||
#else
|
||||
#include "ldpc384_byte_128.c"
|
||||
#endif
|
||||
#include "ldpc384_byte.c"
|
||||
#include "ldpc352_byte.c"
|
||||
#include "ldpc352_byte_128.c"
|
||||
#include "ldpc320_byte.c"
|
||||
#include "ldpc320_byte_128.c"
|
||||
#include "ldpc288_byte.c"
|
||||
#include "ldpc288_byte_128.c"
|
||||
#include "ldpc256_byte.c"
|
||||
#include "ldpc256_byte_128.c"
|
||||
#include "ldpc240_byte.c"
|
||||
#include "ldpc224_byte.c"
|
||||
#include "ldpc224_byte_128.c"
|
||||
#include "ldpc208_byte.c"
|
||||
#include "ldpc192_byte.c"
|
||||
#include "ldpc192_byte_128.c"
|
||||
#include "ldpc176_byte.c"
|
||||
#include "ldpc384_byte_128.c"
|
||||
#include "ldpc352_byte_128.c"
|
||||
#include "ldpc320_byte_128.c"
|
||||
#include "ldpc288_byte_128.c"
|
||||
#include "ldpc256_byte_128.c"
|
||||
#include "ldpc224_byte_128.c"
|
||||
#include "ldpc192_byte_128.c"
|
||||
#endif
|
||||
#include "ldpc_BG2_Zc384_byte.c"
|
||||
#include "ldpc_BG2_Zc384_byte_128.c"
|
||||
#include "ldpc_BG2_Zc352_byte.c"
|
||||
@@ -82,7 +90,14 @@
|
||||
|
||||
static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG, short Zc, int simd_size, int ncols, time_stats_t *tinput_memcpy)
|
||||
{
|
||||
unsigned char c[2 * 22 * Zc * simd_size] __attribute__((aligned(64))); //double size matrix of c
|
||||
// For the alignr path (aarch64, BG1, Zc=384) the simd_size copies are skipped,
|
||||
// so only one copy is needed — avoid a 32x overallocation on the stack.
|
||||
#ifdef USE_ALIGNR
|
||||
int vla_simd = (BG == 1 && Zc >= 176) ? 1 : simd_size;
|
||||
#else
|
||||
int vla_simd = simd_size;
|
||||
#endif
|
||||
unsigned char c[2 * 22 * Zc * vla_simd] __attribute__((aligned(64))); //double size matrix of c
|
||||
if (tinput_memcpy)
|
||||
start_meas(tinput_memcpy);
|
||||
for (int i1 = 0; i1 < ncols; i1++) {
|
||||
@@ -90,7 +105,7 @@ static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG, sh
|
||||
memcpy(&c[(2 * i1 + 1) * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char));
|
||||
}
|
||||
#if (defined(USE_PERMUTEX) && defined(__AVX512VBMI__)) || defined(USE_ALIGNR)
|
||||
if (Zc < 384 || BG == 2)
|
||||
if (BG == 2)
|
||||
#endif
|
||||
{
|
||||
for (int i1 = 1; i1 < simd_size; i1++) {
|
||||
|
||||
@@ -36,6 +36,7 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
|
||||
int nind=0;
|
||||
int indlist[1000];
|
||||
int indlist2[1000];
|
||||
int indlist3[1000];
|
||||
|
||||
const short *Gen_shift_values = choose_generator_matrix(BG, Zc);
|
||||
if (Gen_shift_values==NULL) {
|
||||
@@ -193,6 +194,51 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
|
||||
}
|
||||
fclose(fd);
|
||||
fclose(fd2);
|
||||
|
||||
// 4-wide 128-bit variant: process 4 consecutive i2 values per outer iteration.
|
||||
// Each group of 4 x 16-byte loads to the same base index lands in one 64-byte
|
||||
// cache line, matching AVX-512 cache utilisation using four NEON registers.
|
||||
if ((Zc & 63) == 0) {
|
||||
sprintf(fname,"ldpc_BG%d_Zc%d_byte_128_x4.c",BG,Zc);
|
||||
FILE *fd3 = fopen(fname,"w");
|
||||
AssertFatal(fd3!=NULL,"cannot open %s\n",fname);
|
||||
fprintf(fd3,"#include \"PHY/sse_intrin.h\"\n");
|
||||
fprintf(fd3,"// generated code for Zc=%d, 4-wide 128-bit byte encoding\n",Zc);
|
||||
fprintf(fd3,"static inline void ldpc_BG%d_Zc%d_byte_128_x4(uint8_t *c,uint8_t *d) {\n",BG,Zc);
|
||||
fprintf(fd3," simde__m128i *csimd=(simde__m128i *)c,*dsimd=(simde__m128i *)d;\n");
|
||||
fprintf(fd3," simde__m128i *c2_0,*c2_1,*c2_2,*c2_3;\n");
|
||||
fprintf(fd3," simde__m128i *d2_0,*d2_1,*d2_2,*d2_3;\n");
|
||||
fprintf(fd3," int i2;\n");
|
||||
fprintf(fd3," for (i2=0; i2<%d; i2+=4) {\n",Zc>>4);
|
||||
fprintf(fd3," c2_0=&csimd[i2]; c2_1=&csimd[i2+1]; c2_2=&csimd[i2+2]; c2_3=&csimd[i2+3];\n");
|
||||
fprintf(fd3," d2_0=&dsimd[i2]; d2_1=&dsimd[i2+1]; d2_2=&dsimd[i2+2]; d2_3=&dsimd[i2+3];\n");
|
||||
|
||||
for (i1 = 0; i1 < nrows; i1++) {
|
||||
fprintf(fd3,"\n//row: %d\n",i1);
|
||||
int row_offset3 = (Zc*i1)>>4;
|
||||
// recompute index list with 128-bit shift/mask
|
||||
int nind3 = 0;
|
||||
for (i3=0; i3 < ncols; i3++) {
|
||||
int tp = i1 * ncols + i3;
|
||||
for (i4=0; i4 < no_shift_values[tp]; i4++) {
|
||||
int v = (int)((i3*Zc + (Gen_shift_values[pointer_shift_values[tp]+i4]+1)%Zc)/Zc);
|
||||
int idx = v*2*Zc + (i3*Zc + (Gen_shift_values[pointer_shift_values[tp]+i4]+1)%Zc) % Zc;
|
||||
indlist3[nind3++] = ((idx&15)*((2*Zc*ncols)>>4))+(idx>>4);
|
||||
}
|
||||
}
|
||||
int stream;
|
||||
for (stream=0; stream<4; stream++) {
|
||||
fprintf(fd3," d2_%d[%d]=",stream,row_offset3);
|
||||
for (i4=0; i4<nind3-1; i4++)
|
||||
fprintf(fd3,"simde_mm_xor_si128(c2_%d[%d],",stream,indlist3[i4]);
|
||||
fprintf(fd3,"c2_%d[%d]",stream,indlist3[i4]);
|
||||
for (i4=0; i4<nind3-1; i4++) fprintf(fd3,")");
|
||||
fprintf(fd3,";\n");
|
||||
}
|
||||
}
|
||||
fprintf(fd3," }\n}\n");
|
||||
fclose(fd3);
|
||||
}
|
||||
}
|
||||
else if(gen_code==0)
|
||||
{
|
||||
|
||||
@@ -134,28 +134,78 @@ int LDPCencoder(uint8_t **input, uint8_t *output, encoder_implemparams_t *impp)
|
||||
#endif
|
||||
|
||||
#ifdef __aarch64__
|
||||
simde__m128i shufmask = simde_mm_set_epi64x(0x0101010101010101, 0x0000000000000000);
|
||||
simde__m128i andmask = simde_mm_set1_epi64x(0x0102040810204080); // every 8 bits -> 8 bytes, pattern repeats.
|
||||
simde__m128i zero128 = simde_mm_setzero_si128();
|
||||
simde__m128i masks[8];
|
||||
register simde__m128i c128;
|
||||
masks[0] = simde_mm_set1_epi8(0x1);
|
||||
masks[1] = simde_mm_set1_epi8(0x2);
|
||||
masks[2] = simde_mm_set1_epi8(0x4);
|
||||
masks[3] = simde_mm_set1_epi8(0x8);
|
||||
masks[4] = simde_mm_set1_epi8(0x10);
|
||||
masks[5] = simde_mm_set1_epi8(0x20);
|
||||
masks[6] = simde_mm_set1_epi8(0x40);
|
||||
masks[7] = simde_mm_set1_epi8(0x80);
|
||||
// Direct NEON: broadcast 1 byte to all 8 lanes (ldr-b + dup), VTST bit-test mask.
|
||||
// ns=8 fast path: fully unrolled, 2-level asm-volatile barrier OR-tree, no j-loop
|
||||
// overhead. Barrier 1 forces 4 independent level-1 ORRs; GCC fills the level-2
|
||||
// ORR latency gap with scalar loop work, letting A72's OoO engine start the next
|
||||
// iteration's address computation while ORRs are still in flight.
|
||||
#include <arm_neon.h>
|
||||
static const uint8_t _amask[16] __attribute__((aligned(16))) =
|
||||
{0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
|
||||
0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
|
||||
const uint8x16_t amask_v = vld1q_u8(_amask);
|
||||
uint8x16_t segmasks[8];
|
||||
for (int k = 0; k < 8; k++) segmasks[k] = vdupq_n_u8(1u << k);
|
||||
|
||||
for (; i_byte < ((block_length >> 4 ) << 4); i_byte += 16) {
|
||||
unsigned int i = i_byte >> 4;
|
||||
c128 = simde_mm_and_si128(simde_mm_cmpeq_epi8(simde_mm_andnot_si128(simde_mm_shuffle_epi8(simde_mm_set1_epi16(((uint16_t*)input[macro_segment])[i]), shufmask),andmask),zero128),masks[0]);
|
||||
for (int j=macro_segment+1; j < macro_segment_end; j++) {
|
||||
c128 = simde_mm_or_si128(simde_mm_and_si128(simde_mm_cmpeq_epi8(simde_mm_andnot_si128(simde_mm_shuffle_epi8(simde_mm_set1_epi32(((uint16_t*)input[j])[i]), shufmask),andmask),zero128),masks[j-macro_segment]),c128);
|
||||
#define CONTRIB(p, bi, k) \
|
||||
vandq_u8(vtstq_u8(vcombine_u8(vld1_dup_u8((p) + (bi)), \
|
||||
vld1_dup_u8((p) + (bi) + 1)), amask_v), segmasks[k])
|
||||
|
||||
int ns = (int)(macro_segment_end - macro_segment);
|
||||
if (ns == 8) {
|
||||
// Pre-extract segment base pointers so GCC holds them in registers across the loop.
|
||||
const uint8_t *p0 = input[macro_segment + 0];
|
||||
const uint8_t *p1 = input[macro_segment + 1];
|
||||
const uint8_t *p2 = input[macro_segment + 2];
|
||||
const uint8_t *p3 = input[macro_segment + 3];
|
||||
const uint8_t *p4 = input[macro_segment + 4];
|
||||
const uint8_t *p5 = input[macro_segment + 5];
|
||||
const uint8_t *p6 = input[macro_segment + 6];
|
||||
const uint8_t *p7 = input[macro_segment + 7];
|
||||
for (; i_byte < ((block_length >> 4) << 4); i_byte += 16) {
|
||||
unsigned int bi = i_byte >> 3;
|
||||
uint8x16_t r0 = CONTRIB(p0, bi, 0);
|
||||
uint8x16_t r1 = CONTRIB(p1, bi, 1);
|
||||
uint8x16_t r2 = CONTRIB(p2, bi, 2);
|
||||
uint8x16_t r3 = CONTRIB(p3, bi, 3);
|
||||
uint8x16_t r4 = CONTRIB(p4, bi, 4);
|
||||
uint8x16_t r5 = CONTRIB(p5, bi, 5);
|
||||
uint8x16_t r6 = CONTRIB(p6, bi, 6);
|
||||
uint8x16_t r7 = CONTRIB(p7, bi, 7);
|
||||
// Barrier 1: force all 8 contributions into physical NEON registers before
|
||||
// any ORR starts. Without this GCC greedily issues each ORR as soon as ONE
|
||||
// input is ready, producing a 7-step serial left-fold (28-cycle critical path).
|
||||
asm volatile ("" : "+w"(r0), "+w"(r1), "+w"(r2), "+w"(r3),
|
||||
"+w"(r4), "+w"(r5), "+w"(r6), "+w"(r7));
|
||||
// Level-1 ORRs: all 4 are data-independent; A72's 2-wide NEON issues pairs/cycle.
|
||||
uint8x16_t r01 = vorrq_u8(r0, r1);
|
||||
uint8x16_t r23 = vorrq_u8(r2, r3);
|
||||
uint8x16_t r45 = vorrq_u8(r4, r5);
|
||||
uint8x16_t r67 = vorrq_u8(r6, r7);
|
||||
// Barrier 2: force all level-1 results into registers before level-2.
|
||||
// GCC's scheduler then fills the level-2 ORR latency gap with the loop's
|
||||
// scalar work (add i_byte, cmp), placing those instructions between the
|
||||
// level-2 and level-3/4 ORRs. This lets the A72's OoO engine start the
|
||||
// next iteration's address computation (lsr bi = i_byte>>3) ~4 cycles earlier
|
||||
// than if the scalar work came after all ORRs, hiding load latency for free.
|
||||
asm volatile ("" : "+w"(r01), "+w"(r23), "+w"(r45), "+w"(r67));
|
||||
vst1q_u8(cc + i_byte, vorrq_u8(vorrq_u8(r01, r23), vorrq_u8(r45, r67)));
|
||||
}
|
||||
} else {
|
||||
uint8x16_t c128_v, vv;
|
||||
for (; i_byte < ((block_length >> 4) << 4); i_byte += 16) {
|
||||
unsigned int bi = i_byte >> 3;
|
||||
vv = vcombine_u8(vld1_dup_u8(input[macro_segment] + bi),
|
||||
vld1_dup_u8(input[macro_segment] + bi + 1));
|
||||
c128_v = vandq_u8(vtstq_u8(vv, amask_v), segmasks[0]);
|
||||
for (int j = macro_segment + 1; j < macro_segment_end; j++) {
|
||||
vv = vcombine_u8(vld1_dup_u8(input[j] + bi), vld1_dup_u8(input[j] + bi + 1));
|
||||
c128_v = vorrq_u8(vandq_u8(vtstq_u8(vv, amask_v), segmasks[j - macro_segment]), c128_v);
|
||||
}
|
||||
vst1q_u8(cc + i_byte, c128_v);
|
||||
}
|
||||
((simde__m128i *)cc)[i] = c128;
|
||||
}
|
||||
#undef CONTRIB
|
||||
#endif
|
||||
|
||||
for (; i_byte < block_length; i_byte++) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
@@ -810,6 +855,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
|
||||
time_stats_t *dlsch_rate_matching_stats = &gNB->dlsch_rate_matching_stats;
|
||||
time_stats_t *dlsch_interleaving_stats = &gNB->dlsch_interleaving_stats;
|
||||
time_stats_t *dlsch_segmentation_stats = &gNB->dlsch_segmentation_stats;
|
||||
time_stats_t *dlsch_crc_stats = &gNB->dlsch_crc_stats;
|
||||
|
||||
size_t size_output = 0;
|
||||
|
||||
@@ -876,7 +922,8 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
|
||||
tconcat,
|
||||
dlsch_rate_matching_stats,
|
||||
dlsch_interleaving_stats,
|
||||
dlsch_segmentation_stats)
|
||||
dlsch_segmentation_stats,
|
||||
dlsch_crc_stats)
|
||||
== -1) {
|
||||
return;
|
||||
}
|
||||
@@ -884,7 +931,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -27,7 +33,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
time_stats_t *tconcat,
|
||||
time_stats_t *dlsch_rate_matching_stats,
|
||||
time_stats_t *dlsch_interleaving_stats,
|
||||
time_stats_t *dlsch_segmentation_stats);
|
||||
time_stats_t *dlsch_segmentation_stats,
|
||||
time_stats_t *dlsch_crc_stats);
|
||||
|
||||
void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB);
|
||||
|
||||
|
||||
@@ -98,7 +98,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
time_stats_t *tconcat,
|
||||
time_stats_t *dlsch_rate_matching_stats,
|
||||
time_stats_t *dlsch_interleaving_stats,
|
||||
time_stats_t *dlsch_segmentation_stats)
|
||||
time_stats_t *dlsch_segmentation_stats,
|
||||
time_stats_t *dlsch_crc_stats)
|
||||
{
|
||||
nrLDPC_TB_encoding_parameters_t TBs[n_dlsch];
|
||||
memset(TBs, 0, sizeof(TBs));
|
||||
@@ -140,6 +141,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0];
|
||||
}
|
||||
|
||||
start_meas(dlsch_crc_stats);
|
||||
int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * rel15->nrOfLayers * 1056;
|
||||
int B;
|
||||
if (A > NR_MAX_PDSCH_TBS) {
|
||||
@@ -165,6 +167,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
memcpy(dlsch->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc
|
||||
}
|
||||
|
||||
stop_meas(dlsch_crc_stats);
|
||||
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i];
|
||||
|
||||
// The harq_pid is not unique among the active HARQ processes in the instance so we use i instead
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -437,6 +437,7 @@ typedef struct PHY_VARS_gNB_s {
|
||||
time_stats_t dlsch_rate_matching_stats;
|
||||
time_stats_t dlsch_interleaving_stats;
|
||||
time_stats_t dlsch_segmentation_stats;
|
||||
time_stats_t dlsch_crc_stats;
|
||||
|
||||
time_stats_t dci_generation_stats;
|
||||
time_stats_t phase_comp_stats;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -1046,6 +1046,7 @@ int main(int argc, char **argv)
|
||||
reset_meas(&gNB->dlsch_interleaving_stats);
|
||||
reset_meas(&gNB->dlsch_rate_matching_stats);
|
||||
reset_meas(&gNB->dlsch_segmentation_stats);
|
||||
reset_meas(&gNB->dlsch_crc_stats);
|
||||
reset_meas(&gNB->dlsch_modulation_stats);
|
||||
reset_meas(&gNB->dlsch_pdsch_generation_stats);
|
||||
reset_meas(&gNB->dlsch_precoding_stats);
|
||||
@@ -1440,6 +1441,7 @@ int main(int argc, char **argv)
|
||||
printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx");
|
||||
printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time");
|
||||
printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
|
||||
printStatIndent3(&gNB->dlsch_crc_stats,"DLSCH Outer CRC time");
|
||||
printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time");
|
||||
printStatIndent3(&gNB->tinput,"DLSCH LDPC input processing time");
|
||||
printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time");
|
||||
@@ -1447,16 +1449,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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
Submodule openair2/E2AP/flexric updated: ef6d722f22...340c36bc83
Reference in New Issue
Block a user