Compare commits

...

67 Commits

Author SHA1 Message Date
Raymond Knopp
005d2b8075 initial commit of fp16 procedures (tested only on TX for AVX512_FP16) 2026-02-05 03:21:12 +01:00
Raymond Knopp
2c85c8f024 fp16 changes for rotation on aarch64 (merge conversion to q15 at output with rotation) 2025-12-26 18:08:32 +00:00
Raymond Knopp
3872bf9ae5 fp16 testing x86 2025-12-26 08:53:14 +01:00
Raymond Knopp
d1328fd61f Merge remote-tracking branch 'origin/rm_interleaving_simd' into fp16_tx 2025-12-24 15:31:29 +01:00
Raymond Knopp
05c022c476 Merge branch 'ldpc_encoder_cuda' into ldpc_encoder_cuda_gh200 2025-12-23 21:38:34 +00:00
Raymond Knopp
db6f2acfb5 Merge remote-tracking branch 'origin/develop' into ldpc_encoder_cuda 2025-12-22 10:06:12 +00:00
Raymond.Knopp
f43544d078 deinterleaving tail condition for SSE4/SIMDe 2025-12-20 14:23:11 +01:00
Raymond Knopp
b6fc82ed08 fixed bug detected by clang 2025-12-20 11:04:26 +01:00
Raymond Knopp
665135c0ef refresh flexric 2025-12-20 10:54:12 +01:00
Raymond Knopp
862b738105 Merge branch 'develop' into rm_interleaving_simd 2025-12-20 10:39:38 +01:00
Raymond Knopp
9526463e81 attribute(aligned) for gcc>12 2025-12-20 10:27:53 +01:00
Raymond Knopp
98c3354d63 nothing 2025-12-20 10:20:19 +01:00
Raymond Knopp
f5916e97dd minor cleanup 2025-12-19 06:27:01 +00:00
Raymond Knopp
055f5af403 fix for 6-way deinterleave on aarch64 2025-12-19 06:21:31 +00:00
Raymond Knopp
96fc26f2b3 modifiations for LDPC rate-matching and deinterleaving for various SIMD configurations 2025-12-18 10:02:55 +00:00
Raymond Knopp
3873022325 gh200 configurations 2025-10-28 13:02:28 +00:00
Raymond Knopp
c21edcba55 ldpctest memory allocations 2025-10-28 12:02:55 +01:00
Raymond Knopp
29f1cc36be intermediate commit 2025-10-14 17:50:13 +00:00
Raymond Knopp
80f628954b Merge branch 'precoder_optimization' into ldpc_encoder_cuda 2025-10-03 13:11:36 +00:00
Raymond Knopp
d4dcf33f69 more support for fp16 2025-09-29 05:44:18 +00:00
Raymond Knopp
c7c2c6390a Merge remote-tracking branch 'origin/develop' into ldpc_encoder_cuda 2025-09-28 15:51:05 +00:00
Raymond Knopp
9eb2034208 first set of changes to support fp16 arithmetic. modulation table generation, options to run with fp16 in gNB/UE. 2025-09-28 07:51:14 +00:00
Laurent THOMAS
50f98554b5 use c16_t type for pm weights, as it is already same type
simplify SIMD version of precoder
2025-09-24 17:15:04 +02:00
Raymond Knopp
bfcde899df fixed precoder_simd after CI run (test for n_layers=1) failed 2025-09-24 09:20:00 +02:00
Raymond Knopp
4abcdc7ba9 aarch64 optimizations for precoding, more complete timing reporting in
nr_dlsim
2025-09-24 09:20:00 +02:00
Raymond Knopp
4a8b592e11 optimization of DLSCH precoding for AVX2 2025-09-24 09:20:00 +02:00
Raymond Knopp
43bb81a7fa precoder optimizations for AVX512 2025-09-24 09:20:00 +02:00
Raymond Knopp
d62b522b05 Handle larger RB step size in precoding 2025-09-24 09:20:00 +02:00
Raymond Knopp
65076a200b Add measurements for performance analysis 2025-09-24 09:20:00 +02:00
Raymond Knopp
4057b35034 fix for compiler definition 2025-09-22 11:56:19 +00:00
Raymond Knopp
d8dc0120b2 fix for use_gpu flag 2025-09-20 09:54:20 +00:00
Raymond Knopp
458797dba5 added build options for including CUDA in OAI L1 libraries. Some initial
memory allocations for CUDA targets (harq->b) for gNB transmitter
2025-09-20 11:43:58 +02:00
Raymond Knopp
75ea127b16 input processing on GPU 2025-09-15 00:14:10 +00:00
Raymond Knopp
e234f586bb modifications for Jetson 2025-09-15 01:16:45 +02:00
Raymond Knopp
905271e89b more GPU offloading (ldpc input processing, circular copy) 2025-09-14 21:31:53 +00:00
Raymond Knopp
162d3782b9 memory allocations for Jetson, gh200 and PCIe-based targets 2025-09-14 12:19:57 +02:00
jetson2-oai
01622f21f9 changes for jetson 2025-09-12 23:23:59 +02:00
Raymond Knopp
f9a87ac94c changes for gh200 (removal of cudaMemcpy) 2025-09-06 10:57:42 +00:00
Raymond Knopp
1088139162 Merge remote-tracking branch 'origin/develop' into ldpc_encoder_cuda 2025-09-06 09:49:32 +00:00
Raymond Knopp
ef8959c457 complex rotation optimization for NEON 2025-08-27 16:26:41 +00:00
Raymond Knopp
a7c53da958 Merge branch 'develop' into ldpc_encoder_cuda 2025-08-26 13:45:47 +02:00
Raymond.Knopp
964ffdbf8c remove warnings/errors related to cuda_support_init call on machine without GPUs. 2025-08-25 18:00:45 +02:00
Raymond Knopp
0f98b5a960 removed alignr option for AVX512, instruction is not amenable easily for more than 128-bit SIMD 2025-08-25 17:35:01 +02:00
Raymond Knopp
34ac55fa4e use permutex2var instead of alignr for AVX512 ldpc encoder after tests on AMD Siena (8004) 2025-08-25 12:53:16 +02:00
Raymond Knopp
06b18029c0 alignr for AVX512 in lpdc_encoder to compare 2025-08-25 12:41:02 +02:00
Raymond Knopp
faa19016c9 missing encoder file for aarch64/SSE 2025-08-25 10:37:34 +00:00
Raymond Knopp
3bea864336 some additional changes for AVX512 and AARCH64 and other minor stuff in ldpc_encoder 2025-08-25 09:34:18 +00:00
Raymond Knopp
42cc4d9320 test on AVX512_VBMI capable machine (AMD Genoa) 2025-08-24 21:55:47 +02:00
Raymond Knopp
b878fb0b72 ORAN version 2025-08-24 21:12:46 +02:00
Raymond Knopp
25c696697e added timing information for memcpy in LDPC encoder (CPU and CUDA). New
extension for AVX512 Zc=384 using permutex2var instruction
2025-08-24 21:08:53 +02:00
Raymond Knopp
28e998ebb7 support for PCIe NVidia GPUs (tested with A100) 2025-08-22 21:10:39 +02:00
Raymond Knopp
32248a6628 use ldpc shared lib for sizes other than 384 or 384 with less than 9 segments 2025-08-19 16:23:27 +00:00
Raymond Knopp
9c77c7e513 added check for new tconcat timer 2025-08-15 16:23:46 +00:00
Raymond Knp
bdc8e1efa1 more optimization of segement concatenation at output of encoder 2025-08-15 16:41:09 +02:00
Raymond Knopp
b51697c2c1 128-bit NEON optimizations for input and output data formatting 2025-08-15 09:15:56 +00:00
Raymond Knopp
a3adab8312 added missing file for cuda encoder 2025-08-08 15:34:21 +00:00
Raymond Knopp
e4d3520648 add ldpc_encoder32.c. Cleanup of commented code in cuda encoder host functions 2025-08-08 15:32:59 +00:00
Raymond Knopp
3420c2df41 interleaver optimization 2025-08-08 08:27:36 +00:00
Raymond Knopp
7831e52798 handling of multiple 32-bit segment groups, segment interleaving/deinterleaving optimization 2025-08-07 16:45:48 +00:00
Raymond Knopp
b0cf5e4b27 generator for single-worker 2025-06-14 14:43:26 +00:00
Raymond Knopp
4ac89e6d46 removed ldpc_encoder generated file 2025-06-05 07:33:59 +00:00
Raymond Knopp
1c8f88bbb8 added ifdef for unified CPU/GPU memory configuration (e.g. Gracehopper). 2025-06-01 21:22:34 +00:00
Raymond Knopp
2ad88ae0f3 initial implementation of 32-segment interleaved LDPC encoder for NVidia GPU (CUDA). functionally correct and integrated in existing CUDA library. Works only BG1 Zc 384. Integrated into ldpctest 2025-06-01 10:34:20 +00:00
Raymond Knopp
b6a67635ee change to CODING/CMakeLists.txt 2025-05-30 13:01:45 +00:00
Raymond Knopp
3cf8f6344c added initial CUDA implementation (and code generator) for ldpc encoder 2025-05-30 12:56:44 +00:00
Raymond Knopp
6856460923 added entry LDPC encoder routines for CUDA parity check implementation. Limited to BG1 Zc=384 for now. Also, left unoptimized interleaving of input for 32-bit. Will do after with SIMD bit-interleaving. 2025-05-27 21:19:42 +00:00
Raymond Knopp
9a76f26b91 added first version of generator for CUDA LDPC encoder code 2025-05-27 13:31:38 +00:00
61 changed files with 5057 additions and 609 deletions

3
.gitmodules vendored
View File

@@ -1,4 +1,3 @@
[submodule "openair2/E2AP/flexric"]
path = openair2/E2AP/flexric
url = https://gitlab.eurecom.fr/mosaic5g/flexric.git
branch = remotes/origin/service-models-integration
url = https://gitlab.eurecom.fr/mosaic5g/flexric

View File

@@ -113,6 +113,9 @@ else()
message(WARNING "did not find /proc/cpuinfo -- not setting any x86-specific compilation variables")
endif()
eval_boolean(AUTODETECT_AVX512_FP16 DEFINED CPUFLAGS AND CPUFLAGS MATCHES "avx512_fp16")
add_boolean_option(AVX512_FP16 ${AUTODETECT_AVX512_FP16} "Whether AVX512_FP16 intrinsics are available on the host processor" ON)
eval_boolean(AUTODETECT_AVX512 DEFINED CPUFLAGS AND CPUFLAGS MATCHES "avx512")
add_boolean_option(AVX512 ${AUTODETECT_AVX512} "Whether AVX512 intrinsics is available on the host processor" ON)
@@ -127,8 +130,11 @@ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
# The following intrinsics are assumed to be available on any x86 system
# (avx, f16c, fma, gnfi, mmx, pclmul, sse, sse2, sse3, xop)
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -DSIMDE_X86_AVX_NATIVE -DSIMDE_X86_AVX_NATIVE -DSIMDE_X86_F16C_NATIVE -DSIMDE_X86_FMA_NATIVE -DSIMDE_X86_GFNI_NATIVE -DSIMDE_X86_MMX_NATIVE -DSIMDE_X86_PCLMUL_NATIVE -DSIMDE_X86_SSE2_NATIVE -DSIMDE_X86_SSE3_NATIVE -DSIMDE_X86_SSE_NATIVE -DSIMDE_X86_XOP_HAVE_COM_ -DSIMDE_X86_XOP_NATIVE")
message(STATUS "AVX512_FP16 intrinsics are ${AVX512_FP16}")
message(STATUS "AVX512 intrinsics are ${AVX512}")
if(${AVX512})
if (${AVX512_FP16})
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -DSIMDE_X86_AVX512BW_NATIVE -DSIMDE_X86_AVX512F_NATIVE -DSIMDE_X86_AVX512VL_NATIVE -mavx512bw -march=sapphirerapids -mtune=sapphirerapids")
elseif(${AVX512})
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -DSIMDE_X86_AVX512BW_NATIVE -DSIMDE_X86_AVX512F_NATIVE -DSIMDE_X86_AVX512VL_NATIVE -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512")
else()
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mno-avx512f -march=native")
@@ -183,6 +189,10 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang
set(commonOpts "${commonOpts} -Wno-unused-command-line-argument")
endif()
if (ENABLE_CUDA)
set(commonOpts "${commonOpts} -DENABLE_CUDA")
endif()
set(CMAKE_C_FLAGS
"${C_FLAGS_PROCESSOR} ${commonOpts} -std=gnu11 -funroll-loops ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS
@@ -970,6 +980,8 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/srs_rx.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c
)
set(PHY_NR_SRC_CU
)
set(PHY_NR_UE_SRC
${OPENAIR1_DIR}/PHY/INIT/nr_parms.c
${OPENAIR1_DIR}/PHY/MODULATION/nr_modulation.c
@@ -1047,7 +1059,17 @@ target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE
add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
add_library(PHY_NR ${PHY_NR_SRC})
if (ENABLE_CUDA)
find_package(CUDA REQUIRED)
if (NOT CUDA_FOUND)
message(FATAL_ERROR "no CUDA found")
endif()
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-arch=sm_87;")
set(CUDA_VERBOS_BUILD_ON)
cuda_add_library(PHY_NR ${PHY_NR_SRC} ${PHY_NR_SRC_CU})
else()
add_library(PHY_NR ${PHY_NR_SRC})
endif()
target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5)
add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC})
@@ -1943,13 +1965,21 @@ target_link_libraries(smallblocktest PRIVATE
)
#if (ENABLE_CUDA)
# find_package(CUDA REQUIRED)
# if (NOT CUDA_FOUND)
# message(FATAL_ERROR "no CUDA found")
# endif()
# cuda_add_library(ldpctest)
#else()
#endif()
add_executable(ldpctest
${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c
)
target_link_libraries(ldpctest PRIVATE
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON -Wl,--end-group
m pthread dl shlib_loader ${T_LIB}
m pthread dl shlib_loader ${T_LIB} ${CUDA_LIBRARIES}
# link 'check_crc' to make it resolved in the LDPC coding libraries
# 'check_crc' is not used in ldpctest so it is not linked in the executable by default
# --whole-archive links 'check_crc' in the executable even though it is note used, see 'man ld'

View File

@@ -135,6 +135,8 @@ Options:
CC=/usr/bin/clang CXX=/usr/bin/clang++ ./build_oai ... --sanitize-memory
--sanitize-thread | -fsanitize=thread
Enable the thread sanitizer on all targets
--use-cuda
Tell build to use NVCC for appropriate .cu files and cuda_runtime functions
-h | --help
Print this help"
}
@@ -382,6 +384,9 @@ function main() {
--sanitize-thread | -fsanitize=thread)
CMAKE_CMD="$CMAKE_CMD -DSANITIZE_THREAD=True"
shift;;
--use-cuda)
CMAKE_CMD="$CMAKE_CMD -DENABLE_CUDA=True"
shift;;
--trace-asn1c-enc-dec)
CMAKE_CMD="$CMAKE_CMD -DTRACE_ASN1C_ENC_DEC=ON"
echo_info "Enabling asn1c internal traces via OAI logging system"

View File

@@ -32,7 +32,11 @@
#include <stdint.h>
#include <stdbool.h>
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
#ifdef __aarch64__
#include <arm_fp16.h>
#endif
#define ALIGNARRAYSIZE(a, b) (((a + b - 1) / b) * b)
#define ALNARS_16_4(a) ALIGNARRAYSIZE(a, 4)
@@ -46,6 +50,18 @@ typedef struct complexf {
float i;
} cf_t;
#ifdef FLT16_MAX
typedef struct complexf16 {
#ifdef __aarch64__
float16_t r;
float16_t i;
#else
_Float16 r;
_Float16 i;
#endif
} cf16_t;
#endif
typedef struct complex8 {
int8_t r;
int8_t i;

View File

@@ -105,7 +105,7 @@ static inline uint64_t rdtsc_oai(void) __attribute__((always_inline));
static inline uint64_t rdtsc_oai(void)
{
uint64_t r = 0;
asm volatile("mrs %0, cntvct_el0" : "=r"(r));
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(r));
return r;
}
@@ -113,7 +113,7 @@ static inline uint64_t rdtsc_oai(void)
static inline uint32_t rdtsc_oai(void) __attribute__((always_inline));
static inline uint32_t rdtsc_oai(void) {
uint32_t r = 0;
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(r) );
__asm__ volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(r) );
return r;
}
#endif

View File

@@ -96,7 +96,8 @@
#define CONFIG_HLP_TELN "Start embedded telnet server \n"
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
#define CONFIG_HLP_NOS1 "Disable s1 interface\n"
#define CONFIG_HLP_USEGPU "Use GPU for processing offload"
#define CONFIG_HLP_USEFP16 "Use FP16 arithmetic when possible"
/*--------------------------------------------------------------------------------------------------------------------------------*/
/* command line parameters for LOG utility */
/* optname helpstr paramflags XXXptr defXXXval type numelt */

View File

@@ -103,6 +103,7 @@ unsigned int mmapped_dma=0;
uint64_t downlink_frequency[MAX_NUM_CCs][4];
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
char *uecap_file;
uint32_t use_gpu;
runmode_t mode = normal_txrx;

View File

@@ -27,6 +27,8 @@
{"U" , CONFIG_HLP_ULBM_PHYTEST, 0, .u64ptr=&ulsch_slot_bitmap, .defintval=0, TYPE_UINT64, 0}, \
{"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0, .iptr=&usrp_tx_thread, .defstrval=0, TYPE_INT, 0}, \
{"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \
{"use_gpu", CONFIG_HLP_USE_GPU, 0, .uptr=&use_gpu, .defintval=0, TYPE_UINT, 0}, \
{"use_fp16", CONFIG_HLP_USE_FP16, 0, .uptr=&use_fp16, .defintval=0, TYPE_UINT, 0}, \
}
// clang-format on
@@ -39,7 +41,8 @@ extern uint32_t target_ul_bw;
extern uint64_t dlsch_slot_bitmap;
extern uint64_t ulsch_slot_bitmap;
extern char *uecap_file;
extern uint32_t use_gpu;
extern uint32_t use_fp16;
// In nr-gnb.c
extern void init_gNB();
extern void stop_gNB(int);

View File

@@ -12,6 +12,7 @@ target_link_libraries(coding PRIVATE log_headers)
add_library(ldpc_orig MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder.c
nrLDPC_encoder/ldpc_encoder32.c
)
set_target_properties(ldpc_orig PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_orig PRIVATE ldpc_segment ldpc_gen_HEADERS)
@@ -19,6 +20,7 @@ target_link_libraries(ldpc_orig PRIVATE ldpc_segment ldpc_gen_HEADERS)
add_library(ldpc MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
nrLDPC_encoder/ldpc_encoder32.c
)
set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc PRIVATE ldpc_segment ldpc_gen_HEADERS)
@@ -41,22 +43,28 @@ if (ENABLE_LDPC_CUDA)
if (NOT CUDA_FOUND)
message(FATAL_ERROR "no CUDA found")
endif()
SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;")
SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-arch=sm_90;")
SET(CUDA_VERBOSE_BUILD ON)
cuda_add_library(ldpc_cuda MODULE
nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
# nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
nrLDPC_encoder/ldpc_encoder_cuda32.c
nrLDPC_encoder/ldpc_BG1_Zc384_32bit.cu
nrLDPC_encoder/ldpc_input.cu
# The slot coding layer cannot be linked with
# target_link_libraries like above
# because of cuda_add_library
# which already uses target_link_libraries
nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c
nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder_cuda.c
nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c
)
target_link_libraries(ldpc_cuda ldpc_gen_HEADERS ${T_LIB})
set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_compile_definitions(ldpc_cuda PRIVATE ENABLE_CUDA)
add_dependencies(ldpctest ldpc_cuda)
add_dependencies(nr-softmodem ldpc_cuda)
add_dependencies(nr-uesoftmodem ldpc_cuda)

View File

@@ -34,6 +34,9 @@
#include "openair1/PHY/defs_nr_common.h"
#include "coding_unitary_defs.h"
#include "common/utils/LOG/log.h"
#ifdef ENABLE_CUDA
#include <cuda_runtime.h>
#endif
#define MAX_BLOCK_LENGTH 8448
@@ -104,14 +107,16 @@ one_measurement_t test_ldpc(short max_iterations,
unsigned char qbits,
short Kprime,
unsigned int ntrials,
int n_segments)
int n_segments,
int gen_code,
int use32bit)
{
one_measurement_t ret = {0};
reset_meas(&ret.time_optim);
reset_meas(&ret.time_decoder);
// clock initiate
// time_stats_t time,time_optim,tinput,tprep,tparity,toutput, time_decoder;
time_stats_t time, tinput, tprep, tparity, toutput;
time_stats_t time, tinput, tinput_memcpy, tprep, tparity, toutput;
double n_iter_mean = 0;
double n_iter_std = 0;
int n_iter_max = 0;
@@ -119,14 +124,22 @@ one_measurement_t test_ldpc(short max_iterations,
double sigma;
sigma = 1.0 / sqrt(2 * SNR);
cpu_meas_enabled = 1;
uint8_t *test_input[MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * NR_MAX_NB_LAYERS];
uint8_t estimated_output[MAX_NUM_DLSCH_SEGMENTS][Kprime];
#ifdef ENABLE_CUDA
uint8_t **test_input,*test_input_p;
#else
uint8_t *test_input[n_segments * NR_MAX_NB_LAYERS];
#endif
uint8_t *channel_input[n_segments];
uint8_t estimated_output[n_segments][Kprime];
memset(estimated_output, 0, sizeof(estimated_output));
uint8_t *channel_input[MAX_NUM_DLSCH_SEGMENTS];
uint8_t *channel_input_optim;
// double channel_output[68 * 384];
double modulated_input[MAX_NUM_DLSCH_SEGMENTS][68 * 384] = {0};
int8_t channel_output_fixed[MAX_NUM_DLSCH_SEGMENTS][68 * 384] = {0};
double modulated_input[n_segments][68 * 384];
memset(modulated_input,0,sizeof(modulated_input));
int8_t channel_output_fixed[n_segments][68 * 384];
memset(channel_output_fixed,0,sizeof(channel_output_fixed));
short BG = 0, nrows = 0; //,ncols;
int i1, Kb = 0;
int R_ind = 0;
@@ -134,7 +147,7 @@ one_measurement_t test_ldpc(short max_iterations,
int code_rate_vec[8] = {15, 13, 25, 12, 23, 34, 56, 89};
// double code_rate_actual_vec[8] = {0.2, 0.33333, 0.4, 0.5, 0.66667, 0.73333, 0.81481, 0.88};
t_nrLDPC_dec_params decParams[MAX_NUM_DLSCH_SEGMENTS] = {0};
t_nrLDPC_dec_params decParams[n_segments];
t_nrLDPC_time_stats decoder_profiler = {0};
@@ -142,6 +155,7 @@ one_measurement_t test_ldpc(short max_iterations,
reset_meas(&time);
reset_meas(&tinput);
reset_meas(&tinput_memcpy);
reset_meas(&tprep);
reset_meas(&tparity);
reset_meas(&toutput);
@@ -259,18 +273,29 @@ one_measurement_t test_ldpc(short max_iterations,
printf("To: %d\n", (Kb + nrows - no_punctured_columns) * Zc - removed_bit);
printf("number of undecoded bits: %d\n", (Kb + nrows - no_punctured_columns - 2) * Zc - removed_bit);
// ldpc_toCompare.LDPCinit();
// generate input block
for (int j = 0; j < MAX_NUM_DLSCH_SEGMENTS; j++) {
#ifdef ENABLE_CUDA
cudaHostAlloc((void**)&test_input_p,n_segments*sizeof(uint8_t*),cudaHostAllocMapped);
test_input=(uint8_t **)test_input_p;
printf("test input %p\n",test_input);
#endif
for (int j = 0; j < n_segments; j++) {
#ifdef ENABLE_CUDA
cudaHostAlloc((void**)&test_input[j],((K + 7) & ~7) / 8,cudaHostAllocMapped);
printf("test input[%d] %p\n",j,test_input[j]);
#else
test_input[j] = malloc16(((K + 7) & ~7) / 8);
memset(test_input[j], 0, ((K + 7) & ~7) / 8);
#endif
channel_input[j] = malloc16(68 * 384);
memset(channel_input[j], 0, 68 * 384);
}
channel_input_optim = malloc16(68 * 384);
memset(channel_input_optim, 0, 68 * 384);
channel_input_optim = malloc16(68 * 384 * sizeof(uint32_t));
if (use32bit ==0) memset(channel_input_optim, 0, 68 * 384 * sizeof(uint32_t));
// Fill input segments with random values
for (int j = 0; j < MAX_NUM_DLSCH_SEGMENTS; j++) {
for (int j = 0; j < n_segments; j++) {
int i = 0;
for (i = 0; i < ((Kprime + 7) & ~7) / 8; i++)
test_input[j][i] = (uint8_t)rand();
@@ -282,13 +307,17 @@ one_measurement_t test_ldpc(short max_iterations,
}
encoder_implemparams_t impp = {.Zc = Zc, .Kb = Kb, .BG = BG, .K = K};
impp.gen_code = 1;
impp.gen_code = gen_code;
impp.tparity = &tparity;
impp.tinput = &tinput;
impp.tinput_memcpy = &tinput_memcpy;
impp.toutput = &toutput;
if (ntrials == 0)
ldpc_orig.LDPCencoder(test_input, channel_input[0], &impp);
impp.gen_code = 0;
decode_abort_t dec_abort;
init_abort(&dec_abort);
uint32_t **output32;
for (int trial = 0; trial < ntrials; trial++) {
unsigned int segment_bler = 0;
//// encoder
@@ -301,26 +330,27 @@ one_measurement_t test_ldpc(short max_iterations,
impp.n_segments = n_segments;
start_meas(&ret.time_optim);
impp.first_seg = 0;
ldpc_toCompare.LDPCencoder(test_input, channel_input_optim, &impp);
if (use32bit==0) ldpc_toCompare.LDPCencoder(test_input, channel_input_optim, &impp);
else output32=ldpc_toCompare.LDPCencoder32(test_input, &impp);
stop_meas(&ret.time_optim);
if (ntrials == 1)
for (int j = 0; j < n_segments; j++)
for (int i = 0; i < K + (nrows - no_punctured_columns) * Zc - removed_bit; i++) {
if (channel_input[j][i] != ((channel_input_optim[i] >> j) & 0x1)) {
printf("differ in seg %d pos %d (%u,%u)\n", j, i, channel_input[j][i], (channel_input_optim[i] >> j) & 0x1);
return ret;
}
if (((use32bit == 0) && (channel_input[j][i] != ((channel_input_optim[i] >> j) & 0x1))) || ((use32bit == 1) && (channel_input[j][i] != (((output32[0][i] >> j) & 0x1))))) {
printf("differ in seg %d pos %d (%u,%u)\n", j, i, channel_input[j][i], (((uint32_t*)channel_input_optim)[i] >> j) & 0x1);
return ret;
}
}
int bit;
for (int j = 0; j < n_segments; j++) {
for (int i = 2 * Zc; i < (Kb + nrows - no_punctured_columns) * Zc - removed_bit; i++) {
#ifdef DEBUG_CODER
if ((i & 0xf) == 0)
printf("\ne %d..%d: ", i, i + 15);
#endif
if (((channel_input_optim[i - 2 * Zc] >> j) & 0x1) == 0)
bit = (use32bit==0) ? ((channel_input_optim[i - 2 * Zc] >> j) & 0x1) : ((output32[0][i - 2 * Zc] >> j) & 0x1);
if (bit == 0)
modulated_input[j][i] = 1.0; /// sqrt(2); //QPSK
else
modulated_input[j][i] = -1.0; /// sqrt(2);
@@ -345,7 +375,6 @@ one_measurement_t test_ldpc(short max_iterations,
decParams[j].numMaxIter = max_iterations;
decParams[j].outMode = nrLDPC_outMode_BIT;
decParams[j].Kprime = Kprime;
ldpc_toCompare.LDPCinit();
}
for (int j = 0; j < n_segments; j++) {
start_meas(&ret.time_decoder);
@@ -388,8 +417,12 @@ one_measurement_t test_ldpc(short max_iterations,
ret.errors_bit_uncoded = ret.errors_bit_uncoded / (double)((Kb + nrows - no_punctured_columns - 2) * Zc - removed_bit);
for (int j = 0; j < MAX_NUM_DLSCH_SEGMENTS; j++) {
for (int j = 0; j < n_segments; j++) {
#ifdef ENABLE_CUDA
cudaFree(test_input[j]);
#else
free(test_input[j]);
#endif
free(channel_input[j]);
}
free(channel_input_optim);
@@ -397,6 +430,7 @@ one_measurement_t test_ldpc(short max_iterations,
print_meas(&time, "ldpc_encoder", NULL, NULL);
print_meas(&ret.time_optim, "ldpc_encoder_optim", NULL, NULL);
print_meas(&tinput, "ldpc_encoder_optim(input)", NULL, NULL);
print_meas(&tinput_memcpy, "ldpc_encoder_optim(input memcpy)", NULL, NULL);
print_meas(&tprep, "ldpc_encoder_optim(prep)", NULL, NULL);
print_meas(&tparity, "ldpc_encoder_optim(parity)", NULL, NULL);
print_meas(&toutput, "ldpc_encoder_optim(output)", NULL, NULL);
@@ -437,19 +471,20 @@ int main(int argc, char *argv[])
int n_trials = 1;
double SNR_step = 0.1;
randominit();
int gen_code = 1;
randominit(0);
int test_uncoded = 0;
n_iter_stats_t dec_iter[400] = {0};
short BG = 0, Zc;
int use32bit=0;
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
exit_fun("[LDPCTEST] Error, configuration module init failed\n");
}
logInit();
while ((c = getopt(argc, argv, "--:O:q:r:s:S:l:G:n:d:i:t:u:hv:")) != -1) {
while ((c = getopt(argc, argv, "--:O:q:r:s:S:l:Gn:d:i:t:u:hv:g:")) != -1) {
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
if (c == 1 || c == '-' || c == 'O')
@@ -475,6 +510,7 @@ int main(int argc, char *argv[])
case 'G':
ldpc_version = "_cuda";
use32bit=1;
break;
case 'n':
@@ -503,6 +539,11 @@ int main(int argc, char *argv[])
case 'v':
ldpc_version = strdup(optarg);
break;
case 'g':
gen_code = atoi(optarg);
AssertFatal(gen_code <= 4, "gen_code %d is not allowed\n",gen_code);
n_trials=0;
break;
case 'h':
default:
printf("CURRENTLY SUPPORTED CODE RATES: \n");
@@ -559,7 +600,9 @@ int main(int argc, char *argv[])
qbits,
Kprime, // block length bytes
n_trials,
n_segments);
n_segments,
gen_code,
use32bit);
decoded_errors[i] = res.errors;
dec_iter[i] = res.dec_iter;

View File

@@ -152,6 +152,7 @@ typedef struct nrLDPC_segment_encoding_parameters_s{
time_stats_t ts_interleave;
time_stats_t ts_rate_match;
time_stats_t ts_ldpc_encode;
time_stats_t ts_output;
} nrLDPC_segment_encoding_parameters_t;
/**
@@ -201,6 +202,7 @@ typedef struct nrLDPC_TB_encoding_parameters_s{
uint32_t C;
nrLDPC_segment_encoding_parameters_t *segments;
unsigned char *output;
uint8_t **c_dev;
} nrLDPC_TB_encoding_parameters_t;
/**
@@ -226,10 +228,13 @@ typedef struct nrLDPC_slot_encoding_parameters_s{
int nb_TBs;
tpool_t *threadPool;
time_stats_t *tinput;
time_stats_t *tinput_memcpy;
time_stats_t *tprep;
time_stats_t *tparity;
time_stats_t *toutput;
time_stats_t *tconcat;
nrLDPC_TB_encoding_parameters_t *TBs;
uint32_t use_gpu;
} nrLDPC_slot_encoding_parameters_t;
typedef int32_t(nrLDPC_coding_init_t)(void);

View File

@@ -280,6 +280,11 @@ int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_de
int32_t nrLDPC_coding_init(void)
{
LOG_I(NR_PHY,"Initializing coding library\n");
#ifdef ENABLE_CUDA
LOG_I(NR_PHY,"Calling cuda_support_init()\n");
#endif
cuda_support_init();
return 0;
}

View File

@@ -367,9 +367,11 @@ static int nrLDPC_launch_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_s
encoder_implemparams_t common_segment_params = {
.n_segments = nrLDPC_TB_encoding_parameters->C,
.tinput = nrLDPC_slot_encoding_parameters->tinput,
.tinput_memcpy = nrLDPC_slot_encoding_parameters->tinput_memcpy,
.tprep = nrLDPC_slot_encoding_parameters->tprep,
.tparity = nrLDPC_slot_encoding_parameters->tparity,
.toutput = nrLDPC_slot_encoding_parameters->toutput,
.tconcat = nrLDPC_slot_encoding_parameters->tconcat,
.Kb = nrLDPC_TB_encoding_parameters->Kb,
.Zc = nrLDPC_TB_encoding_parameters->Z,
.BG = nrLDPC_TB_encoding_parameters->BG,
@@ -406,16 +408,24 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) {
// Compute number of tasks to encode TB
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1));
nbTasks += n_seg;
// Search for maximum E for sizing encoder output f and f2
for (int seg_id = 0; seg_id < nrLDPC_TB_encoding_parameters->C; seg_id++) {
uint32_t E = nrLDPC_TB_encoding_parameters->segments[seg_id].E;
Emax = E > Emax ? E : Emax;
#if defined(ENABLE_CUDA)
if (nrLDPC_slot_encoding_parameters->use_gpu && nrLDPC_TB_encoding_parameters->C > 8 && nrLDPC_TB_encoding_parameters->Z == 384) {
nrLDPC_coding_encoder32(nrLDPC_slot_encoding_parameters,nrLDPC_TB_encoding_parameters);
}
}
else {
#endif
size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1));
nbTasks += n_seg;
// Search for maximum E for sizing encoder output f and f2
for (int seg_id = 0; seg_id < nrLDPC_TB_encoding_parameters->C; seg_id++) {
uint32_t E = nrLDPC_TB_encoding_parameters->segments[seg_id].E;
Emax = E > Emax ? E : Emax;
}
#if defined(ENABLE_CUDA)
}
#endif
}
// Create f and f2 to old encoding tasks outputs
uint32_t Emax_ceil_mod = ceil_mod(Emax, 64);
uint8_t f[nbTasks][Emax_ceil_mod] __attribute__((aligned(64)));
@@ -432,6 +442,10 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
// For easier indexing we store the pointers to sub arrays of f and f2 in pointer arrays
// Then a function to which we pass the pointer arrays can directly use f_2d[j] ans f2_2d[j]
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
#if defined(ENABLE_CUDA)
if (nrLDPC_slot_encoding_parameters->use_gpu && nrLDPC_TB_encoding_parameters->C > 8 && nrLDPC_TB_encoding_parameters->Z == 384)
continue;
#endif
size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1));
uint8_t *f_2d[n_seg];
uint8_t *f2_2d[n_seg];
@@ -449,16 +463,21 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
completed_many_task_ans(&ans, nbTasks - nbEncode);
}
// Execute thread pool tasks
join_task_ans(&ans);
if (nbTasks > 0) join_task_ans(&ans);
// Write output
time_stats_t *tconcat = nrLDPC_slot_encoding_parameters->tconcat;
if(tconcat != NULL) start_meas(tconcat);
nbTasks = 0;
for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) {
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
uint32_t C = nrLDPC_TB_encoding_parameters->C;
#if defined(ENABLE_CUDA)
if (nrLDPC_slot_encoding_parameters->use_gpu && C > 8 && nrLDPC_TB_encoding_parameters->Z == 384)
continue;
#endif
size_t n_seg = (C / 8 + ((C & 7) == 0 ? 0 : 1));
time_stats_t *toutput = nrLDPC_slot_encoding_parameters->toutput;
for (int j = 0; j < n_seg; j++) {
unsigned int macro_segment = j * 8;
@@ -478,7 +497,6 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
}
}
if(toutput != NULL) start_meas(toutput);
uint32_t Eoffset=0;
for (int s=0; s<macro_segment; s++)
@@ -494,10 +512,10 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
nrLDPC_TB_encoding_parameters->output,
Eoffset);
if(toutput != NULL) stop_meas(toutput);
}
nbTasks += n_seg;
}
if(tconcat != NULL) stop_meas(tconcat);
return 0;
}

View File

@@ -0,0 +1,688 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
* \brief Top-level routines for implementing LDPC encoding of transport channels
*/
#include "nr_rate_matching.h"
#include "PHY/defs_gNB.h"
#include "PHY/CODING/coding_extern.h"
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/lte_interleaver_inline.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
#include "SCHED_NR/sched_nr.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "common/utils/LOG/log.h"
#include "common/utils/nr/nr_common.h"
#include <openair2/UTIL/OPT/opt.h>
#include <syscall.h>
//#define DEBUG_LDPC_ENCODING
//#define DEBUG_LDPC_ENCODING_FREE 1
extern uint32_t **d_host;
static void unpack_output(uint32_t *f,
uint32_t E,
uint32_t *f2,
uint32_t E2,
uint32_t E2_first_segment32,
uint32_t E2_first_segment,
uint32_t nb_segments,
uint8_t *output) {
uint32_t s;
// int s0;
uint32_t *fp;
int foffset;
uint32_t *output_p = (uint32_t *)output;
//printf("unpack: E %d, E2 %d, E2_first_segment %d, E2_first_segment32 %d, nb_segments %d\n",E,E2,E2_first_segment,E2_first_segment32,nb_segments);
uint32_t bit_index = 0;
#ifdef __AVX2__
simde__m256i shift0=simde_mm256_set_epi32(7,6,5,4,3,2,1,0);
simde__m256i shift1=simde_mm256_set_epi32(15,14,13,12,11,10,9,8);
simde__m256i shift2=simde_mm256_set_epi32(23,22,21,20,19,18,17,16);
simde__m256i shift3=simde_mm256_set_epi32(31,30,29,28,27,26,25,24);
simde__m256i vmask0=simde_mm256_set_epi32(0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1);
simde__m256i vmask1=simde_mm256_set_epi32(0x8000,0x4000,0x2000,0x1000,0x800,0x400,0x200,0x100);
simde__m256i vmask2=simde_mm256_set_epi32(0x800000,0x400000,0x200000,0x100000,0x80000,0x40000,0x20000,0x10000);
simde__m256i vmask3=simde_mm256_set_epi32(0x80000000,0x40000000,0x20000000,0x10000000,0x8000000,0x4000000,0x2000000,0x1000000);
int s2=0;
for (s = 0; s < E2_first_segment ; s++) {
s2 = s&31;
foffset = (s>>5)*E;
fp = f+foffset;
int i;
if ((bit_index&31) == 0 ) {
for (i = 0; i < (E>>5)<<5; i+=32) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
*(output_p + (bit_index>>5)) = simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7);
bit_index+=32;
}
uint32_t Emod32=E&31;
if (Emod32 != 0) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
*(output_p + (bit_index>>5)) = (simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7))&((1<<Emod32)-1);
bit_index+=Emod32;
}
}
else {
for (i = 0; i < (E>>5)<<5; i+=32) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
uint32_t tmp = simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=32;
}
uint32_t Emod32=E&31;
if (Emod32 != 0) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
uint32_t tmp = (simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7))&((1<<Emod32)-1);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=Emod32;
}
}
}
for ( ; s < nb_segments ; s++){
s2 = s&31;
foffset = ((s>>5)-E2_first_segment32)*E2;
fp = f2+foffset;
int i;
if ((bit_index&31) == 0 ) {
for (i = 0; i < (E2>>5)<<5; i+=32) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
*(output_p + (bit_index>>5)) = simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7);
bit_index+=32;
}
uint32_t E2mod32=E2&31;
if (E2mod32 != 0) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
*(output_p + (bit_index>>5)) = (simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7))&((1<<E2mod32)-1);
bit_index+=E2mod32;
}
}
else {
for (i = 0; i < (E2>>5)<<5; i+=32) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
uint32_t tmp = simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=32;
}
uint32_t E2mod32=E2&31;
if (E2mod32 != 0) {
simde__m256i f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i],s2);
simde__m256i cshift = simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift0),vmask0);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+8],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift1),vmask1),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+16],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift2),vmask2),cshift);
f256 = simde_mm256_srli_epi32(*(simde__m256i*)&fp[i+24],s2);
cshift = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_sllv_epi32(f256,shift3),vmask3),cshift);
uint32_t tmp = (simde_mm256_extract_epi32(cshift,0) |
simde_mm256_extract_epi32(cshift,1) |
simde_mm256_extract_epi32(cshift,2) |
simde_mm256_extract_epi32(cshift,3) |
simde_mm256_extract_epi32(cshift,4) |
simde_mm256_extract_epi32(cshift,5) |
simde_mm256_extract_epi32(cshift,6) |
simde_mm256_extract_epi32(cshift,7))&((1<<E2mod32)-1);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=E2mod32;
}
}
}
#elif defined(__aarch64__)
const int32_t ucShift0[32][4] = { {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}, {-12,-11,-10,-9}, {-13,-12,-11,-10}, {-14,-13,-12,-11}, {-15,-14,-13,-12}, {-16,-15,-14,-13}, {-17,-16,-15,-14}, {-18,-17,-16,-15}, {-19,-18,-17,-16}, {-20,-19,-18,-17}, {-21,-20,-19,-18}, {-22,-21,-20,-19}, {-23,-22,-21,-20}, {-24,-23,-22,-21}, {-25,-24,-23,-22}, {-26,-25,-24,-23}, {-27,-26,-25,-24}, {-28,-27,-26,-25}, {-29,-28,-27,-26}, {-30,-29,-28,-27}, {-31,-30,-29,-28}};
const int32_t ucShift1[32][4] = { {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}, {-12,-11,-10,-9}, {-13,-12,-11,-10}, {-14,-13,-12,-11}, {-15,-14,-13,-12}, {-16,-15,-14,-13}, {-17,-16,-15,-14}, {-18,-17,-16,-15}, {-19,-18,-17,-16}, {-20,-19,-18,-17}, {-21,-20,-19,-18}, {-22,-21,-20,-19}, {-23,-22,-21,-20}, {-24,-23,-22,-21}, {-25,-24,-23,-22}, {-26,-25,-24,-23}, {-27,-26,-25,-24}};
const int32_t ucShift2[32][4] = { {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}, {-12,-11,-10,-9}, {-13,-12,-11,-10}, {-14,-13,-12,-11}, {-15,-14,-13,-12}, {-16,-15,-14,-13}, {-17,-16,-15,-14}, {-18,-17,-16,-15}, {-19,-18,-17,-16}, {-20,-19,-18,-17}, {-21,-20,-19,-18}, {-22,-21,-20,-19},{-23,-22,-21,-20}};
const int32_t ucShift3[32][4] = { {12,13,14,15}, {11,12,13,14}, {10,11,12,13}, {9,10,11,12}, {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}, {-12,-11,-10,-9}, {-13,-12,-11,-10}, {-14,-13,-12,-11}, {-15,-14,-13,-12}, {-16,-15,-14,-13}, {-17,-16,-15,-14}, {-18,-17,-16,-15}, {-19,-18,-17,-16}};
const int32_t ucShift4[32][4] = { {16,17,18,19}, {15,16,17,18}, {14,15,16,17}, {13,14,15,16}, {12,13,14,15}, {11,12,13,14}, {10,11,12,13}, {9,10,11,12}, {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}, {-12,-11,-10,-9}, {-13,-12,-11,-10}, {-14,-13,-12,-11}, {-15,-14,-13,-12}};
const int32_t ucShift5[32][4] = { {20,21,22,23}, {19,20,21,22}, {18,19,20,21}, {17,18,19,20}, {16,17,18,19}, {15,16,17,18}, {14,15,16,17}, {13,14,15,16}, {12,13,14,15}, {11,12,13,14}, {10,11,12,13}, {9,10,11,12}, {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}, {-8,-7,-6,-5}, {-9,-8,-7,-6}, {-10,-9,-8,-7}, {-11,-10,-9,-8}};
const int32_t ucShift6[32][4] = { {24,25,26,27}, {23,24,25,26}, {22,23,24,25}, {21,22,23,24}, {20,21,22,23}, {19,20,21,22}, {18,19,20,21}, {17,18,19,20}, {16,17,18,19}, {15,16,17,18}, {14,15,16,17}, {13,14,15,16}, {12,13,14,15}, {11,12,13,14}, {10,11,12,13}, {9,10,11,12}, {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}, {-4,-3,-2,-1}, {-5,-4,-3,-2}, {-6,-5,-4,-3}, {-7,-6,-5,-4}};
const int32_t ucShift7[32][4] = { {28,29,30,31}, {27,28,29,30}, {26,27,28,29}, {25,26,27,28}, {24,25,26,27}, {23,24,25,26}, {22,23,24,25}, {21,22,23,24}, {20,21,22,23}, {19,20,21,22}, {18,19,20,21}, {17,18,19,20}, {16,17,18,19}, {15,16,17,18}, {14,15,16,17}, {13,14,15,16}, {12,13,14,15}, {11,12,13,14}, {10,11,12,13}, {9,10,11,12}, {8,9,10,11},{7,8,9,10}, {6,7,8,9}, {5,6,7,8}, {4,5,6,7}, {3,4,5,6}, {2,3,4,5}, {1,2,3,4}, {0,1,2,3}, {-1,0,1,2},{-2,-1,0,1}, {-3,-2,-1,0}};
const uint32_t __attribute__ ((aligned (16))) masks0[4] = {0x1,0x2,0x4,0x8};
const uint32_t __attribute__ ((aligned (16))) masks1[4] = {0x10,0x20,0x40,0x80};
const uint32_t __attribute__ ((aligned (16))) masks2[4] = {0x100,0x200,0x400,0x800};
const uint32_t __attribute__ ((aligned (16))) masks3[4] = {0x1000,0x2000,0x4000,0x8000};
const uint32_t __attribute__ ((aligned (16))) masks4[4] = {0x10000,0x20000,0x40000,0x80000};
const uint32_t __attribute__ ((aligned (16))) masks5[4] = {0x100000,0x200000,0x400000,0x800000};
const uint32_t __attribute__ ((aligned (16))) masks6[4] = {0x1000000,0x2000000,0x4000000,0x8000000};
const uint32_t __attribute__ ((aligned (16))) masks7[4] = {0x10000000,0x20000000,0x40000000,0x80000000};
int32x4_t vshift0[32],vshift1[32],vshift2[32],vshift3[32],vshift4[32],vshift5[32],vshift6[32],vshift7[32];
for (int n=0;n<32;n++) {
vshift0[n] = vld1q_s32(ucShift0[n]);
vshift1[n] = vld1q_s32(ucShift1[n]);
vshift2[n] = vld1q_s32(ucShift2[n]);
vshift3[n] = vld1q_s32(ucShift3[n]);
vshift4[n] = vld1q_s32(ucShift4[n]);
vshift5[n] = vld1q_s32(ucShift5[n]);
vshift6[n] = vld1q_s32(ucShift6[n]);
vshift7[n] = vld1q_s32(ucShift7[n]);
}
uint32x4_t vmask0 = vld1q_u32(masks0);
uint32x4_t vmask1 = vld1q_u32(masks1);
uint32x4_t vmask2 = vld1q_u32(masks2);
uint32x4_t vmask3 = vld1q_u32(masks3);
uint32x4_t vmask4 = vld1q_u32(masks4);
uint32x4_t vmask5 = vld1q_u32(masks5);
uint32x4_t vmask6 = vld1q_u32(masks6);
uint32x4_t vmask7 = vld1q_u32(masks7);
uint32_t output_tmp=0;
int s2=0;
for (s = 0; s < E2_first_segment ; s++) {
s2 = s&31;
foffset = (s>>5)*E;
fp = f+foffset;
int i;
if ((bit_index&31) == 0 ) {
for (i = 0; i < (E>>5)<<5; i+=32) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
*(output_p + (bit_index>>5)) = vaddvq_u32(cshift);
bit_index+=32;
}
uint32_t Emod32=E&31;
if (Emod32 != 0) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
*(output_p + (bit_index>>5)) = vaddvq_u32(cshift)&((1<<Emod32)-1);
bit_index+=Emod32;
}
}
else {
for (i = 0; i < (E>>5)<<5; i+=32) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
/*
uint32_t tmp = vaddvq_u32(cshift);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
*/
uint64_t tmp = (uint64_t)vaddvq_u32(cshift);
*(uint64_t*)(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
bit_index+=32;
}
uint32_t Emod32=E&31;
if (Emod32 != 0) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
uint32_t tmp = vaddvq_u32(cshift);
tmp&=((1<<Emod32)-1);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=Emod32;
}
}
}
// s0 = s;
for ( ; s < nb_segments ; s++){
s2 = s&31;
foffset = ((s>>5)-E2_first_segment32)*E2;
fp = f2+foffset;
int i;
if ((bit_index&31) == 0 ) {
for (i = 0; i < (E2>>5)<<5; i+=32) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
*(output_p + (bit_index>>5)) = vaddvq_u32(cshift);
bit_index+=32;
}
uint32_t E2mod32=E2&31;
if (E2mod32 != 0) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
*(output_p + (bit_index>>5)) = vaddvq_u32(cshift)&((1<<E2mod32)-1);
bit_index+=E2mod32;
}
}
else {
for (i = 0; i < (E2>>5)<<5; i+=32) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[7],vshift7[s2]),vmask7));
uint32_t tmp = vaddvq_u32(cshift);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=32;
}
uint32_t E2mod32=E2&31;
if (E2mod32 != 0) {
uint32x4_t *fp128 = (uint32x4_t*)&fp[i];
uint32x4_t cshift = vandq_u32(vshlq_u32(fp128[0],vshift0[s2]),vmask0);
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[1],vshift1[s2]),vmask1));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[2],vshift2[s2]),vmask2));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[3],vshift3[s2]),vmask3));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[4],vshift4[s2]),vmask4));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[5],vshift5[s2]),vmask5));
cshift = vorrq_u32(cshift,vandq_u32(vshlq_u32(fp128[6],vshift6[s2]),vmask6));
uint32_t tmp = vaddvq_u32(cshift);
tmp&=((1<<E2mod32)-1);
*(output_p + (bit_index>>5)) |= (tmp<<(bit_index&31));
*(output_p + (bit_index>>5)+1) |= (tmp>>(32-(bit_index&31)));
bit_index+=E2mod32;
}
}
}
#else // non SIMD version
unsigned int segpos,s2;
for (s = 0; s < E2_first_segment ; s++) {
foffset = (s>>5)*E;
fp = f+foffset;
s2=s&31;
segpos = (1<<s2);
// printf("E %d s %d: foffset %d, s2 %d, segpos %u\n",E,s,foffset,s2,segpos);
for (int i = 0; i < E; i++) {
output_p[bit_index>>5]|=((fp[i] & segpos)!=0)<<(bit_index&31);
//printf("bit_index %d, output_p[%d] %x\n",bit_index, bit_index>>5,output_p[bit_index>>5]);
bit_index++;
}
}
for ( ; s < nb_segments ; s++){
foffset = ((s>>5)-E2_first_segment32)*E2;
fp = f2+foffset;
s2=s&31;
segpos = (1<<s2);
// printf("E2 %d s %d: foffset %d, s2 %d, segpos %u\n",E2,s,foffset,s2,segpos);
for (int i = 0; i < E2; i++) {
output_p[bit_index>>5]|=((fp[i] & segpos)!=0)<<(bit_index&31);
bit_index++;
}
}
#endif
}
/**
* \typedef ldpc8blocks_args_t
* \struct ldpc8blocks_args_s
* \brief Arguments of an encoding task
* encode up to 8 code blocks
* \var nrLDPC_TB_encoding_parameters TB encoding parameters as defined in the coding library interface
* \var impp encoder implementation specific parameters for the task
* \var f first interleaver output to be filled by the task
* \var f2 second interleaver output to be filled by the task
* in case of a shift of E in the code blocks group processed by the task
*/
static void ldpcnblocks(nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters, encoder_implemparams_t impp)
{
uint8_t mod_order = nrLDPC_TB_encoding_parameters->Qm;
uint16_t nb_rb = nrLDPC_TB_encoding_parameters->nb_rb;
uint32_t A = nrLDPC_TB_encoding_parameters->A;
unsigned int G = nrLDPC_TB_encoding_parameters->G;
LOG_D(PHY, "dlsch coding A %d K %d G %d (nb_rb %d, mod_order %d)\n", A, impp.K, G, nb_rb, (int)mod_order);
// nrLDPC_encoder output is in "d"
// let's make this interface happy!
// uint32_t d[4][68*384];
uint8_t *c[nrLDPC_TB_encoding_parameters->C];
if (!nrLDPC_TB_encoding_parameters->c_dev)
for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++)
c[r] = nrLDPC_TB_encoding_parameters->segments[r].c;
start_meas(&nrLDPC_TB_encoding_parameters->segments[impp.first_seg].ts_ldpc_encode);
LDPCencoder32(nrLDPC_TB_encoding_parameters->c_dev ? nrLDPC_TB_encoding_parameters->c_dev : c, &impp);
stop_meas(&nrLDPC_TB_encoding_parameters->segments[impp.first_seg].ts_ldpc_encode);
// Compute where to place in output buffer that is concatenation of all segments
#ifdef DEBUG_LDPC_ENCODING
LOG_D(PHY, "rvidx in encoding = %d\n", nrLDPC_TB_encoding_parameters->rv_index);
#endif
const uint32_t E = nrLDPC_TB_encoding_parameters->segments[0].E;
uint32_t E2=E;
uint32_t Emax = E;
int n_seg = nrLDPC_TB_encoding_parameters->C>>5;
int n_seg2 = n_seg;
if ((nrLDPC_TB_encoding_parameters->C & 31) > 0) n_seg2++;
int r_shift = n_seg2;
int r_shift2 = nrLDPC_TB_encoding_parameters->C;
for (int s=0;s<nrLDPC_TB_encoding_parameters->C;s++) {
//printf("segment %d E %d\n",s,nrLDPC_TB_encoding_parameters->segments[s].E);
if (nrLDPC_TB_encoding_parameters->segments[s].E != E) {
E2=nrLDPC_TB_encoding_parameters->segments[s].E;
if(E2 > Emax)
Emax = E2;
r_shift = s>>5;
r_shift2 = s;
// printf("r_shift %d, r_shift2 %d\n",r_shift,r_shift2);
break;
}
}
LOG_D(NR_PHY,
"Rate Matching, Code segment %d...%d r_shift %d n_seg2 %d (coded bits (G) %u, E %d, E2 %d Filler bits %d, Filler offset %d mod_order %d, nb_rb "
"%d,nrOfLayer %d)...\n",
0,
impp.n_segments-1,
r_shift,
n_seg2,
G,
E,E2,
impp.F,
impp.K - impp.F - 2 * impp.Zc,
mod_order,
nb_rb,
nrLDPC_TB_encoding_parameters->nb_layers);
/*
printf("Rate Matching, Code segment 0..%d r_shift %d r_shift2 %d n_seg2 %d (coded bits (G) %u, E %d, E2 %d Filler bits %d, Filler offset %d mod_order %d, nb_rb "
"%d,nrOfLayer %d)...\n",
impp.n_segments-1,
r_shift,
r_shift2,
n_seg2,
G,
E,E2,
impp.F,
impp.K - impp.F - 2 * impp.Zc,
mod_order,
nb_rb,
nrLDPC_TB_encoding_parameters->nb_layers);
*/
uint32_t Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm;
uint32_t e[E*(r_shift+1)];
uint32_t e2[E2*(n_seg2-r_shift)];
uint32_t f[E*(r_shift+1)] __attribute__ ((aligned (64)));
uint32_t f2[E2*(n_seg2-r_shift)] __attribute__ ((aligned (64)));
// Interleaver outputs are stored in the output arrays
uint8_t *output = nrLDPC_TB_encoding_parameters->output;
start_meas(&nrLDPC_TB_encoding_parameters->segments[0].ts_rate_match);
memset(e,0,sizeof(e));
memset(f,0,sizeof(f));
if (1/*r_shift < n_seg2*/) {
memset(e2,0,sizeof(e2));
memset(f2,0,sizeof(f2));
}
for (int r=0;r<n_seg2;r++) {
if (r<=r_shift)
nr_rate_matching_ldpc32(Tbslbrm,
impp.BG,
impp.Zc,
d_host[r],
e+(r*E),
impp.n_segments,
impp.F,
impp.K - impp.F - 2 * impp.Zc,
nrLDPC_TB_encoding_parameters->rv_index,
E);
if (r>=r_shift)
nr_rate_matching_ldpc32(Tbslbrm,
impp.BG,
impp.Zc,
d_host[r],
e2+((r-r_shift)*E2),
impp.n_segments,
impp.F,
impp.K - impp.F - 2 * impp.Zc,
nrLDPC_TB_encoding_parameters->rv_index,
E2);
/*
if (r==(n_seg2-1)) {
for (int i=0;i<16;i++) printf("rm: %x %x\n",d[n_seg2-1][i],e2[((n_seg2-1)*E2)+i]);
}
*/
}
stop_meas(&nrLDPC_TB_encoding_parameters->segments[0].ts_rate_match);
if (impp.K - impp.F - 2 * impp.Zc > E) {
LOG_E(PHY,
"dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n",
A,
impp.K,
G,
nb_rb,
(int)mod_order);
LOG_E(NR_PHY,
"Rate Matching, Code segments 0..%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, "
"nb_rb %d)...\n",
impp.n_segments,
G,
E,
impp.K,
impp.F,
impp.K - impp.F - 2 * impp.Zc,
mod_order,
nb_rb);
}
//printf("interleaving r_shift %d, n_seg2 %d\n",r_shift,n_seg2);
start_meas(&nrLDPC_TB_encoding_parameters->segments[0].ts_interleave);
for (int r=0;r<=r_shift;r++)
nr_interleaving_ldpc32(E,
mod_order,
e+E*r,
f+E*r);
for (int r=r_shift;r<n_seg2;r++)
nr_interleaving_ldpc32(E2,
mod_order,
e2+E2*(r-r_shift),
f2+E2*(r-r_shift));
/*
for (int i=0;i<16;i++) printf("intl (f offset %d): %x %x\n",(n_seg2-1)*E2,e2[((n_seg2-1)*E2)+i],f2[((n_seg2-1)*E2)+i]);
printf("-------------------\n");
for (int i=E2-16;i<E2;i++) printf("intl (f offset %d): %x %x\n",(n_seg2-1)*E2,e2[((n_seg2-1)*E2)+i],f2[((n_seg2-1)*E2)+i]);
*/
stop_meas(&nrLDPC_TB_encoding_parameters->segments[0].ts_interleave);
if (impp.tconcat) start_meas(impp.tconcat);
unpack_output(f,E,f2,E2,r_shift,r_shift2,nrLDPC_TB_encoding_parameters->C,output);
if (impp.tconcat) stop_meas(impp.tconcat);
}
int nrLDPC_coding_encoder32(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters)
{
encoder_implemparams_t common_segment_params = {
.n_segments = nrLDPC_TB_encoding_parameters->C,
.tinput = nrLDPC_slot_encoding_parameters->tinput,
.tinput_memcpy = nrLDPC_slot_encoding_parameters->tinput_memcpy,
.tprep = nrLDPC_slot_encoding_parameters->tprep,
.tparity = nrLDPC_slot_encoding_parameters->tparity,
.toutput = nrLDPC_slot_encoding_parameters->toutput,
.tconcat = nrLDPC_slot_encoding_parameters->tconcat,
.Kb = nrLDPC_TB_encoding_parameters->Kb,
.Zc = nrLDPC_TB_encoding_parameters->Z,
.BG = nrLDPC_TB_encoding_parameters->BG,
.output = nrLDPC_TB_encoding_parameters->output,
.K = nrLDPC_TB_encoding_parameters->K,
.F = nrLDPC_TB_encoding_parameters->F,
};
LOG_D(NR_PHY,"Calling ldpcnblocks (C %d, Z %d, K %d)\n",common_segment_params.n_segments,common_segment_params.Zc,common_segment_params.K);
ldpcnblocks(nrLDPC_TB_encoding_parameters, common_segment_params);
return 0;
}

View File

@@ -24,7 +24,8 @@
#include "common/utils/LOG/log.h"
// #define RM_DEBUG 1
#define USE128BIT
static const uint8_t index_k0[2][4] = {{0, 17, 33, 56}, {0, 13, 25, 43}};
void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e, uint8_t *f)
@@ -65,7 +66,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e, uint8_t *f)
simde__m128i *f_128 = (simde__m128i *)f;
simde__m128i *e0_128 = (simde__m128i *)e0;
simde__m128i *e1_128 = (simde__m128i *)e1;
for (; i < (EQm & ~15); i += 64) {
for (; i < (EQm & ~15); i += 16) {
simde__m128i e0j = simde_mm_loadu_si128(e0_128++);
simde__m128i e1j = simde_mm_loadu_si128(e1_128++);
simde_mm_storeu_si128(f_128++, simde_mm_unpacklo_epi8(e0j, e1j));
@@ -359,14 +360,15 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e, uint8_t *f)
f = (uint8_t *)f_512;
#endif
#ifdef USE128BIT
e0_128 = (simde__m128i *)e0;
e1_128 = (simde__m128i *)e1;
e2_128 = (simde__m128i *)e2;
e3_128 = (simde__m128i *)e3;
e4_128 = (simde__m128i *)e4;
e5_128 = (simde__m128i *)e5;
e6_128 = (simde__m128i *)e6;
e7_128 = (simde__m128i *)e7;
simde__m128i *e0_128 = (simde__m128i *)e0;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *e2_128 = (simde__m128i *)e2;
simde__m128i *e3_128 = (simde__m128i *)e3;
simde__m128i *e4_128 = (simde__m128i *)e4;
simde__m128i *e5_128 = (simde__m128i *)e5;
simde__m128i *e6_128 = (simde__m128i *)e6;
simde__m128i *e7_128 = (simde__m128i *)e7;
simde__m128i *f_128 = (simde__m128i *)f;
for (; i < (EQm & ~15); i += 16) {
simde__m128i e0j = simde_mm_loadu_si128(e0_128++);
simde__m128i e1j = simde_mm_loadu_si128(e1_128++);
@@ -444,25 +446,461 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e, uint8_t *f)
}
}
void nr_interleaving_ldpc32(uint32_t E, uint8_t Qm, uint32_t *e, uint32_t *f)
{
const uint32_t EQm = E / Qm;
memset(f, 0, E * sizeof(uint32_t));
switch(Qm) {
case 2: {
uint32_t *e0 = e;
uint32_t *e1 = e + EQm;
int i = 0;
for (; i < EQm; i++) {
*f++ = *e0++;
*f++ = *e1++;
}
} break;
case 4: {
uint32_t *e0 = e;
uint32_t *e1 = e0 + EQm;
uint32_t *e2 = e1 + EQm;
uint32_t *e3 = e2 + EQm;
int i = 0;
for (; i < EQm; i++) {
*f++ = *e0++;
*f++ = *e1++;
*f++ = *e2++;
*f++ = *e3++;
}
} break;
case 6: {
uint32_t *e0 = e;
uint32_t *e1 = e0 + EQm;
uint32_t *e2 = e1 + EQm;
uint32_t *e3 = e2 + EQm;
uint32_t *e4 = e3 + EQm;
uint32_t *e5 = e4 + EQm;
int i = 0;
#if 0
simde__m128i *e0_128 = (simde__m128i *)e0;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *e2_128 = (simde__m128i *)e2;
simde__m128i *e3_128 = (simde__m128i *)e3;
simde__m128i *e4_128 = (simde__m128i *)e4;
simde__m128i *e5_128 = (simde__m128i *)e5;
simde__m128i *f128 = (simde__m128i *)f;
for (; i < (EQm & ~3); i += 4) {
simde__m128i e0j = simde_mm_loadu_si128(e0_128++);
simde__m128i e1j = simde_mm_loadu_si128(e1_128++);
simde__m128i e2j = simde_mm_loadu_si128(e2_128++);
simde__m128i e3j = simde_mm_loadu_si128(e3_128++);
simde__m128i e4j = simde_mm_loadu_si128(e4_128++);
simde__m128i e5j = simde_mm_loadu_si128(e5_128++);
simde__m128i tmp0 = simde_mm_unpacklo_epi32(e0j, e1j); // e0(i) e1(i) e0(i+1) e1(i+1)
simde__m128i tmp1 = simde_mm_unpacklo_epi32(e2j, e3j); // e2(i) e3(i) e2(i+1) e3(i+1)
simde__m128i tmp2 = simde_mm_unpacklo_epi32(e4j, e5j); // e4(i) e5(i) e4(i+1) e5(i+1)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp0, tmp1)); // e0(i) e1(i) e2(i) e3(i)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp2,simde_mm_unpackhi_epi64(tmp0,tmp0))); // e4(i) e5(i) e0(i+1) e1(i+1)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp1,tmp2)); // e2(i+1) e3(i+1) e4(i+1) e5(i+1)
tmp0 = simde_mm_unpackhi_epi32(e0j, e1j); // e0(i+2) e1(i+2) e0(i+3) e1(i+3)
tmp1 = simde_mm_unpackhi_epi32(e2j, e3j); // e2(i+2) e3(i+2) e2(i+3) e3(i+3)
tmp2 = simde_mm_unpackhi_epi32(e4j, e5j); // e4(i+2) e5(i+2) e4(i+3) e5(i+3)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp0, tmp1)); // e0(i+2) e1(i+2) e2(i+2) e3(i+2)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp2,simde_mm_unpackhi_epi64(tmp0,tmp0))); // e4(i+2) e5(i+2) e0(i+3) e1(i+3)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp1,tmp2)); // e2(i+3) e3(i+3) e4(i+3) e5(i+3)
}
e0 = (uint32_t *)e0_128;
e1 = (uint32_t *)e1_128;
e2 = (uint32_t *)e2_128;
e3 = (uint32_t *)e3_128;
e4 = (uint32_t *)e4_128;
e5 = (uint32_t *)e5_128;
f = (uint32_t *)f128;
#endif
for (; i < EQm; i++) {
*f++ = *e0++;
*f++ = *e1++;
*f++ = *e2++;
*f++ = *e3++;
*f++ = *e4++;
*f++ = *e5++;
}
} break;
case 8: {
uint32_t *e0 = e;
uint32_t *e1 = e0 + EQm;
uint32_t *e2 = e1 + EQm;
uint32_t *e3 = e2 + EQm;
uint32_t *e4 = e3 + EQm;
uint32_t *e5 = e4 + EQm;
uint32_t *e6 = e5 + EQm;
uint32_t *e7 = e6 + EQm;
int i = 0;
#if 0 /*def __AVX2__, this needs to be fixed, revert to 128-bit below*/
simde__m256i *e0_256 = (simde__m256i *)e0;
simde__m256i *e1_256 = (simde__m256i *)e1;
simde__m256i *e2_256 = (simde__m256i *)e2;
simde__m256i *e3_256 = (simde__m256i *)e3;
simde__m256i *e4_256 = (simde__m256i *)e4;
simde__m256i *e5_256 = (simde__m256i *)e5;
simde__m256i *e6_256 = (simde__m256i *)e6;
simde__m256i *e7_256 = (simde__m256i *)e7;
simde__m256i *f256 = (simde__m256i *)f;
for (; i < (EQm & ~7); i += 8) {
simde__m256i e0j = simde_mm256_loadu_si256(e0_256++);
simde__m256i e1j = simde_mm256_loadu_si256(e1_256++);
simde__m256i e2j = simde_mm256_loadu_si256(e2_256++);
simde__m256i e3j = simde_mm256_loadu_si256(e3_256++);
simde__m256i e4j = simde_mm256_loadu_si256(e4_256++);
simde__m256i e5j = simde_mm256_loadu_si256(e5_256++);
simde__m256i e6j = simde_mm256_loadu_si256(e6_256++);
simde__m256i e7j = simde_mm256_loadu_si256(e7_256++);
simde__m256i tmp0 = simde_mm256_unpacklo_epi32(e0j, e1j); // e0(i) e1(i) e0(i+1) e1(i+1) e0(i+4) e1(i+4) e0(i+5) e1(i+5)
simde__m256i tmp1 = simde_mm256_unpacklo_epi32(e2j, e3j); // e2(i) e3(i) e2(i+1) e3(i+1) e2(i+4) e3(i+4) e2(i+5) e3(i+5)
simde__m256i tmp2 = simde_mm256_unpacklo_epi32(e4j, e5j); // e4(i) e5(i) e4(i+1) e5(i+1) e4(i+4) e5(i+4) e4(i+5) e5(i+5)
simde__m256i tmp3 = simde_mm256_unpacklo_epi32(e6j, e7j); // e6(i) e7(i) e6(i+1) e7(i+1) e6(i+4) e7(i+4) e6(i+5) e7(i+5)
//
simde__m256i tmp4 = simde_mm256_unpacklo_epi64(tmp0, tmp1); // e0(i) e1(i) e2(i) e3(i) e0(i+4) e1(i+4) e2(i+4) e3(i+4)
simde__m256i tmp5 = simde_mm256_unpacklo_epi64(tmp2, tmp3); // e4(i) e5(i) e6(i) e7(i) e4(i+4) e5(i+4) e6(i+4) e7(i+4)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp4,tmp5,0x20)); // e0(i) e1(i) e2(i) e3(i) e4(i) e5(i) e6(i) e7(i)
simde__m256i tmp6 = simde_mm256_unpackhi_epi64(tmp0, tmp1); // e0(i+1) e1(i+1) e2(i+1) e3(i+1) e0(i+5) e1(i+5) e2(i+5) e3(i+5)
simde__m256i tmp7 = simde_mm256_unpackhi_epi64(tmp2, tmp3); // e4(i+1) e5(i+1) e6(i+1) e7(i+1) e4(i+5) e5(i+5) e6(i+5) e7(i+5)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp6,tmp7,0x20)); // e0(i+1) e1(i+1) e2(i+1) e3(i+1) e4(i+1) e5(i+1) e6(i+1) e7(i+1)
//
tmp0 = simde_mm256_unpackhi_epi32(e0j, e1j); // e0(i+2) e1(i+2) e0(i+3) e1(i+3) e0(i+6) e1(i+6) e0(i+7) e1(i+7)
tmp1 = simde_mm256_unpackhi_epi32(e2j, e3j); // e2(i+2) e3(i+2) e2(i+3) e3(i+3) e2(i+6) e3(i+6) e2(i+7) e3(i+7)
tmp2 = simde_mm256_unpackhi_epi32(e4j, e5j); // e4(i+2) e5(i+2) e4(i+3) e5(i+3) e4(i+6) e5(i+6) e4(i+7) e5(i+7)
tmp3 = simde_mm256_unpackhi_epi32(e6j, e7j); // e6(i+2) e7(i+2) e6(i+3) e7(i+3) e6(i+6) e7(i+6) e6(i+7) e7(i+7)
//
simde__m256i tmp8 = simde_mm256_unpacklo_epi64(tmp0, tmp1); // e0(i+2) e1(i+2) e2(i+2) e3(i+2) e0(i+6) e1(i+6) e2(i+6) e3(i+6)
simde__m256i tmp9 = simde_mm256_unpacklo_epi64(tmp2, tmp3); // e4(i+2) e5(i+2) e6(i+2) e7(i+2) e4(i+6) e5(i+6) e6(i+6) e7(i+6)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp8,tmp9,0x20)); // e0(i+2) e1(i+2) e2(i+2) e3(i+2) e4(i+2) e5(i+2) e6(i+2) e7(i+2)
simde__m256i tmp10 = simde_mm256_unpackhi_epi64(tmp0, tmp1); // e0(i+3) e1(i+3) e2(i+3) e3(i+3) e0(i+7) e1(i+7) e2(i+7) e3(i+7)
simde__m256i tmp11 = simde_mm256_unpackhi_epi64(tmp2, tmp3); // e4(i+3) e5(i+3) e6(i+3) e7(i+3) e4(i+7) e5(i+7) e6(i+7) e7(i+7)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp10,tmp11,0x20)); // e0(i+3) e1(i+3) e2(i+3) e3(i+3) e4(i+3) e5(i+3) e6(i+3) e7(i+3)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp4,tmp5,0x31)); // e0(i+4) e1(i+4) e2(i+4) e3(i+4) e4(i+4) e5(i+4) e6(i+4) e7(i+4)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp6,tmp7,0x31)); // e0(i+5) e1(i+5) e2(i+5) e3(i+5) e4(i+5) e5(i+5) e6(i+5) e7(i+5)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp8,tmp9,0x31)); // e0(i+6) e1(i+6) e2(i+6) e3(i+6) e4(i+6) e5(i+6) e6(i+6) e7(i+6)
simde_mm256_storeu_si256(f256++,_mm256_permute2x128_si256(tmp10,tmp11,0x31)); // e0(i+7) e1(i+7) e2(i+7) e3(i+7) e4(i+7) e5(i+7) e6(i+7) e7(i+7)
}
e0 = (uint32_t *)e0_256;
e1 = (uint32_t *)e1_256;
e2 = (uint32_t *)e2_256;
e3 = (uint32_t *)e3_256;
e4 = (uint32_t *)e4_256;
e5 = (uint32_t *)e5_256;
e6 = (uint32_t *)e6_256;
e7 = (uint32_t *)e7_256;
f = (uint32_t *)f256;
#endif
simde__m128i *e0_128 = (simde__m128i *)e0;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *e2_128 = (simde__m128i *)e2;
simde__m128i *e3_128 = (simde__m128i *)e3;
simde__m128i *e4_128 = (simde__m128i *)e4;
simde__m128i *e5_128 = (simde__m128i *)e5;
simde__m128i *e6_128 = (simde__m128i *)e6;
simde__m128i *e7_128 = (simde__m128i *)e7;
simde__m128i *f128 = (simde__m128i *)f;
for (; i < (EQm & ~3); i += 4) {
simde__m128i e0j = simde_mm_loadu_si128(e0_128++);
simde__m128i e1j = simde_mm_loadu_si128(e1_128++);
simde__m128i e2j = simde_mm_loadu_si128(e2_128++);
simde__m128i e3j = simde_mm_loadu_si128(e3_128++);
simde__m128i e4j = simde_mm_loadu_si128(e4_128++);
simde__m128i e5j = simde_mm_loadu_si128(e5_128++);
simde__m128i e6j = simde_mm_loadu_si128(e6_128++);
simde__m128i e7j = simde_mm_loadu_si128(e7_128++);
simde__m128i tmp0 = simde_mm_unpacklo_epi32(e0j, e1j); // e0(i) e1(i) e0(i+1) e1(i+1)
simde__m128i tmp1 = simde_mm_unpacklo_epi32(e2j, e3j); // e2(i) e3(i) e2(i+1) e3(i+1)
simde__m128i tmp2 = simde_mm_unpacklo_epi32(e4j, e5j); // e4(i) e5(i) e4(i+1) e5(i+1)
simde__m128i tmp3 = simde_mm_unpacklo_epi32(e6j, e7j); // e6(i) e7(i) e6(i+1) e7(i+1)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp0, tmp1)); // e0(i) e1(i) e2(i) e3(i)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp2, tmp3)); // e4(i) e5(i) e6(i) e7(i)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp0, tmp1)); // e0(i+1) e1(i+1) e2(i+1) e3(i+1)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp2, tmp3)); // e4(i+1) e5(i+1) e6(i+1) e7(i+1)
tmp0 = simde_mm_unpackhi_epi32(e0j, e1j); // e0(i+2) e1(i+2) e0(i+3) e1(i+3)
tmp1 = simde_mm_unpackhi_epi32(e2j, e3j); // e2(i+2) e3(i+2) e2(i+3) e3(i+3)
tmp2 = simde_mm_unpackhi_epi32(e4j, e5j); // e4(i+2) e5(i+2) e4(i+3) e5(i+3)
tmp3 = simde_mm_unpackhi_epi32(e6j, e7j); // e6(i+2) e7(i+2) e6(i+3) e7(i+3)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp0, tmp1)); // e0(i+2) e1(i+2) e2(i+2) e3(i+2)
simde_mm_storeu_si128(f128++,simde_mm_unpacklo_epi64(tmp2, tmp3)); // e4(i+2) e5(i+2) e6(i+2) e7(i+2)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp0, tmp1)); // e0(i+3) e1(i+3) e2(i+3) e3(i+3)
simde_mm_storeu_si128(f128++,simde_mm_unpackhi_epi64(tmp2, tmp3)); //e4(i+3) e5(i+3) e6(i+3) e7(i+3)
}
e0 = (uint32_t *)e0_128;
e1 = (uint32_t *)e1_128;
e2 = (uint32_t *)e2_128;
e3 = (uint32_t *)e3_128;
e4 = (uint32_t *)e4_128;
e5 = (uint32_t *)e5_128;
e6 = (uint32_t *)e6_128;
e7 = (uint32_t *)e7_128;
f = (uint32_t *)f128;
for (; i < EQm; i++) {
*f++ = *e0++;
*f++ = *e1++;
*f++ = *e2++;
*f++ = *e3++;
*f++ = *e4++;
*f++ = *e5++;
*f++ = *e6++;
*f++ = *e7++;
}
}
break;
default:
AssertFatal(false, "Should be here!\n");
}
}
#if defined(__aarch64__)
static inline uint8x16_t tbl96_u8(uint8x16_t b0, uint8x16_t b1, uint8x16_t b2,
uint8x16_t b3, uint8x16_t b4, uint8x16_t b5,
uint8x16_t idx /* 0..95 */)
{
// Table 0: bytes 0..63
uint8x16x4_t T0 = {{ b0, b1, b2, b3 }};
uint8x16_t r0 = vqtbl4q_u8(T0, idx);
// Table 1: bytes 64..95, presented as a 64-byte table:
// bytes 0..31 map to original 64..95, bytes 32..63 are dummy (return 0)
uint8x16_t z = vdupq_n_u8(0);
uint8x16x4_t T1 = {{ b4, b5, z, z }};
// idx1 = idx - 64 (wrap-safe via unsigned subtract); only valid when idx>=64
uint8x16_t idx1 = vsubq_u8(idx, vdupq_n_u8(64));
uint8x16_t r1 = vqtbl4q_u8(T1, idx1);
// Select r1 where idx >= 64, else r0
uint8x16_t sel = vcgeq_u8(idx, vdupq_n_u8(64)); // 0xFF where idx>=64
return vbslq_u8(sel, r1, r0);
}
static inline uint8x16_t tbl128_u8(uint8x16_t b0, uint8x16_t b1, uint8x16_t b2, uint8x16_t b3,
uint8x16_t b4, uint8x16_t b5, uint8x16_t b6, uint8x16_t b7,
uint8x16_t idx /* 0..127 */)
{
// Table low: bytes 0..63
uint8x16x4_t T0 = {{ b0, b1, b2, b3 }};
uint8x16_t r0 = vqtbl4q_u8(T0, idx);
// Table high: bytes 64..127, mapped to 0..63 by subtracting 64
uint8x16x4_t T1 = {{ b4, b5, b6, b7 }};
uint8x16_t idx1 = vsubq_u8(idx, vdupq_n_u8(64));
uint8x16_t r1 = vqtbl4q_u8(T1, idx1);
// Select high where idx >= 64 else low
uint8x16_t sel = vcgeq_u8(idx, vdupq_n_u8(64));
return vbslq_u8(sel, r1, r0);
}
#elif defined(__AVX512BW__)
static inline __m512i idx_stride_u16(int ways, int k)
{
uint16_t idx[32] __attribute__((aligned(64)));
for (int n = 0; n < 32; n++) idx[n] = (uint16_t)(k + ways*n);
return _mm512_load_si512((const void*)idx);
}
// Build indices for k = 0..5, lanes n=0..15: p = k + 6*n
static inline __m512i make_idx_ab(int k) {
uint16_t idx[32] __attribute__((aligned(64))) = { 0 };
for (int n = 0; n < 16; n++) {
idx[n] = (uint16_t)(k + 6*n); // p in [0..95]
}
return _mm512_load_si512((const void*)idx);
}
static inline __m512i make_idx_bc(int k) {
uint16_t idx[32] __attribute__((aligned(64))) = { 0 };
for (int n = 0; n < 16; n++) {
int p = k + 6*n;
// For (B,C) pair, global p maps to:
// indices 0..31 -> B lanes 0..31 (global 32..63)
// indices 32..63 -> C lanes 0..31 (global 64..95)
// so use (p - 32) as index into [B|C] when p >= 32.
idx[n] = (uint16_t)(p - 32);
}
return _mm512_load_si512((const void*)idx);
}
static inline __mmask32 make_mask_bc(int k) {
// lanes needing BC are those with p >= 64 (since AB covers global 0..63)
__mmask32 m = 0;
for (int n = 0; n < 16; n++) {
int p = k + 6*n;
if (p >= 64) m |= (1u << n);
}
return m;
}
#endif
void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e, int16_t *f)
{
const uint32_t EQm = E / Qm;
switch (Qm) {
case 2: {
AssertFatal(E % 2 == 0, "");
int16_t *e1 = e + (E / 2);
int16_t *end = f + E - 1;
while (f < end) {
int16_t *e1 = e + EQm;
int i=0;
#if defined(__aarch64__)
for (; i + 8 <= EQm; i += 8) {
int16x8x2_t v = vld2q_s16(f); // 8 groups
f += 16;
vst1q_s16(e, v.val[0]); e += 8;
vst1q_s16(e1, v.val[1]); e1 += 8;
}
#elif defined(__AVX512BW__)
const __m512i idx0 = idx_stride_u16(2, 0);
const __m512i idx1 = idx_stride_u16(2, 1);
for (; i + 32 <= EQm; i += 32) {
// 32 groups * 2 u16 = 64 u16 = 2x512b
__m512i A = _mm512_loadu_si512((const void*)(f + 0)); // u16[0..31]
__m512i B = _mm512_loadu_si512((const void*)(f + 32)); // u16[32..63]
f += 64;
__m512i o0 = _mm512_permutex2var_epi16(A, idx0, B);
__m512i o1 = _mm512_permutex2var_epi16(A, idx1, B);
_mm512_storeu_si512((void*)e, o0); e += 32;
_mm512_storeu_si512((void*)e1, o1); e1 += 32;
}
#else
simde__m128i *e0_128 = (simde__m128i *)e;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *f128 = (simde__m128i *)f;
const uint8_t shuf4[16] __attribute__((aligned(16))) = {0,1,4,5,8,9,12,13,2,3,6,7,10,11,14,15};
const simde__m128i *shuf4_128 = (const simde__m128i *)shuf4;
for (; i < (EQm & ~7); i += 8) {
simde__m128i f0j = simde_mm_loadu_si128(f128++); // f0(i) f0(i+1) f0(i+2) f0(i+3) f0(i+4) f0(i+5) f0(i+6) f0(i+7)
simde__m128i f1j = simde_mm_loadu_si128(f128++); // f1(i) f1(i+1) f1(i+2) f1(i+3) f1(i+4) f1(i+5) f1(i+6) f1(i+7)
simde__m128i tmp0 = simde_mm_shuffle_epi8(f0j,*shuf4_128); // f0(i) f0(i+2) f0(i+4) f0(i+6) f0(i+1) f0(i+3) f0(i+5) f0(i+7)
simde__m128i tmp1 = simde_mm_shuffle_epi8(f1j,*shuf4_128); // f1(i) f1(i+2) f1(i+4) f1(i+6) f1(i+1) f1(i+3) f1(i+5) f1(i+7)
simde_mm_storeu_si128(e0_128++,simde_mm_unpacklo_epi64(tmp0, tmp1)); // f0(i) f0(i+2) f0(i+4) f0(i+6) f1(i) f1(i+2) f1(i+4) f1(i+6)
simde_mm_storeu_si128(e1_128++,simde_mm_unpackhi_epi64(tmp0, tmp1)); // f0(i+1) f0(i+3) f0(i+5) f0(i+7) f1(i+1) f1(i+3) f1(i+5) f1(i+7)
}
e=(int16_t *)e0_128;
e1=(int16_t *)e1_128;
f=(int16_t *)f128;
#endif
for (; i < EQm; i++) {
*e++ = *f++;
*e1++ = *f++;
}
} break;
case 4: {
AssertFatal(E % 4 == 0, "");
int16_t *e1 = e + (E / 4);
int16_t *e2 = e1 + (E / 4);
int16_t *e3 = e2 + (E / 4);
int16_t *end = f + E - 3;
while (f < end) {
int i=0;
int16_t *e1 = e + EQm;
int16_t *e2 = e1 + EQm;
int16_t *e3 = e2 + EQm;
#if defined(__aarch64__)
for (; i + 8 <= EQm; i += 8) {
int16x8x4_t v = vld4q_s16(f); // 8 groups
f += 32;
vst1q_s16(e, v.val[0]); e += 8;
vst1q_s16(e1, v.val[1]); e1 += 8;
vst1q_s16(e2, v.val[2]); e2 += 8;
vst1q_s16(e3, v.val[3]); e3 += 8;
}
#elif defined(__AVX512BW__)
const __m512i idx0 = idx_stride_u16(4, 0);
const __m512i idx1 = idx_stride_u16(4, 1);
const __m512i idx2 = idx_stride_u16(4, 2);
const __m512i idx3 = idx_stride_u16(4, 3);
for (; i + 32 <= EQm; i += 32) {
// 32 groups * 4 u16 = 128 u16 = 4x512b
__m512i A = _mm512_loadu_si512((const void*)(f + 0));
__m512i B = _mm512_loadu_si512((const void*)(f + 32));
__m512i C = _mm512_loadu_si512((const void*)(f + 64));
__m512i D = _mm512_loadu_si512((const void*)(f + 96));
f += 128;
// Build results from (A,B) and (C,D) with masking (boundary at 64 u16)
__m512i o0_ab = _mm512_permutex2var_epi16(A, idx0, B);
__m512i o1_ab = _mm512_permutex2var_epi16(A, idx1, B);
__m512i o2_ab = _mm512_permutex2var_epi16(A, idx2, B);
__m512i o3_ab = _mm512_permutex2var_epi16(A, idx3, B);
__m512i idx0_cd = _mm512_sub_epi16(idx0, _mm512_set1_epi16(64));
__m512i idx1_cd = _mm512_sub_epi16(idx1, _mm512_set1_epi16(64));
__m512i idx2_cd = _mm512_sub_epi16(idx2, _mm512_set1_epi16(64));
__m512i idx3_cd = _mm512_sub_epi16(idx3, _mm512_set1_epi16(64));
__m512i o0_cd = _mm512_permutex2var_epi16(C, idx0_cd, D);
__m512i o1_cd = _mm512_permutex2var_epi16(C, idx1_cd, D);
__m512i o2_cd = _mm512_permutex2var_epi16(C, idx2_cd, D);
__m512i o3_cd = _mm512_permutex2var_epi16(C, idx3_cd, D);
// lanes needing CD are those where idx >= 64
__mmask32 m0 = _mm512_cmpge_epu16_mask(idx0, _mm512_set1_epi16(64));
__mmask32 m1 = _mm512_cmpge_epu16_mask(idx1, _mm512_set1_epi16(64));
__mmask32 m2 = _mm512_cmpge_epu16_mask(idx2, _mm512_set1_epi16(64));
__mmask32 m3 = _mm512_cmpge_epu16_mask(idx3, _mm512_set1_epi16(64));
__m512i o0 = _mm512_mask_mov_epi16(o0_ab, m0, o0_cd);
__m512i o1 = _mm512_mask_mov_epi16(o1_ab, m1, o1_cd);
__m512i o2 = _mm512_mask_mov_epi16(o2_ab, m2, o2_cd);
__m512i o3 = _mm512_mask_mov_epi16(o3_ab, m3, o3_cd);
_mm512_storeu_si512((void*)e, o0); e += 32;
_mm512_storeu_si512((void*)e1, o1); e1 += 32;
_mm512_storeu_si512((void*)e2, o2); e2 += 32;
_mm512_storeu_si512((void*)e3, o3); e3 += 32;
}
#else
simde__m128i *e0_128 = (simde__m128i *)e;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *e2_128 = (simde__m128i *)e2;
simde__m128i *e3_128 = (simde__m128i *)e3;
simde__m128i *f128 = (simde__m128i *)f;
const uint8_t shuf16[16] __attribute__((aligned(16))) = {0,1,8,9,2,3,10,11,4,5,12,13,6,7,14,15};
const simde__m128i *shuf16_128 = (const simde__m128i *)shuf16;
for (i=0; i < (EQm & ~7); i += 8) {
simde__m128i f0j = simde_mm_loadu_si128(f128++);
simde__m128i f1j = simde_mm_loadu_si128(f128++);
simde__m128i f2j = simde_mm_loadu_si128(f128++);
simde__m128i f3j = simde_mm_loadu_si128(f128++);
simde__m128i tmp0 = simde_mm_shuffle_epi8(f0j,*shuf16_128); // f0(i) f0(i+4) f0(i+1) f0(i+5) f0(i+2) f0(i+6) f0(i+3) f0(i+7)
simde__m128i tmp1 = simde_mm_shuffle_epi8(f1j,*shuf16_128); // f1(i) f1(i+4) f1(i+1) f1(i+5) f1(i+2) f1(i+6) f1(i+3) f1(i+7)
simde__m128i tmp2 = simde_mm_shuffle_epi8(f2j,*shuf16_128); // f2(i) f2(i+4) f2(i+1) f2(i+5) f2(i+2) f2(i+6) f2(i+3) f2(i+7)
simde__m128i tmp3 = simde_mm_shuffle_epi8(f3j,*shuf16_128); // f3(i) f3(i+2) f3(i+1) f3(i+5) f3(i+2) f3(i+6) f3(i+3) f3(i+7)
simde__m128i tmp4 = simde_mm_unpacklo_epi32(tmp0,tmp1); // f0(i) f0(i+4) f1(i) f1(i+4) f0(i+1) f0(i+5) f1(i+1) f1(i+5)
simde__m128i tmp5 = simde_mm_unpacklo_epi32(tmp2,tmp3); // f2(i) f2(i+4) f3(i) f3(i+4) f2(i+1) f2(i+5) f3(i+1) f3(i+5)
simde_mm_storeu_si128(e0_128++,simde_mm_unpacklo_epi64(tmp4, tmp5)); // f0(i) f0(i+4) f1(i) f1(i+4) f2(i) f2(i+4) f3(i) f3(i+4)
simde_mm_storeu_si128(e1_128++,simde_mm_unpackhi_epi64(tmp4, tmp5)); // f0(i+1) f0(i+5) f1(i+1) f1(i+5) f2(i+1) f2(i+5) f3(i+1) f3(i+5)
tmp4 = simde_mm_unpackhi_epi32(tmp0,tmp1); // f0(i+2) f0(i+6) f1(i+2) f1(i+6) f0(i+3) f0(i+7) f1(i+3) f1(i+7)
tmp5 = simde_mm_unpackhi_epi32(tmp2,tmp3); // f2(i+2) f2(i+6) f3(i+2) f3(i+6) f2(i+3) f2(i+7) f3(i+3) f3(i+7)
simde_mm_storeu_si128(e2_128++,simde_mm_unpacklo_epi64(tmp4, tmp5)); // f0(i+2) f0(i+6) f1(i+2) f1(i+6) f2(i+2) f2(i+6) f3(i+2) f3(i+6)
simde_mm_storeu_si128(e3_128++,simde_mm_unpackhi_epi64(tmp4, tmp5)); // f0(i+3) f0(i+7) f1(i+3) f1(i+7) f2(i+3) f2(i+7) f3(i+3) f3(i+7)
}
e=(int16_t *)e0_128;
e1=(int16_t *)e1_128;
e2=(int16_t *)e2_128;
e3=(int16_t *)e3_128;
f=(int16_t *)f128;
#endif
for (; i < EQm; i++) {
*e++ = *f++;
*e1++ = *f++;
*e2++ = *f++;
@@ -471,13 +909,108 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e, int16_t *f)
} break;
case 6: {
AssertFatal(E % 6 == 0, "");
int16_t *e1 = e + (E / 6);
int16_t *e2 = e1 + (E / 6);
int16_t *e3 = e2 + (E / 6);
int16_t *e4 = e3 + (E / 6);
int16_t *e5 = e4 + (E / 6);
int16_t *end = f + E - 5;
while (f < end) {
int16_t *e1 = e + EQm;
int16_t *e2 = e1 + EQm;
int16_t *e3 = e2 + EQm;
int16_t *e4 = e3 + EQm;
int16_t *e5 = e4 + EQm;
int i=0;
#if defined(__aarch64__)
// Byte indices for extracting each stream
// Each s16 occupies 2 bytes → indices are 2*(k + 6*n)
const uint8x16_t idx0 = { 0, 1, 12, 13, 24, 25, 36, 37,
48, 49, 60, 61, 72, 73, 84, 85 };
const uint8x16_t idx1 = { 2, 3, 14, 15, 26, 27, 38, 39,
50, 51, 62, 63, 74, 75, 86, 87 };
const uint8x16_t idx2 = { 4, 5, 16, 17, 28, 29, 40, 41,
52, 53, 64, 65, 76, 77, 88, 89 };
const uint8x16_t idx3 = { 6, 7, 18, 19, 30, 31, 42, 43,
54, 55, 66, 67, 78, 79, 90, 91 };
const uint8x16_t idx4 = { 8, 9, 20, 21, 32, 33, 44, 45,
56, 57, 68, 69, 80, 81, 92, 93 };
const uint8x16_t idx5 = { 10, 11, 22, 23, 34, 35, 46, 47,
58, 59, 70, 71, 82, 83, 94, 95 };
for (; i + 8 < EQm; i += 8) {
// Load 96 bytes (48 u16)
uint8x16_t b0 = vld1q_u8((const uint8_t*)(f + 0)); // bytes 0..15
uint8x16_t b1 = vld1q_u8((const uint8_t*)(f + 8)); // bytes 16..31
uint8x16_t b2 = vld1q_u8((const uint8_t*)(f + 16)); // bytes 32..47
uint8x16_t b3 = vld1q_u8((const uint8_t*)(f + 24)); // bytes 48..63
uint8x16_t b4 = vld1q_u8((const uint8_t*)(f + 32)); // bytes 64..79
uint8x16_t b5 = vld1q_u8((const uint8_t*)(f + 40)); // bytes 80..95
f += 48;
uint8x16_t o0b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx0);
uint8x16_t o1b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx1);
uint8x16_t o2b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx2);
uint8x16_t o3b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx3);
uint8x16_t o4b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx4);
uint8x16_t o5b = tbl96_u8(b0,b1,b2,b3,b4,b5, idx5);
vst1q_s16(e, vreinterpretq_s16_u8(o0b)); e += 8;
vst1q_s16(e1, vreinterpretq_s16_u8(o1b)); e1 += 8;
vst1q_s16(e2, vreinterpretq_s16_u8(o2b)); e2 += 8;
vst1q_s16(e3, vreinterpretq_s16_u8(o3b)); e3 += 8;
vst1q_s16(e4, vreinterpretq_s16_u8(o4b)); e4 += 8;
vst1q_s16(e5, vreinterpretq_s16_u8(o5b)); e5 += 8;
}
#elif defined(__AVX512BW__)
// Precompute permute control once (all compile-time constant patterns)
const __m512i idx0_ab = make_idx_ab(0), idx1_ab = make_idx_ab(1);
const __m512i idx2_ab = make_idx_ab(2), idx3_ab = make_idx_ab(3);
const __m512i idx4_ab = make_idx_ab(4), idx5_ab = make_idx_ab(5);
const __m512i idx0_bc = make_idx_bc(0), idx1_bc = make_idx_bc(1);
const __m512i idx2_bc = make_idx_bc(2), idx3_bc = make_idx_bc(3);
const __m512i idx4_bc = make_idx_bc(4), idx5_bc = make_idx_bc(5);
const __mmask32 m0 = make_mask_bc(0), m1 = make_mask_bc(1), m2 = make_mask_bc(2);
const __mmask32 m3 = make_mask_bc(3), m4 = make_mask_bc(4), m5 = make_mask_bc(5);
const __mmask32 store16 = 0xFFFFu; // store only first 16 lanes (16x u16)
for (; i + 16 <= EQm; i += 16) {
// 16 groups = 16*(6 u16) = 96 u16 = 192 bytes = 3 * 64B
__m512i A = _mm512_loadu_si512((const void*)(f + 0)); // u16[0..31]
__m512i B = _mm512_loadu_si512((const void*)(f + 32)); // u16[32..63]
__m512i C = _mm512_loadu_si512((const void*)(f + 64)); // u16[64..95]
f += 96;
// Gather from AB (global 0..63) and BC (global 32..95)
__m512i o0_ab = _mm512_permutex2var_epi16(A, idx0_ab, B);
__m512i o1_ab = _mm512_permutex2var_epi16(A, idx1_ab, B);
__m512i o2_ab = _mm512_permutex2var_epi16(A, idx2_ab, B);
__m512i o3_ab = _mm512_permutex2var_epi16(A, idx3_ab, B);
__m512i o4_ab = _mm512_permutex2var_epi16(A, idx4_ab, B);
__m512i o5_ab = _mm512_permutex2var_epi16(A, idx5_ab, B);
__m512i o0_bc = _mm512_permutex2var_epi16(B, idx0_bc, C);
__m512i o1_bc = _mm512_permutex2var_epi16(B, idx1_bc, C);
__m512i o2_bc = _mm512_permutex2var_epi16(B, idx2_bc, C);
__m512i o3_bc = _mm512_permutex2var_epi16(B, idx3_bc, C);
__m512i o4_bc = _mm512_permutex2var_epi16(B, idx4_bc, C);
__m512i o5_bc = _mm512_permutex2var_epi16(B, idx5_bc, C);
// Select lanes that crossed the 64-element boundary
__m512i o0 = _mm512_mask_mov_epi16(o0_ab, m0, o0_bc);
__m512i o1 = _mm512_mask_mov_epi16(o1_ab, m1, o1_bc);
__m512i o2 = _mm512_mask_mov_epi16(o2_ab, m2, o2_bc);
__m512i o3 = _mm512_mask_mov_epi16(o3_ab, m3, o3_bc);
__m512i o4 = _mm512_mask_mov_epi16(o4_ab, m4, o4_bc);
__m512i o5 = _mm512_mask_mov_epi16(o5_ab, m5, o5_bc);
// Store only the first 16 lanes (16 groups) to each plane
_mm512_mask_storeu_epi16((void*)e, store16, o0); e += 16;
_mm512_mask_storeu_epi16((void*)e1, store16, o1); e1 += 16;
_mm512_mask_storeu_epi16((void*)e2, store16, o2); e2 += 16;
_mm512_mask_storeu_epi16((void*)e3, store16, o3); e3 += 16;
_mm512_mask_storeu_epi16((void*)e4, store16, o4); e4 += 16;
_mm512_mask_storeu_epi16((void*)e5, store16, o5); e5 += 16;
}
//
#endif
for (; i < EQm; i++) {
*e++ = *f++;
*e1++ = *f++;
*e2++ = *f++;
@@ -488,15 +1021,181 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e, int16_t *f)
} break;
case 8: {
AssertFatal(E % 8 == 0, "");
int16_t *e1 = e + (E / 8);
int16_t *e2 = e1 + (E / 8);
int16_t *e3 = e2 + (E / 8);
int16_t *e4 = e3 + (E / 8);
int16_t *e5 = e4 + (E / 8);
int16_t *e6 = e5 + (E / 8);
int16_t *e7 = e6 + (E / 8);
int16_t *end = f + E - 7;
while (f < end) {
int16_t *e1 = e + EQm;
int16_t *e2 = e1 + EQm;
int16_t *e3 = e2 + EQm;
int16_t *e4 = e3 + EQm;
int16_t *e5 = e4 + EQm;
int16_t *e6 = e5 + EQm;
int16_t *e7 = e6 + EQm;
int i=0;
#if 0 //defined(__aarch64__)
// SIMDE version below is more efficient than tbl128
// For 8 groups: byte indices for stream k are 2*(k + 8*n) for n=0..7.
// That is: 2k + 16n (and +1 for the high byte of the u16).
const uint8x16_t idx0 = { 0, 1, 16, 17, 32, 33, 48, 49, 64, 65, 80, 81, 96, 97,112,113 };
const uint8x16_t idx1 = { 2, 3, 18, 19, 34, 35, 50, 51, 66, 67, 82, 83, 98, 99,114,115 };
const uint8x16_t idx2 = { 4, 5, 20, 21, 36, 37, 52, 53, 68, 69, 84, 85,100,101,116,117 };
const uint8x16_t idx3 = { 6, 7, 22, 23, 38, 39, 54, 55, 70, 71, 86, 87,102,103,118,119 };
const uint8x16_t idx4 = { 8, 9, 24, 25, 40, 41, 56, 57, 72, 73, 88, 89,104,105,120,121 };
const uint8x16_t idx5 = { 10, 11, 26, 27, 42, 43, 58, 59, 74, 75, 90, 91,106,107,122,123 };
const uint8x16_t idx6 = { 12, 13, 28, 29, 44, 45, 60, 61, 76, 77, 92, 93,108,109,124,125 };
const uint8x16_t idx7 = { 14, 15, 30, 31, 46, 47, 62, 63, 78, 79, 94, 95,110,111,126,127 };
for (; i + 8 <= EQm; i += 8) {
// Load 128 bytes = 64 u16 = 8 groups (aligned-friendly, but vld1q_u8 is fine either way)
uint8x16_t b0 = vld1q_u8((const uint8_t*)(f + 0)); // bytes 0..15
uint8x16_t b1 = vld1q_u8((const uint8_t*)(f + 8)); // bytes 16..31
uint8x16_t b2 = vld1q_u8((const uint8_t*)(f + 16)); // bytes 32..47
uint8x16_t b3 = vld1q_u8((const uint8_t*)(f + 24)); // bytes 48..63
uint8x16_t b4 = vld1q_u8((const uint8_t*)(f + 32)); // bytes 64..79
uint8x16_t b5 = vld1q_u8((const uint8_t*)(f + 40)); // bytes 80..95
uint8x16_t b6 = vld1q_u8((const uint8_t*)(f + 48)); // bytes 96..111
uint8x16_t b7 = vld1q_u8((const uint8_t*)(f + 56)); // bytes 112..127
f += 64; // consumed 64 u16
uint8x16_t o0b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx0);
uint8x16_t o1b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx1);
uint8x16_t o2b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx2);
uint8x16_t o3b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx3);
uint8x16_t o4b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx4);
uint8x16_t o5b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx5);
uint8x16_t o6b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx6);
uint8x16_t o7b = tbl128_u8(b0,b1,b2,b3,b4,b5,b6,b7, idx7);
vst1q_s16(e, vreinterpretq_s16_u8(o0b)); e += 8;
vst1q_s16(e1, vreinterpretq_s16_u8(o1b)); e1 += 8;
vst1q_s16(e2, vreinterpretq_s16_u8(o2b)); e2 += 8;
vst1q_s16(e3, vreinterpretq_s16_u8(o3b)); e3 += 8;
vst1q_s16(e4, vreinterpretq_s16_u8(o4b)); e4 += 8;
vst1q_s16(e5, vreinterpretq_s16_u8(o5b)); e5 += 8;
vst1q_s16(e6, vreinterpretq_s16_u8(o6b)); e6 += 8;
vst1q_s16(e7, vreinterpretq_s16_u8(o7b)); e7 += 8;
}
#elif defined(__AVX512BW__)
// Precompute indices for each stream k=0..7
const __m512i idx0 = idx_stride_u16(8,0);
const __m512i idx1 = idx_stride_u16(8,1);
const __m512i idx2 = idx_stride_u16(8,2);
const __m512i idx3 = idx_stride_u16(8,3);
const __m512i idx4 = idx_stride_u16(8,4);
const __m512i idx5 = idx_stride_u16(8,5);
const __m512i idx6 = idx_stride_u16(8,6);
const __m512i idx7 = idx_stride_u16(8,7);
const __m512i c64 = _mm512_set1_epi16(64);
const __m512i c128 = _mm512_set1_epi16(128);
const __m512i c192 = _mm512_set1_epi16(192);
for (; i + 32 <= EQm; i += 32) {
// 32 groups * 8 u16 = 256 u16 = 8 * 32 u16 = 8 ZMM vectors
__m512i A = _mm512_loadu_si512((const void*)(f + 0)); // u16[ 0.. 31]
__m512i B = _mm512_loadu_si512((const void*)(f + 32)); // u16[ 32.. 63]
__m512i C = _mm512_loadu_si512((const void*)(f + 64)); // u16[ 64.. 95]
__m512i D = _mm512_loadu_si512((const void*)(f + 96)); // u16[ 96..127]
__m512i E = _mm512_loadu_si512((const void*)(f + 128)); // u16[128..159]
__m512i F = _mm512_loadu_si512((const void*)(f + 160)); // u16[160..191]
__m512i G = _mm512_loadu_si512((const void*)(f + 192)); // u16[192..223]
__m512i H = _mm512_loadu_si512((const void*)(f + 224)); // u16[224..255]
f += 256;
// Helper macro: compute one stream (k) by permuting from 4 segments and blending
#define DO_STREAM(IDX, OUTPTR) do { \
/* segment masks based on global index p = k+8*n */ \
__mmask32 m1 = _mm512_cmpge_epu16_mask((IDX), c64); \
__mmask32 m2 = _mm512_cmpge_epu16_mask((IDX), c128); \
__mmask32 m3 = _mm512_cmpge_epu16_mask((IDX), c192); \
/* indices relative to each segment base */ \
__m512i i0 = (IDX); \
__m512i i1 = _mm512_sub_epi16((IDX), c64); \
__m512i i2 = _mm512_sub_epi16((IDX), c128); \
__m512i i3 = _mm512_sub_epi16((IDX), c192); \
/* permute from each 64-u16 segment (two ZMMs per segment) */ \
__m512i r0 = _mm512_permutex2var_epi16(A, i0, B); \
__m512i r1 = _mm512_permutex2var_epi16(C, i1, D); \
__m512i r2 = _mm512_permutex2var_epi16(E, i2, F); \
__m512i r3 = _mm512_permutex2var_epi16(G, i3, H); \
/* blend: later segments overwrite earlier where applicable */ \
__m512i r = _mm512_mask_mov_epi16(r0, m1, r1); \
r = _mm512_mask_mov_epi16(r, m2, r2); \
r = _mm512_mask_mov_epi16(r, m3, r3); \
_mm512_storeu_si512((void*)(OUTPTR), r); \
(OUTPTR) += 32; \
} while(0)
DO_STREAM(idx0, e);
DO_STREAM(idx1, e1);
DO_STREAM(idx2, e2);
DO_STREAM(idx3, e3);
DO_STREAM(idx4, e4);
DO_STREAM(idx5, e5);
DO_STREAM(idx6, e6);
DO_STREAM(idx7, e7);
#undef DO_STREAM
}
#else
simde__m128i *e0_128 = (simde__m128i *)e;
simde__m128i *e1_128 = (simde__m128i *)e1;
simde__m128i *e2_128 = (simde__m128i *)e2;
simde__m128i *e3_128 = (simde__m128i *)e3;
simde__m128i *e4_128 = (simde__m128i *)e4;
simde__m128i *e5_128 = (simde__m128i *)e5;
simde__m128i *e6_128 = (simde__m128i *)e6;
simde__m128i *e7_128 = (simde__m128i *)e7;
simde__m128i *f128 = (simde__m128i *)f;
for (i=0; i < (EQm & ~7); i += 8) {
simde__m128i f0j = simde_mm_loadu_si128(f128++);
simde__m128i f1j = simde_mm_loadu_si128(f128++);
simde__m128i f2j = simde_mm_loadu_si128(f128++);
simde__m128i f3j = simde_mm_loadu_si128(f128++);
simde__m128i f4j = simde_mm_loadu_si128(f128++);
simde__m128i f5j = simde_mm_loadu_si128(f128++);
simde__m128i f6j = simde_mm_loadu_si128(f128++);
simde__m128i f7j = simde_mm_loadu_si128(f128++);
simde__m128i tmp0 = simde_mm_unpacklo_epi16(f0j, f1j); // f0(i) f1(i) f0(i+1) f1(i+1) f0(i+2) f1(i+2) f0(i+3) f1(i+3)
simde__m128i tmp1 = simde_mm_unpacklo_epi16(f2j, f3j); // f2(i) f3(i) f2(i+1) f3(i+1) f2(i+2) f3(i+2) f2(i+3) f3(i+3)
simde__m128i tmp2 = simde_mm_unpacklo_epi16(f4j, f5j); // f4(i) f5(i) f4(i+1) f5(i+1) f4(i+2) f5(i+2) f4(i+3) f5(i+3)
simde__m128i tmp3 = simde_mm_unpacklo_epi16(f6j, f7j); // f6(i) f7(i) f6(i+1) f7(i+1) f6(i+2) f7(i+2) f6(i+3) f7(i+3)
//
simde__m128i tmp4 = simde_mm_unpacklo_epi32(tmp0, tmp1); // f0(i) f1(i) f2(i) f3(i) f0(i+1) f1(i+1) f2(i+1) f3(i+1)
simde__m128i tmp5 = simde_mm_unpacklo_epi32(tmp2, tmp3); // f4(i) f5(i) f6(i) f7(i) f4(i+1) f5(i+1) f6(i+1) f7(i+1)
simde_mm_storeu_si128(e0_128++,simde_mm_unpacklo_epi64(tmp4, tmp5)); // f0(i) f1(i) f2(i) f3(i) f4(i) f5(i) f7(i) f7(i)
simde_mm_storeu_si128(e1_128++,simde_mm_unpackhi_epi64(tmp4, tmp5));// f0(i+1) f1(i+1) f2(i+1) f3(i+1) f4(i+1) f5(i+1) f6(i+1) f7(i+1)
//
tmp4 = simde_mm_unpackhi_epi32(tmp0, tmp1); // f0(i+2) f1(i+2) f2(i+2) f3(i+2) f0(i+3) f1(i+3) f2(i+3) f3(i+3)
tmp5 = simde_mm_unpackhi_epi32(tmp2, tmp3); // f4(i+2) f5(i+2) f6(i+2) f7(i+2) f4(i+3) f5(i+3) f6(i+3) f7(i+3)
simde_mm_storeu_si128(e2_128++,simde_mm_unpacklo_epi64(tmp4, tmp5));// f0(i+2) f1(i+2) f2(i+2) f3(i+2) f4(i+2) f5(i+2) f7(i+2) f7(i+2)
simde_mm_storeu_si128(e3_128++,simde_mm_unpackhi_epi64(tmp4, tmp5)); // f0(i+3) f1(i+3) f2(i+3) f3(i+3) f4(i+3) f5(i+3) f7(i+3) f7(i+3)
tmp0 = simde_mm_unpackhi_epi16(f0j, f1j); // f0(i+4) f1(i+4) f0(i+5) f1(i+5) f0(i+6) f1(i+6) f0(i+7) f1(i+7)
tmp1 = simde_mm_unpackhi_epi16(f2j, f3j); // f2(i+4) f3(i+4) f2(i+5) f3(i+5) f2(i+6) f3(i+6) f2(i+7) f3(i+7)
tmp2 = simde_mm_unpackhi_epi16(f4j, f5j); // f4(i+4) f5(i+4) f4(i+5) f5(i+5) f4(i+6) f5(i+6) f4(i+7) f5(i+7)
tmp3 = simde_mm_unpackhi_epi16(f6j, f7j); // f6(i+4) f7(i+4) f6(i+5) f7(i+5) f6(i+6) f7(i+6) f6(i+7) f7(i+7)
//
tmp4 = simde_mm_unpacklo_epi32(tmp0, tmp1); // f0(i+4) f1(i+4) f2(i+4) f3(i+4) f0(i+5) f1(i+5) f2(i+5) f3(i+5)
tmp5 = simde_mm_unpacklo_epi32(tmp2, tmp3); // f4(i+4) f5(i+4) f6(i+4) f7(i+4) f4(i+5) f5(i+5) f6(i+5) f7(i+5)
simde_mm_storeu_si128(e4_128++,simde_mm_unpacklo_epi64(tmp4, tmp5)); // f0(i+4) f1(i+4) f2(i+4) f3(i+4) f4(i+4) f5(i+4) f7(i+4) f7(i+4)
simde_mm_storeu_si128(e5_128++,simde_mm_unpackhi_epi64(tmp4, tmp5));// f0(i+5) f1(i+5) f2(i+5) f3(i+5) f4(i+5) f5(i+5) f6(i+5) f7(i+5)
tmp4 = simde_mm_unpackhi_epi32(tmp0, tmp1); // f0(i+6) f1(i+6) f2(i+6) f3(i+6) f0(i+6) f1(i+6) f2(i+6) f3(i+6)
tmp5 = simde_mm_unpackhi_epi32(tmp2, tmp3); // f4(i+6) f5(i+6) f6(i+6) f7(i+6) f4(i+6) f5(i+6) f6(i+6) f7(i+6)
simde_mm_storeu_si128(e6_128++,simde_mm_unpacklo_epi64(tmp4, tmp5));// f0(i+6) f1(i+6) f2(i+6) f3(i+6) f4(i+6) f5(i+6) f7(i+6) f7(i+6)
simde_mm_storeu_si128(e7_128++,simde_mm_unpackhi_epi64(tmp4, tmp5)); // f0(i+7) f1(i+7) f2(i+7) f3(i+7) f4(i+7) f5(i+7) f7(i+7) f7(i+7)
}
e = (int16_t *)e0_128;
e1 = (int16_t *)e1_128;
e2 = (int16_t *)e2_128;
e3 = (int16_t *)e3_128;
e4 = (int16_t *)e4_128;
e5 = (int16_t *)e5_128;
e6 = (int16_t *)e6_128;
e7 = (int16_t *)e7_128;
f = (int16_t *)f128;
#endif
for(;i < EQm ; i++) {
*e++ = *f++;
*e1++ = *f++;
*e2++ = *f++;
@@ -511,6 +1210,7 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e, int16_t *f)
AssertFatal(1 == 0, "Should not get here : Qm %d\n", Qm);
break;
}
}
int nr_rate_matching_ldpc(uint32_t Tbslbrm,
@@ -610,6 +1310,108 @@ int nr_rate_matching_ldpc(uint32_t Tbslbrm,
return 0;
}
int nr_rate_matching_ldpc32(uint32_t Tbslbrm,
uint8_t BG,
uint16_t Z,
uint32_t *d,
uint32_t *e,
uint8_t C,
uint32_t F,
uint32_t Foffset,
uint8_t rvidx,
uint32_t E)
{
if (C == 0) {
LOG_E(PHY, "nr_rate_matching: invalid parameter C %d\n", C);
return -1;
}
//Bit selection
uint32_t N = (BG == 1) ? (66 * Z) : (50 * Z);
uint32_t Ncb;
if (Tbslbrm == 0)
Ncb = N;
else {
uint32_t Nref = 3 * Tbslbrm / (2 * C); //R_LBRM = 2/3
Ncb = min(N, Nref);
}
uint32_t ind = (index_k0[BG - 1][rvidx] * Ncb / N) * Z;
#ifdef RM_DEBUG
printf("nr_rate_matching_ldpc: E %u, F %u, Foffset %u, k0 %u, Ncb %u, rvidx %d, Tbslbrm %u\n",
E,
F,
Foffset,
ind,
Ncb,
rvidx,
Tbslbrm);
#endif
if (Foffset > E) {
LOG_E(PHY,
"nr_rate_matching: invalid parameters (Foffset %d > E %d) F %d, k0 %d, Ncb %d, rvidx %d, Tbslbrm %d\n",
Foffset,
E,
F,
ind,
Ncb,
rvidx,
Tbslbrm);
return -1;
}
if (Foffset > Ncb) {
LOG_E(PHY, "nr_rate_matching: invalid parameters (Foffset %d > Ncb %d)\n", Foffset, Ncb);
return -1;
}
if (ind >= Foffset && ind < (F + Foffset))
ind = F + Foffset;
uint32_t k = 0;
if (ind < Foffset) { // case where we have some bits before the filler and the rest after
memcpy((void *)e, (void *)(d + ind), (Foffset - ind)<<2);
if (E + F <= Ncb - ind) { // E+F doesn't contain all coded bits
memcpy((void *)(e + Foffset - ind), (void *)(d + Foffset + F), (E - Foffset + ind)<<2);
k = E;
} else {
memcpy((void *)(e + Foffset - ind), (void *)(d + Foffset + F), (Ncb - Foffset - F)<<2);
k = Ncb - F - ind;
}
} else {
if (E <= Ncb - ind) { // E+F doesn't contain all coded bits
memcpy((void *)(e), (void *)(d + ind), E<<2);
k = E;
} else {
memcpy((void *)(e), (void *)(d + ind), (Ncb - ind)<<2);
k = Ncb - ind;
}
}
while (k < E) { // case where we do repetitions (low mcs)
for (ind = 0; (ind < Ncb) && (k < E); ind++) {
#ifdef RM_DEBUG
printf("RM_TX k%u Ind: %u (%d)\n", k, ind, d[ind]);
#endif
if (ind == Foffset)
ind = F + Foffset; // skip filler bits
e[k++] = d[ind];
}
}
return 0;
}
//#define USE_SCALAR 1
#define RMLOOP for (;ind<(ind2&7);k+=8,ind+=8) \
simde_mm_storeu_si128(&d[ind],simde_mm_adds_epi16(simde_mm_loadu_si128(&soft_input[k]),simde_mm_loadu_si128(&d[ind])));\
for (; ind<ind2 ; ind++,k++) d[ind] += soft_input[k];
int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm,
uint8_t BG,
uint16_t Z,
@@ -662,7 +1464,8 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm,
memset(d, 0, Ncb * sizeof(int16_t));
uint32_t k = 0;
if (ind < Foffset)
if (ind < Foffset) {
#ifdef USE_SCALAR
for (; (ind < Foffset) && (k < E); ind++) {
#ifdef RM_DEBUG
printf("RM_RX k%u Ind %u(before filler): %d (%d)=>", k, ind, d[ind], soft_input[k]);
@@ -672,9 +1475,14 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm,
printf("%d\n", d[ind]);
#endif
}
#else
int ind2 = ind + min(Foffset-ind,E);
RMLOOP;
#endif
}
if (ind >= Foffset && ind < Foffset + F)
ind = Foffset + F;
#ifdef USE_SCALAR
for (; (ind < Ncb) && (k < E); ind++) {
#ifdef RM_DEBUG
printf("RM_RX k%u Ind %u(after filler) %d (%d)=>", k, ind, d[ind], soft_input[k]);
@@ -684,8 +1492,13 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm,
printf("%d\n", d[ind]);
#endif
}
#else
int ind2 = ind + min(Ncb-ind,E-k);
RMLOOP;
#endif
while (k < E) {
#ifdef USE_SCALAR
for (ind = 0; (ind < Foffset) && (k < E); ind++) {
#ifdef RM_DEBUG
printf("RM_RX k%u Ind %u(before filler) %d(%d)=>", k, ind, d[ind], soft_input[k]);
@@ -704,6 +1517,14 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm,
printf("%d\n", d[ind]);
#endif
}
#else
ind=0;
ind2 = min(Foffset,E-k);
RMLOOP;
ind = Foffset+F;
ind2 = ind + min(Ncb-ind,E-k);
RMLOOP;
#endif
}
return 0;
}

View File

@@ -33,6 +33,15 @@
*/
void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e, uint8_t *f);
/**
* \brief interleave a code segment after encoding and rate matching (32bit)
* \param E size of the code segment in bits
* \param Qm modulation order
* \param e input rate matched segment
* \param f output interleaved segment
*/
void nr_interleaving_ldpc32(uint32_t E, uint8_t Qm, uint32_t *e, uint32_t *f);
/**
* \brief deinterleave a code segment before RX rate matching and decoding
* \param E size of the code segment in bits
@@ -66,6 +75,30 @@ int nr_rate_matching_ldpc(uint32_t Tbslbrm,
uint8_t rvidx,
uint32_t E);
/**
* \brief rate match a code segment after encoding (32bit)
* \Tbslbrm Transport Block size LBRM
* \param BG LDPC base graph number
* \param Z segment lifting size
* \param d input encoded segment
* \param e output rate matched segment
* \param C number of segments in the Transport Block
* \param F number of filler bits in the segment
* \param Foffset offset of the filler bits in the segment
* \param rvidx redundancy version index
* \param E size of the code segment in bits
*/
int nr_rate_matching_ldpc32(uint32_t Tbslbrm,
uint8_t BG,
uint16_t Z,
uint32_t *d,
uint32_t *e,
uint8_t C,
uint32_t F,
uint32_t Foffset,
uint8_t rvidx,
uint32_t E);
/**
* \brief rate match a code segment before decoding
* \Tbslbrm Transport Block size LBRM

View File

@@ -161,6 +161,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr,
int32_t LDPCinit()
{
cuda_support_init();
return 0;
}

View File

@@ -55,9 +55,11 @@ typedef struct {
unsigned int first_seg; // optim8segmulti
unsigned char gen_code; // orig
time_stats_t *tinput;
time_stats_t *tinput_memcpy;
time_stats_t *tprep;
time_stats_t *tparity;
time_stats_t *toutput;
time_stats_t *tconcat;
/// Size in bits of the code segments
uint32_t K;
/// Number of lifting sizes to fit the payload
@@ -91,5 +93,7 @@ typedef int32_t(LDPC_decoderfunc_t)(t_nrLDPC_dec_params *p_decParams,
t_nrLDPC_time_stats *time_stats,
decode_abort_t *ab);
typedef int32_t(LDPC_encoderfunc_t)(uint8_t **, uint8_t *, encoder_implemparams_t *);
typedef uint32_t**(LDPC_encoderfunc32_t)(uint8_t **, encoder_implemparams_t *);
void cuda_support_init(void);
#endif

View File

@@ -0,0 +1,214 @@
#include <stdio.h>
#include <stdint.h>
#include <cuda_runtime.h>
// generated code for Zc=384, byte encoding
__global__ void ldpc_BG1_Zc384_worker(uint32_t *c[4],uint32_t *d[4]) {
uint32_t *c32=c[blockIdx.x];
uint32_t *d32=d[blockIdx.x]+8448-2*384;
int i2 = threadIdx.x;
int i1 = blockIdx.y;
if (i2 < 384) {
c32+=i2;
d32+=i2;
switch(i1) {
case 0:
d32[0]=c32[307]^c32[76]^c32[205]^c32[276]^c32[787]^c32[1018]^c32[855]^c32[1586]^c32[1612]^c32[1864]^c32[2673]^c32[2377]^c32[2304]^c32[3360]^c32[3404]^c32[3347]^c32[4021]^c32[3984]^c32[4096]^c32[4824]^c32[4769]^c32[4807]^c32[5707]^c32[5643]^c32[5529]^c32[6475]^c32[6304]^c32[6200]^c32[7229]^c32[7090]^c32[6975]^c32[7968]^c32[7809]^c32[7812]^c32[8557]^c32[8743]^c32[8753]^c32[9233]^c32[9558]^c32[9447]^c32[10341]^c32[10184]^c32[10325]^c32[10969]^c32[10840]^c32[10964]^c32[11735]^c32[11619]^c32[11573]^c32[12394]^c32[12642]^c32[12592]^c32[13170]^c32[13187]^c32[13356]^c32[14066]^c32[14064]^c32[14095]^c32[14772]^c32[14923]^c32[14797]^c32[15690]^c32[15373]^c32[15399]^c32[16474]^c32[16240]^c32[16485];
break;
case 1:
d32[384]=c32[307]^c32[308]^c32[77]^c32[206]^c32[277]^c32[787]^c32[788]^c32[1019]^c32[856]^c32[1586]^c32[1587]^c32[1613]^c32[1865]^c32[2673]^c32[2674]^c32[2378]^c32[2305]^c32[3361]^c32[3405]^c32[3348]^c32[4021]^c32[4022]^c32[3985]^c32[4097]^c32[4824]^c32[4825]^c32[4770]^c32[4808]^c32[5708]^c32[5644]^c32[5530]^c32[6476]^c32[6305]^c32[6201]^c32[7229]^c32[7230]^c32[7091]^c32[6976]^c32[7968]^c32[7969]^c32[7810]^c32[7813]^c32[8557]^c32[8558]^c32[8744]^c32[8754]^c32[9233]^c32[9234]^c32[9559]^c32[9448]^c32[10341]^c32[10342]^c32[10185]^c32[10326]^c32[10970]^c32[10841]^c32[10965]^c32[11735]^c32[11736]^c32[11620]^c32[11574]^c32[12394]^c32[12395]^c32[12643]^c32[12593]^c32[13171]^c32[13188]^c32[13357]^c32[14066]^c32[14067]^c32[14065]^c32[14096]^c32[14772]^c32[14773]^c32[14924]^c32[14798]^c32[15690]^c32[15691]^c32[15374]^c32[15400]^c32[16474]^c32[16475]^c32[16241]^c32[16486];
break;
case 2:
d32[768]=c32[308]^c32[77]^c32[205]^c32[206]^c32[276]^c32[277]^c32[788]^c32[1018]^c32[1019]^c32[855]^c32[856]^c32[1587]^c32[1613]^c32[1864]^c32[1865]^c32[2674]^c32[2378]^c32[2304]^c32[2305]^c32[3361]^c32[3404]^c32[3405]^c32[3347]^c32[3348]^c32[4022]^c32[3985]^c32[4096]^c32[4097]^c32[4825]^c32[4769]^c32[4770]^c32[4807]^c32[4808]^c32[5708]^c32[5643]^c32[5644]^c32[5529]^c32[5530]^c32[6476]^c32[6304]^c32[6305]^c32[6200]^c32[6201]^c32[7230]^c32[7091]^c32[6975]^c32[6976]^c32[7969]^c32[7809]^c32[7810]^c32[7812]^c32[7813]^c32[8558]^c32[8744]^c32[8753]^c32[8754]^c32[9234]^c32[9559]^c32[9447]^c32[9448]^c32[10342]^c32[10184]^c32[10185]^c32[10325]^c32[10326]^c32[10970]^c32[10840]^c32[10841]^c32[10964]^c32[10965]^c32[11736]^c32[11620]^c32[11573]^c32[11574]^c32[12395]^c32[12643]^c32[12592]^c32[12593]^c32[13171]^c32[13187]^c32[13188]^c32[13356]^c32[13357]^c32[14067]^c32[14064]^c32[14065]^c32[14095]^c32[14096]^c32[14773]^c32[14924]^c32[14797]^c32[14798]^c32[15691]^c32[15373]^c32[15374]^c32[15399]^c32[15400]^c32[16475]^c32[16241]^c32[16485]^c32[16486];
break;
case 3:
d32[1152]=c32[308]^c32[77]^c32[206]^c32[276]^c32[277]^c32[788]^c32[1019]^c32[855]^c32[856]^c32[1587]^c32[1613]^c32[1865]^c32[2674]^c32[2378]^c32[2304]^c32[2305]^c32[3361]^c32[3405]^c32[3347]^c32[3348]^c32[4022]^c32[3985]^c32[4097]^c32[4825]^c32[4770]^c32[4807]^c32[4808]^c32[5708]^c32[5644]^c32[5529]^c32[5530]^c32[6476]^c32[6305]^c32[6200]^c32[6201]^c32[7230]^c32[7091]^c32[6976]^c32[7969]^c32[7810]^c32[7812]^c32[7813]^c32[8558]^c32[8744]^c32[8753]^c32[8754]^c32[9234]^c32[9559]^c32[9447]^c32[9448]^c32[10342]^c32[10185]^c32[10325]^c32[10326]^c32[10970]^c32[10841]^c32[10964]^c32[10965]^c32[11736]^c32[11620]^c32[11574]^c32[12395]^c32[12643]^c32[12592]^c32[12593]^c32[13171]^c32[13188]^c32[13356]^c32[13357]^c32[14067]^c32[14065]^c32[14095]^c32[14096]^c32[14773]^c32[14924]^c32[14798]^c32[15691]^c32[15374]^c32[15399]^c32[15400]^c32[16475]^c32[16241]^c32[16485]^c32[16486];
break;
case 4:
d32[1536]=c32[332]^c32[949];
break;
case 5:
d32[1920]=c32[80]^c32[233]^c32[362]^c32[49]^c32[195]^c32[944]^c32[791]^c32[1012]^c32[782]^c32[1743]^c32[1769]^c32[1637]^c32[2446]^c32[2534]^c32[2461]^c32[2419]^c32[3133]^c32[3177]^c32[3120]^c32[4178]^c32[4141]^c32[3869]^c32[4981]^c32[4926]^c32[4964]^c32[5480]^c32[5416]^c32[5686]^c32[6248]^c32[6461]^c32[6357]^c32[7002]^c32[7247]^c32[7132]^c32[7741]^c32[7966]^c32[7969]^c32[8714]^c32[8516]^c32[8526]^c32[9390]^c32[9331]^c32[9220]^c32[9382]^c32[10114]^c32[10341]^c32[10098]^c32[11126]^c32[10997]^c32[11121]^c32[11892]^c32[11776]^c32[11730]^c32[12551]^c32[12415]^c32[12365]^c32[12529]^c32[13327]^c32[13344]^c32[13129]^c32[13839]^c32[13837]^c32[13868]^c32[14929]^c32[14696]^c32[14954]^c32[15463]^c32[15530]^c32[15556]^c32[16247]^c32[16397]^c32[16258]^c32[16179];
break;
case 6:
d32[2304]=c32[278]^c32[4865]^c32[7681]^c32[8799]^c32[10076]^c32[13309]^c32[13842]^c32[15585];
break;
case 7:
d32[2688]=c32[9]^c32[830]^c32[3388]^c32[5709]^c32[6434]^c32[10866];
break;
case 8:
d32[3072]=c32[374]^c32[94]^c32[143]^c32[247]^c32[272]^c32[375]^c32[376]^c32[343]^c32[62]^c32[63]^c32[307]^c32[854]^c32[958]^c32[1085]^c32[804]^c32[805]^c32[922]^c32[1025]^c32[1026]^c32[947]^c32[1653]^c32[1757]^c32[1679]^c32[1783]^c32[1547]^c32[1650]^c32[1651]^c32[2356]^c32[2460]^c32[2444]^c32[2548]^c32[2371]^c32[2474]^c32[2475]^c32[2469]^c32[3427]^c32[3147]^c32[3087]^c32[3190]^c32[3191]^c32[3414]^c32[3133]^c32[3134]^c32[4088]^c32[4192]^c32[4051]^c32[4155]^c32[4163]^c32[3882]^c32[3883]^c32[4891]^c32[4611]^c32[4836]^c32[4939]^c32[4940]^c32[4874]^c32[4977]^c32[4978]^c32[5390]^c32[5494]^c32[5710]^c32[5429]^c32[5430]^c32[5596]^c32[5699]^c32[5700]^c32[6158]^c32[6262]^c32[6371]^c32[6474]^c32[6475]^c32[6267]^c32[6370]^c32[6371]^c32[6912]^c32[7016]^c32[7157]^c32[7261]^c32[7042]^c32[7145]^c32[7146]^c32[8035]^c32[7755]^c32[7876]^c32[7979]^c32[7980]^c32[7879]^c32[7982]^c32[7983]^c32[8624]^c32[8728]^c32[8810]^c32[8530]^c32[8820]^c32[8539]^c32[8540]^c32[9300]^c32[9404]^c32[9241]^c32[9345]^c32[9514]^c32[9233]^c32[9234]^c32[9234]^c32[10024]^c32[10128]^c32[10251]^c32[10354]^c32[10355]^c32[10008]^c32[10111]^c32[10112]^c32[11036]^c32[10756]^c32[10907]^c32[11010]^c32[11011]^c32[11031]^c32[11134]^c32[11135]^c32[11802]^c32[11522]^c32[11686]^c32[11790]^c32[11640]^c32[11743]^c32[11744]^c32[12461]^c32[12565]^c32[12325]^c32[12429]^c32[12659]^c32[12378]^c32[12379]^c32[12327]^c32[13237]^c32[13341]^c32[13254]^c32[13357]^c32[13358]^c32[13423]^c32[13142]^c32[13143]^c32[14133]^c32[13853]^c32[14131]^c32[13850]^c32[13851]^c32[14162]^c32[13881]^c32[13882]^c32[14839]^c32[14943]^c32[14606]^c32[14710]^c32[14864]^c32[14967]^c32[14968]^c32[14816]^c32[15373]^c32[15477]^c32[15440]^c32[15543]^c32[15544]^c32[15466]^c32[15569]^c32[15570]^c32[16157]^c32[16261]^c32[16307]^c32[16411]^c32[16168]^c32[16271]^c32[16272]^c32[16496];
break;
case 9:
d32[3456]=c32[366]^c32[1000]^c32[8001]^c32[8581]^c32[10041]^c32[13359]^c32[13887]^c32[15442];
break;
case 10:
d32[3840]=c32[869]^c32[1875]^c32[3346]^c32[5487]^c32[6527]^c32[11106];
break;
case 11:
d32[4224]=c32[257]^c32[38]^c32[39]^c32[26]^c32[192]^c32[155]^c32[321]^c32[226]^c32[8]^c32[48]^c32[1121]^c32[902]^c32[903]^c32[968]^c32[1134]^c32[805]^c32[971]^c32[870]^c32[1536]^c32[1701]^c32[1702]^c32[1562]^c32[1728]^c32[1814]^c32[1596]^c32[2623]^c32[2404]^c32[2405]^c32[2327]^c32[2493]^c32[2638]^c32[2420]^c32[3310]^c32[3092]^c32[3354]^c32[3136]^c32[3297]^c32[3079]^c32[3971]^c32[4136]^c32[4137]^c32[3934]^c32[4100]^c32[4046]^c32[4212]^c32[4774]^c32[4939]^c32[4940]^c32[4719]^c32[4885]^c32[4757]^c32[4923]^c32[5657]^c32[5439]^c32[5593]^c32[5759]^c32[5479]^c32[5645]^c32[6425]^c32[6207]^c32[6254]^c32[6420]^c32[6150]^c32[6316]^c32[7179]^c32[6960]^c32[6961]^c32[7040]^c32[7206]^c32[6925]^c32[7091]^c32[7918]^c32[7699]^c32[7700]^c32[7759]^c32[7925]^c32[7762]^c32[7928]^c32[8507]^c32[8672]^c32[8673]^c32[8693]^c32[8475]^c32[8703]^c32[8485]^c32[9567]^c32[9348]^c32[9349]^c32[9508]^c32[9290]^c32[9397]^c32[9563]^c32[9224]^c32[10291]^c32[10072]^c32[10073]^c32[10134]^c32[10300]^c32[10275]^c32[10057]^c32[10919]^c32[11085]^c32[10790]^c32[10956]^c32[10914]^c32[11080]^c32[11685]^c32[11850]^c32[11851]^c32[11569]^c32[11735]^c32[11523]^c32[11689]^c32[12344]^c32[12509]^c32[12510]^c32[12592]^c32[12374]^c32[12542]^c32[12324]^c32[12335]^c32[13120]^c32[13286]^c32[13137]^c32[13303]^c32[13306]^c32[13088]^c32[14016]^c32[14181]^c32[14182]^c32[14014]^c32[14180]^c32[14045]^c32[13827]^c32[14722]^c32[14887]^c32[14888]^c32[14873]^c32[14655]^c32[14747]^c32[14913]^c32[15640]^c32[15421]^c32[15422]^c32[15707]^c32[15489]^c32[15733]^c32[15515]^c32[16424]^c32[16205]^c32[16206]^c32[16190]^c32[16356]^c32[16435]^c32[16217]^c32[16316];
break;
case 12:
d32[4608]=c32[77]^c32[954]^c32[7854]^c32[8680]^c32[10034]^c32[13898];
break;
case 13:
d32[4992]=c32[293]^c32[294]^c32[63]^c32[192]^c32[263]^c32[313]^c32[773]^c32[774]^c32[1005]^c32[842]^c32[1572]^c32[1573]^c32[1599]^c32[1851]^c32[2659]^c32[2660]^c32[2364]^c32[2675]^c32[2481]^c32[3347]^c32[3391]^c32[3334]^c32[4007]^c32[4008]^c32[3971]^c32[4083]^c32[4810]^c32[4811]^c32[4756]^c32[4794]^c32[5694]^c32[5630]^c32[5516]^c32[5642]^c32[6462]^c32[6291]^c32[6187]^c32[7215]^c32[7216]^c32[7077]^c32[6962]^c32[7954]^c32[7955]^c32[7796]^c32[7799]^c32[8543]^c32[8544]^c32[8730]^c32[8740]^c32[9219]^c32[9220]^c32[9545]^c32[9434]^c32[10327]^c32[10328]^c32[10171]^c32[10312]^c32[10956]^c32[10827]^c32[10951]^c32[11721]^c32[11722]^c32[11606]^c32[11560]^c32[12380]^c32[12381]^c32[12629]^c32[12579]^c32[13157]^c32[13174]^c32[13343]^c32[14052]^c32[14053]^c32[14051]^c32[14082]^c32[14758]^c32[14759]^c32[14910]^c32[14784]^c32[15676]^c32[15677]^c32[15360]^c32[15386]^c32[15475]^c32[16460]^c32[16461]^c32[16227]^c32[16472];
break;
case 14:
d32[5376]=c32[142]^c32[9464]^c32[11657]^c32[12377]^c32[13403]^c32[16140];
break;
case 15:
d32[5760]=c32[193]^c32[346]^c32[91]^c32[161]^c32[162]^c32[241]^c32[1057]^c32[904]^c32[1124]^c32[1125]^c32[770]^c32[1856]^c32[1882]^c32[1750]^c32[2559]^c32[2647]^c32[2573]^c32[2574]^c32[3246]^c32[3290]^c32[3232]^c32[3233]^c32[3907]^c32[3870]^c32[3982]^c32[4710]^c32[4655]^c32[4692]^c32[4693]^c32[5593]^c32[5529]^c32[5414]^c32[5415]^c32[6361]^c32[6190]^c32[6469]^c32[6470]^c32[7115]^c32[6976]^c32[7245]^c32[7854]^c32[7695]^c32[7697]^c32[7698]^c32[7890]^c32[8827]^c32[8629]^c32[8638]^c32[8639]^c32[9503]^c32[9444]^c32[9332]^c32[9333]^c32[10227]^c32[10070]^c32[10210]^c32[10211]^c32[10302]^c32[10855]^c32[11110]^c32[10849]^c32[10850]^c32[11621]^c32[11889]^c32[11843]^c32[12664]^c32[12528]^c32[12477]^c32[12478]^c32[13056]^c32[13073]^c32[13241]^c32[13242]^c32[13952]^c32[13950]^c32[13980]^c32[13981]^c32[13879]^c32[14658]^c32[14809]^c32[14683]^c32[15576]^c32[15643]^c32[15668]^c32[15669]^c32[16360]^c32[16510]^c32[16370]^c32[16371];
break;
case 16:
d32[6144]=c32[364]^c32[133]^c32[262]^c32[333]^c32[844]^c32[1075]^c32[912]^c32[781]^c32[1643]^c32[1669]^c32[1537]^c32[2346]^c32[2434]^c32[2361]^c32[2642]^c32[3417]^c32[3077]^c32[3404]^c32[4078]^c32[4041]^c32[4153]^c32[4881]^c32[4826]^c32[4864]^c32[5380]^c32[5700]^c32[5586]^c32[6148]^c32[6361]^c32[6257]^c32[7286]^c32[7147]^c32[7032]^c32[8025]^c32[7866]^c32[7869]^c32[8614]^c32[8800]^c32[8810]^c32[8505]^c32[9290]^c32[9231]^c32[9504]^c32[10014]^c32[10241]^c32[9998]^c32[11026]^c32[10897]^c32[11021]^c32[11792]^c32[11676]^c32[11630]^c32[12451]^c32[12315]^c32[12649]^c32[13227]^c32[13244]^c32[13413]^c32[14123]^c32[14121]^c32[14152]^c32[14829]^c32[14596]^c32[14854]^c32[15363]^c32[15430]^c32[15456]^c32[15649]^c32[16147]^c32[16297]^c32[16158];
break;
case 17:
d32[6528]=c32[260]^c32[11055]^c32[12369]^c32[13414]^c32[16503];
break;
case 18:
d32[6912]=c32[898]^c32[9379]^c32[10264]^c32[13956]^c32[14596];
break;
case 19:
d32[7296]=c32[145]^c32[981]^c32[5720]^c32[6386]^c32[7877];
break;
case 20:
d32[7680]=c32[366]^c32[135]^c32[264]^c32[335]^c32[187]^c32[846]^c32[1077]^c32[914]^c32[1645]^c32[1671]^c32[1539]^c32[2348]^c32[2436]^c32[2363]^c32[2510]^c32[3419]^c32[3079]^c32[3406]^c32[4080]^c32[4043]^c32[4155]^c32[4883]^c32[4828]^c32[4866]^c32[5382]^c32[5702]^c32[5588]^c32[6150]^c32[6363]^c32[6259]^c32[7288]^c32[7149]^c32[7034]^c32[7176]^c32[8027]^c32[7868]^c32[7871]^c32[8616]^c32[8802]^c32[8812]^c32[8789]^c32[9292]^c32[9233]^c32[9506]^c32[10016]^c32[10243]^c32[10000]^c32[11028]^c32[10899]^c32[11023]^c32[11794]^c32[11678]^c32[11632]^c32[12453]^c32[12317]^c32[12651]^c32[13229]^c32[13246]^c32[13415]^c32[14125]^c32[14123]^c32[14154]^c32[14831]^c32[14598]^c32[14856]^c32[15365]^c32[15432]^c32[15458]^c32[16149]^c32[16299]^c32[16160];
break;
case 21:
d32[8064]=c32[973]^c32[3942]^c32[12616]^c32[15573]^c32[16225];
break;
case 22:
d32[8448]=c32[30]^c32[9227]^c32[10217]^c32[13078];
break;
case 23:
d32[8832]=c32[792]^c32[1625]^c32[7741]^c32[13851];
break;
case 24:
d32[9216]=c32[157]^c32[310]^c32[55]^c32[126]^c32[298]^c32[1021]^c32[868]^c32[1089]^c32[1820]^c32[1846]^c32[1714]^c32[2523]^c32[2611]^c32[2538]^c32[2462]^c32[3210]^c32[3254]^c32[3197]^c32[3307]^c32[3871]^c32[4218]^c32[3946]^c32[4674]^c32[4619]^c32[4657]^c32[5557]^c32[5493]^c32[5379]^c32[6325]^c32[6154]^c32[6434]^c32[7079]^c32[6940]^c32[7209]^c32[7818]^c32[8043]^c32[8046]^c32[8791]^c32[8593]^c32[8603]^c32[8787]^c32[9467]^c32[9408]^c32[9297]^c32[10191]^c32[10034]^c32[10175]^c32[10819]^c32[11074]^c32[10814]^c32[11585]^c32[11853]^c32[11807]^c32[12628]^c32[12492]^c32[12442]^c32[13404]^c32[13421]^c32[13206]^c32[13916]^c32[13914]^c32[13945]^c32[14622]^c32[14773]^c32[14647]^c32[15540]^c32[15607]^c32[15633]^c32[16324]^c32[16474]^c32[16335];
break;
case 25:
d32[9600]=c32[840]^c32[4625]^c32[5759]^c32[11064];
break;
case 26:
d32[9984]=c32[71]^c32[1617]^c32[3148]^c32[11656];
break;
case 27:
d32[10368]=c32[962]^c32[4802]^c32[6245];
break;
case 28:
d32[10752]=c32[222]^c32[3091]^c32[14836]^c32[16402];
break;
case 29:
d32[11136]=c32[2]^c32[155]^c32[284]^c32[354]^c32[355]^c32[866]^c32[1097]^c32[933]^c32[934]^c32[1020]^c32[1665]^c32[1691]^c32[1559]^c32[2368]^c32[2456]^c32[2382]^c32[2383]^c32[3439]^c32[3099]^c32[3425]^c32[3426]^c32[4100]^c32[4063]^c32[4175]^c32[4903]^c32[4848]^c32[4885]^c32[4886]^c32[5402]^c32[5722]^c32[5607]^c32[5608]^c32[6170]^c32[6383]^c32[6278]^c32[6279]^c32[6924]^c32[7169]^c32[7054]^c32[8047]^c32[7888]^c32[7890]^c32[7891]^c32[8636]^c32[8822]^c32[8831]^c32[8448]^c32[9312]^c32[9253]^c32[9525]^c32[9526]^c32[10036]^c32[10263]^c32[10019]^c32[10020]^c32[11048]^c32[10919]^c32[11042]^c32[11043]^c32[10757]^c32[11814]^c32[11698]^c32[11652]^c32[12473]^c32[12337]^c32[12670]^c32[12671]^c32[13249]^c32[13266]^c32[13434]^c32[13435]^c32[14145]^c32[14143]^c32[14173]^c32[14174]^c32[13971]^c32[14851]^c32[14618]^c32[14876]^c32[15385]^c32[15452]^c32[15477]^c32[15478]^c32[16169]^c32[16319]^c32[16179]^c32[16180];
break;
case 30:
d32[11520]=c32[14]^c32[167]^c32[295]^c32[296]^c32[366]^c32[367]^c32[159]^c32[878]^c32[1108]^c32[1109]^c32[945]^c32[946]^c32[1677]^c32[1703]^c32[1570]^c32[1571]^c32[2380]^c32[2468]^c32[2394]^c32[2395]^c32[3451]^c32[3110]^c32[3111]^c32[3437]^c32[3438]^c32[4112]^c32[4075]^c32[4186]^c32[4187]^c32[4915]^c32[4859]^c32[4860]^c32[4897]^c32[4898]^c32[5414]^c32[5733]^c32[5734]^c32[5619]^c32[5620]^c32[6182]^c32[6394]^c32[6395]^c32[6290]^c32[6291]^c32[6936]^c32[7181]^c32[7065]^c32[7066]^c32[8059]^c32[7899]^c32[7900]^c32[7902]^c32[7903]^c32[7909]^c32[8648]^c32[8450]^c32[8459]^c32[8460]^c32[9324]^c32[9265]^c32[9537]^c32[9538]^c32[10048]^c32[10274]^c32[10275]^c32[10031]^c32[10032]^c32[10244]^c32[11060]^c32[10930]^c32[10931]^c32[11054]^c32[11055]^c32[11826]^c32[11710]^c32[11663]^c32[11664]^c32[12485]^c32[12349]^c32[12298]^c32[12299]^c32[13261]^c32[13277]^c32[13278]^c32[13062]^c32[13063]^c32[14157]^c32[14154]^c32[14155]^c32[14185]^c32[14186]^c32[14863]^c32[14630]^c32[14887]^c32[14888]^c32[15397]^c32[15463]^c32[15464]^c32[15489]^c32[15490]^c32[16181]^c32[16331]^c32[16191]^c32[16192];
break;
case 31:
d32[11904]=c32[181]^c32[180]^c32[334]^c32[333]^c32[79]^c32[78]^c32[150]^c32[148]^c32[149]^c32[1045]^c32[1044]^c32[892]^c32[891]^c32[1113]^c32[1111]^c32[1112]^c32[868]^c32[1844]^c32[1843]^c32[1870]^c32[1869]^c32[1738]^c32[1737]^c32[2547]^c32[2546]^c32[2635]^c32[2634]^c32[2562]^c32[2560]^c32[2561]^c32[3234]^c32[3233]^c32[3278]^c32[3277]^c32[3221]^c32[3219]^c32[3220]^c32[3895]^c32[3894]^c32[3858]^c32[3857]^c32[3970]^c32[3969]^c32[4698]^c32[4697]^c32[4643]^c32[4642]^c32[4681]^c32[4679]^c32[4680]^c32[5581]^c32[5580]^c32[5517]^c32[5516]^c32[5403]^c32[5401]^c32[5402]^c32[5591]^c32[6349]^c32[6348]^c32[6178]^c32[6177]^c32[6458]^c32[6456]^c32[6457]^c32[7103]^c32[7102]^c32[6964]^c32[6963]^c32[7233]^c32[7232]^c32[7842]^c32[7841]^c32[7683]^c32[7682]^c32[7686]^c32[7684]^c32[7685]^c32[8815]^c32[8814]^c32[8617]^c32[8616]^c32[8627]^c32[8625]^c32[8626]^c32[9491]^c32[9490]^c32[9432]^c32[9431]^c32[9321]^c32[9319]^c32[9320]^c32[10215]^c32[10214]^c32[10058]^c32[10057]^c32[10199]^c32[10197]^c32[10198]^c32[10843]^c32[10842]^c32[11098]^c32[11097]^c32[10838]^c32[10836]^c32[10837]^c32[11609]^c32[11608]^c32[11877]^c32[11876]^c32[11831]^c32[11830]^c32[12652]^c32[12651]^c32[12516]^c32[12515]^c32[12466]^c32[12464]^c32[12465]^c32[13428]^c32[13427]^c32[13061]^c32[13060]^c32[13230]^c32[13228]^c32[13229]^c32[13940]^c32[13939]^c32[13938]^c32[13937]^c32[13969]^c32[13967]^c32[13968]^c32[14646]^c32[14645]^c32[14797]^c32[14796]^c32[14671]^c32[14670]^c32[15564]^c32[15563]^c32[15631]^c32[15630]^c32[15657]^c32[15655]^c32[15656]^c32[16348]^c32[16347]^c32[16498]^c32[16497]^c32[16359]^c32[16357]^c32[16358];
break;
case 32:
d32[12288]=c32[211]^c32[364]^c32[108]^c32[109]^c32[179]^c32[180]^c32[102]^c32[1075]^c32[921]^c32[922]^c32[1142]^c32[1143]^c32[1874]^c32[1900]^c32[1767]^c32[1768]^c32[2577]^c32[2665]^c32[2591]^c32[2592]^c32[3264]^c32[3307]^c32[3308]^c32[3250]^c32[3251]^c32[3925]^c32[3888]^c32[3999]^c32[4000]^c32[4728]^c32[4672]^c32[4673]^c32[4710]^c32[4711]^c32[5611]^c32[5546]^c32[5547]^c32[5432]^c32[5433]^c32[6379]^c32[6207]^c32[6208]^c32[6487]^c32[6488]^c32[7133]^c32[6994]^c32[7262]^c32[7263]^c32[7872]^c32[7712]^c32[7713]^c32[7715]^c32[7716]^c32[8461]^c32[8647]^c32[8656]^c32[8657]^c32[9521]^c32[9462]^c32[9350]^c32[9351]^c32[9417]^c32[10245]^c32[10087]^c32[10088]^c32[10228]^c32[10229]^c32[10873]^c32[11127]^c32[11128]^c32[10867]^c32[10868]^c32[10927]^c32[11639]^c32[11523]^c32[11860]^c32[11861]^c32[12298]^c32[12546]^c32[12495]^c32[12496]^c32[13074]^c32[13090]^c32[13091]^c32[13259]^c32[13260]^c32[13970]^c32[13967]^c32[13968]^c32[13998]^c32[13999]^c32[14676]^c32[14827]^c32[14700]^c32[14701]^c32[15594]^c32[15660]^c32[15661]^c32[15686]^c32[15687]^c32[16378]^c32[16144]^c32[16388]^c32[16389];
break;
case 33:
d32[12672]=c32[1091]^c32[1544]^c32[8809]^c32[16233];
break;
case 34:
d32[13056]=c32[230]^c32[5524]^c32[11722]^c32[13368];
break;
case 35:
d32[13440]=c32[189]^c32[342]^c32[87]^c32[158]^c32[1053]^c32[900]^c32[1121]^c32[1088]^c32[1852]^c32[1878]^c32[1746]^c32[2555]^c32[2643]^c32[2570]^c32[3242]^c32[3286]^c32[3229]^c32[3903]^c32[3866]^c32[3978]^c32[4706]^c32[4651]^c32[4689]^c32[4943]^c32[5589]^c32[5525]^c32[5411]^c32[6357]^c32[6186]^c32[6466]^c32[7111]^c32[6972]^c32[7241]^c32[7850]^c32[7691]^c32[7694]^c32[8823]^c32[8625]^c32[8635]^c32[9499]^c32[9440]^c32[9329]^c32[9218]^c32[10223]^c32[10066]^c32[10207]^c32[10851]^c32[11106]^c32[10846]^c32[11617]^c32[11885]^c32[11839]^c32[12660]^c32[12524]^c32[12474]^c32[13436]^c32[13069]^c32[13238]^c32[13948]^c32[13946]^c32[13977]^c32[14654]^c32[14805]^c32[14679]^c32[15572]^c32[15639]^c32[15665]^c32[16356]^c32[16506]^c32[16367];
break;
case 36:
d32[13824]=c32[210]^c32[11065]^c32[11817]^c32[13845];
break;
case 37:
d32[14208]=c32[38]^c32[39]^c32[192]^c32[321]^c32[8]^c32[902]^c32[903]^c32[1134]^c32[971]^c32[1037]^c32[1701]^c32[1702]^c32[1728]^c32[1596]^c32[2404]^c32[2405]^c32[2493]^c32[2420]^c32[3092]^c32[3136]^c32[3079]^c32[4136]^c32[4137]^c32[4100]^c32[4212]^c32[4939]^c32[4940]^c32[4885]^c32[4923]^c32[5439]^c32[5759]^c32[5645]^c32[6207]^c32[6420]^c32[6316]^c32[6960]^c32[6961]^c32[7206]^c32[7091]^c32[7699]^c32[7700]^c32[7925]^c32[7928]^c32[8672]^c32[8673]^c32[8475]^c32[8485]^c32[9348]^c32[9349]^c32[9290]^c32[9563]^c32[10072]^c32[10073]^c32[10300]^c32[10057]^c32[10066]^c32[11085]^c32[10956]^c32[11080]^c32[11850]^c32[11851]^c32[11735]^c32[11689]^c32[12509]^c32[12510]^c32[12374]^c32[12324]^c32[13286]^c32[13303]^c32[13088]^c32[14181]^c32[14182]^c32[14180]^c32[13827]^c32[14887]^c32[14888]^c32[14655]^c32[14913]^c32[15421]^c32[15422]^c32[15489]^c32[15515]^c32[16205]^c32[16206]^c32[16356]^c32[16217];
break;
case 38:
d32[14592]=c32[185]^c32[7089]^c32[7969]^c32[9430];
break;
case 39:
d32[14976]=c32[1026]^c32[2397]^c32[5722]^c32[14889];
break;
case 40:
d32[15360]=c32[175]^c32[6181]^c32[13368];
break;
case 41:
d32[15744]=c32[820]^c32[2618]^c32[7051]^c32[14112];
break;
case 42:
d32[16128]=c32[142]^c32[295]^c32[39]^c32[40]^c32[110]^c32[111]^c32[113]^c32[1006]^c32[852]^c32[853]^c32[1073]^c32[1074]^c32[1805]^c32[1831]^c32[1698]^c32[1699]^c32[2508]^c32[2596]^c32[2522]^c32[2523]^c32[3195]^c32[3238]^c32[3239]^c32[3181]^c32[3182]^c32[3086]^c32[3856]^c32[4203]^c32[3930]^c32[3931]^c32[4659]^c32[4987]^c32[4988]^c32[4641]^c32[4642]^c32[5542]^c32[5477]^c32[5478]^c32[5747]^c32[5748]^c32[6310]^c32[6522]^c32[6523]^c32[6418]^c32[6419]^c32[7064]^c32[6925]^c32[7193]^c32[7194]^c32[7803]^c32[8027]^c32[8028]^c32[8030]^c32[8031]^c32[8776]^c32[8578]^c32[8587]^c32[8588]^c32[9452]^c32[9393]^c32[9281]^c32[9282]^c32[10176]^c32[10018]^c32[10019]^c32[10159]^c32[10160]^c32[10804]^c32[11058]^c32[11059]^c32[10798]^c32[10799]^c32[11570]^c32[11838]^c32[11791]^c32[11792]^c32[12613]^c32[12477]^c32[12426]^c32[12427]^c32[13389]^c32[13405]^c32[13406]^c32[13190]^c32[13191]^c32[13901]^c32[13898]^c32[13899]^c32[13929]^c32[13930]^c32[14607]^c32[14758]^c32[14631]^c32[14632]^c32[15525]^c32[15591]^c32[15592]^c32[15617]^c32[15618]^c32[16309]^c32[16459]^c32[16319]^c32[16320];
break;
case 43:
d32[16512]=c32[92]^c32[245]^c32[374]^c32[60]^c32[61]^c32[956]^c32[803]^c32[1023]^c32[1024]^c32[881]^c32[1755]^c32[1781]^c32[1649]^c32[2458]^c32[2546]^c32[2472]^c32[2473]^c32[3145]^c32[3189]^c32[3131]^c32[3132]^c32[4190]^c32[4153]^c32[3881]^c32[4609]^c32[4938]^c32[4975]^c32[4976]^c32[5492]^c32[5428]^c32[5697]^c32[5698]^c32[6260]^c32[6473]^c32[6368]^c32[6369]^c32[7014]^c32[7259]^c32[7144]^c32[7753]^c32[7978]^c32[7980]^c32[7981]^c32[8726]^c32[8528]^c32[8537]^c32[8538]^c32[9402]^c32[9343]^c32[9231]^c32[9232]^c32[10126]^c32[10353]^c32[10109]^c32[10110]^c32[10754]^c32[11009]^c32[11132]^c32[11133]^c32[11520]^c32[11788]^c32[11742]^c32[12563]^c32[12427]^c32[12376]^c32[12377]^c32[12420]^c32[13339]^c32[13356]^c32[13140]^c32[13141]^c32[13851]^c32[13849]^c32[13879]^c32[13880]^c32[13938]^c32[14941]^c32[14708]^c32[14966]^c32[15475]^c32[15542]^c32[15567]^c32[15568]^c32[16259]^c32[16409]^c32[16269]^c32[16270];
break;
case 44:
d32[16896]=c32[197]^c32[350]^c32[95]^c32[166]^c32[80]^c32[1061]^c32[908]^c32[1129]^c32[1860]^c32[1886]^c32[1754]^c32[2563]^c32[2651]^c32[2578]^c32[3250]^c32[3294]^c32[3237]^c32[3911]^c32[3874]^c32[3986]^c32[4714]^c32[4659]^c32[4697]^c32[5597]^c32[5533]^c32[5419]^c32[5454]^c32[6365]^c32[6194]^c32[6474]^c32[7119]^c32[6980]^c32[7249]^c32[7075]^c32[7858]^c32[7699]^c32[7702]^c32[8831]^c32[8633]^c32[8643]^c32[9507]^c32[9448]^c32[9337]^c32[10231]^c32[10074]^c32[10215]^c32[10859]^c32[11114]^c32[10854]^c32[11625]^c32[11893]^c32[11847]^c32[12668]^c32[12532]^c32[12482]^c32[13060]^c32[13077]^c32[13246]^c32[13956]^c32[13954]^c32[13985]^c32[14662]^c32[14813]^c32[14687]^c32[15580]^c32[15647]^c32[15673]^c32[16364]^c32[16130]^c32[16375];
break;
case 45:
d32[17280]=c32[903]^c32[4757]^c32[7695];
break;
}
}
}
extern "C" int ldpc_BG1_Zc384_cuda32(uint32_t *c[4],uint32_t *d[4],int n_inputs) {
dim3 numblocks(n_inputs,46);
ldpc_BG1_Zc384_worker<<<numblocks,384>>>(c,d);
cudaError_t err=cudaPeekAtLastError();
if (err!=cudaSuccess) {
printf("cuda error: %s (c %p, d %p)\n",cudaGetErrorString(err),c,d);
exit(-1);
}
cudaDeviceSynchronize();
return(0);
}

View File

@@ -103,9 +103,11 @@
#include "ldpc_BG2_Zc80_byte.c"
#include "ldpc_BG2_Zc72_byte.c"
static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG,short Zc,short Kb, int simd_size, int ncols)
static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG,short Zc,short Kb, 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
if (tinput_memcpy) start_meas(tinput_memcpy);
for (int i1 = 0; i1 < ncols; i1++) {
memcpy(&c[2 * i1 * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char));
memcpy(&c[(2 * i1 + 1) * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char));
@@ -118,6 +120,7 @@ static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG,sho
memcpy(&c[(2 * ncols * Zc * i1)], &c[i1], (2 * ncols * Zc * sizeof(unsigned char)) - i1);
}
}
if (tinput_memcpy) stop_meas(tinput_memcpy);
if (BG == 1) {
switch (Zc) {
case 176:

View File

@@ -0,0 +1,94 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*!\file ldpc_encode_parity_check.c
* \brief Parity check function used by ldpc encoders
* \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
* \email openair_tech@eurecom.fr
* \date 27-03-2018
* \version 1.0
* \note
* \warning
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "assertions.h"
#include "common/utils/LOG/log.h"
#include <cuda_runtime.h>
int ldpc_BG1_Zc384_cuda32(uint32_t **c,uint32_t **d,int n_inputs);
void encode_parity_check_part_cuda(uint32_t **c, uint32_t **d, short BG,short Zc,short Kb, int ncols, int n_inputs)
{
if (BG == 1) {
switch (Zc) {
case 176:
case 192:
case 208:
case 224:
case 240:
case 256:
case 288:
case 320:
case 352:
AssertFatal(1==0,"BG %d Zc %d not supported yet for CUDA\n",BG, Zc);
break;
case 384:
ldpc_BG1_Zc384_cuda32(c, d, n_inputs);
break;
default:
AssertFatal(false, "BG %d Zc %d is not supported yet\n", BG, Zc);
}
} else if (BG == 2) {
switch (Zc) {
case 72:
case 80:
case 88:
case 96:
case 104:
case 112:
case 120:
case 128:
case 144:
case 160:
case 176:
case 192:
case 208:
case 224:
case 240:
case 256:
case 288:
case 320:
case 352:
case 384:
default:
AssertFatal(false , "BG %d Zc %d is not supported yet\n", BG, Zc);
}
} else
AssertFatal(false, "BG %d is not supported\n", BG);
}

View File

@@ -58,11 +58,10 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
int no_punctured_columns, removed_bit;
int nind=0;
int indlist[1000];
int indlist2[1000];
const short *Gen_shift_values = choose_generator_matrix(BG, Zc);
if (Gen_shift_values==NULL) {
printf("ldpc_encoder_orig: could not find generator matrix\n");
printf("ldpc_encoder_orig: could not find generator matrix BG %d Zc %d\n",BG,Zc);
return(-1);
}
@@ -93,32 +92,35 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
// parity check part
if (gen_code>=1)
if (gen_code==1 || gen_code==2 || gen_code==3)
{
char fname[100];
sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc);
FILE *fd=fopen(fname,"w");
AssertFatal(fd!=NULL,"cannot open %s\n",fname);
sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc);
FILE *fd2=fopen(fname,"w");
AssertFatal(fd2!=NULL,"cannot open %s\n",fname);
int shift;
char data_type[100];
char xor_command[100];
int mask;
char permutex_command[100];
int use_permutex=0;
char alignr_command[100];
int use_alignr=0;
fprintf(fd,"#include \"PHY/sse_intrin.h\"\n");
fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n");
if (gen_code == 1 && (Zc&63)==0) {
shift=6;
mask=63;
strcpy(data_type,"__m512i");
strcpy(xor_command,"_mm512_xor_si512");
strcpy(permutex_command,"_mm512_permutex2var_epi8");
strcpy(alignr_command,"_mm512_alignr_epi8");
use_alignr=1;
}
else if (gen_code == 1 && (Zc&31)==0) {
shift=5; // AVX2 - 256-bit SIMD
@@ -126,14 +128,15 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
strcpy(data_type,"simde__m256i");
strcpy(xor_command,"simde_mm256_xor_si256");
}
else if ((Zc&15)==0) {
else if ((gen_code <=2) && (Zc&15)==0) {
shift=4; // SSE4 - 128-bit SIMD
mask=15;
strcpy(data_type,"simde__m128i");
strcpy(xor_command,"simde_mm_xor_si128");
strcpy(alignr_command,"simde_mm_alignr_epi8");
use_alignr=1;
}
else if ((Zc&7)==0) {
else if ((gen_code <=2) && (Zc&7)==0) {
shift=3; // MMX - 64-bit SIMD
mask=7;
strcpy(data_type,"simde__m64");
@@ -145,21 +148,30 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
strcpy(data_type,"uint8_t");
strcpy(xor_command,"scalar_xor");
fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n");
fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n");
}
fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc);
if (use_permutex==1) {
fprintf(fd," const uint8_t abshift_bytes[%d][%d] __attribute__((aligned(64)))= {\n",1+mask,1+mask);
for (int i=0;i<=mask;i++) {
fprintf(fd,"{");
for (int j=0;j<=mask;j++) {
fprintf(fd,"%d",i+j);
if (j<mask) fprintf(fd,",");
else fprintf(fd,"}");
}
if (i<mask) fprintf(fd,",\n");
else fprintf(fd,"};\n");
}
fprintf(fd,"static inline __m512i abshift_get(int r)\n {\n");
fprintf(fd," return * (const __m512i *) abshift_bytes[r];\n}");
}
fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc);
fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc);
fprintf(fd," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
fprintf(fd2," %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
fprintf(fd," %s *c2,*d2;\n\n",data_type);
fprintf(fd2," %s *c2,*d2;\n\n",data_type);
fprintf(fd," int i2;\n");
fprintf(fd2," int i2;\n");
fprintf(fd," for (i2=0; i2<%d; i2++) {\n",Zc>>shift);
if (shift > 0)
fprintf(fd2," for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1));
for (i2=0; i2 < 1; i2++)
{
//t=Kb*Zc+i2;
@@ -169,53 +181,122 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
fprintf(fd," c2=&csimd[i2];\n");
fprintf(fd," d2=&dsimd[i2];\n");
fprintf(fd2," c2=&csimd[i2];\n");
fprintf(fd2," d2=&dsimd[i2];\n");
for (i1 = 0; i1 < nrows; i1++)
{
fprintf(fd,"\n//row: %d\n",i1);
fprintf(fd2,"\n//row: %d\n",i1);
AssertFatal(shift > 0 , "The result of the right shift is undefined because the right operand is negative\n");
AssertFatal(shift >= 0 , "The result of the right shift is undefined because the right operand is negative\n");
fprintf(fd," d2[%d]=",(Zc*i1)>>shift);
fprintf(fd2," d2[%d]=",(Zc*i1)>>(shift-1));
nind=0;
for (i3=0; i3 < ncols; i3++)
{
temp_prime=i1 * ncols + i3;
for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
{
{
var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
printf("var %d, i3 %d, i4 %d, index %d, shift %d, Zc %d, pointer_shift_values[%d] %d gen_shift_value %d\n",var,i3,i4,index,shift,Zc,temp_prime,pointer_shift_values[temp_prime],Gen_shift_values[pointer_shift_values[temp_prime]]);
indlist[nind] = ((index&mask)*((2*Zc*ncols)>>shift)/* *Kb */)+(index>>shift);
printf("indlist[%d] %d, index&mask %d, index>>shift %d\n",nind,indlist[nind],index&mask,index>>shift);
indlist2[nind++] = ((index&(mask>>1))*((2*Zc*ncols)>>(shift-1))*Kb)+(index>>(shift-1));
}
}
printf("indlist[%d] %d, index&mask %d, index>>shift %d\n",nind,indlist[nind],index&mask,index>>shift);
if (use_permutex==1 || use_alignr==1) {
indlist[nind++] = index;
}
else {
indlist[nind] = ((index&mask)*((2*Zc*ncols)>>shift)/* *Kb */)+(index>>shift);
}
}//i4
}//i3
for (i4=0;i4<nind-1;i4++) {
fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
fprintf(fd2,"%s(c2[%d],",xor_command,indlist2[i4]);
if (use_permutex==0 && use_alignr==0) {
fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
}
else {
if ((indlist[i4]&mask) == 0) {
fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]>>shift);
}
else if (use_permutex==1) {
fprintf(fd,"%s(%s(c2[%d],abshift_get(%d),c2[%d]),",xor_command,permutex_command,(indlist[i4]>>shift),indlist[i4]&mask,(indlist[i4]>>shift)+1);
}
else if (use_alignr==1) {
fprintf(fd,"%s(%s(c2[%d],c2[%d],%d),",xor_command,alignr_command,(indlist[i4]>>shift)+1,(indlist[i4]>>shift),indlist[i4]&mask);
}
}
} //i4
if (use_permutex==0 && use_alignr==0)
fprintf(fd,"c2[%d]",indlist[i4]);
else {
if ((indlist[i4]&mask) == 0) {
fprintf(fd,"c2[%d]",indlist[i4]>>shift);
}
else if (use_permutex==1){
fprintf(fd,"%s(c2[%d],abshift_get(%d),c2[%d])",permutex_command,(indlist[i4]>>shift),indlist[i4]&mask,(indlist[i4]>>shift)+1);
}
else if (use_alignr==1) {
fprintf(fd,"%s(c2[%d],c2[%d],%d)",alignr_command,(indlist[i4]>>shift)+1,(indlist[i4]>>shift),indlist[i4]&mask);
}
}
fprintf(fd,"c2[%d]",indlist[i4]);
fprintf(fd2,"c2[%d]",indlist2[i4]);
for (i4=0;i4<nind-1;i4++) { fprintf(fd,")"); fprintf(fd2,")"); }
fprintf(fd,";\n");
fprintf(fd2, ";\n");
}
fprintf(fd," }\n}\n");
fprintf(fd2," }\n}\n");
}
for (i4=0;i4<nind-1;i4++) fprintf(fd,")");
fprintf(fd,";\n");
} // i1
fprintf(fd," }\n}\n");
} // i2
fclose(fd);
}
else if (gen_code == 4) { // CUDA
char fname[100];
sprintf(fname,"ldpc_BG%d_Zc%d_32bit.cu",BG,Zc);
FILE *fd=fopen(fname,"w");
AssertFatal(fd!=NULL,"cannot open %s\n",fname);
printf("Writing to %s\n",fname);
fprintf(fd,"#include <stdio.h>\n#include <stdint.h>\n#include <cuda_runtime.h>\n");
fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
fprintf(fd,"__global__ void ldpc_BG%d_Zc%d_worker(uint32_t *c[4],uint32_t *d[4]) {\n",BG,Zc);
fprintf(fd," uint32_t *c32=c[blockIdx.x];\n uint32_t *d32=d[blockIdx.x];\n\n");
fprintf(fd," int i2 = threadIdx.x;\n");
fprintf(fd," int i1 = blockIdx.y;\n");
fprintf(fd," if (i2 < %d) {\n",Zc);
fprintf(fd," c32+=i2;\n");
fprintf(fd," d32+=i2;\n");
fprintf(fd," switch(i1) {\n");
for (int i1=0;i1<nrows;i1++) {
nind = 0;
fprintf(fd," case %d:\n",i1);
fprintf(fd," d32[%d]=",(Zc*i1));
for (i3=0; i3 < ncols; i3++)
{
temp_prime=i1 * ncols + i3;
for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
{
var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
printf("var %d, i3 %d, i4 %d, index %d (index mod 2Zc) %d, Zc %d, pointer_shift_values[%d] %d gen_shift_value %d offset %d\n",var,i3,i4,index,index%(2*Zc),Zc,temp_prime,pointer_shift_values[temp_prime],Gen_shift_values[pointer_shift_values[temp_prime]],(i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc);
if (index%(2*Zc) >= Zc) printf("***********************\n");
indlist[nind] = index;
printf("indlist[%d] %d, index %d\n",nind,indlist[nind],index);
nind++;
} //i4
} // i3
for (i4=0;i4<nind-1;i4++) {
fprintf(fd,"c32[%d]^",indlist[i4]);
} //i4
fprintf(fd,"c32[%d];\n\n",indlist[i4]);
fprintf(fd," break;\n");
}// i1
fprintf(fd," }\n");
fprintf(fd," }\n");
fprintf(fd,"}\n");
fprintf(fd,"extern \"C\" int ldpc_BG%d_Zc%d_cuda32(uint32_t *c[4],uint32_t *d[4],int n_inputs) { \n",BG,Zc);
fprintf(fd,"dim3 numblocks(n_inputs,%d);\n",nrows);
fprintf(fd,"ldpc_BG%d_Zc%d_worker<<<numblocks,%d>>>(c,d);\n",BG,Zc,Zc);
fprintf(fd," cudaDeviceSynchronize();\n");
fprintf(fd," return(0);\n");
fprintf(fd,"}\n");
fclose(fd);
fclose(fd2);
}
else if(gen_code==0)
{
@@ -241,10 +322,12 @@ int LDPCencoder(unsigned char **inputArray, unsigned char *outputArray, encoder_
for (i4 = 0; i4 < no_shift_values[temp_prime]; i4++) {
channel_temp = channel_temp ^ c[i3 * Zc + Gen_shift_values[pointer_shift_values[temp_prime] + i4]];
//if (i1==0) printf("index %d\n",i3 * Zc + Gen_shift_values[pointer_shift_values[temp_prime] + i4]);
}
}
d[i2+i1*Zc]=channel_temp;
//if (i1==0) printf("reference: d[%d] %d c[%d] %d\n",i2,d[i2],i2,c[i2]);
// output[t+i1*Zc]=channel_temp;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*!\file ldpc_encoder.c
* \brief Defines the LDPC encoder
* \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
* \email openair_tech@eurecom.fr
* \date 27-03-2018
* \version 1.0
* \note
* \warning
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "assertions.h"
#include "openair1/PHY/CODING/nrLDPC_defs.h"
#include "openair1/PHY/CODING/nrLDPC_extern.h"
#include "ldpc_generate_coefficient.c"
void cuda_support_init() {
return;
}
uint32_t **LDPCencoder32(uint8_t **input,encoder_implemparams_t *impp)
{
AssertFatal(1==0,"Should not be getting here\n");
}

View File

@@ -0,0 +1,791 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file ldpc_encoder_optim8segmulti.c
* \brief Defines the optimized LDPC encoder
* \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
* \email openair_tech@eurecom.fr
* \date 27-03-2018
* \version 1.0
* \note
* \warning
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "assertions.h"
#include "common/utils/LOG/log.h"
#include "time_meas.h"
#include "openair1/PHY/CODING/nrLDPC_defs.h"
#include "PHY/sse_intrin.h"
#include "openair1/PHY/CODING/nrLDPC_extern.h"
#include "ldpc_generate_coefficient.c"
#include <cuda_runtime.h>
//#define DEBUG_LDPC 1
#include "ldpc_encode_parity_check_cuda.c"
uint32_t *c_dev;
uint32_t **c_host;
uint32_t *c_devh[4];
uint32_t *d_dev;
uint32_t **d_host;
uint32_t *d_devh[4];
uint32_t *cc_dev;
uint32_t **cc_host;
uint32_t *cc_devh[4];
uint32_t *input_dev;
uint32_t **input_host;
uint32_t *input_devh[128];
int managed = 0, concurrent = 0, uva = 0, pageable = 0, pageable_uses_host = 0, register_host = 0;
//#define USE_GPU_CIRCCOPY 1
//#define USE_GPU_FOR_INPUT 1
void cuda_support_init() {
int dev = 0;
struct cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, dev);
cudaDeviceGetAttribute(&managed, cudaDevAttrManagedMemory, dev);
cudaDeviceGetAttribute(&concurrent, cudaDevAttrConcurrentManagedAccess, dev);
cudaDeviceGetAttribute(&uva, cudaDevAttrUnifiedAddressing, dev);
cudaDeviceGetAttribute(&pageable, cudaDevAttrPageableMemoryAccess, dev);
cudaDeviceGetAttribute(&pageable_uses_host, cudaDevAttrPageableMemoryAccessUsesHostPageTables, dev);
cudaDeviceGetAttribute(&register_host, cudaDevAttrHostRegisterSupported,dev);
LOG_I(NR_PHY,"Device: %s (cc %d.%d)\n", prop.name, prop.major, prop.minor);
LOG_I(NR_PHY,"Unified Virtual Addressing (UVA): %s\n", uva ? "YES" : "NO");
LOG_I(NR_PHY,"Managed (Unified) Memory: %s\n", managed ? "YES" : "NO");
LOG_I(NR_PHY,"Concurrent managed access: %s\n", concurrent ? "YES" : "NO");
LOG_I(NR_PHY,"Pageable memory access: %s\n", pageable ? "YES" : "NO");
LOG_I(NR_PHY,"Uses host page tables: %s\n", pageable_uses_host ? "YES" : "NO");
LOG_I(NR_PHY,"Host Register supported: %s\n", register_host ? "YES" : "NO");
// initialize input and output memory
if (!pageable && !register_host) {
cudaError_t err=cudaMalloc((void **)&c_dev,4*sizeof(uint32_t*));
AssertFatal(err == cudaSuccess,"CUDA Error (c_dev): %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&c_host,4*sizeof(uint32_t*),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (c_host): %s\n", cudaGetErrorString(err));
for (int i=0;i<4;i++) {
err=cudaMalloc((void**)&c_devh[i],2*22*384*sizeof(uint32_t));
AssertFatal(err == cudaSuccess,"CUDA Error (c_devh[%d]): %s\n", i,cudaGetErrorString(err));
err=cudaHostAlloc((void**)&c_host[i],2*22*384*sizeof(uint32_t),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (chost[%d]): %s\n", i,cudaGetErrorString(err));
}
err = cudaMemcpy(c_dev,c_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy c_devh -> c_dev): %s\n", cudaGetErrorString(err));
err=cudaMalloc((void**)&d_dev,4*sizeof(uint32_t*));
AssertFatal(err == cudaSuccess,"CUDA Error: %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&d_host,4*sizeof(uint32_t*),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (d_host): %s\n", cudaGetErrorString(err));
for (int i=0;i<4;i++) {
err=cudaMalloc((void**)&d_devh[i],68*384*sizeof(uint32_t));
AssertFatal(err == cudaSuccess,"CUDA Error (d_devh[%d]: %s\n", i,cudaGetErrorString(err));
err=cudaHostAlloc((void**)&d_host[i],68*384*sizeof(uint32_t),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (d_host[%d]): %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(d_dev,d_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy d_devh -> d_dev): %s\n", cudaGetErrorString(err));
err=cudaMalloc((void**)&cc_dev,4*sizeof(uint32_t*));
AssertFatal(err == cudaSuccess,"CUDA Error: %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&cc_host,4*sizeof(uint32_t*),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (cc_host): %s\n", cudaGetErrorString(err));
for (int i=0;i<4;i++) {
err=cudaMalloc((void**)&cc_devh[i],68*384*sizeof(uint32_t));
AssertFatal(err == cudaSuccess,"CUDA Error (cc_devh[%d]: %s\n", i,cudaGetErrorString(err));
err=cudaHostAlloc((void**)&cc_host[i],68*384*sizeof(uint32_t),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (cc_host[%d]): %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(cc_dev,cc_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy cc_devh -> d_dev): %s\n", cudaGetErrorString(err));
err=cudaMalloc((void**)&input_dev,128*sizeof(uint8_t*));
AssertFatal(err == cudaSuccess,"CUDA Error: %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&input_host,128*sizeof(uint8_t*),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (cc_host): %s\n", cudaGetErrorString(err));
for (int i=0;i<128;i++) {
err=cudaMalloc((void**)&input_devh[i],(8448/8)*sizeof(uint8_t));
AssertFatal(err == cudaSuccess,"CUDA Error (input_devh[%d]: %s\n", i,cudaGetErrorString(err));
err=cudaHostAlloc((void**)&input_host[i],(8448/8)*sizeof(uint8_t),cudaHostAllocDefault);
AssertFatal(err == cudaSuccess,"CUDA Error (input_host[%d]): %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(input_dev,input_devh,128*sizeof(uint8_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy cc_devh -> d_dev): %s\n", cudaGetErrorString(err));
}
else {
LOG_I(NR_PHY,"Allocating c,d,cc arrays for CPU/GPU shared-memory\n");
cudaError_t err=cudaHostAlloc((void **)&c_host,4*sizeof(uint32_t*),cudaHostAllocMapped|cudaHostAllocPortable);
AssertFatal(err == cudaSuccess,"CUDA Error (c_host): %s\n", cudaGetErrorString(err));
err = cudaHostGetDevicePointer((void**)&c_dev, c_host, 0);
AssertFatal(err == cudaSuccess,"CUDA Error (c_dev): %s\n", cudaGetErrorString(err));
LOG_I(NR_PHY,"c_host %p, c_dev %p\n",c_host,c_dev);
for (int i=0;i<4;i++) {
err=cudaHostAlloc((void**)&c_host[i],2*22*384*sizeof(uint32_t),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (c_host[%d]): %s\n", i,cudaGetErrorString(err));
err = cudaHostGetDevicePointer((void**)&c_devh[i], c_host[i], 0);
AssertFatal(err == cudaSuccess,"CUDA Error (c_devh[%d]): %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(c_dev,c_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy c_devh -> c_dev): %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&d_host,4*sizeof(uint32_t*),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (d_host): %s\n", cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&d_dev, d_host, 0);
AssertFatal(err == cudaSuccess,"CUDA Error cudaHostGetDevicePointer(d_dev): %s\n", cudaGetErrorString(err));
LOG_I(NR_PHY,"d_host %p, d_dev %p\n",d_host,d_dev);
for (int i=0;i<4;i++) {
err=cudaHostAlloc((void**)&d_host[i],68*384*sizeof(uint32_t),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (d_host[%d]): %s\n", i,cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&d_devh[i], d_host[i], 0);
AssertFatal(err == cudaSuccess,"CUDA Error (cudaHostGetDevicePointer) d_devh[%d]: %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(d_dev,d_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy d_devh -> d_dev): %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&cc_host,4*sizeof(uint32_t*),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (cc_host): %s\n", cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&cc_dev, cc_host, 0);
AssertFatal(err == cudaSuccess,"CUDA Error cudaHostGetDevicePointer(cc_dev): %s\n", cudaGetErrorString(err));
LOG_I(NR_PHY,"cc_host %p, cc_dev %p\n",cc_host,cc_dev);
for (int i=0;i<4;i++) {
err=cudaHostAlloc((void**)&cc_host[i],68*384*sizeof(uint32_t),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (cc_host[%d]): %s\n", i,cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&cc_devh[i], cc_host[i], 0);
AssertFatal(err == cudaSuccess,"CUDA Error (cudaHostGetDevicePointer) cc_devh[%d]: %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(cc_dev,cc_devh,4*sizeof(uint32_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy d_devh -> d_dev): %s\n", cudaGetErrorString(err));
err=cudaHostAlloc((void **)&input_host,128*sizeof(uint8_t*),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (input_host): %s\n", cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&input_dev, input_host, 0);
AssertFatal(err == cudaSuccess,"CUDA Error cudaHostGetDevicePointer(cc_host): %s\n", cudaGetErrorString(err));
LOG_I(NR_PHY,"input_host %p, input_dev %p\n",input_host,input_dev);
/*
for (int i=0;i<128;i++) {
err=cudaHostAlloc((void**)&input_host[i],(8448/8)*sizeof(uint8_t),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (input_host[%d]): %s\n", i,cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&input_devh[i], input_host[i], 0);
AssertFatal(err == cudaSuccess,"CUDA Error (cudaHostGetDevicePointer) input_devh[%d]: %s\n", i,cudaGetErrorString(err));
}
err=cudaMemcpy(input_dev,input_devh,128*sizeof(uint8_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy input_devh -> input_dev): %s\n", cudaGetErrorString(err));
*/
}
}
uint32_t **LDPCencoder32(uint8_t **input, encoder_implemparams_t *impp)
{
//set_log(PHY, 4);
int Zc = impp->Zc;
int Kb = impp->Kb;
short block_length = impp->K;
short BG = impp->BG;
int nrows=0,ncols=0;
int rate=3;
int no_punctured_columns,removed_bit;
if(impp->tinput != NULL) start_meas(impp->tinput);
//determine number of bits in codeword
if (BG==1)
{
nrows=46; //parity check bits
ncols=22; //info bits
rate=3;
}
else if (BG==2)
{
nrows=42; //parity check bits
ncols=10; // info bits
rate=5;
}
#ifdef DEBUG_LDPC
LOG_I(PHY,"ldpc_encoder_cuda32: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,impp->n_segments);
LOG_I(PHY,"ldpc_encoder_cuda32: PDU (seg 0) %x %x %x %x\n",input[0][0],input[0][1],input[0][2],input[0][3]);
#endif
AssertFatal(Zc > 0, "no valid Zc found for block length %d\n", block_length);
int n_inputs = (impp->n_segments/32)+(((impp->n_segments&31) > 0) ? 1: 0);
// uint32_t cc[4][22*Zc]; //padded input, unpacked, max size
// calculate number of punctured bits
no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
// clear input
/*
for (int i=0;i<n_inputs;i++) {
if (!pageable && !register_host)
cudaMemset(cc_devh[i],0,22*Zc*sizeof(uint32_t));
else
memset(cc_host[i],0,22*Zc*sizeof(uint32_t));
}*/
#if 0
// unoptimized version of input processing
unsigned int temp;
for (int i_dword=0; i_dword < block_length; i_dword++) {
unsigned int i = i_dword;
for (int j = 0; j < impp->n_segments; j++) {
temp = (input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
cc[j>>5][i] |= (temp << (j&31));
}
}
#else
// uint32_t *ccp[4];
// for (int s=0;s<n_inputs;s++) ccp[s]=cc[s];
#ifdef USE_GPU_FOR_INPUT
if (!pageable && !register_host) {
for (int r=0;r<impp->n_segments;r++) {
cudaMemcpy(input_devh[r],input[r],block_length>>3,cudaMemcpyHostToDevice);
}
}
ldpc_input(pageable||register_host? input : input_dev,(uint32_t**)cc_dev,block_length,impp->n_segments);
// for (int i=0;i<16;i++) printf("i %d: cc[0] %x\n",i,cc[0][i]);
#else
#ifndef __aarch64__
simde__m256i andmask = simde_mm256_set_epi32(0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80); // every 8 bits -> 8 bytes, pattern repeats.
simde__m256i zero256 = simde_mm256_setzero_si256();
simde__m256i masks[32];
register simde__m256i c256;
for (int i=0;i<32;i++) {
masks[i] = simde_mm256_set1_epi32(1<<i);
}
int i;
for (i=0; i < block_length; i += 8) {
unsigned int i8 = i >> 3;
for (int j0=0;j0<n_inputs;j0++) {
c256 = simde_mm256_and_si256(simde_mm256_cmpeq_epi32(simde_mm256_andnot_si256(simde_mm256_set1_epi32(input[j0<<5][i8]),andmask),zero256),masks[0]);
int j2 = 32;
if (j0==(n_inputs-1)) j2= impp->n_segments-(j0<<5);
for (int j=1; j < j2; j++) {
c256 = simde_mm256_or_si256(simde_mm256_and_si256(simde_mm256_cmpeq_epi32(simde_mm256_andnot_si256(simde_mm256_set1_epi32(input[(j0<<5)+j][i8]),andmask),zero256),masks[j]),c256);
}
((simde__m256i *)cc_host[j0])[i8] = c256;
}
}
#else
int i2=0;
const int32_t ucShifta[32][4] = {
{-7,-6,-5,-4}, // 0
{-6,-5,-4,-3}, // 1
{-5,-4,-3,-2}, // 2
{-4,-3,-2,-1}, // 3
{-3,-2,-1,0}, // 4
{-2,-1,0,1}, // 5
{-1,0,1,2}, // 6
{0,1,2,3}, // 7
{1,2,3,4}, // 8
{2,3,4,5}, // 9
{3,4,5,6}, // 10
{4,5,6,7}, // 11
{5,6,7,8}, // 12
{6,7,8,9}, // 13
{7,8,9,10}, // 14
{8,9,10,11}, // 15
{9,10,11,12}, // 16
{10,11,12,13}, // 17
{11,12,13,14}, // 18
{12,13,14,15}, // 19
{13,14,15,16}, // 20
{14,15,16,17}, // 21
{15,16,17,18}, // 22
{16,17,18,19}, // 23
{17,18,19,20}, // 24
{18,19,20,21}, // 25
{19,20,21,22}, // 26
{20,21,22,23}, // 27
{21,22,23,24}, // 28
{22,23,24,25}, // 29
{23,24,25,26}, // 30
{24,25,26,27}}; // 31
const int32_t ucShiftb[32][4] = {
{-3,-2,-1,0}, // 0
{-2,-1,0,1}, // 1
{-1,0,1,2}, // 2
{0,1,2,3}, // 3
{1,2,3,4}, // 4
{2,3,4,5}, // 5
{3,4,5,6}, // 6
{4,5,6,7}, // 7
{5,6,7,8}, // 8
{6,7,8,9}, // 9
{7,8,9,10}, // 10
{8,9,10,11}, // 11
{9,10,11,12}, // 12
{10,11,12,13}, // 13
{11,12,13,14}, // 14
{12,13,14,15}, // 15
{13,14,15,16}, // 16
{14,15,16,17}, // 17
{15,16,17,18}, // 18
{16,17,18,19}, // 19
{17,18,19,20}, // 20
{18,19,20,21}, // 21
{19,20,21,22}, // 22
{20,21,22,23}, // 23
{21,22,23,24}, // 24
{22,23,24,25}, // 25
{23,24,25,26}, // 26
{24,25,26,27}, // 27
{25,26,27,28}, // 28
{26,27,28,29}, // 29
{27,28,29,30}, // 30
{28,29,30,31}}; // 31
const int32_t ucShiftc[32][4] = {
{-15,-14,-13,-12}, // 0
{-14,-13,-12,-11}, // 1
{-13,-12,-11,-10}, // 2
{-12,-11,-10,-9}, // 3
{-11,-10,-9,-8}, // 4
{-10,-9,-8,-7}, // 5
{-9,-8,-7,-6}, // 6
{-8,-7,-6,-5}, // 7
{-7,-6,-5,-4}, // 8
{-6,-5,-4,-3}, // 9
{-5,-4,-3,-2}, // 10
{-4,-3,-2,-1}, // 11
{-3,-2,-1,0}, // 12
{-2,-1,0,1}, // 13
{-1,0,1,2}, // 14
{0,1,2,3}, // 15
{1,2,3,4}, // 16
{2,3,4,5}, // 17
{3,4,5,6}, // 18
{4,5,6,7}, // 19
{5,6,7,8}, // 20
{6,7,8,9}, // 21
{7,8,9,10}, // 22
{8,9,10,11}, // 23
{9,10,11,12}, // 24
{10,11,12,13}, // 25
{11,12,13,14}, // 26
{12,13,14,15}, // 27
{13,14,15,16}, // 28
{14,15,16,17}, // 29
{15,16,17,18}, // 30
{16,17,18,19}}; // 31
const int32_t ucShiftd[32][4] = {
{-11,-10,-9,-8}, // 0
{-10,-9,-8,-7}, // 1
{-9,-8,-7,-6}, // 2
{-8,-7,-6,-5}, // 3
{-7,-6,-5,-4}, // 4
{-6,-5,-4,-3}, // 5
{-5,-4,-3,-2}, // 6
{-4,-3,-2,-1}, // 7
{-3,-2,-1,0}, // 8
{-2,-1,0,1}, // 9
{-1,0,1,2}, // 10
{0,1,2,3}, // 11
{1,2,3,4}, // 12
{2,3,4,5}, // 13
{3,4,5,6}, // 14
{4,5,6,7}, // 15
{5,6,7,8}, // 16
{6,7,8,9}, // 17
{7,8,9,10}, // 18
{8,9,10,11}, // 19
{9,10,11,12}, // 20
{10,11,12,13}, // 21
{11,12,13,14}, // 22
{12,13,14,15}, // 23
{13,14,15,16}, // 24
{14,15,16,17}, // 25
{15,16,17,18}, // 26
{16,17,18,19}, // 27
{17,18,19,20}, // 28
{18,19,20,21}, // 29
{19,20,21,22}, // 30
{20,21,22,23}};// 31
const int32_t ucShifte[32][4] = {
{-23,-22,-21,-20}, // 0
{-22,-21,-20,-19}, // 1
{-21,-20,-19,-18}, // 2
{-20,-19,-18,-17}, // 3
{-19,-18,-17,-16}, // 4
{-18,-17,-16,-15}, // 5
{-17,-16,-15,-14}, // 6
{-16,-15,-14,-13}, // 7
{-15,-14,-13,-12}, // 8
{-14,-13,-12,-11}, // 9
{-13,-12,-11,-10}, // 10
{-12,-11,-10,-9}, // 11
{-11,-10,-9,-8}, // 12
{-10,-9,-8,-7}, // 13
{-9,-8,-7,-6}, // 14
{-8,-7,-6,-5}, // 15
{-7,-6,-5,-4}, // 16
{-6,-5,-4,-3}, // 17
{-5,-4,-3,-2}, // 18
{-4,-3,-2,-1}, // 19
{-3,-2,-1,0}, // 20
{-2,-1,0,1}, // 21
{-1,0,1,2}, // 22
{0,1,2,3}, // 23
{1,2,3,4}, // 24
{2,3,4,5}, // 25
{3,4,5,6}, // 26
{4,5,6,7}, // 27
{5,6,7,8}, // 28
{6,7,8,9}, // 29
{7,8,9,10}, // 30
{8,9,10,11}}; // 31
const int32_t ucShiftf[32][4] = {
{-19,-18,-17,-16}, // 0
{-18,-17,-16,-15}, // 1
{-17,-16,-15,-14}, // 2
{-16,-15,-14,-13}, // 3
{-15,-14,-13,-12}, // 4
{-14,-13,-12,-11}, // 5
{-13,-12,-11,-10}, // 6
{-12,-11,-10,-9}, // 7
{-11,-10,-9,-8}, // 8
{-10,-9,-8,-7}, // 9
{-9,-8,-7,-6}, // 10
{-8,-7,-6,-5}, // 11
{-7,-6,-5,-4}, // 12
{-6,-5,-4,-3}, // 13
{-5,-4,-3,-2}, // 14
{-4,-3,-2,-1}, // 15
{-3,-2,-1,0}, // 16
{-2,-1,0,1}, // 17
{-1,0,1,2}, // 18
{0,1,2,3}, // 19
{1,2,3,4}, // 20
{2,3,4,5}, // 21
{3,4,5,6}, // 22
{4,5,6,7}, // 23
{5,6,7,8}, // 24
{6,7,8,9}, // 25
{7,8,9,10}, // 26
{8,9,10,11}, // 27
{9,10,11,12}, // 28
{10,11,12,13}, // 29
{11,12,13,14}, // 30
{12,13,14,15}}; // 31
const int32_t ucShiftg[32][4] = {
{-31,-30,-29,-28},
{-30,-29,-28,-27},
{-29,-28,-27,-26},
{-28,-27,-26,-25},
{-27,-26,-25,-24},
{-26,-25,-24,-23},
{-25,-24,-23,-22},
{-24,-23,-22,-21},
{-23,-22,-21,-20}, // 0
{-22,-21,-20,-19}, // 1
{-21,-20,-19,-18}, // 2
{-20,-19,-18,-17}, // 3
{-19,-18,-17,-16}, // 4
{-18,-17,-16,-15}, // 5
{-17,-16,-15,-14}, // 6
{-16,-15,-14,-13}, // 7
{-15,-14,-13,-12}, // 8
{-14,-13,-12,-11}, // 9
{-13,-12,-11,-10}, // 10
{-12,-11,-10,-9}, // 11
{-11,-10,-9,-8}, // 12
{-10,-9,-8,-7}, // 13
{-9,-8,-7,-6}, // 14
{-8,-7,-6,-5}, // 15
{-7,-6,-5,-4}, // 16
{-6,-5,-4,-3}, // 17
{-5,-4,-3,-2}, // 18
{-4,-3,-2,-1}, // 19
{-3,-2,-1,0}, // 20
{-2,-1,0,1}, // 21
{-1,0,1,2}, // 22
{0,1,2,3}}; // 23
const int32_t ucShifth[32][4] = {
{-27,-26,-25,-24}, // 0
{-26,-25,-24,-23}, // 1
{-25,-24,-23,-22}, // 2
{-24,-23,-22,-21}, // 3
{-23,-22,-21,-20}, // 4
{-22,-21,-20,-19}, // 5
{-21,-20,-19,-18}, // 6
{-20,-19,-18,-17}, // 7
{-19,-18,-17,-16}, // 8
{-18,-17,-16,-15}, // 9
{-17,-16,-15,-14}, // 10
{-16,-15,-14,-13}, // 11
{-15,-14,-13,-12}, // 12
{-14,-13,-12,-11}, // 13
{-13,-12,-11,-10}, // 14
{-12,-11,-10,-9}, // 15
{-11,-10,-9,-8}, // 16
{-10,-9,-8,-7}, // 17
{-9,-8,-7,-6}, // 18
{-8,-7,-6,-5}, // 19
{-7,-6,-5,-4}, // 20
{-6,-5,-4,-3}, // 21
{-5,-4,-3,-2}, // 22
{-4,-3,-2,-1}, // 23
{-3,-2,-1,0}, // 24
{-2,-1,0,1}, // 25
{-1,0,1,2}, // 26
{0,1,2,3}, // 27
{1,2,3,4}, // 28
{2,3,4,5}, // 29
{3,4,5,6}, // 30
{4,5,6,7}}; // 31
const uint32_t __attribute__ ((aligned (16))) masksa[4] = {0x80,0x40,0x20,0x10};
const uint32_t __attribute__ ((aligned (16))) masksb[4] = {0x8,0x4,0x2,0x1};
const uint32_t __attribute__ ((aligned (16))) masksc[4] = {0x8000,0x4000,0x2000,0x1000};
const uint32_t __attribute__ ((aligned (16))) masksd[4] = {0x800,0x400,0x200,0x100};
const uint32_t __attribute__ ((aligned (16))) maskse[4] = {0x800000,0x400000,0x200000,0x100000};
const uint32_t __attribute__ ((aligned (16))) masksf[4] = {0x80000,0x40000,0x20000,0x10000};
const uint32_t __attribute__ ((aligned (16))) masksg[4] = {0x80000000,0x40000000,0x20000000,0x10000000};
const uint32_t __attribute__ ((aligned (16))) masksh[4] = {0x8000000,0x4000000,0x2000000,0x1000000};
int32x4_t vshifta[32],vshiftb[32],vshiftc[32],vshiftd[32],vshifte[32],vshiftf[32],vshiftg[32],vshifth[32];
uint32x4_t vmasksa = vld1q_u32(masksa);
uint32x4_t vmasksb = vld1q_u32(masksb);
uint32x4_t vmasksc = vld1q_u32(masksc);
uint32x4_t vmasksd = vld1q_u32(masksd);
uint32x4_t vmaskse = vld1q_u32(maskse);
uint32x4_t vmasksf = vld1q_u32(masksf);
uint32x4_t vmasksg = vld1q_u32(masksg);
uint32x4_t vmasksh = vld1q_u32(masksh);
uint32x4_t in;
for (int n=0;n<32;n++) {
vshifta[n] = vld1q_s32(ucShifta[n]);
vshiftb[n] = vld1q_s32(ucShiftb[n]);
vshiftc[n] = vld1q_s32(ucShiftc[n]);
vshiftd[n] = vld1q_s32(ucShiftd[n]);
vshifte[n] = vld1q_s32(ucShifte[n]);
vshiftf[n] = vld1q_s32(ucShiftf[n]);
vshiftg[n] = vld1q_s32(ucShiftg[n]);
vshifth[n] = vld1q_s32(ucShifth[n]);
}
i2=0;
int j0=0,j1=0,j2=0,j3=0;
if (impp->n_segments <= 32) {
j0=impp->n_segments;
}
else if (impp->n_segments <= 64) {
j0=32;
j1=impp->n_segments-32;
}
else if (impp->n_segments <= 96) {
j0=32; j1=32;
j2=impp->n_segments-64;
}
else if (impp->n_segments <= 128) {
j0=32; j1=32; j2=32;
j3=impp->n_segments-96;
}
uint32x4_t *ccp,cc0,cc1,cc2,cc3,cc4,cc5,cc6,cc7;
for (int i=0; i < (block_length>>5); i++,i2+=8) {
in = vdupq_n_u32(((uint32_t*)input[0])[i]);
cc0 = vshlq_u32(vandq_u32(in,vmasksa),vshifta[0]);
cc1 = vshlq_u32(vandq_u32(in,vmasksb),vshiftb[0]);
cc2 = vshlq_u32(vandq_u32(in,vmasksc),vshiftc[0]);
cc3 = vshlq_u32(vandq_u32(in,vmasksd),vshiftd[0]);
cc4 = vshlq_u32(vandq_u32(in,vmaskse),vshifte[0]);
cc5 = vshlq_u32(vandq_u32(in,vmasksf),vshiftf[0]);
cc6 = vshlq_u32(vandq_u32(in,vmasksg),vshiftg[0]);
cc7 = vshlq_u32(vandq_u32(in,vmasksh),vshifth[0]);
for (int j = 1; j < j0; j++) {
in = vdupq_n_u32(((uint32_t*)input[j])[i]);
cc0 = vorrq_u32(cc0,vshlq_u32(vandq_u32(in,vmasksa),vshifta[j]));
cc1 = vorrq_u32(cc1,vshlq_u32(vandq_u32(in,vmasksb),vshiftb[j]));
cc2 = vorrq_u32(cc2,vshlq_u32(vandq_u32(in,vmasksc),vshiftc[j]));
cc3 = vorrq_u32(cc3,vshlq_u32(vandq_u32(in,vmasksd),vshiftd[j]));
cc4 = vorrq_u32(cc4,vshlq_u32(vandq_u32(in,vmaskse),vshifte[j]));
cc5 = vorrq_u32(cc5,vshlq_u32(vandq_u32(in,vmasksf),vshiftf[j]));
cc6 = vorrq_u32(cc6,vshlq_u32(vandq_u32(in,vmasksg),vshiftg[j]));
cc7 = vorrq_u32(cc7,vshlq_u32(vandq_u32(in,vmasksh),vshifth[j]));
}
ccp=&((uint32x4_t *)cc_host[0])[i2];
ccp[0] = cc0;
ccp[1] = cc1;
ccp[2] = cc2;
ccp[3] = cc3;
ccp[4] = cc4;
ccp[5] = cc5;
ccp[6] = cc6;
ccp[7] = cc7;
if (j1>0) {
in = vdupq_n_u32(((uint32_t*)input[32])[i]);
cc0 = vshlq_u32(vandq_u32(in,vmasksa),vshifta[0]);
cc1 = vshlq_u32(vandq_u32(in,vmasksb),vshiftb[0]);
cc2 = vshlq_u32(vandq_u32(in,vmasksc),vshiftc[0]);
cc3 = vshlq_u32(vandq_u32(in,vmasksd),vshiftd[0]);
cc4 = vshlq_u32(vandq_u32(in,vmaskse),vshifte[0]);
cc5 = vshlq_u32(vandq_u32(in,vmasksf),vshiftf[0]);
cc6 = vshlq_u32(vandq_u32(in,vmasksg),vshiftg[0]);
cc7 = vshlq_u32(vandq_u32(in,vmasksh),vshifth[0]);
for (int j = 1; j < j1; j++) {
in = vdupq_n_u32(((uint32_t*)input[32+j])[i]);
cc0 = vorrq_u32(cc0,vshlq_u32(vandq_u32(in,vmasksa),vshifta[j]));
cc1 = vorrq_u32(cc1,vshlq_u32(vandq_u32(in,vmasksb),vshiftb[j]));
cc2 = vorrq_u32(cc2,vshlq_u32(vandq_u32(in,vmasksc),vshiftc[j]));
cc3 = vorrq_u32(cc3,vshlq_u32(vandq_u32(in,vmasksd),vshiftd[j]));
cc4 = vorrq_u32(cc4,vshlq_u32(vandq_u32(in,vmaskse),vshifte[j]));
cc5 = vorrq_u32(cc5,vshlq_u32(vandq_u32(in,vmasksf),vshiftf[j]));
cc6 = vorrq_u32(cc6,vshlq_u32(vandq_u32(in,vmasksg),vshiftg[j]));
cc7 = vorrq_u32(cc7,vshlq_u32(vandq_u32(in,vmasksh),vshifth[j]));
}
ccp=&((uint32x4_t *)cc_host[1])[i2];
ccp[0] = cc0;
ccp[1] = cc1;
ccp[2] = cc2;
ccp[3] = cc3;
ccp[4] = cc4;
ccp[5] = cc5;
ccp[6] = cc6;
ccp[7] = cc7;
}
if (j2>0) {
in = vdupq_n_u32(((uint32_t*)input[64])[i]);
cc0 = vshlq_u32(vandq_u32(in,vmasksa),vshifta[0]);
cc1 = vshlq_u32(vandq_u32(in,vmasksb),vshiftb[0]);
cc2 = vshlq_u32(vandq_u32(in,vmasksc),vshiftc[0]);
cc3 = vshlq_u32(vandq_u32(in,vmasksd),vshiftd[0]);
cc4 = vshlq_u32(vandq_u32(in,vmaskse),vshifte[0]);
cc5 = vshlq_u32(vandq_u32(in,vmasksf),vshiftf[0]);
cc6 = vshlq_u32(vandq_u32(in,vmasksg),vshiftg[0]);
cc7 = vshlq_u32(vandq_u32(in,vmasksh),vshifth[0]);
for (int j = 1; j < j2; j++) {
in = vdupq_n_u32(((uint32_t*)input[64+j])[i]);
cc0 = vorrq_u32(cc0,vshlq_u32(vandq_u32(in,vmasksa),vshifta[j]));
cc1 = vorrq_u32(cc1,vshlq_u32(vandq_u32(in,vmasksb),vshiftb[j]));
cc2 = vorrq_u32(cc2,vshlq_u32(vandq_u32(in,vmasksc),vshiftc[j]));
cc3 = vorrq_u32(cc3,vshlq_u32(vandq_u32(in,vmasksd),vshiftd[j]));
cc4 = vorrq_u32(cc4,vshlq_u32(vandq_u32(in,vmaskse),vshifte[j]));
cc5 = vorrq_u32(cc5,vshlq_u32(vandq_u32(in,vmasksf),vshiftf[j]));
cc6 = vorrq_u32(cc6,vshlq_u32(vandq_u32(in,vmasksg),vshiftg[j]));
cc7 = vorrq_u32(cc7,vshlq_u32(vandq_u32(in,vmasksh),vshifth[j]));
}
ccp=&((uint32x4_t *)cc_host[2])[i2];
ccp[0] = cc0;
ccp[1] = cc1;
ccp[2] = cc2;
ccp[3] = cc3;
ccp[4] = cc4;
ccp[5] = cc5;
ccp[6] = cc6;
ccp[7] = cc7;
}
if (j3>0) {
in = vdupq_n_u32(((uint32_t*)input[96])[i]);
cc0 = vshlq_u32(vandq_u32(in,vmasksa),vshifta[0]);
cc1 = vshlq_u32(vandq_u32(in,vmasksb),vshiftb[0]);
cc2 = vshlq_u32(vandq_u32(in,vmasksc),vshiftc[0]);
cc3 = vshlq_u32(vandq_u32(in,vmasksd),vshiftd[0]);
cc4 = vshlq_u32(vandq_u32(in,vmaskse),vshifte[0]);
cc5 = vshlq_u32(vandq_u32(in,vmasksf),vshiftf[0]);
cc6 = vshlq_u32(vandq_u32(in,vmasksg),vshiftg[0]);
cc7 = vshlq_u32(vandq_u32(in,vmasksh),vshifth[0]);
for (int j = 1; j < j3; j++) {
in = vdupq_n_u32(((uint32_t*)input[96+j])[i]);
cc0 = vorrq_u32(cc0,vshlq_u32(vandq_u32(in,vmasksa),vshifta[j]));
cc1 = vorrq_u32(cc1,vshlq_u32(vandq_u32(in,vmasksb),vshiftb[j]));
cc2 = vorrq_u32(cc2,vshlq_u32(vandq_u32(in,vmasksc),vshiftc[j]));
cc3 = vorrq_u32(cc3,vshlq_u32(vandq_u32(in,vmasksd),vshiftd[j]));
cc4 = vorrq_u32(cc4,vshlq_u32(vandq_u32(in,vmaskse),vshifte[j]));
cc5 = vorrq_u32(cc5,vshlq_u32(vandq_u32(in,vmasksf),vshiftf[j]));
cc6 = vorrq_u32(cc6,vshlq_u32(vandq_u32(in,vmasksg),vshiftg[j]));
cc7 = vorrq_u32(cc7,vshlq_u32(vandq_u32(in,vmasksh),vshifth[j]));
}
ccp=&((uint32x4_t *)cc_host[3])[i2];
ccp[0] = cc0;
ccp[1] = cc1;
ccp[2] = cc2;
ccp[3] = cc3;
ccp[4] = cc4;
ccp[5] = cc5;
ccp[6] = cc6;
ccp[7] = cc7;
}
}
#endif
#endif
#endif
if(impp->tinput != NULL) stop_meas(impp->tinput);
if(impp->tinput_memcpy != NULL) start_meas(impp->tinput_memcpy);
#ifdef USE_GPU_CIRCCOPY
circcopy_c(cc_dev,c_dev,n_inputs);
#else
#ifdef USE_CUDA_MEMCPY
for (int s=0;s<n_inputs;s++) {
for (int i1 = 0; i1 < ncols; i1++) {
cudaError_t err = cudaMemcpy(&c_devh[s][2 * i1 * Zc], &cc_devh[s][i1 * Zc], Zc * sizeof(uint32_t),cudaMemcpyDeviceToDevice);
AssertFatal(err == cudaSuccess, "1st memcpy cc_devh[%d] -> c_devh[%d] %p CUDA Error: %s\n", s, s, c_devh[s],cudaGetErrorString(err));
err = cudaMemcpy(&c_devh[s][(2 * i1 + 1) * Zc], &cc_devh[s][i1 * Zc], Zc * sizeof(uint32_t),cudaMemcpyDeviceToDevice);
AssertFatal(err == cudaSuccess, "2nd memcpy cc_devh[%d] -> c_devh[%d] %p CUDA Error: %s\n", s, s, c_devh[s],cudaGetErrorString(err));
}
#else
for (int s=0;s<n_inputs;s++) {
for (int i1 = 0; i1 < ncols; i1++) {
memcpy(&c_host[s][2 * i1 * Zc], &cc_host[s][i1 * Zc], Zc * sizeof(uint32_t));
memcpy(&c_host[s][(2 * i1 + 1) * Zc], &cc_host[s][i1 * Zc], Zc * sizeof(uint32_t));
}
if (!pageable && !register_host) {
cudaError_t err = cudaMemcpy(c_devh[s],c_host[s],sizeof(uint32_t)*2*22*Zc,cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess, "memcpy c_host[%d] -> c_devh[%d] %p CUDA Error: %s\n", s, s, c_devh[s],cudaGetErrorString(err));
}
}
#endif
#endif
if(impp->tinput != NULL) stop_meas(impp->tinput_memcpy);
if (BG==1 && Zc==384) {
//parity check part
if(impp->tparity != NULL) start_meas(impp->tparity);
encode_parity_check_part_cuda((uint32_t**)c_dev, (uint32_t**)d_dev, BG, Zc, Kb, ncols,n_inputs);
if(impp->tparity != NULL) stop_meas(impp->tparity);
}
else {
AssertFatal(1==0,"Only BG1 Zc=384 for now\n");
}
if(impp->toutput != NULL) start_meas(impp->toutput);
for (int s=0;s<n_inputs;s++) {
if (!pageable && !register_host) {
cudaMemcpy(d_host[s],&cc_devh[s][2*Zc],sizeof(uint32_t)*(block_length-(2*Zc)),cudaMemcpyDeviceToHost);
cudaError_t err = cudaMemcpy(&d_host[s][block_length-(2*Zc)],d_devh[s]+block_length-(2*Zc),sizeof(uint32_t)*((nrows-no_punctured_columns) * Zc-removed_bit),cudaMemcpyDeviceToHost);
AssertFatal(err == cudaSuccess, "d_dev[%d] %p CUDA Error: %s\n", s, d_devh[s],cudaGetErrorString(err));
}
else {
memcpy(d_host[s],&cc_host[s][2*Zc],sizeof(uint32_t)*(block_length-(2*Zc)));
}
}
if(impp->toutput != NULL) stop_meas(impp->toutput);
return d_host;
}

View File

@@ -43,6 +43,11 @@
#include "ldpc_encode_parity_check.c"
#include "ldpc_generate_coefficient.c"
void ini_input32_luts() {
return;
}
int LDPCencoder(uint8_t **input, uint8_t *output, encoder_implemparams_t *impp)
{
//set_log(PHY, 4);
@@ -107,7 +112,6 @@ int LDPCencoder(uint8_t **input, uint8_t *output, encoder_implemparams_t *impp)
//interleave up to 8 transport-block segements at a time
unsigned int i_byte = 0;
#if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512VBMI__)
const __m512i masks5[8] = { _mm512_set1_epi8(0x1), _mm512_set1_epi8(0x2),
_mm512_set1_epi8(0x4), _mm512_set1_epi8(0x8),
@@ -193,12 +197,9 @@ int LDPCencoder(uint8_t **input, uint8_t *output, encoder_implemparams_t *impp)
if(impp->tinput != NULL) stop_meas(impp->tinput);
if ((BG==1 && Zc>=176) || (BG==2 && Zc>=72)) {
// extend matrix
if(impp->tprep != NULL) start_meas(impp->tprep);
if(impp->tprep != NULL) stop_meas(impp->tprep);
//parity check part
if(impp->tparity != NULL) start_meas(impp->tparity);
encode_parity_check_part_optim(cc, dd, BG, Zc, Kb, simd_size, ncols);
encode_parity_check_part_optim(cc, dd, BG, Zc, Kb, simd_size, ncols,impp->tinput_memcpy);
if(impp->tparity != NULL) stop_meas(impp->tparity);
}
else {
@@ -207,8 +208,10 @@ int LDPCencoder(uint8_t **input, uint8_t *output, encoder_implemparams_t *impp)
return(-1);
}
}
if(impp->toutput != NULL) start_meas(impp->toutput);
memcpy(output,&cc[2*Zc],(block_length-(2*Zc)));
memcpy(output+block_length-(2*Zc),dd,((nrows-no_punctured_columns) * Zc-removed_bit));
if(impp->toutput != NULL) stop_meas(impp->toutput);
return 0;
}

View File

@@ -0,0 +1,175 @@
#include <stdio.h>
#include <stdint.h>
#include <cuda_runtime.h>
/*
__device__ const uint32_t masks[4] = {0x80,0x8000,0x800000,0x80000000};
__global__ void ldpc_input_worker(uint32_t **input,uint32_t *cc[4],int block_length,int nseg) {
int block_off = blockIdx.x*blockDim.x<<2;
int i2 = threadIdx.x<<2;
uint32_t *out=cc[blockIdx.y] + block_off + i2;
int nseg0 = (blockIdx.y << 5);
int nseg1;
if ((nseg0 + 32) <= nseg) nseg1 = nseg0+32;
else nseg1 = nseg0 + (nseg&31);
int bit_offset = i2+block_off;
int uint32_offset = bit_offset>>5;
uint32_t mask = masks[(bit_offset&31)>>3];
uint32_t mask0 = mask>>(bit_offset&7);bit_offset++;
uint32_t mask1 = mask>>(bit_offset&7);bit_offset++;
uint32_t mask2 = mask>>(bit_offset&7);bit_offset++;
uint32_t mask3 = mask>>(bit_offset&7);
uint32_t tmp,jmod;
uint32_t otmp0,otmp1,otmp2,otmp3;
if (bit_offset < block_length) {
tmp=input[nseg0][uint32_offset];
otmp0 = ((tmp&mask0) > 0);
otmp1 = ((tmp&mask1) > 0);
otmp2 = ((tmp&mask2) > 0);
otmp3 = ((tmp&mask3) > 0);
for (int j=nseg0+1;j<nseg1;j++) {
tmp=input[j][uint32_offset];
jmod = j&31;
otmp0 |= (((tmp&mask0) > 0)<<jmod);
otmp1 |= (((tmp&mask1) > 0)<<jmod);
otmp2 |= (((tmp&mask2) > 0)<<jmod);
otmp3 |= (((tmp&mask3) > 0)<<jmod);
}
out[0]=otmp0;
out[1]=otmp1;
out[2]=otmp2;
out[3]=otmp3;
}
}
*/
#define ITERATIONS 1
#define NTHREADS 384
__device__ uint32_t masks[32] = {
0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1,
0x8000,0x4000,0x2000,0x1000,0x800,0x400,0x200,0x100,
0x800000,0x400000,0x200000,0x100000,0x80000,0x40000,0x20000,0x10000,
0x80000000,0x40000000,0x20000000,0x10000000,0x8000000,0x4000000,0x2000000,0x1000000};
__global__ void ldpc_input_worker(uint32_t **input,uint32_t *cc[4],int block_length,int nseg) {
int block_off = blockIdx.x*blockDim.x*ITERATIONS;
int i2 = threadIdx.x*ITERATIONS;
uint32_t *out=cc[blockIdx.y] + block_off + i2;
int nseg0 = (blockIdx.y << 5);
int nseg1;
if ((nseg0 + 32) <= nseg) nseg1 = nseg0+32;
else nseg1 = nseg0 + (nseg&31);
int bit_offset = i2+block_off;
int uint32_offset = bit_offset>>5;
#if ITERATIONS==1
uint32_t mask0 = masks[bit_offset&31];
#else
uint32_t *mask = &masks[bit_offset&31];
uint32_t mask0 = mask[0];
#endif
#if ITERATIONS==4 || ITERATIONS==8
uint32_t mask1 = mask[1];
uint32_t mask2 = mask[2];
uint32_t mask3 = mask[3];
#endif
#if ITERATIONS==8
uint32_t mask4 = mask[4];
uint32_t mask5 = mask[5];
uint32_t mask6 = mask[6];
uint32_t mask7 = mask[7];
#endif
uint32_t tmp,jmod;
uint32_t otmp0;
#if ITERATIONS==4 || ITERATIONS==8
uint32_t otmp1,otmp2,otmp3;
#endif
#if ITERATIONS==8
uint32_t otmp4,otmp5,otmp6,otmp7;
#endif
if (bit_offset < block_length) {
tmp=input[nseg0][uint32_offset];
otmp0 = ((tmp&mask0) > 0);
#if ITERATIONS==4 || ITERATIONS==8
otmp1 = ((tmp&mask1) > 0);
otmp2 = ((tmp&mask2) > 0);
otmp3 = ((tmp&mask3) > 0);
#endif
#if ITERATIONS==8
otmp4 = ((tmp&mask4) > 0);
otmp5 = ((tmp&mask5) > 0);
otmp6 = ((tmp&mask6) > 0);
otmp7 = ((tmp&mask7) > 0);
#endif
for (int j=nseg0+1;j<nseg1;j++) {
tmp=input[j][uint32_offset];
jmod = j&31;
otmp0 |= (((tmp&mask0) > 0)<<jmod);
#if ITERATIONS==4 || ITERATIONS==8
otmp1 |= (((tmp&mask1) > 0)<<jmod);
otmp2 |= (((tmp&mask2) > 0)<<jmod);
otmp3 |= (((tmp&mask3) > 0)<<jmod);
#endif
#if ITERATIONS==8
otmp4 |= (((tmp&mask4) > 0)<<jmod);
otmp5 |= (((tmp&mask5) > 0)<<jmod);
otmp6 |= (((tmp&mask6) > 0)<<jmod);
otmp7 |= (((tmp&mask7) > 0)<<jmod);
#endif
}
out[0]=otmp0;
#if ITERATIONS==4 || ITERATIONS==8
out[1]=otmp1;
out[2]=otmp2;
out[3]=otmp3;
#endif
#if ITERATIONS==8
out[4]=otmp4;
out[5]=otmp5;
out[6]=otmp6;
out[7]=otmp7;
#endif
}
}
__global__ void circcopy_c_worker(uint32_t **cc,uint32_t **c) {
int s = blockIdx.x;
int i1 = blockIdx.y;
int i = threadIdx.x;
uint32_t tmp;
if (i<384) {
tmp = cc[s][(i1*384) + i];
c[s][2*i1*384 + i] = tmp;
c[s][(2*i1+1)*384 + i] = tmp;
}
}
extern "C" int ldpc_input(uint32_t **input,uint32_t *cc[4],int block_length,int nseg) {
int numb = block_length/(NTHREADS*ITERATIONS);
if ((block_length%(NTHREADS*ITERATIONS)) > 0) numb++;
int ns = nseg>>5;
if ((nseg&31)>0) ns++;
dim3 numblocks(numb,ns);
ldpc_input_worker<<<numblocks,NTHREADS>>>(input,cc,block_length,nseg);
cudaError_t err=cudaPeekAtLastError();
if (err!=cudaSuccess) {
printf("cuda error: %s (input %p, cc %p, block_length %d, nseg %d, numb %d, ns %d)\n",cudaGetErrorString(err),input,cc,block_length,nseg,numb,ns);
exit(-1);
}
cudaDeviceSynchronize();
return(0);
}
extern "C" int circcopy_c(uint32_t **cc,uint32_t **c,int n_inputs) {
dim3 numblocks(n_inputs,22);
circcopy_c_worker<<<numblocks,384>>>(cc,c);
cudaError_t err=cudaPeekAtLastError();
if (err!=cudaSuccess) {
printf("cuda error: %s (cc %p, c %p, n_inputs %d)\n",cudaGetErrorString(err),cc,c,n_inputs);
exit(-1);
}
cudaDeviceSynchronize();
return(0);
}

View File

@@ -29,6 +29,7 @@ typedef struct ldpc_interface_s {
LDPC_shutdownfunc_t *LDPCshutdown;
LDPC_decoderfunc_t *LDPCdecoder;
LDPC_encoderfunc_t *LDPCencoder;
LDPC_encoderfunc32_t *LDPCencoder32;
} ldpc_interface_t;
/* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */
@@ -37,6 +38,7 @@ int free_LDPClib(ldpc_interface_t *ldpc_interface);
LDPC_decoderfunc_t LDPCdecoder;
LDPC_encoderfunc_t LDPCencoder;
LDPC_encoderfunc32_t LDPCencoder32;
// inline functions:
#endif

View File

@@ -56,14 +56,17 @@ int load_LDPClib(char *version, ldpc_interface_t *itf)
loader_shlibfunc_t shlib_fdesc[] = {{.fname = "LDPCinit"},
{.fname = "LDPCshutdown"},
{.fname = "LDPCdecoder"},
{.fname = "LDPCencoder"}};
{.fname = "LDPCencoder"},
{.fname = "LDPCencoder32"}};
int ret;
ret = load_module_version_shlib(libname, version, shlib_fdesc, sizeofArray(shlib_fdesc), NULL);
AssertFatal((ret >= 0), "Error loading ldpc decoder");
LOG_I(NR_PHY,"loading LDPC version %s\n",version);
itf->LDPCinit = (LDPC_initfunc_t *)shlib_fdesc[0].fptr;
itf->LDPCshutdown = (LDPC_shutdownfunc_t *)shlib_fdesc[1].fptr;
itf->LDPCdecoder = (LDPC_decoderfunc_t *)shlib_fdesc[2].fptr;
itf->LDPCencoder = (LDPC_encoderfunc_t *)shlib_fdesc[3].fptr;
itf->LDPCencoder32 = (LDPC_encoderfunc32_t *)shlib_fdesc[4].fptr;
AssertFatal(itf->LDPCinit() == 0, "error starting LDPC library %s %s\n", libname, version);

View File

@@ -21,6 +21,7 @@
#include "executables/softmodem-common.h"
#include "executables/nr-softmodem-common.h"
#include "executables/nr-softmodem.h"
#include "common/utils/nr/nr_common.h"
#include "common/ran_context.h"
#include "PHY/defs_gNB.h"
@@ -105,6 +106,10 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
// shortcuts
NR_DL_FRAME_PARMS *const fp = &gNB->frame_parms;
nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
gNB->use_gpu = use_gpu;
gNB->use_fp16 = use_fp16;
NR_gNB_COMMON *const common_vars = &gNB->common_vars;
common_vars->analog_bf = cfg->analog_beamforming_ve.analog_bf_vendor_ext.value;
LOG_I(PHY, "L1 configured with%s analog beamforming\n", common_vars->analog_bf ? "" : "out");
@@ -342,7 +347,12 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB,
nr_init_frame_parms(gNB_config, fp);
fp->ofdm_offset_divisor = UINT_MAX;
init_symbol_rotation(fp);
printf("Init symbol rotation, fp16 %s\n",gNB->use_fp16?"yes":"no");
init_symbol_rotation(fp
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
init_timeshift_rotation(fp);
gNB->configured = 1;
@@ -395,7 +405,12 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config)
RC.gNB[Mod_id]->configured = 1;
fp->ofdm_offset_divisor = RC.gNB[Mod_id]->ofdm_offset_divisor;
init_symbol_rotation(fp);
printf("Init symbol rotation, fp16 %s\n",RC.gNB[Mod_id]->use_fp16?"yes":"no");
init_symbol_rotation(fp
#ifdef FLT16_MAX
,RC.gNB[Mod_id]->use_fp16
#endif
);
init_timeshift_rotation(fp);
}
@@ -407,7 +422,7 @@ static void init_DLSCH_struct(PHY_VARS_gNB *gNB)
gNB->dlsch = calloc(gNB->max_nb_pdsch, sizeof(*gNB->dlsch));
for (int i = 0; i < gNB->max_nb_pdsch; i++) {
LOG_D(PHY, "Allocating Transport Channel Buffers for DLSCH %d/%d\n", i, gNB->max_nb_pdsch);
gNB->dlsch[i] = new_gNB_dlsch(fp, grid_size);
gNB->dlsch[i] = new_gNB_dlsch(fp, grid_size, gNB->use_gpu);
}
}
@@ -417,7 +432,7 @@ static void destroy_DLSCH_struct(const PHY_VARS_gNB *gNB)
const nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
const uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value;
for (int i = 0; i < gNB->max_nb_pdsch; i++) {
free_gNB_dlsch(&gNB->dlsch[i], grid_size, fp);
free_gNB_dlsch(&gNB->dlsch[i], grid_size, fp, gNB->use_gpu);
}
free(gNB->dlsch);
}

View File

@@ -273,7 +273,11 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
}
ue->init_averaging = 1;
init_symbol_rotation(fp);
init_symbol_rotation(fp
#ifdef FLT16_MAX
,ue->use_fp16
#endif
);
init_timeshift_rotation(fp);
// initialize to false only for SA since in do-ra and phy-test it is already set to true before getting here

View File

@@ -656,7 +656,11 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
// ssb_offset_pointa points to the first RE where Sidelink-PSBCH starts
fp->ssb_start_subcarrier = config->sl_bwp_config.sl_ssb_offset_point_a;
perform_symbol_rotation(fp, fp->sl_CarrierFreq, fp->symbol_rotation[link_type_sl]);
perform_symbol_rotation(fp, fp->sl_CarrierFreq, fp->symbol_rotation[link_type_sl]
#ifdef FLT16_MAX
,0//use_fp16
#endif
);
init_timeshift_rotation(fp);
// Not used for Sidelink

View File

@@ -18,11 +18,11 @@
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "nr_modulation.h"
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include "executables/softmodem-common.h"
#include <simde/x86/avx512.h>
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include <float.h>
// Lacking declaration in present simde external package, will be detected as compilation error when they will add it
#define simde_mm512_extracti64x2_epi64(a...) _mm512_extracti64x2_epi64(a)
@@ -117,112 +117,179 @@ const char nr_W_4l_4p[5][4][4] = {
{{'1', '1', '1', '1'}, {'1', 'n', '1', 'n'}, {'j', 'j', 'o', 'o'}, {'j', 'o', 'o', 'j'}} // pmi 4
};
#ifdef FLT16_MAX
void nr_modulation(const uint32_t *in, uint32_t length, uint16_t mod_order, int16_t *out, _Float16 *out_fp16)
#else
void nr_modulation(const uint32_t *in, uint32_t length, uint16_t mod_order, int16_t *out)
#endif
{
const uint16_t mask = ((1 << mod_order) - 1);
#ifdef FLT16_MAX
AssertFatal((!out && out_fp16) || (out && !out_fp16), "out %p, out_fp16 %p, one needs to be null\n",out,out_fp16);
#else
AssertFatal(out == NULL, "out is NULL\n");
#endif
uint16_t mask = ((1 << mod_order) - 1);
int32_t *nr_mod_table32;
int64_t *nr_mod_table64;
#ifdef FLT16_MAX
int32_t *out32 = out?(int32_t*)out:(int32_t*)out_fp16;
#else
int32_t *out32 = (int32_t *)out;
#endif
int64_t *out64 = (int64_t *)out32;
const uint8_t *in_bytes = (const uint8_t *)in;
const uint64_t *in64 = (const uint64_t *)in;
int64_t *out64 = (int64_t *)out;
uint32_t i = 0;
LOG_D(PHY, "nr_modulation: length %d, mod_order %d\n", length, mod_order);
#if defined(__SSE2__) || defined(__aarch64__)
simde__m128i *nr_mod_table128;
simde__m128i *out128 = (simde__m128i *)out32;
#endif
LOG_D(PHY, "nr_modulation: length %d, mod_order %d (fp16 %s)\n", length, mod_order,out_fp16?"yes":"no");
switch (mod_order) {
case 2: {
simde__m128i *nr_mod_table128 = (simde__m128i *)nr_qpsk_byte_mod_table;
simde__m128i *out128 = (simde__m128i *)out;
#if defined(__SSE2__) || defined(__aarch64__)
case 2:
#ifdef FLT16_MAX
if (out_fp16)
nr_mod_table128 = (simde__m128i *)nr_qpsk_byte_mod_table_fp16;
else
#endif
nr_mod_table128 = (simde__m128i *)nr_qpsk_byte_mod_table;
for (i = 0; i < length / 8; i++)
out128[i] = nr_mod_table128[in_bytes[i]];
// the bits that are left out
i = i * 8 / 2;
int32_t *nr_mod_table32 = (int32_t *)nr_qpsk_mod_table;
#ifdef FLT16_MAX
if (out_fp16)
nr_mod_table32 = (int32_t *)nr_qpsk_mod_table_fp16;
else
#endif
nr_mod_table32 = (int32_t *)nr_qpsk_mod_table;
while (i < length / 2) {
const int idx = ((in_bytes[(i * 2) / 8] >> ((i * 2) & 0x7)) & mask);
out32[i] = nr_mod_table32[idx];
i++;
}
}
return;
#else
case 2:
#ifdef FLT16_MAX
if (out_fp16)
nr_mod_table32 = (int32_t *)nr_qpsk_mod_table_fp16;
else
#endif
nr_mod_table32 = (int32_t *)nr_qpsk_mod_table;
for (i = 0; i < length / mod_order; i++) {
const int idx = ((in[i * 2 / 32] >> ((i * 2) & 0x1f)) & mask);
out32[i] = nr_mod_table32[idx];
}
return;
#endif
case 4:
#ifdef FLT16_MAX
if (out_fp16) {
nr_mod_table64 = (int64_t *)nr_16qam_byte_mod_table_fp16;
nr_mod_table32 = (int32_t *)nr_16qam_mod_table_fp16;
}
else
#endif
{
nr_mod_table64 = (int64_t *)nr_16qam_byte_mod_table;
nr_mod_table32 = (int32_t *)nr_16qam_mod_table;
}
for (i = 0; i < length / 8; i++)
out64[i] = nr_16qam_byte_mod_table[in_bytes[i]];
out64[i] = nr_mod_table64[in_bytes[i]];
// the bits that are left out
i = i * 8 / 4;
while (i < length / 4) {
const int idx = ((in_bytes[(i * 4) / 8] >> ((i * 4) & 0x7)) & mask);
out32[i] = nr_16qam_mod_table[idx];
out32[i] = nr_mod_table32[idx];
i++;
}
return;
case 6:
#ifdef FLT16_MAX
if (out_fp16)
nr_mod_table64 = (int64_t *)nr_64qam_mod_table_fp16;
else
#endif
nr_mod_table64 = (int64_t *)nr_64qam_mod_table;
if (length > (3 * 64))
for (i = 0; i < length - 3 * 64; i += 3 * 64) {
uint64_t x = *in64++;
uint64_t x1 = x & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x >> 12) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x >> 24) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x >> 36) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x >> 48) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
uint64_t x2 = (x >> 60);
x = *in64++;
x2 |= x << 4;
x1 = x2 & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 12) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 24) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 36) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 48) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x2 = ((x >> 56) & 0xf0) | (x2 >> 60);
x = *in64++;
x2 |= x << 8;
x1 = x2 & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 12) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 24) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 36) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (x2 >> 48) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x2 = ((x >> 52) & 0xff0) | (x2 >> 60);
*out64++ = nr_64qam_mod_table[x2];
*out64++ = nr_mod_table64[x2];
}
while (i + 24 <= length) {
uint32_t xx = 0;
memcpy(&xx, in_bytes + i / 8, 3);
uint64_t x1 = xx & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
x1 = (xx >> 12) & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
i += 24;
}
if (i != length) {
uint32_t xx = 0;
memcpy(&xx, in_bytes + i / 8, 2);
uint64_t x1 = xx & 0xfff;
*out64++ = nr_64qam_mod_table[x1];
*out64++ = nr_mod_table64[x1];
}
return;
case 8: {
int32_t *nr_mod_table32 = (int32_t *)nr_256qam_mod_table;
case 8:
#ifdef FLT16_MAX
if (out_fp16)
nr_mod_table32 = (int32_t *)nr_256qam_mod_table_fp16;
else
#endif
nr_mod_table32 = (int32_t *)nr_256qam_mod_table;
for (i = 0; i < length / 8; i++)
out32[i] = nr_mod_table32[in_bytes[i]];
}
return;
default:
@@ -589,7 +656,11 @@ void nr_dft(c16_t *z, c16_t *d, uint32_t Msc_PUSCH)
}
}
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation)
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
const int nsymb = fp->symbols_per_slot * fp->slots_per_frame / 10;
const double Tc = (1 / 480e3 / 4096);
@@ -615,23 +686,35 @@ void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rot
poff = 2 * M_PI * (tl + (Ncp * Tc)) * f0;
exp_re = cos(poff);
exp_im = sin(-poff);
symbol_rotation[l].r = (int16_t)floor(exp_re * 32767);
symbol_rotation[l].i = (int16_t)floor(exp_im * 32767);
LOG_D(PHY,
"Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",
l,
nsymb,
tl,
symbol_rotation[l].r,
symbol_rotation[l].i,
(poff / 2 / M_PI) - floor(poff / 2 / M_PI));
#ifdef FLT16_MAX
if (use_fp16) {
(*(cf16_t*)&symbol_rotation[l]).r = (_Float16)exp_re;
(*(cf16_t*)&symbol_rotation[l]).i = (_Float16)exp_im;
// printf("initialize fp16 rotation %d: %f %f\n", l, (double) (*(cf16_t*)&symbol_rotation[l]).r, (double) (*(cf16_t*)&symbol_rotation[l]).i);
}
else
#endif
{
symbol_rotation[l].r = (int16_t)floor(exp_re * 32767);
symbol_rotation[l].i = (int16_t)floor(exp_im * 32767);
LOG_D(PHY,
"Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",
l,
nsymb,
tl,
symbol_rotation[l].r,
symbol_rotation[l].i,
(poff / 2 / M_PI) - floor(poff / 2 / M_PI));
}
tl += (Nu + Ncp) * Tc;
}
}
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp)
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
double f[2] = {(double)fp->dl_CarrierFreq, (double)fp->ul_CarrierFreq};
@@ -640,8 +723,16 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp)
if (f0 == 0)
continue;
c16_t *rot = fp->symbol_rotation[ll];
perform_symbol_rotation(fp, f0, rot);
#ifdef FLT16_MAX
printf("Initializing rotation %d fp16 %s\n",ll,use_fp16?"yes":"no");
#else
printf("Initializing rotation %d\n",ll);
#endif
perform_symbol_rotation(fp, f0, rot
#ifdef FLT16_MAX
,use_fp16
#endif
);
}
}
@@ -706,7 +797,11 @@ c16_t nr_layer_precoder_cm(int n_layers,
c16_t datatx_F_precoding[n_layers][symSz],
int ap,
nfapi_nr_pm_pdu_t *pmi_pdu,
int offset)
int offset
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
c16_t precodatatx_F = {0};
for (int al = 0; al < n_layers; al++) {
@@ -808,6 +903,9 @@ static inline __attribute__((always_inline)) __m128i cmac_prec128(__m128i y, __m
const Type w_s##Rank = Instruct(c16toI32(c16swap(pmi_pdu->weights[Rank][ant]))); \
const Type *in##Rank = (Type *)(txdataF_res_mapped[Rank] + sc_offset + (out-beginning));
#define load_consts_fp16(Type, Instruct, Rank) \
const Type w##Rank = (Type)Instruct(*(uint32_t *)&(weights_fp16[Rank])); \
const Type *in##Rank = (Type*)(txdataF_res_mapped[Rank] + sc_offset + (out-beginning));
void nr_layer_precoder_simd(const int n_layers,
const int symSz,
const c16_t txdataF_res_mapped[n_layers][symSz],
@@ -815,7 +913,11 @@ void nr_layer_precoder_simd(const int n_layers,
const nfapi_nr_pm_pdu_t *pmi_pdu,
const int sc_offset,
const int re_cnt,
c16_t *txdataF_precoded)
c16_t *txdataF_precoded
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
// For x86, use 256 SIMD for every 8 RE and 128 SIMD for last 4 RE
// For aarch64, use 128 SIMD for every 4 RE
@@ -824,7 +926,63 @@ void nr_layer_precoder_simd(const int n_layers,
// 512/256 SIMD: Do 16/8 RE in one iteration, 3 iterations for 2 RB
c16_t *beginning = txdataF_precoded + sc_offset;
c16_t *out=beginning;
#if defined(__AVX512F__) && defined(__AVX512BW__)
printf("nr_layer_precoder_simd, use_fp16 %d\n",use_fp16);
// 512-bit SIMD section
#if defined(__AVX512BW__)
c16_t *end = out + (re_cnt & ~15);
#if defined(FLT16_MAX) && defined(__AVX512FP16__)
cf16_t weights_fp16[n_layers];
if (use_fp16) {
for (int l=0;l<n_layers;l++) {
weights_fp16[l].r = ((_Float16)pmi_pdu->weights[l][ant].r)/32768.0;
weights_fp16[l].i = ((_Float16)pmi_pdu->weights[l][ant].i)/32768.0;
}
load_consts_fp16(__m512h, _mm512_set1_epi32,0);
if (n_layers == 1) {
for (; out < end; out += sizeof(__m512i) / sizeof(*out)) {
const __m512h x0 = (__m512h)_mm512_loadu_si512(in0++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m512h y = _mm512_cmul_pch(x0, w0);
_mm512_storeu_si512(out, (__m512i)y);
}
} else if (n_layers == 2) {
load_consts_fp16(__m512h, _mm512_set1_epi32,1);
const __m512h x0 = (__m512h)_mm512_loadu_si512(in0++);
const __m512h x1 = (__m512h)_mm512_loadu_si512(in1++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m512h y = _mm512_cmul_pch(x0, w0);
y=_mm512_fmadd_pch(x1,w1,y);
_mm512_storeu_si512(out, (__m512i)y);
} else if (n_layers == 3) {
load_consts_fp16(__m512h, _mm512_set1_epi32,1);
load_consts_fp16(__m512h, _mm512_set1_epi32,2);
const __m512h x0 = (__m512h)_mm512_loadu_si512(in0++);
const __m512h x1 = (__m512h)_mm512_loadu_si512(in1++);
const __m512h x2 = (__m512h)_mm512_loadu_si512(in2++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m512h y = _mm512_cmul_pch(x0, w0);
y=_mm512_fmadd_pch(x1,w1,y);
y=_mm512_fmadd_pch(x2,w2,y);
_mm512_storeu_si512(out, (__m512i)y);
} else if (n_layers == 4) {
load_consts_fp16(__m512h, _mm512_set1_epi32,1);
load_consts_fp16(__m512h, _mm512_set1_epi32,2);
load_consts_fp16(__m512h, _mm512_set1_epi32,3);
const __m512h x0 = (__m512h)_mm512_loadu_si512(in0++);
const __m512h x1 = (__m512h)_mm512_loadu_si512(in1++);
const __m512h x2 = (__m512h)_mm512_loadu_si512(in2++);
const __m512h x3 = (__m512h)_mm512_loadu_si512(in3++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m512h y = _mm512_cmul_pch(x0, w0);
y=_mm512_fmadd_pch(x1,w1,y);
y=_mm512_fmadd_pch(x2,w2,y);
y=_mm512_fmadd_pch(x3,w3,y);
_mm512_storeu_si512(out, (__m512i)y);
}
}
else
#endif
{
c16_t *end = out + (re_cnt & ~15);
load_consts(__m512i, _mm512_set1_epi32, 0);
@@ -877,7 +1035,55 @@ void nr_layer_precoder_simd(const int n_layers,
}
}
#endif
// 256-bit SIMD section
#ifdef __AVX2__
#if defined(FLT16_MAX) && defined(__AVX512FP16__)
if (use_fp16) {
load_consts_fp16(__m256h, _mm256_set1_epi32,0);
if (n_layers == 1) {
for (; out < end; out += sizeof(__m256i) / sizeof(*out)) {
const __m256h x0 = (__m256h)_mm256_loadu_si256((__m256i*)in0++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m256h y = _mm256_cmul_pch(x0, w0);
_mm256_storeu_si256((__m256i*)out, (__m256i)y);
}
} else if (n_layers == 2) {
load_consts_fp16(__m256h, _mm256_set1_epi32,1);
const __m256h x0 = (__m256h)_mm256_loadu_si256((__m256i*)in0++);
const __m256h x1 = (__m256h)_mm256_loadu_si256((__m256i*)in1++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m256h y = _mm256_cmul_pch(x0, w0);
y=_mm256_fmadd_pch(x1,w1,y);
_mm256_storeu_si256((__m256i*)out, (__m256i)y);
} else if (n_layers == 3) {
load_consts_fp16(__m256h, _mm256_set1_epi32,1);
load_consts_fp16(__m256h, _mm256_set1_epi32,2);
const __m256h x0 = (__m256h)_mm256_loadu_si256((__m256i*)in0++);
const __m256h x1 = (__m256h)_mm256_loadu_si256((__m256i*)in1++);
const __m256h x2 = (__m256h)_mm256_loadu_si256((__m256i*)in2++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m256h y = _mm256_cmul_pch(x0, w0);
y=_mm256_fmadd_pch(x1,w1,y);
y=_mm256_fmadd_pch(x2,w2,y);
_mm256_storeu_si256((__m256i*)out, (__m256i)y);
} else if (n_layers == 4) {
load_consts_fp16(__m256h, _mm256_set1_epi32,1);
load_consts_fp16(__m256h, _mm256_set1_epi32,2);
load_consts_fp16(__m256h, _mm256_set1_epi32,3);
const __m256h x0 = (__m256h)_mm256_loadu_si256((__m256i*)in0++);
const __m256h x1 = (__m256h)_mm256_loadu_si256((__m256i*)in1++);
const __m256h x2 = (__m256h)_mm256_loadu_si256((__m256i*)in2++);
const __m256h x3 = (__m256h)_mm256_loadu_si256((__m256i*)in3++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m256h y = _mm256_cmul_pch(x0, w0);
y=_mm256_fmadd_pch(x1,w1,y);
y=_mm256_fmadd_pch(x2,w2,y);
y=_mm256_fmadd_pch(x3,w3,y);
_mm256_storeu_si256((__m256i*)out, (__m256i)y);
}
}
else
#endif
{
c16_t *end = beginning + (re_cnt & ~7);
load_consts(simde__m256i, simde_mm256_set1_epi32, 0);
@@ -932,7 +1138,6 @@ void nr_layer_precoder_simd(const int n_layers,
}
}
#endif
c16_t *end = beginning + (re_cnt & ~3);
#ifdef DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // Get result with trivial solution, TODO: To be removed
// 128 SIMD: Do 4 RE in one iteration, 3 iterations for 1 RB
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
@@ -943,112 +1148,244 @@ void nr_layer_precoder_simd(const int n_layers,
}
#endif
#ifdef __aarch64__
load_consts(int16x8_t, vdupq_n_s16, 0);
if (n_layers == 1) {
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
c16_t *end = beginning + (re_cnt & ~3);
#ifdef FLT16_MAX
if (use_fp16) {
printf("Running precoding for aarch64 fp16\n");
cf16_t weights_fp16[n_layers];
for (int l=0;l<n_layers;l++) {
weights_fp16[l].r = ((float16_t)pmi_pdu->weights[l][ant].r)/32768.0;
weights_fp16[l].i = ((float16_t)pmi_pdu->weights[l][ant].i)/32768.0;
}
load_consts_fp16(float16x8_t, vdupq_n_f16, 0);
float16x8_t zero=vdupq_n_f16(0.0f);
if (n_layers == 1) {
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const float16x8_t x0 = vld1q_f16((float16_t*)(in0++));
// Accumulate the product
float16x8_t y = vcmlaq_f16(zero,x0,w0);
y = vcmlaq_rot90_f16(y,x0,w0);
// Store the result to txdataF
*(float16x8_t *)out = y;
printf("re %ld %f.%f\n",out-beginning, ((cf16_t*)out)[0].r, ((cf16_t*)out)[0].i);
printf("re %ld %f.%f\n",out-beginning+1, ((cf16_t*)out)[1].r, ((cf16_t*)out)[1].i);
printf("re %ld %f.%f\n",out-beginning+2, ((cf16_t*)out)[2].r, ((cf16_t*)out)[2].i);
printf("re %ld %f.%f\n",out-beginning+3, ((cf16_t*)out)[3].r, ((cf16_t*)out)[3].i);
}
}
else if (n_layers == 2) {
load_consts_fp16(float16x8_t, vdupq_n_f16, 1);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const float16x8_t x0 = vld1q_f16((float16_t*)(in0++));
const float16x8_t x1 = vld1q_f16((float16_t*)(in1++));
// Accumulate the product
float16x8_t y = vcmlaq_f16(zero,x0,w0);
y = vcmlaq_rot90_f16(y,x0,w0);
y = vcmlaq_f16(y,x1,w1);
y = vcmlaq_rot90_f16(y,x1,w1);
// Store the result to txdataF
*(float16x8_t *)out = y;
}
}
else if (n_layers == 3) {
load_consts_fp16(float16x8_t, vdupq_n_f16, 1);
load_consts_fp16(float16x8_t, vdupq_n_f16, 2);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const float16x8_t x0 = vld1q_f16((float16_t*)(in0++));
const float16x8_t x1 = vld1q_f16((float16_t*)(in1++));
const float16x8_t x2 = vld1q_f16((float16_t*)(in2++));
// Accumulate the product
float16x8_t y = vcmlaq_f16(zero,x0,w0);
y = vcmlaq_rot90_f16(y,x0,w0);
y = vcmlaq_f16(y,x1,w1);
y = vcmlaq_rot90_f16(y,x1,w1);
y = vcmlaq_f16(y,x2,w2);
y = vcmlaq_rot90_f16(y,x2,w2);
// Store the result to txdataF
*(float16x8_t *)out = y;
}
}
else if (n_layers == 4) {
load_consts_fp16(float16x8_t, vdupq_n_f16, 1);
load_consts_fp16(float16x8_t, vdupq_n_f16, 2);
load_consts_fp16(float16x8_t, vdupq_n_f16, 3);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const float16x8_t x0 = vld1q_f16((float16_t*)(in0++));
const float16x8_t x1 = vld1q_f16((float16_t*)(in1++));
const float16x8_t x2 = vld1q_f16((float16_t*)(in2++));
const float16x8_t x3 = vld1q_f16((float16_t*)(in3++));
// Accumulate the product
float16x8_t y = vcmlaq_f16(zero,x0,w0);
y = vcmlaq_rot90_f16(y,x0,w0);
y = vcmlaq_f16(y,x1,w1);
y = vcmlaq_rot90_f16(y,x1,w1);
y = vcmlaq_f16(y,x2,w2);
y = vcmlaq_rot90_f16(y,x2,w2);
y = vcmlaq_f16(y,x3,w3);
y = vcmlaq_rot90_f16(y,x3,w3);
// Store the result to txdataF
*(float16x8_t *)out = y;
}
}
}
if (n_layers == 2) {
load_consts(int16x8_t, vdupq_n_s16, 1);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
const int16x8_t x1 = vld1q_s16((const int16_t *)in1++);
// Accumulate the product
int16x8_t y = cmac0_prec128(x0, w_c0, w_s0);
y = cmac_prec128(y, x1, w_c1, w_s1);
// Store the result to txdataF
*(int16x8_t *)out = y;
else
#endif
{
load_consts(int16x8_t, vdupq_n_s16, 0);
if (n_layers == 1) {
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
}
}
}
if (n_layers == 3) {
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
if (n_layers == 2) {
load_consts(int16x8_t, vdupq_n_s16, 1);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
const int16x8_t x0 = vld1q_s16((const int16_t *)in0++);
const int16x8_t x1 = vld1q_s16((const int16_t *)in1++);
// Accumulate the product
int16x8_t y = cmac0_prec128(x0, w_c0, w_s0);
y = cmac_prec128(y, x1, w_c1, w_s1);
// Store the result to txdataF
*(int16x8_t *)out = y;
}
}
}
if (n_layers == 4) {
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
load_consts(int16x8_t, vdupq_n_s16, 3);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
if (n_layers == 3) {
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
}
}
if (n_layers == 4) {
load_consts(int16x8_t, vdupq_n_s16, 1);
load_consts(int16x8_t, vdupq_n_s16, 2);
load_consts(int16x8_t, vdupq_n_s16, 3);
for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) {
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;
}
}
}
#else
load_consts(simde__m128i, simde_mm_set1_epi32, 0);
if (n_layers == 1) {
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
// Accumulate the product
simde__m128i y = cmac0_prec128(x0, w_c0, w_s0);
// Store the result to txdataF
simde_mm_storeu_si128(out, y);
#if defined(FLT16_MAX) && defined(__AVX512FP16__)
if (use_fp16) {
load_consts_fp16(__m128h, _mm_set1_epi32,0);
if (n_layers == 1) {
for (; out < end; out += sizeof(__m128i) / sizeof(*out)) {
const __m128h x0 = (__m128h)_mm_loadu_si128((__m128i*)in0++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m128h y = _mm_cmul_pch(x0, w0);
_mm_storeu_si128((__m128i*)out, (__m128i)y);
}
} else if (n_layers == 2) {
load_consts_fp16(__m128h, _mm_set1_epi32,1);
const __m128h x0 = (__m128h)_mm_loadu_si128((__m128i*)in0++);
const __m128h x1 = (__m128h)_mm_loadu_si128((__m128i*)in1++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m128h y = _mm_cmul_pch(x0, w0);
y=_mm_fmadd_pch(x1,w1,y);
_mm_storeu_si128((__m128i*)out, (__m128i)y);
} else if (n_layers == 3) {
load_consts_fp16(__m128h, _mm_set1_epi32,1);
load_consts_fp16(__m128h, _mm_set1_epi32,2);
const __m128h x0 = (__m128h)_mm_loadu_si128((__m128i*)in0++);
const __m128h x1 = (__m128h)_mm_loadu_si128((__m128i*)in1++);
const __m128h x2 = (__m128h)_mm_loadu_si128((__m128i*)in2++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m128h y = _mm_cmul_pch(x0, w0);
y=_mm_fmadd_pch(x1,w1,y);
y=_mm_fmadd_pch(x2,w2,y);
_mm_storeu_si128((__m128i*)out, (__m128i)y);
} else if (n_layers == 4) {
load_consts_fp16(__m128h, _mm_set1_epi32,1);
load_consts_fp16(__m128h, _mm_set1_epi32,2);
load_consts_fp16(__m128h, _mm_set1_epi32,3);
const __m128h x0 = (__m128h)_mm_loadu_si128((__m128i*)in0++);
const __m128h x1 = (__m128h)_mm_loadu_si128((__m128i*)in1++);
const __m128h x2 = (__m128h)_mm_loadu_si128((__m128i*)in2++);
const __m128h x3 = (__m128h)_mm_loadu_si128((__m128i*)in3++);
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
__m128h y = _mm_cmul_pch(x0, w0);
y=_mm_fmadd_pch(x1,w1,y);
y=_mm_fmadd_pch(x2,w2,y);
y=_mm_fmadd_pch(x3,w3,y);
_mm_storeu_si128((__m128i*)out, (__m128i)y);
}
} else if (n_layers == 2) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
// Accumulate the product
simde__m128i y = cmac0_prec128(x0, w_c0, w_s0);
y = cmac_prec128(y, x1, w_c1, w_s1);
// Store the result to txdataF
simde_mm_storeu_si128(out, y);
}
} else if (n_layers == 3) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
load_consts(simde__m128i, simde_mm_set1_epi32, 2);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
const simde__m128i x2 = simde_mm_loadu_si128(in2++);
simde__m128i 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
simde_mm_storeu_si128(out, y);
}
} else if (n_layers == 4) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
load_consts(simde__m128i, simde_mm_set1_epi32, 2);
load_consts(simde__m128i, simde_mm_set1_epi32, 3);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
const simde__m128i x2 = simde_mm_loadu_si128(in2++);
const simde__m128i x3 = simde_mm_loadu_si128(in3++);
simde__m128i 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
simde_mm_storeu_si128(out, y);
}
else
#endif
{
load_consts(simde__m128i, simde_mm_set1_epi32, 0);
if (n_layers == 1) {
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
// Accumulate the product
simde__m128i y = cmac0_prec128(x0, w_c0, w_s0);
// Store the result to txdataF
simde_mm_storeu_si128(out, y);
}
} else if (n_layers == 2) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
// Accumulate the product
simde__m128i y = cmac0_prec128(x0, w_c0, w_s0);
y = cmac_prec128(y, x1, w_c1, w_s1);
// Store the result to txdataF
simde_mm_storeu_si128(out, y);
}
} else if (n_layers == 3) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
load_consts(simde__m128i, simde_mm_set1_epi32, 2);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
const simde__m128i x2 = simde_mm_loadu_si128(in2++);
simde__m128i 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
simde_mm_storeu_si128(out, y);
}
} else if (n_layers == 4) {
load_consts(simde__m128i, simde_mm_set1_epi32, 1);
load_consts(simde__m128i, simde_mm_set1_epi32, 2);
load_consts(simde__m128i, simde_mm_set1_epi32, 3);
for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) {
const simde__m128i x0 = simde_mm_loadu_si128(in0++);
const simde__m128i x1 = simde_mm_loadu_si128(in1++);
const simde__m128i x2 = simde_mm_loadu_si128(in2++);
const simde__m128i x3 = simde_mm_loadu_si128(in3++);
simde__m128i 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
simde_mm_storeu_si128(out, y);
}
}
}
#endif

View File

@@ -44,7 +44,11 @@ extern const char nr_W_4l_4p[5][4][4];
void nr_modulation(const uint32_t *in,
uint32_t length,
uint16_t mod_order,
int16_t *out);
int16_t *out
#ifdef FLT16_MAX
,_Float16 *out_fp16
#endif
);
/*! \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
@@ -109,11 +113,23 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
int slot,
int nb_rb,
int first_symbol,
int nsymb);
int nsymb
#ifdef FLT16_MAX
,int use_fp16,int tx_amp
#endif
);
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation);
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation
#ifdef FLT16_MAX
,int use_fp16
#endif
);
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp);
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp
#ifdef FLT16_MAX
,int use_fp16
#endif
);
void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp);
@@ -136,7 +152,11 @@ c16_t nr_layer_precoder_cm(int n_layers,
c16_t datatx_F_precoding[n_layers][symSz],
int ap,
nfapi_nr_pm_pdu_t *pmi_pdu,
int offset);
int offset
#ifdef FLT16_MAX
,int use_fp16
#endif
);
/*! \brief Precoding with SIMDe, txdataF_precoded[] = prec_matrix[] * txdataF_res_mapped[]
@param[in] txdataF_res_mapped Tx data after resource mapping, before precoding.
@@ -151,5 +171,9 @@ void nr_layer_precoder_simd(const int n_layers,
const nfapi_nr_pm_pdu_t *pmi_pdu,
const int sc_offset,
const int re_cnt,
c16_t *txdataF_precoded);
c16_t *txdataF_precoded
#ifdef FLT16_MAX
,int use_fp16
#endif
);
#endif

View File

@@ -38,6 +38,8 @@ This section deals with basic functions for OFDM Modulation.
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "modulation_common.h"
#include "PHY/LTE_TRANSPORT/transport_common_proto.h"
#include <math.h>
#include <float.h>
//#define DEBUG_OFDM_MOD
// Use 64-byte alignment for IDFT output buffer to ensure no
@@ -292,7 +294,11 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
int slot,
int nb_rb,
int first_symbol,
int nsymb)
int nsymb
#ifdef FLT16_MAX
,int use_fp16,int tx_amp
#endif
)
{
int symb_offset = (slot % fp->slots_per_subframe) * fp->symbols_per_slot;
@@ -310,19 +316,54 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
this_rotation->i);
if (nb_rb & 1) {
rotate_cpx_vector(this_symbol, this_rotation, this_symbol,
(nb_rb + 1) * 6, 15);
rotate_cpx_vector(this_symbol + fp->first_carrier_offset - 6,
this_rotation,
this_symbol + fp->first_carrier_offset - 6,
(nb_rb + 1) * 6, 15);
#ifdef FLT16_MAX
if (use_fp16) {
rotate_cpx_vector_fp16((cf16_t*)this_symbol, (cf16_t*)this_rotation, (cf16_t*)this_symbol,
(nb_rb + 1) * 6);
fp16_to_q15((cf16_t*)this_symbol,this_symbol,(nb_rb + 1) * 6,tx_amp);
rotate_cpx_vector_fp16((cf16_t*)this_symbol + fp->first_carrier_offset - 6,
(cf16_t*)this_rotation,
(cf16_t*)this_symbol + fp->first_carrier_offset - 6,
(nb_rb + 1) * 6);
fp16_to_q15((cf16_t*)this_symbol + fp->first_carrier_offset - 6,
this_symbol + fp->first_carrier_offset - 6,
(nb_rb + 1) * 6,tx_amp);
}
else
#endif
{
rotate_cpx_vector(this_symbol, this_rotation, this_symbol,
(nb_rb + 1) * 6, 15);
rotate_cpx_vector(this_symbol + fp->first_carrier_offset - 6,
this_rotation,
this_symbol + fp->first_carrier_offset - 6,
(nb_rb + 1) * 6, 15);
}
} else {
rotate_cpx_vector(this_symbol, this_rotation, this_symbol,
nb_rb * 6, 15);
rotate_cpx_vector(this_symbol + fp->first_carrier_offset,
this_rotation,
this_symbol + fp->first_carrier_offset,
nb_rb * 6, 15);
#ifdef FLT16_MAX
if (use_fp16) {
rotate_cpx_vector_fp16in_q15out((cf16_t*)this_symbol, (cf16_t*)this_rotation, tx_amp, (cf16_t*)this_symbol,
nb_rb * 6);
//fp16_to_q15((cf16_t*)this_symbol,this_symbol,nb_rb * 6,tx_amp);
rotate_cpx_vector_fp16in_q15out((cf16_t*)this_symbol + fp->first_carrier_offset,
(cf16_t*)this_rotation, tx_amp,
(cf16_t*)this_symbol + fp->first_carrier_offset,
nb_rb * 6);
//fp16_to_q15((cf16_t*)this_symbol + fp->first_carrier_offset,
// this_symbol + fp->first_carrier_offset,
// nb_rb * 6,
// tx_amp);
}
else
#endif
{
rotate_cpx_vector(this_symbol, this_rotation, this_symbol,
nb_rb * 6, 15);
rotate_cpx_vector(this_symbol + fp->first_carrier_offset,
this_rotation,
this_symbol + fp->first_carrier_offset,
nb_rb * 6, 15);
}
}
}
}

View File

@@ -47,7 +47,7 @@ void nr_symbol_fep(const NR_DL_FRAME_PARMS *frame_parms,
if (dft_stats) start_meas(dft_stats);
dft(dftsize, (int16_t *)rxdata[aa], (int16_t *)rxdataF[aa], 1);
if (dft_stats) stop_meas(dft_stats);
//if (symbol==11) for (int i =0 ; i<72 ; i++) printf("rxdataF[%d] %d + (%dj)\n",i,(rxdataF[aa]+frame_parms->first_carrier_offset+i)->r,(rxdataF[aa]+frame_parms->first_carrier_offset + i)->i);
const bool is_sl = (link_type == link_type_sl);
apply_nr_rotation_symbol_RX(frame_parms,
rxdataF[aa],

View File

@@ -18,61 +18,102 @@
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "nr_refsig.h"
#include "nr_mod_table.h"
c16_t nr_qpsk_mod_table[4];
simde__m128i nr_qpsk_byte_mod_table[256];
int32_t nr_16qam_mod_table[16];
int64_t nr_16qam_byte_mod_table[256];
int64_t nr_16qam_byte_mod_table[1024];
int64_t nr_64qam_mod_table[4096];
int32_t nr_256qam_mod_table[256];
#ifdef FLT16_MAX
cf16_t nr_qpsk_mod_table_fp16[4];
int32_t nr_16qam_mod_table_fp16[16];
simde__m128i nr_qpsk_byte_mod_table_fp16[256];
int64_t nr_16qam_byte_mod_table_fp16[1024];
int64_t nr_64qam_mod_table_fp16[4096];
int32_t nr_256qam_mod_table_fp16[256];
#endif
void nr_generate_modulation_table() {
float sqrt2 = 0.70711;
float sqrt10 = 0.31623;
float sqrt42 = 0.15430;
float sqrt170 = 0.076696;
float val = 32768.0;
uint32_t i,j;
short* table;
int i,j;
int16_t* table;
#ifdef FLT16_MAX
_Float16* table2;
#endif
// QPSK
for (i=0; i<4; i++) {
nr_qpsk_mod_table[i].r = (short)(1 - 2 * (i & 1)) * val * sqrt2 * sqrt2;
nr_qpsk_mod_table[i].i = (short)(1 - 2 * ((i >> 1) & 1)) * val * sqrt2 * sqrt2;
#ifdef FLT16_MAX
nr_qpsk_mod_table_fp16[i].r = (_Float16)((1 - 2 * (i & 1)) * sqrt2 * sqrt2);
nr_qpsk_mod_table_fp16[i].i = (_Float16)((1 - 2 * ((i >> 1) & 1)) * sqrt2 * sqrt2);
#endif
//printf("%d j%d\n",nr_qpsk_mod_table[i*2],nr_qpsk_mod_table[i*2+1]);
}
//QPSK m128
table = (short*) nr_qpsk_byte_mod_table;
table = (int16_t*) nr_qpsk_byte_mod_table;
#ifdef FLT16_MAX
table2 = (_Float16*) nr_qpsk_byte_mod_table_fp16;
#endif
for (i=0; i<256; i++) {
for (j=0; j<4; j++) {
*table++ = (short)(1 - 2 * ((i >> (j * 2)) & 1)) * val * sqrt2 * sqrt2;
*table++ = (short)(1 - 2 * ((i >> (j * 2 + 1)) & 1)) * val * sqrt2 * sqrt2;
*table++ = (int16_t)(1 - 2 * ((i >> (j * 2)) & 1)) * val * sqrt2 * sqrt2;
*table++ = (int16_t)(1 - 2 * ((i >> (j * 2 + 1)) & 1)) * val * sqrt2 * sqrt2;
#ifdef FLT16_MAX
*table2++ = (_Float16)((1 - 2 * ((i >> (j * 2)) & 1)) * sqrt2 * sqrt2);
*table2++ = (_Float16)((1 - 2 * ((i >> (j * 2 + 1)) & 1)) * sqrt2 * sqrt2);
#endif
//printf("%d j%d\n",nr_qpsk_byte_mod_table[i*8+(j*2)],nr_qpsk_byte_mod_table[i*8+(j*2)+1]);
}
}
//16QAM
table = (short*) nr_16qam_byte_mod_table;
table = (int16_t*) nr_16qam_byte_mod_table;
#ifdef FLT16_MAX
table2 = (_Float16*) nr_16qam_byte_mod_table_fp16;
#endif
for (i=0; i<256; i++) {
for (j=0; j<2; j++) {
*table++ = (short)((1 - 2 * ((i >> (j * 4)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 2)) & 1)))) * val * sqrt10 * sqrt2;
*table++ = (short)((1 - 2 * ((i >> (j * 4 + 1)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 3)) & 1)))) * val * sqrt10 * sqrt2;
*table++ = (int16_t)((1 - 2 * ((i >> (j * 4)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 2)) & 1)))) * val * sqrt10 * sqrt2;
*table++ = (int16_t)((1 - 2 * ((i >> (j * 4 + 1)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 3)) & 1)))) * val * sqrt10 * sqrt2;
#ifdef FLT16_MAX
*table2++ = (_Float16)(((1 - 2 * ((i >> (j * 4)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 2)) & 1)))) * sqrt10 * sqrt2);
*table2++ = (_Float16)(((1 - 2 * ((i >> (j * 4 + 1)) & 1)) * (2 - (1 - 2 * ((i >> (j * 4 + 3)) & 1)))) * sqrt10 * sqrt2);
#endif
// printf("%d j%d\n",nr_16qam_byte_mod_table[i*4+(j*2)],nr_16qam_byte_mod_table[i*4+(j*2)+1]);
}
}
table = (short*) nr_16qam_mod_table;
table = (int16_t*) nr_16qam_mod_table;
#ifdef FLT16_MAX
table2 = (_Float16*) nr_16qam_mod_table_fp16;
#endif
for (i=0; i<16; i++) {
*table++ = (short)((1 - 2 * (i & 1)) * (2 - (1 - 2 * ((i >> 2) & 1)))) * val * sqrt10 * sqrt2;
*table++ = (short)((1 - 2 * ((i >> 1) & 1)) * (2 - (1 - 2 * ((i >> 3) & 1)))) * val * sqrt10 * sqrt2;
//printf("%d j%d\n",table[i*2],table[i*2+1]);
*table++ = (int16_t)((1 - 2 * (i & 1)) * (2 - (1 - 2 * ((i >> 2) & 1)))) * val * sqrt10 * sqrt2;
*table++ = (int16_t)((1 - 2 * ((i >> 1) & 1)) * (2 - (1 - 2 * ((i >> 3) & 1)))) * val * sqrt10 * sqrt2;
#ifdef FLT16_MAX
*table2++ = (_Float16)(((1 - 2 * (i & 1)) * (2 - (1 - 2 * ((i >> 2) & 1)))) * sqrt10 * sqrt2);
*table2++ = (_Float16)(((1 - 2 * ((i >> 1) & 1)) * (2 - (1 - 2 * ((i >> 3) & 1)))) * sqrt10 * sqrt2);
#endif
//printf("%d j%d\n",table[i*2],table[i*2+1]);
}
//64QAM
table = (short*) nr_64qam_mod_table;
#ifdef FLT16_MAX
table2 = (_Float16*) nr_64qam_mod_table_fp16;
#endif
for (i=0; i<4096; i++) {
for (j=0; j<2; j++) {
*table++ = (short)((1 - 2 * ((i >> (j * 6)) & 1))
@@ -81,19 +122,48 @@ void nr_generate_modulation_table() {
*table++ = (short)((1 - 2 * ((i >> (j * 6 + 1)) & 1))
* (4 - (1 - 2 * ((i >> (j * 6 + 3)) & 1)) * (2 - (1 - 2 * ((i >> (j * 6 + 5)) & 1)))))
* val * sqrt42 * sqrt2;
#ifdef FLT16_MAX
*table2++ = (_Float16)((1 - 2 * ((i >> (j * 6)) & 1))
* (4 - (1 - 2 * ((i >> (j * 6 + 2)) & 1)) * (2 - (1 - 2 * ((i >> (j * 6 + 4)) & 1)))))
* sqrt42 * sqrt2;
*table2++ = (_Float16)((1 - 2 * ((i >> (j * 6 + 1)) & 1))
* (4 - (1 - 2 * ((i >> (j * 6 + 3)) & 1)) * (2 - (1 - 2 * ((i >> (j * 6 + 5)) & 1)))))
* sqrt42 * sqrt2;
#endif
//printf("%d j%d\n",table[i*4+(j*2)],table[i*4+(j*2)+1]);
}
}
//256QAM
table = (short*) nr_256qam_mod_table;
#ifdef FLT16_MAX
table2 = (_Float16*) nr_256qam_mod_table_fp16;
#endif
for (i=0; i<256; i++) {
*table++ = (short)((1 - 2 * (i & 1))
table[2*i] = (short)((1 - 2 * (i & 1))
* (8 - (1 - 2 * ((i >> 2) & 1)) * (4 - (1 - 2 * ((i >> 4) & 1)) * (2 - (1 - 2 * ((i >> 6) & 1))))))
* val * sqrt170 * sqrt2;
*table++ = (short)((1 - 2 * ((i >> 1) & 1))
table[1+2*i] = (short)((1 - 2 * ((i >> 1) & 1))
* (8 - (1 - 2 * ((i >> 3) & 1)) * (4 - (1 - 2 * ((i >> 5) & 1)) * (2 - (1 - 2 * ((i >> 7) & 1))))))
* val * sqrt170 * sqrt2;
#ifdef FLT16_MAX
table2[2*i] = (_Float16)(((1 - 2 * (i & 1))
* (8 - (1 - 2 * ((i >> 2) & 1)) * (4 - (1 - 2 * ((i >> 4) & 1)) * (2 - (1 - 2 * ((i >> 6) & 1))))))
* sqrt170 * sqrt2);
table2[1+2*i] = (_Float16)(((1 - 2 * ((i >> 1) & 1))
* (8 - (1 - 2 * ((i >> 3) & 1)) * (4 - (1 - 2 * ((i >> 5) & 1)) * (2 - (1 - 2 * ((i >> 7) & 1))))))
* sqrt170 * sqrt2);
/* printf("256QAM %d : %f,%f, (%f,%f) (%f,%f)\n",i,(float)table2[2*i],(float)table2[1+2*i],
(float)((1 - 2 * (i & 1))
* (8 - (1 - 2 * ((i >> 2) & 1)) * (4 - (1 - 2 * ((i >> 4) & 1)) * (2 - (1 - 2 * ((i >> 6) & 1))))))
* sqrt170 * sqrt2,
(float)((1 - 2 * ((i >> 1) & 1))
* (8 - (1 - 2 * ((i >> 3) & 1)) * (4 - (1 - 2 * ((i >> 5) & 1)) * (2 - (1 - 2 * ((i >> 7) & 1))))))
* sqrt170 * sqrt2, ((double)table[2*i])/32768.0,((double)table[1+2*i])/32768
);
*/
#endif
}
}

View File

@@ -22,6 +22,10 @@
#ifndef __PHY_NR_REFSIG_NR_MOD_TABLE__H__
#define __PHY_NR_REFSIG_NR_MOD_TABLE__H__
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
#define NR_MOD_TABLE_SIZE_SHORT 686
#define NR_MOD_TABLE_BPSK_OFFSET 1
#define NR_MOD_TABLE_QAM16_OFFSET 7
@@ -29,12 +33,33 @@
#define NR_MOD_TABLE_QAM256_OFFSET 87
extern c16_t nr_qpsk_mod_table[4];
extern simde__m128i nr_qpsk_byte_mod_table[256];
#ifdef FLT16_MAX
extern cf16_t nr_qpsk_mod_table_fp16[4];
#endif
extern int32_t nr_16qam_mod_table[16];
extern int64_t nr_16qam_byte_mod_table[256];
#ifdef FLT16_MAX
extern int32_t nr_16qam_mod_table_fp16[16];
#endif
#if defined(__SSE2__) || defined(__aarch64__)
extern simde__m128i nr_qpsk_byte_mod_table[256];
#ifdef FLT16_MAX
extern simde__m128i nr_qpsk_byte_mod_table_fp16[256];
#endif
#endif
extern int64_t nr_16qam_byte_mod_table[1024];
#ifdef FLT16_MAX
extern int64_t nr_16qam_byte_mod_table_fp16[1024];
#endif
extern int64_t nr_64qam_mod_table[4096];
extern int32_t nr_256qam_mod_table[256];
#ifdef FLT16_MAX
extern int64_t nr_64qam_mod_table_fp16[4096];
#endif
extern int32_t nr_256qam_mod_table[256];
#ifdef FLT16_MAX
extern int32_t nr_256qam_mod_table_fp16[256];
#endif
#endif

View File

@@ -39,7 +39,7 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
uint8_t dmrs_type,
int16_t dmrs_scaling);
void nr_generate_modulation_table(void);
void nr_generate_modulation_table();
extern simde__m128i byte2m128i[256];

View File

@@ -34,6 +34,10 @@
#include "nr_dci.h"
#include "nr_dlsch.h"
#include "nr_sch_dmrs.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
#include "PHY/MODULATION/nr_modulation.h"
#include "common/utils/nr/nr_common.h"
#include "SCHED_NR/sched_nr.h"
@@ -116,8 +120,15 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
/// DMRS QPSK modulation
for (int symb = cset_start_symb; symb < cset_start_symb + pdcch_pdu_rel15->DurationSymbols; symb++) {
const uint32_t *gold = nr_gold_pdcch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, dci_pdu->ScramblingId, slot, symb);
nr_modulation(gold, dmrs_length, DMRS_MOD_ORDER, (int16_t *)mod_dmrs[symb]); // Qm = 2 as DMRS is QPSK modulated
#ifdef FLT16_MAX
if (gNB->use_fp16)
nr_modulation(gold, dmrs_length, DMRS_MOD_ORDER, NULL,(_Float16 *)mod_dmrs[symb]); // Qm = 2 as DMRS is QPSK modulated
else
nr_modulation(gold, dmrs_length, DMRS_MOD_ORDER, (int16_t *)mod_dmrs[symb],NULL); // Qm = 2 as DMRS is QPSK modulated
#else
nr_modulation(gold, dmrs_length, DMRS_MOD_ORDER, (int16_t *)mod_dmrs[symb]); // Qm = 2 as DMRS is QPSK modulated
#endif
#ifdef DEBUG_PDCCH_DMRS
if(dci_pdu->RNTI!=0xFFFF) {
for (int i=0; i<dmrs_length>>1; i++)
@@ -165,11 +176,22 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
#endif
/// QPSK modulation
c16_t mod_dci[NR_MAX_DCI_SIZE / 2] __attribute__((aligned(16)));
nr_modulation(scrambled_output, encoded_length, DMRS_MOD_ORDER, (int16_t *)mod_dci); // Qm = 2 as DMRS is QPSK modulated
#ifdef FLT16_MAX
if (gNB->use_fp16)
nr_modulation(scrambled_output, encoded_length, DMRS_MOD_ORDER, NULL, (_Float16 *)mod_dci); // Qm = 2 as DMRS is QPSK modulated
else
nr_modulation(scrambled_output, encoded_length, DMRS_MOD_ORDER, (int16_t *)mod_dci,NULL); // Qm = 2 as DMRS is QPSK modulated
#else
nr_modulation(scrambled_output, encoded_length, DMRS_MOD_ORDER, (int16_t *)mod_dci); // Qm = 2 as DMRS is QPSK modulated
#endif
#ifdef DEBUG_DCI
for (int i=0; i<encoded_length>>1; i++)
printf("i %d mod_dci %d %d\n", i, mod_dci[i].r, mod_dci[i].i);
#ifdef FLT16_MAX
if (gNB->use_fp16) printf("i %d mod_dci %f %f\n", i, ((cf16_t *)mod_dci)[i].r, ((cf16_t *)mod_dci)[i].i);
else
#endif
printf("i %d mod_dci %d %d\n", i, mod_dci[i].r, mod_dci[i].i);
#endif
@@ -199,36 +221,68 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
dmrs_idx = (reg_list[d][reg_count] + rb_offset) * 3;
int k_prime = 0;
for (int m = 0; m < NR_NB_SC_PER_RB; m++) {
if (m == (k_prime << 2) + 1) { // DMRS if not already mapped
txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dmrs[l][dmrs_idx], amp, 15);
#ifdef FLT16_MAX
if (gNB->use_fp16) {
for (int m = 0; m < NR_NB_SC_PER_RB; m++) {
if (m == (k_prime << 2) + 1) { // DMRS if not already mapped
txdataF[l * frame_parms->ofdm_symbol_size + k] = mod_dmrs[l][dmrs_idx];
#ifdef DEBUG_PDCCH_DMRS
LOG_I(NR_PHY_DCI,
"PDCCH DMRS %d: l %d position %d => (%d,%d)\n",
dmrs_idx,
l,
k,
txdataF[l * frame_parms->ofdm_symbol_size + k].r,
txdataF[l * frame_parms->ofdm_symbol_size + k].i);
LOG_I(NR_PHY_DCI,
"PDCCH DMRS %d: l %d position %d => (%d,%d)\n",
dmrs_idx,
l,
k,
txdataF[l * frame_parms->ofdm_symbol_size + k].r,
txdataF[l * frame_parms->ofdm_symbol_size + k].i);
#endif
dmrs_idx++;
k_prime++;
dmrs_idx++;
k_prime++;
} else { // DCI payload
txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dci[dci_idx], amp, 15);
dci_idx++;
}
} else { // DCI payload
txdataF[l * frame_parms->ofdm_symbol_size + k] = mod_dci[dci_idx];
dci_idx++;
}
k++;
k++;
if (k >= frame_parms->ofdm_symbol_size)
k -= frame_parms->ofdm_symbol_size;
} // m
} // reg_count
} // symbol_idx
if (k >= frame_parms->ofdm_symbol_size)
k -= frame_parms->ofdm_symbol_size;
} // m
}
else
#endif
for (int m = 0; m < NR_NB_SC_PER_RB; m++) {
if (m == (k_prime << 2) + 1) { // DMRS if not already mapped
txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dmrs[l][dmrs_idx], amp, 15);
#ifdef DEBUG_PDCCH_DMRS
LOG_I(NR_PHY_DCI,
"PDCCH DMRS %d: l %d position %d => (%d,%d)\n",
dmrs_idx,
l,
k,
txdataF[l * frame_parms->ofdm_symbol_size + k].r,
txdataF[l * frame_parms->ofdm_symbol_size + k].i);
#endif
dmrs_idx++;
k_prime++;
} else { // DCI payload
txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dci[dci_idx], amp, 15);
dci_idx++;
}
k++;
if (k >= frame_parms->ofdm_symbol_size)
k -= frame_parms->ofdm_symbol_size;
} // m
} // reg_count
} // symbol_idx
LOG_D(NR_PHY_DCI,
"DCI: payloadSize = %d | payload = %llx\n",

View File

@@ -1,7 +1,6 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* contributor license agreements. See the NOTICE file dis* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
@@ -56,8 +55,9 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
int symbol_sz,
c16_t *txF,
c16_t *tx_layer,
int amp,
c16_t *mod_ptrs)
void *amp,
c16_t *mod_ptrs,
int use_fp16)
{
int ptrs_idx = 0;
int k = start_sc;
@@ -69,7 +69,10 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
if (is_ptrs_re) {
/* check if cuurent RE is PTRS RE*/
uint16_t beta_ptrs = 1;
txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15);
if (use_fp16)
txF[k] = mod_ptrs[ptrs_idx];
else
txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * *(int16_t*)amp, 15);
#ifdef DEBUG_DLSCH_MAPPING
printf("ptrs_idx %d\t \t k %d \t \t txdataF: %d %d, mod_ptrs: %d %d\n",
ptrs_idx,
@@ -81,7 +84,10 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
#endif
ptrs_idx++;
} else {
txF[k] = c16mulRealShift(*in++, amp, 15);
if (use_fp16)
txF[k] = *in++;
else
txF[k] = c16mulRealShift(*in++, *(int16_t*)amp, 15);
#ifdef DEBUG_DLSCH_MAPPING
printf("k %d \t txdataF: %d %d\n", k, txF[k].r, txF[k].i);
#endif
@@ -97,59 +103,123 @@ typedef union {
c16_t s[2];
} amp_t;
static inline int interleave_with_0_signal_first(c16_t *output, c16_t *mod_dmrs, const int16_t amp_dmrs, int sz)
static inline int interleave_with_0_signal_first(c16_t *output, c16_t *mod_dmrs, void *amp_dmrs, int sz, int use_fp16)
{
#ifdef DEBUG_DLSCH_MAPPING
printf("doing DMRS pattern for port 0 : d0 0 d1 0 ... dNm2 0 dNm1 0 (ul %d, rr %d)\n", upper_limit, remaining_re);
#endif
// add filler to process all as SIMD
c16_t *out = output;
int i = 0;
int end = sz / 2;
#if defined(__AVX512BW__)
simde__m512i zeros512 = simde_mm512_setzero_si512(), amp_dmrs512 = simde_mm512_set1_epi16(amp_dmrs);
simde__m512i perml = simde_mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
simde__m512i permh = simde_mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
simde__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(mod_dmrs + i)), amp_dmrs512);
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, perml, zeros512));
out += 16;
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, permh, zeros512));
out += 16;
if (use_fp16) {
#if defined(__AVX512FP16__) && defined(FLT16_MAX)
__m512i zeros512 = _mm512_setzero_si512();
__m512h amp_dmrs512 = _mm512_set1_ph(*(int16_t*)amp_dmrs);
__m512i perml = _mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
__m512i permh = _mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
__m512h d0 = _mm512_mul_ph(_mm512_loadu_ph((__m512h *)(mod_dmrs + i)), amp_dmrs512);
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32((__m512i)d0, perml, zeros512));
out += 16;
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32((__m512i)d0, permh, zeros512));
out += 16;
}
__m256i zeros256 = _mm256_setzero_si256();
__m256h amp_dmrs256 = _mm256_set1_ph(*(_Float16*)amp_dmrs);
for (; i < (end & ~7); i += 8) {
__m256h d0 = _mm256_mul_ph(_mm256_loadu_ph((__m256h *)(mod_dmrs + i)), amp_dmrs256);
__m256i d2 = _mm256_unpacklo_epi32((__m256i)d0, zeros256);
__m256i d3 = _mm256_unpackhi_epi32((__m256i)d0, zeros256);
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256(d2, d3, 32));
out += 8;
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
__m128i zeros = _mm_setzero_si128();
__m128h amp_dmrs128 = _mm_set1_ph(*(_Float16*)amp_dmrs);
for (; i < (end & ~3); i += 4) {
__m128h d0 = _mm_mul_ph(_mm_loadu_ph((__m128h *)(mod_dmrs + i)), amp_dmrs128);
__m128i d2 = _mm_unpacklo_epi32((__m128i)d0, zeros);
__m128i d3 = _mm_unpackhi_epi32((__m128i)d0, zeros);
_mm_storeu_si128((__m128i *)out, d2);
out += 4;
_mm_storeu_si128((__m128i *)out, d3);
out += 4;
}
#elif defined(__aarch64__)
uint32x4_t zeros = vdupq_n_u32(0);
float16x8_t amp_dmrs128 = vdupq_n_f16(*(float16_t*)amp_dmrs);
//printf("Doing DMRS modulation for 2 CdmGrps, amp_dmrs %f, dmrs0 (%f %f)\n",*(float16_t*)amp_dmrs,((float16_t*)mod_dmrs)[0],((float16_t*)mod_dmrs)[1]);
for (; i < (end & ~3); i += 4) {
float16x8_t d0 = vmulq_f16(vld1q_f16((float16_t *)(mod_dmrs + i)), amp_dmrs128);
float16x8_t d2 = (float16x8_t)vzip1q_u32((uint32x4_t)d0, zeros);
float16x8_t d3 = (float16x8_t)vzip2q_u32((uint32x4_t)d0, zeros);
vst1q_f16((float16_t *)out, d2);
out += 4;
vst1q_f16((float16_t *)out, d3);
out += 4;
}
#else
AssertFatal(1==0,"Architecture doesn't support fp16\n");
#endif
cf16_t *out_cf16 = (cf16_t*)out;
for (; i < end; i++) {
#ifdef __aarch64__
out_cf16->r = mod_dmrs[i].r * *(float16_t*)amp_dmrs;
out_cf16->i = mod_dmrs[i].i * *(float16_t*)amp_dmrs;
#else
out_cf16->r = mod_dmrs[i].r * *(_Float16*)amp_dmrs;
out_cf16->i = mod_dmrs[i].i * *(_Float16*)amp_dmrs;
#endif
out_cf16++;
*out_cf16++ = (cf16_t){};
}
}
else {
//printf("interleave_with_0_signal_first : use_fp16 = 0\n");
#if defined(__AVX512__) && defined(__AVX512BW__)
__m512i zeros512 = _mm512_setzero_si512(), amp_dmrs512 = simde_mm512_set1_epi16(((int16_t*)amp_dmrs);
__m512i perml = _mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
__m512i permh = _mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((__m512i *)(mod_dmrs + i)), amp_dmrs512);
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32(d0, perml, zeros512));
out += 16;
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32(d0, permh, zeros512));
out += 16;
}
#endif
#if defined(__AVX2__)
simde__m256i zeros256 = simde_mm256_setzero_si256(), amp_dmrs256 = simde_mm256_set1_epi16(amp_dmrs);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(mod_dmrs + i)), amp_dmrs256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(d0, zeros256);
simde__m256i d3 = simde_mm256_unpackhi_epi32(d0, zeros256);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
simde__m256i zeros256 = simde_mm256_setzero_si256(), amp_dmrs256 = simde_mm256_set1_epi16(*(int16_t*)amp_dmrs);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(mod_dmrs + i)), amp_dmrs256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(d0, zeros256);
simde__m256i d3 = simde_mm256_unpackhi_epi32(d0, zeros256);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
#endif
#if defined(USE128BIT)
simde__m128i zeros = simde_mm_setzero_si128(), amp_dmrs128 = simde_mm_set1_epi16(amp_dmrs);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(mod_dmrs + i)), amp_dmrs128);
simde__m128i d2 = simde_mm_unpacklo_epi32(d0, zeros);
simde__m128i d3 = simde_mm_unpackhi_epi32(d0, zeros);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
simde__m128i zeros = simde_mm_setzero_si128(), amp_dmrs128 = simde_mm_set1_epi16(*(int16_t*)amp_dmrs);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(mod_dmrs + i)), amp_dmrs128);
simde__m128i d2 = simde_mm_unpacklo_epi32(d0, zeros);
simde__m128i d3 = simde_mm_unpackhi_epi32(d0, zeros);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
#endif
for (; i < end; i++) {
*out++ = c16mulRealShift(mod_dmrs[i], amp_dmrs, 15);
*out++ = (c16_t){};
for (; i < end; i++) {
*out++ = c16mulRealShift(mod_dmrs[i], *(int16_t*)amp_dmrs, 15);
*out++ = (c16_t){};
}
}
return 0;
}
static inline int interleave_with_0_start_with_0(c16_t *output, c16_t *mod_dmrs, const int16_t amp_dmrs, int sz)
static inline int interleave_with_0_start_with_0(c16_t *output, c16_t *mod_dmrs, void *amp_dmrs, int sz, int use_fp16)
{
#ifdef DEBUG_DLSCH_MAPPING
printf("doing DMRS pattern for port 2 : 0 d0 0 d1 ... 0 dNm2 0 dNm1\n");
@@ -157,50 +227,117 @@ static inline int interleave_with_0_start_with_0(c16_t *output, c16_t *mod_dmrs,
c16_t *out = output;
int i = 0;
int end = sz / 2;
#if defined(__AVX512BW__)
simde__m512i zeros512 = simde_mm512_setzero_si512(), amp_dmrs512 = simde_mm512_set1_epi16(amp_dmrs);
simde__m512i perml = simde_mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
simde__m512i permh = simde_mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
simde__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(mod_dmrs + i)), amp_dmrs512);
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(zeros512, perml, d0));
out += 16;
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(zeros512, permh, d0));
out += 16;
if (use_fp16) {
#if defined(__AVX512FP16__) && defined(FLT16_MAX)
__m512i zeros512 = _mm512_setzero_si512();
__m512h amp_dmrs512 = _mm512_set1_ph(*(_Float16*)amp_dmrs);
__m512i perml = _mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
__m512i permh = _mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
__m512h d0 = _mm512_mul_ph(_mm512_loadu_ph((__m512h *)(mod_dmrs + i)), amp_dmrs512);
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32(zeros512, perml, (__m512i)d0));
out += 16;
_mm512_storeu_si512((__m512i *)out, _mm512_permutex2var_epi32(zeros512, permh, (__m512i)d0));
out += 16;
}
__m256i zeros256 = _mm256_setzero_si256();
__m256h amp_dmrs256 = _mm256_set1_ph(*(_Float16*)amp_dmrs);
for (; i < (end & ~7); i += 8) {
__m256h d0 = _mm256_mul_ph(_mm256_loadu_ph((__m256h *)(mod_dmrs + i)), amp_dmrs256);
__m256i d2 = _mm256_unpacklo_epi32(zeros256, (__m256i)d0);
__m256i d3 = _mm256_unpackhi_epi32(zeros256, (__m256i)d0);
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256(d2, d3, 32));
out += 8;
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
__m128i zeros = _mm_setzero_si128();
__m128h amp_dmrs128 = _mm_set1_ph(*(_Float16*)amp_dmrs);
for (; i < (end & ~3); i += 4) {
__m128h d0 = _mm_mul_ph(_mm_loadu_ph((__m128h *)(mod_dmrs + i)), amp_dmrs128);
__m128i d2 = _mm_unpacklo_epi32(zeros, (__m128i)d0);
__m128i d3 = _mm_unpackhi_epi32(zeros, (__m128i)d0);
_mm_storeu_si128((__m128i *)out, d2);
out += 4;
_mm_storeu_si128((__m128i *)out, d3);
out += 4;
}
#elif defined(__aarch64__)
uint32x4_t zeros = vdupq_n_u32(0);
float16x8_t amp_dmrs128 = vdupq_n_f16(*(float16_t*)amp_dmrs);
for (; i < (end & ~3); i += 4) {
float16x8_t d0 = vmulq_f16(vld1q_f16((float16_t *)(mod_dmrs + i)), amp_dmrs128);
float16x8_t d2 = (float16x8_t)vzip1q_u32(zeros, (uint32x4_t)d0);
float16x8_t d3 = (float16x8_t)vzip2q_u32(zeros, (uint32x4_t)d0);
vst1q_f16((float16_t *)out, d2);
out += 4;
vst1q_f16((float16_t *)out, d3);
out += 4;
}
#else
AssertFatal(1==0,"Architecture doesn't support fp16\n");
#endif
cf16_t *out_cf16 = (cf16_t*)out;
for (; i < end; i++) {
*out_cf16++ = (cf16_t){};
#ifdef __aarch64__
out_cf16->r = mod_dmrs[i].r * *(float16_t*)amp_dmrs;
out_cf16->i = mod_dmrs[i].i * *(float16_t*)amp_dmrs;
#else
out_cf16->r = mod_dmrs[i].r * *(_Float16*)amp_dmrs;
out_cf16->i = mod_dmrs[i].i * *(_Float16*)amp_dmrs;
#endif
out_cf16++;
}
}
else
{
//printf("interleave_with_0_start_with_0: use_fp16 = 0\n");
#if defined(__AVX512__) && defined(__AVX512BW__)
simde__m512i zeros512 = simde_mm512_setzero_si512(), amp_dmrs512 = simde_mm512_set1_epi16(*(int16_t*)amp_dmrs);
simde__m512i perml = simde_mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
simde__m512i permh = simde_mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
simde__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(mod_dmrs + i)), amp_dmrs512);
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(zeros512, perml, d0));
out += 16;
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(zeros512, permh, d0));
out += 16;
}
#endif
#if defined(__AVX2__)
simde__m256i zeros256 = simde_mm256_setzero_si256(), amp_dmrs256 = simde_mm256_set1_epi16(amp_dmrs);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(mod_dmrs + i)), amp_dmrs256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(zeros256, d0);
simde__m256i d3 = simde_mm256_unpackhi_epi32(zeros256, d0);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
simde__m256i zeros256 = simde_mm256_setzero_si256(), amp_dmrs256 = simde_mm256_set1_epi16(*(int16_t*)amp_dmrs);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(mod_dmrs + i)), amp_dmrs256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(zeros256, d0);
simde__m256i d3 = simde_mm256_unpackhi_epi32(zeros256, d0);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
#endif
#if defined(USE128BIT)
simde__m128i zeros = simde_mm_setzero_si128(), amp_dmrs128 = simde_mm_set1_epi16(amp_dmrs);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(mod_dmrs + i)), amp_dmrs128);
simde__m128i d2 = simde_mm_unpacklo_epi32(zeros, d0);
simde__m128i d3 = simde_mm_unpackhi_epi32(zeros, d0);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
simde__m128i zeros = simde_mm_setzero_si128(), amp_dmrs128 = simde_mm_set1_epi16(*(int16_t*)amp_dmrs);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(mod_dmrs + i)), amp_dmrs128);
simde__m128i d2 = simde_mm_unpacklo_epi32(zeros, d0);
simde__m128i d3 = simde_mm_unpackhi_epi32(zeros, d0);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
#endif
for (; i < end; i++) {
*out++ = (c16_t){};
*out++ = c16mulRealShift(mod_dmrs[i], amp_dmrs, 15);
for (; i < end; i++) {
*out++ = (c16_t){};
*out++ = c16mulRealShift(mod_dmrs[i], *(int16_t*)amp_dmrs, 15);
}
}
return 0;
}
static inline int interleave_signals(c16_t *output, c16_t *signal1, const int amp, c16_t *signal2, const int amp2, int sz)
static inline int interleave_signals(c16_t *output, c16_t *signal1, void *amp, c16_t *signal2, void *amp2, int sz, int use_fp16)
{
#ifdef DEBUG_DLSCH_MAPPING
printf("doing DMRS pattern for port 0 : d0 X0 d1 X1 ... dNm2 XNm2 dNm1 XNm1\n");
@@ -209,48 +346,123 @@ static inline int interleave_signals(c16_t *output, c16_t *signal1, const int am
c16_t *out = output;
int i = 0;
int end = sz / 2;
#if defined(__AVX512BW__)
simde__m512i amp2512 = simde_mm512_set1_epi16(amp2), amp512 = simde_mm512_set1_epi16(amp);
simde__m512i perml = simde_mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
simde__m512i permh = simde_mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
simde__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(signal2 + i)), amp2512);
simde__m512i d1 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(signal1 + i)), amp512);
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, perml, d1));
out += 16;
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, permh, d1));
out += 16;
if (use_fp16) {
#if defined(__AVX512FP16__) && defined(FLT16_MAX)
__m512h amp2512 = _mm512_set1_ph(*(_Float16*)amp2), amp512 = _mm512_set1_ph(*(_Float16*)amp);
__m512i perml = _mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
__m512i permh = _mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
__m512h d0 = _mm512_mul_ph((__m512h)_mm512_loadu_si512((__m512i *)(signal2 + i)), amp2512);
__m512h d1 = _mm512_mul_ph((__m512h)_mm512_loadu_si512((__m512i *)(signal1 + i)), amp512);
_mm512_storeu_si512((__m512h *)out, _mm512_permutex2var_epi32((__m512i)d0, perml, (__m512i)d1));
out += 16;
_mm512_storeu_si512((__m512h *)out, _mm512_permutex2var_epi32((__m512i)d0, permh, (__m512i)d1));
out += 16;
}
__m256h amp2256 = _mm256_set1_ph(*(_Float16*)amp2), amp256 = _mm256_set1_ph(*(_Float16*)amp);
for (; i < (end & ~7); i += 8) {
__m256h d0 = _mm256_mul_ph((__m256h)_mm256_loadu_si256((__m256i *)(signal2 + i)), amp2256);
__m256h d1 = _mm256_mul_ph((__m256h)_mm256_loadu_si256((__m256i *)(signal1 + i)), amp256);
__m256h d2 = (__m256h)_mm256_unpacklo_epi32((__m256i)d0, (__m256i)d1);
__m256h d3 = (__m256h)_mm256_unpackhi_epi32((__m256i)d0, (__m256i)d1);
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256((__m256i)d2, (__m256i)d3, 32));
out += 8;
_mm256_storeu_si256((__m256i *)out, _mm256_permute2x128_si256((__m256i)d2, (__m256i)d3, 49));
out += 8;
}
__m128h amp2128 = _mm_set1_ph(*(_Float16*)amp2), amp128 = _mm_set1_ph(*(_Float16*)amp);
for (; i < (end & ~3); i += 4) {
__m128h d0 = _mm_mul_ph((__m128h)_mm_loadu_si128((__m128i *)(signal2 + i)), amp2128);
__m128h d1 = _mm_mul_ph((__m128h)_mm_loadu_si128((__m128i *)(signal1 + i)), amp128);
__m128h d2 = (__m128h)_mm_unpacklo_epi32((__m128i)d0, (__m128i)d1);
__m128h d3 = (__m128h)_mm_unpackhi_epi32((__m128i)d0, (__m128i)d1);
_mm_storeu_si128((__m128i *)out, (__m128i)d2);
out += 4;
_mm_storeu_si128((__m128i *)out, (__m128i)d3);
out += 4;
}
#elif defined(__aarch64__)
float16x8_t amp2128 = vdupq_n_f16(*(float16_t*)amp2), amp128 = vdupq_n_f16(*(float16_t*)amp);
for (; i < (end & ~3); i += 4) {
float16x8_t d0 = vmulq_f16(vld1q_f16((float16_t *)(signal2 + i)), amp2128);
float16x8_t d1 = vmulq_f16(vld1q_f16((float16_t *)(signal1 + i)), amp128);
float16x8_t d2 = (float16x8_t)vzip1q_u32((uint32x4_t)d0,(uint32x4_t)d1);
float16x8_t d3 = (float16x8_t)vzip2q_u32((uint32x4_t)d0,(uint32x4_t)d1);
vst1q_f16((float16_t *)out, d2);
out += 4;
vst1q_f16((float16_t *)out, d3);
out += 4;
}
#else
AssertFatal(1==0,"Architecture doesn't support fp16\n");
#endif
cf16_t *out_cf16 = (cf16_t*)out;
for (; i < end; i++) {
cf16_t *s1 = (cf16_t*)signal1,*s2=(cf16_t*)signal2;
#ifdef __aarch64__
out_cf16->r = (float16_t)s2[i].r * *(float16_t*)amp2;
out_cf16->i = (float16_t)s2[i].i * *(float16_t*)amp2;
out_cf16++;
out_cf16->r = (float16_t)s1[i].r * *(float16_t*)amp;
out_cf16->i = (float16_t)s1[i].i * *(float16_t*)amp;
out_cf16++;
#else
out_cf16->r = (_Float16)s2[i].r * *(_Float16*)amp2;
out_cf16->i = (_Float16)s2[i].i * *(_Float16*)amp2;
out_cf16++;
out_cf16->r = (_Float16)s1[i].r * *(_Float16*)amp;
out_cf16->i = (_Float16)s1[i].i * *(_Float16*)amp;
out_cf16++;
#endif
}
}
else
{
//printf("interleave_signals: use_fp16 = 0\n");
#if defined(__AVX512BW__)
simde__m512i amp2512 = simde_mm512_set1_epi16(*(int16_t*)amp2), amp512 = simde_mm512_set1_epi16(*(int16_t*)amp);
simde__m512i perml = simde_mm512_set_epi32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0);
simde__m512i permh = simde_mm512_set_epi32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8);
for (; i < (end & ~15); i += 16) {
simde__m512i d0 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(signal2 + i)), amp2512);
simde__m512i d1 = simde_mm512_mulhrs_epi16(_mm512_loadu_si512((simde__m512i *)(signal1 + i)), amp512);
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, perml, d1));
out += 16;
simde_mm512_storeu_si512((simde__m512i *)out, simde_mm512_permutex2var_epi32(d0, permh, d1));
out += 16;
}
#endif
#if defined(__AVX2__)
simde__m256i amp2256 = simde_mm256_set1_epi16(amp2), amp256 = simde_mm256_set1_epi16(amp);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(signal2 + i)), amp2256);
simde__m256i d1 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(signal1 + i)), amp256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(d0, d1);
simde__m256i d3 = simde_mm256_unpackhi_epi32(d0, d1);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
simde__m256i amp2256 = simde_mm256_set1_epi16(*(int16_t*)amp2), amp256 = simde_mm256_set1_epi16(*(int16_t*)amp);
for (; i < (end & ~7); i += 8) {
simde__m256i d0 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(signal2 + i)), amp2256);
simde__m256i d1 = simde_mm256_mulhrs_epi16(simde_mm256_loadu_si256((simde__m256i *)(signal1 + i)), amp256);
simde__m256i d2 = simde_mm256_unpacklo_epi32(d0, d1);
simde__m256i d3 = simde_mm256_unpackhi_epi32(d0, d1);
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 32));
out += 8;
simde_mm256_storeu_si256((simde__m256i *)out, simde_mm256_permute2x128_si256(d2, d3, 49));
out += 8;
}
#endif
#if defined(USE128BIT)
simde__m128i amp2128 = simde_mm_set1_epi16(amp2), amp128 = simde_mm_set1_epi16(amp);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(signal2 + i)), amp2128);
simde__m128i d1 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(signal1 + i)), amp128);
simde__m128i d2 = simde_mm_unpacklo_epi32(d0, d1);
simde__m128i d3 = simde_mm_unpackhi_epi32(d0, d1);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
#endif
for (; i < end; i++) {
*out++ = c16mulRealShift(signal2[i], amp2, 15);
*out++ = c16mulRealShift(signal1[i], amp, 15);
simde__m128i amp2128 = simde_mm_set1_epi16(*(int16_t*)amp2), amp128 = simde_mm_set1_epi16(*(int16_t*)amp);
for (; i < (end & ~3); i += 4) {
simde__m128i d0 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(signal2 + i)), amp2128);
simde__m128i d1 = simde_mm_mulhrs_epi16(simde_mm_loadu_si128((simde__m128i *)(signal1 + i)), amp128);
simde__m128i d2 = simde_mm_unpacklo_epi32(d0, d1);
simde__m128i d3 = simde_mm_unpackhi_epi32(d0, d1);
simde_mm_storeu_si128((simde__m128i *)out, d2);
out += 4;
simde_mm_storeu_si128((simde__m128i *)out, d3);
out += 4;
}
for (; i < end; i++) {
*out++ = c16mulRealShift(signal2[i], *(int16_t*)amp2, 15);
*out++ = c16mulRealShift(signal1[i], *(int16_t*)amp, 15);
}
}
return sz / 2;
}
@@ -258,8 +470,8 @@ static inline int interleave_signals(c16_t *output, c16_t *signal1, const int am
static inline int dmrs_case00(c16_t *output,
c16_t *txl,
c16_t *mod_dmrs,
const int16_t amp_dmrs,
const int amp,
void *amp_dmrs,
void *amp,
int sz,
int start_sc,
int remaining_re,
@@ -267,7 +479,8 @@ static inline int dmrs_case00(c16_t *output,
const int dmrs_Type,
int symbol_sz,
int l_prime,
uint8_t numDmrsCdmGrpsNoData)
uint8_t numDmrsCdmGrpsNoData,
int use_fp16)
{
// DMRS params for this dmrs port
int Wt[2], Wf[2];
@@ -279,9 +492,23 @@ static inline int dmrs_case00(c16_t *output,
c16_t *in = txl;
uint8_t k_prime = 0;
uint16_t n = 0;
for (int i = 0; i < sz; i++) {
if (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (symbol_sz))) {
output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15);
#ifdef FLT16_MAX
if (use_fp16) {
cf16_t *output_cf16 = (cf16_t*)&output[k];
cf16_t *mod_dmrs_cf16 = (cf16_t*)&mod_dmrs[dmrs_idx];
#ifdef __aarch64__
*output_cf16 = cf16mulReal(*mod_dmrs_cf16, Wt[l_prime] * Wf[k_prime] * *(float16_t*)amp_dmrs);
#else
*output_cf16 = cf16mulReal(*mod_dmrs_cf16, Wt[l_prime] * Wf[k_prime] * *(_Float16*)amp_dmrs);
#endif
}
else
#else
output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * *(int16_t*)amp_dmrs, 15);
#endif
dmrs_idx++;
k_prime = (k_prime + 1) & 1;
n += (k_prime ? 0 : 1);
@@ -289,7 +516,19 @@ static inline int dmrs_case00(c16_t *output,
/* Map PTRS Symbol */
/* Map DATA Symbol */
else if (allowed_xlsch_re_in_dmrs_symbol(k, start_sc, symbol_sz, numDmrsCdmGrpsNoData, dmrs_Type)) {
output[k] = c16mulRealShift(*in++, amp, 15);
#ifdef FLT16_MAX
if (use_fp16) {
cf16_t *output_cf16 = (cf16_t*)&output[k];
cf16_t *in_cf16 = (cf16_t*)in++;
#ifdef __aarch64__
*output_cf16 = cf16mulReal(*in_cf16,*(float16_t*)amp);
#else
*output_cf16 = cf16mulReal(*in_cf16,*(_Float16*)amp);
#endif
}
else
#endif
output[k] = c16mulRealShift(*in++, *(int16_t*)amp, 15);
}
/* mute RE */
else {
@@ -300,41 +539,58 @@ static inline int dmrs_case00(c16_t *output,
return in - txl;
}
static inline int no_ptrs_dmrs_case(c16_t *output, c16_t *txl, const int amp, const int sz)
static inline int no_ptrs_dmrs_case(c16_t *output, c16_t *txl, void *amp, const int sz,int use_fp16)
{
// Loop Over SCs:
int i = 0;
#if (defined(__AVX512FP16__) && defined(FLT16_MAX))|| (defined(__aarch64__) && defined(FLT16_MAX))
if (use_fp16)
memcpy((void*)output,(void*)txl,sz*sizeof(uint32_t));
else
#endif
{
//printf("no_ptrs_dmrs_case: use_fp16=0\n");
#if defined(__AVX512BW__)
simde__m512i amp512 = simde_mm512_set1_epi16(amp);
for (; i < (sz & ~15); i += 16) {
const simde__m512i txL = simde_mm512_loadu_si512((simde__m512i *)(txl + i));
simde_mm512_storeu_si512((simde__m512i *)(output + i), simde_mm512_mulhrs_epi16(amp512, txL));
}
simde__m512i amp512 = simde_mm512_set1_epi16(*(int16_t*)amp);
for (; i < (sz & ~15); i += 16) {
const simde__m512i txL = simde_mm512_loadu_si512((simde__m512i *)(txl + i));
simde_mm512_storeu_si512((simde__m512i *)(output + i), simde_mm512_mulhrs_epi16(amp512, txL));
}
#endif
#if defined(__AVX2__)
simde__m256i amp256 = simde_mm256_set1_epi16(amp);
for (; i < (sz & ~7); i += 8) {
const simde__m256i txL = simde_mm256_loadu_si256((simde__m256i *)(txl + i));
simde_mm256_storeu_si256((simde__m256i *)(output + i), _mm256_mulhrs_epi16(amp256, txL));
}
simde__m256i amp256 = simde_mm256_set1_epi16(*(int16_t*)amp);
for (; i < (sz & ~7); i += 8) {
const simde__m256i txL = simde_mm256_loadu_si256((simde__m256i *)(txl + i));
simde_mm256_storeu_si256((simde__m256i *)(output + i), _mm256_mulhrs_epi16(amp256, txL));
}
#endif
#if defined(USE128BIT)
simde__m128i amp128 = simde_mm_set1_epi16(amp);
for (; i < (sz & ~3); i += 4) {
const simde__m128i txL = simde_mm_loadu_si128((simde__m128i *)(txl + i));
simde_mm_storeu_si128((simde__m128i *)(output + i), simde_mm_mulhrs_epi16(amp128, txL));
}
simde__m128i amp128 = simde_mm_set1_epi16(*(int16_t*)amp);
for (; i < (sz & ~3); i += 4) {
const simde__m128i txL = simde_mm_loadu_si128((simde__m128i *)(txl + i));
simde_mm_storeu_si128((simde__m128i *)(output + i), simde_mm_mulhrs_epi16(amp128, txL));
}
#endif
#if !(defined(__AVX512FP16__) && defined(FLT16_MAX))
for (; i < sz; i++) {
output[i] = c16mulRealShift(txl[i], *(int16_t*)amp, 15);
}
#endif
for (; i < sz; i++) {
output[i] = c16mulRealShift(txl[i], amp, 15);
}
return sz;
}
static inline void neg_dmrs(c16_t *in, c16_t *out, int sz)
static inline void neg_dmrs(c16_t *in, c16_t *out, int sz, int use_fp16)
{
for (int i = 0; i < sz; i++)
*out++ = i % 2 ? (c16_t){-in[i].r, -in[i].i} : in[i];
if (use_fp16)
for (int i = 0; i < sz; i++) {
cf16_t *inp = (cf16_t*)&in[i];
cf16_t *outp = (cf16_t*)out++;
*outp = i % 2 ? (cf16_t){-inp->r, -inp->i} : *inp;
}
else
for (int i = 0; i < sz; i++)
*out++ = i % 2 ? (c16_t){-in[i].r, -in[i].i} : in[i];
}
static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
@@ -348,11 +604,12 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
int l_symbol,
uint16_t dlPtrsSymPos,
int n_ptrs,
int amp,
int16_t amp_dmrs,
void *amp,
void *amp_dmrs,
int l_prime,
nfapi_nr_dmrs_type_e dmrs_Type,
c16_t *dmrs_start)
c16_t *dmrs_start,
int use_fp16)
{
c16_t *txl = txl_start;
const uint sz = rel15->rbSize * NR_NB_SC_PER_RB;
@@ -376,8 +633,17 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
__attribute__((aligned(64))); // max only to please sanitizer, that kills if 0 even if it is not a error
const uint32_t *gold =
nr_gold_pdsch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, NULL, (_Float16 *)mod_ptrs);
else
nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs, NULL);
#else
nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
txl += do_ptrs_symbol(rel15, start_sc, symbol_sz, output, txl, amp, mod_ptrs);
#endif
txl += do_ptrs_symbol(rel15, start_sc, symbol_sz, output, txl, amp, mod_ptrs,use_fp16);
} else if (rel15->dlDmrsSymbPos & (1 << l_symbol)) {
/* Map DMRS Symbol */
@@ -386,47 +652,47 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
if (rel15->numDmrsCdmGrpsNoData == 2) {
switch (dmrs_port & 3) {
case 0:
txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, upper_limit);
txl += interleave_with_0_signal_first(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re);
txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, upper_limit,use_fp16);
txl += interleave_with_0_signal_first(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
break;
case 1: {
c16_t dmrs[sz / 2];
neg_dmrs(dmrs_start, dmrs, sz / 2);
txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, upper_limit);
txl += interleave_with_0_signal_first(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re);
neg_dmrs(dmrs_start, dmrs, sz / 2,use_fp16);
txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, upper_limit,use_fp16);
txl += interleave_with_0_signal_first(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
} break;
case 2:
txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, upper_limit);
txl += interleave_with_0_start_with_0(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re);
txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, upper_limit,use_fp16);
txl += interleave_with_0_start_with_0(output, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
break;
case 3: {
c16_t dmrs[sz / 2];
neg_dmrs(dmrs_start, dmrs, sz / 2);
txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, upper_limit);
txl += interleave_with_0_start_with_0(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re);
neg_dmrs(dmrs_start, dmrs, sz / 2,use_fp16);
txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, upper_limit,use_fp16);
txl += interleave_with_0_start_with_0(output, dmrs + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
} break;
}
} else if (rel15->numDmrsCdmGrpsNoData == 1) {
switch (dmrs_port & 3) {
case 0:
txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, upper_limit);
txl += interleave_signals(output, txl, amp, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re);
txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, upper_limit,use_fp16);
txl += interleave_signals(output, txl, amp, dmrs_start + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
break;
case 1: {
c16_t dmrs[sz / 2];
neg_dmrs(dmrs_start, dmrs, sz / 2);
txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, upper_limit);
txl += interleave_signals(output, txl, amp, dmrs + upper_limit / 2, amp_dmrs, remaining_re);
neg_dmrs(dmrs_start, dmrs, sz / 2,use_fp16);
txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, upper_limit,use_fp16);
txl += interleave_signals(output, txl, amp, dmrs + upper_limit / 2, amp_dmrs, remaining_re,use_fp16);
} break;
case 2:
txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, upper_limit);
txl += interleave_signals(output, dmrs_start + upper_limit / 2, amp_dmrs, txl, amp, remaining_re);
txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, upper_limit,use_fp16);
txl += interleave_signals(output, dmrs_start + upper_limit / 2, amp_dmrs, txl, amp, remaining_re,use_fp16);
break;
case 3: {
c16_t dmrs[sz / 2];
neg_dmrs(dmrs_start, dmrs, sz / 2);
txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, upper_limit);
txl += interleave_signals(output, dmrs + upper_limit / 2, amp_dmrs, txl, amp, remaining_re);
neg_dmrs(dmrs_start, dmrs, sz / 2,use_fp16);
txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, upper_limit,use_fp16);
txl += interleave_signals(output, dmrs + upper_limit / 2, amp_dmrs, txl, amp, remaining_re,use_fp16);
} break;
}
} else
@@ -444,12 +710,19 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
dmrs_Type,
symbol_sz,
l_prime,
rel15->numDmrsCdmGrpsNoData);
rel15->numDmrsCdmGrpsNoData,
use_fp16);
} // generic DMRS case
} else { // no PTRS or DMRS in this symbol
txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, upper_limit);
txl += no_ptrs_dmrs_case(output, txl, amp, remaining_re);
txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, upper_limit,use_fp16);
txl += no_ptrs_dmrs_case(output, txl, amp, remaining_re,use_fp16);
} // no DMRS/PTRS in symbol
/*
if (use_fp16)
for (int i=0;i<72;i++) printf("symbol %d layer %d cdmGrps %d dmrs_port %d output[%d] = (%f,%f) amp %f, amp_dmrs %f\n",l_symbol, layer, rel15->numDmrsCdmGrpsNoData, get_dmrs_port(layer, rel15->dmrsPorts), i,(double)((cf16_t*)(output+start_sc))[i].r,(double)((cf16_t*)(output+start_sc))[i].i,(double)*(float16_t*)amp,(double)*(float16_t*)amp_dmrs);
else
for (int i=0;i<72;i++) printf("symbol %d output[%d] = (%d,%d)\n",l_symbol,i,(output+start_sc)[i].r,(output+start_sc)[i].i);
*/
return txl - txl_start;
}
@@ -480,10 +753,15 @@ static inline void do_txdataF(c16_t **txdataF,
const int re_cnt = NR_NB_SC_PER_RB * rb_step;
if (pmi == 0) { // unitary Precoding
if (subCarrier + re_cnt <= symbol_sz) { // RB does not cross DC
if (ant < rel15->nrOfLayers)
if (ant < rel15->nrOfLayers) {
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][subCarrier],
re_cnt * sizeof(**txdataF));
/*
if (gNB->use_fp16)
for (int i=0;i<re_cnt;i++) printf("txdataF[%d][%d] %f.%f\n",ant,txdataF_offset_per_symbol + subCarrier + i,(double)(*(float16_t*)&txdataF[ant][txdataF_offset_per_symbol+subCarrier+i].r),(double)(*(float16_t*)&txdataF[ant][txdataF_offset_per_symbol+subCarrier+i].i));
*/
}
else
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, re_cnt * sizeof(**txdataF));
} else { // RB does cross DC
@@ -494,6 +772,10 @@ static inline void do_txdataF(c16_t **txdataF,
&txdataF_precoding[ant][subCarrier],
neg_length * sizeof(**txdataF));
memcpy(&txdataF[ant][txdataF_offset_per_symbol], &txdataF_precoding[ant], pos_length * sizeof(**txdataF));
/*
if (gNB->use_fp16)
for (int i=0;i<neg_length;i++) printf("**txdataF[%d][%d] %f.%f\n",ant,txdataF_offset_per_symbol + subCarrier + i,(double)(*(float16_t*)&txdataF[ant][txdataF_offset_per_symbol+subCarrier+i].r),(double)(*(float16_t*)&txdataF[ant][txdataF_offset_per_symbol+i].i));
*/
} else {
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, neg_length * sizeof(**txdataF));
memset(&txdataF[ant][txdataF_offset_per_symbol], 0, pos_length * sizeof(**txdataF));
@@ -524,19 +806,27 @@ static inline void do_txdataF(c16_t **txdataF,
pmi_pdu,
subCarrier,
re_cnt,
&txdataF[ant][txdataF_offset_per_symbol]);
&txdataF[ant][txdataF_offset_per_symbol]
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
subCarrier += re_cnt;
} else { // crossing ofdm_symbol_size, use simple arithmetic operations
for (int i = 0; i < re_cnt; i++) {
txdataF[ant][txdataF_offset_per_symbol + subCarrier] =
nr_layer_precoder_cm(rel15->nrOfLayers, symbol_sz, txdataF_precoding, ant, pmi_pdu, subCarrier);
nr_layer_precoder_cm(rel15->nrOfLayers, symbol_sz, txdataF_precoding, ant, pmi_pdu, subCarrier
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
#ifdef DEBUG_DLSCH_MAPPING
printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n",
printf("antenna %d\t off %d \t subCarrier %d \t txdataF: %d %d\n",
ant,
l_symbol,
txdataF_offset_per_symbol,
subCarrier,
txdataF[ant][l_symbol * symbol_sz + subCarrier + txdataF_offset].r,
txdataF[ant][l_symbol * symbol_sz + subCarrier + txdataF_offset].i);
txdataF[ant][txdataF_offset_per_symbol + subCarrier].r,
txdataF[ant][txdataF_offset_per_symbol + subCarrier].i);
#endif
if (++subCarrier >= symbol_sz) {
subCarrier -= symbol_sz;
@@ -550,7 +840,6 @@ static inline void do_txdataF(c16_t **txdataF,
}
static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch, int slot)
{
const int16_t amp = gNB->TX_AMP;
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats;
@@ -560,7 +849,12 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
const int symbol_sz=frame_parms->ofdm_symbol_size;
const int dmrs_Type = rel15->dmrsConfigType;
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
const int16_t amp_dmrs = min((double)amp * sqrt(rel15->numDmrsCdmGrpsNoData), INT16_MAX); // 3GPP TS 38.214 Section 4.1: Table 4.1-1
#ifdef FLT16_MAX
const _Float16 amp_fp16 = 1.0f;
const _Float16 amp_dmrs_fp16 = (_Float16)sqrt(rel15->numDmrsCdmGrpsNoData);
#endif
const int16_t amp = gNB->TX_AMP;
const int16_t amp_dmrs = min((double)gNB->TX_AMP * sqrt(rel15->numDmrsCdmGrpsNoData), INT16_MAX); // 3GPP TS 38.214 Section 4.1: Table 4.1-1
LOG_D(PHY,
"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
rel15->BWPStart,
@@ -627,7 +921,14 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
stop_meas(dlsch_scrambling_stats);
/// Modulation
start_meas(dlsch_modulation_stats);
#ifdef FLT16_MAX
if (gNB->use_fp16)
nr_modulation(scrambled_output, encoded_length, Qm, NULL, (_Float16 *)mod_symbs[codeWord]);
else
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord],NULL);
#else
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
stop_meas(dlsch_modulation_stats);
#ifdef DEBUG_DLSCH
@@ -718,13 +1019,20 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
slot,
l_symbol);
// Qm = 1 as DMRS is QPSK modulated
#ifdef FLT16_MAX
if (gNB->use_fp16)
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, NULL, (_Float16 *)mod_dmrs);
else
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs,NULL);
#else
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
#endif
#ifdef DEBUG_DLSCH_MAPPING
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
for (int i = 0; i < n_dmrs / 2; i += 8) {
for (int i = 0; i < n_dmrs ; i += 8) {
printf("%d:",i);
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_dmrs[i + j].r, mod_dmrs[i + j].i);
printf("%.2f %.2f ", (double)((cf16_t*)mod_dmrs)[i + j].r, (double)((cf16_t*)mod_dmrs)[i + j].i);
}
printf("\n");
}
@@ -748,15 +1056,20 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
l_symbol,
dlPtrsSymPos,
n_ptrs,
amp,
amp_dmrs,
#ifdef FLT16_MAX
gNB->use_fp16?(void*)&amp_fp16:(void*)&amp,
gNB->use_fp16?(void*)&amp_dmrs_fp16:(void*)&amp_dmrs,
#else
(void*)&amp,
(void*)&amp_dmrs,
#endif
l_prime,
dmrs_Type,
mod_dmrs + dmrs_idx);
mod_dmrs + dmrs_idx,
gNB->use_fp16);
} // layer loop
re_beginning_of_symbol += layer_sz;
stop_meas(&gNB->dlsch_resource_mapping_stats);
start_meas(&gNB->dlsch_precoding_stats);
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz + txdataF_offset;
@@ -777,9 +1090,11 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
time_stats_t *dlsch_encoding_stats = &gNB->dlsch_encoding_stats;
time_stats_t *tinput = &gNB->tinput;
time_stats_t *tinput_memcpy = &gNB->tinput_memcpy;
time_stats_t *tprep = &gNB->tprep;
time_stats_t *tparity = &gNB->tparity;
time_stats_t *toutput = &gNB->toutput;
time_stats_t *tconcat = &gNB->tconcat;
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;
@@ -825,9 +1140,8 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
}
unsigned char output[size_output >> 3] __attribute__((aligned(64)));
bzero(output, sizeof(output));
start_meas(dlsch_encoding_stats);
bzero(output, sizeof(output));
if (nr_dlsch_encoding(gNB,
n_dlsch,
dlsch_array,
@@ -836,15 +1150,18 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
frame_parms,
output,
tinput,
tinput_memcpy,
tprep,
tparity,
toutput,
tconcat,
dlsch_rate_matching_stats,
dlsch_interleaving_stats,
dlsch_segmentation_stats)
== -1) {
return;
}
stop_meas(dlsch_encoding_stats);
unsigned char *output_ptr = output;

View File

@@ -45,12 +45,14 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
NR_DL_FRAME_PARMS *frame_parms,
unsigned char *output,
time_stats_t *tinput,
time_stats_t *tinput_memcpy,
time_stats_t *tprep,
time_stats_t *tparity,
time_stats_t *toutput,
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_output_stats);
void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB);

View File

@@ -39,10 +39,13 @@
#include <syscall.h>
#include <openair2/UTIL/OPT/opt.h>
#ifdef ENABLE_CUDA
#include <cuda_runtime.h>
#endif
// #define DEBUG_DLSCH_CODING
// #define DEBUG_DLSCH_FREE 1
void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARMS *frame_parms)
void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARMS *frame_parms, int use_gpumem)
{
int max_layers = (frame_parms->nb_antennas_tx < NR_MAX_NB_LAYERS) ? frame_parms->nb_antennas_tx : NR_MAX_NB_LAYERS;
uint16_t a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * max_layers;
@@ -53,7 +56,12 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM
}
if (dlsch->b) {
free16(dlsch->b, a_segments * 1056);
#ifdef ENABLE_CUDA
if (use_gpumem)
cudaFreeHost(dlsch->b);
else
#endif
free16(dlsch->b, a_segments * 1056);
dlsch->b = NULL;
}
if (dlsch->f) {
@@ -67,7 +75,7 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM
free(dlsch->c);
}
NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB)
NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB, int use_gpumem)
{
int max_layers = (frame_parms->nb_antennas_tx < NR_MAX_NB_LAYERS) ? frame_parms->nb_antennas_tx : NR_MAX_NB_LAYERS;
uint16_t a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * max_layers; // number of segments to be allocated
@@ -86,16 +94,35 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB)
bzero(dlsch.b, dlsch_bytes);
dlsch.c = (uint8_t **)malloc16(a_segments * sizeof(uint8_t *));
#ifdef ENABLE_CUDA
uint8_t *c_devh[a_segments];
#endif
for (int r = 0; r < a_segments; r++) {
// account for filler in first segment and CRCs for multiple segment case
// [hna] 8448 is the maximum CB size in NR
// 68*348 = 68*(maximum size of Zc)
// In section 5.3.2 in 38.212, the for loop is up to N + 2*Zc (maximum size of N is 66*Zc, therefore 68*Zc)
dlsch.c[r] = malloc16(8448);
AssertFatal(dlsch.c[r], "cannot allocate dlsch.c[%d]\n", r);
bzero(dlsch.c[r], 8448);
#ifdef ENABLE_CUDA
if (use_gpumem) {
cudaHostAlloc((void**)&dlsch.c[r], 8448/8, cudaHostAllocMapped);
cudaError_t err=cudaHostAlloc((void**)&dlsch.c[r],(8448/8)*sizeof(uint8_t),cudaHostAllocMapped);
AssertFatal(err == cudaSuccess,"CUDA Error (dlsch.c[%d]): %s\n", r,cudaGetErrorString(err));
err=cudaHostGetDevicePointer((void**)&c_devh[r], dlsch.c[r], 0);
AssertFatal(err == cudaSuccess,"CUDA Error (cudaHostGetDevicePointer) dlsch.c_devh[%d]: %s\n", r,cudaGetErrorString(err));
}
else
#endif
dlsch.c[r] = malloc16(8448/8);
AssertFatal(dlsch.c[r], "cannot allocate dlsch.cc[%d]\n", r);
bzero(dlsch.c[r], 8448/8);
}
#ifdef ENABLE_CUDA
if (use_gpumem) {
cudaError_t err=cudaMalloc((void**)&dlsch.c_dev,a_segments*sizeof(uint8_t*));
err=cudaMemcpy(dlsch.c_dev,c_devh,a_segments*sizeof(uint8_t*),cudaMemcpyHostToDevice);
AssertFatal(err == cudaSuccess,"CUDA Error (memcpy c_devh -> input_dev): %s\n", cudaGetErrorString(err));
}
#endif
dlsch.f = malloc16(N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS);
AssertFatal(dlsch.f, "cannot allocate dlsch->f\n");
bzero(dlsch.f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS);
@@ -111,9 +138,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
NR_DL_FRAME_PARMS *frame_parms,
unsigned char *output,
time_stats_t *tinput,
time_stats_t *tinput_memcpy,
time_stats_t *tprep,
time_stats_t *tparity,
time_stats_t *toutput,
time_stats_t *tconcat,
time_stats_t *dlsch_rate_matching_stats,
time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats)
@@ -159,6 +188,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0];
}
start_meas(dlsch_segmentation_stats);
int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * rel15->nrOfLayers * 1056;
int B;
if (A > NR_MAX_PDSCH_TBS) {
@@ -261,7 +291,9 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
reset_meas(&segment_parameters->ts_rate_match);
reset_meas(&segment_parameters->ts_ldpc_encode);
}
#ifdef ENABLE_CUDA
if (gNB->use_gpu) TB_parameters->c_dev = (uint8_t**)dlsch->c_dev;
#endif
segments_offset += TB_parameters->C;
/* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits)

View File

@@ -4,6 +4,7 @@
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "PHY/sse_intrin.h"
#include "openair1/PHY/NR_REFSIG/refsig_defs_ue.h"
#include <float.h>
#include "openair1/PHY/NR_REFSIG/nr_mod_table.h"
//#define DEBUG_PRS_MOD
//#define DEBUG_PRS_MAP

View File

@@ -21,6 +21,10 @@
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
//#define NR_PSS_DEBUG
@@ -28,7 +32,11 @@ int nr_generate_pss( c16_t *txdataF,
int16_t amp,
uint8_t ssb_start_symbol,
nfapi_nr_config_request_scf_t* config,
NR_DL_FRAME_PARMS *frame_parms)
NR_DL_FRAME_PARMS *frame_parms
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
int16_t x[NR_PSS_LENGTH];
const int x_initial[7] = {0, 1, 1 , 0, 1, 1, 1};
@@ -57,9 +65,19 @@ int nr_generate_pss( c16_t *txdataF,
uint8_t Nid2 = config->cell_config.phy_cell_id.value % 3;
for (int i = 0; i < NR_PSS_LENGTH; i++) {
int m = (i + 43*Nid2)%(NR_PSS_LENGTH);
int16_t d_pss = (1 - 2*x[m]) * 23170;
#ifdef FLT16_MAX
if (use_fp16) {
double d_pss = (double)(1 - 2*x[m]) / sqrt(2.0f);
((_Float16*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (_Float16)d_pss;
}
else
#endif
{
int16_t d_pss = (1 - 2*x[m]) * 23170;
// printf("pss: writing position k %d / %d\n",k,frame_parms->ofdm_symbol_size);
((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_pss) >> 15;
((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_pss) >> 15;
}
k++;
if (k >= frame_parms->ofdm_symbol_size)

View File

@@ -20,6 +20,10 @@
*/
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
//#define NR_SSS_DEBUG
@@ -27,7 +31,11 @@ int nr_generate_sss( c16_t *txdataF,
int16_t amp,
uint8_t ssb_start_symbol,
nfapi_nr_config_request_scf_t* config,
NR_DL_FRAME_PARMS *frame_parms)
NR_DL_FRAME_PARMS *frame_parms
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
int16_t x0[NR_SSS_LENGTH];
int16_t x1[NR_SSS_LENGTH];
@@ -63,8 +71,17 @@ int nr_generate_sss( c16_t *txdataF,
int l = ssb_start_symbol + 2;
for (int i = 0; i < NR_SSS_LENGTH; i++) {
int16_t d_sss = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 23170;
((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_sss) >> 15;
#ifdef FLT16_MAX
if (use_fp16) {
double d_sss = (double)(1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) / sqrt(2.0f);
((_Float16*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (_Float16)d_sss;
}
else
#endif
{
int16_t d_sss = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 23170;
((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_sss) >> 15;
}
k++;
if (k >= frame_parms->ofdm_symbol_size)

View File

@@ -57,7 +57,11 @@ int nr_generate_pss(c16_t *txdataF,
int16_t amp,
uint8_t ssb_start_symbol,
nfapi_nr_config_request_scf_t *config,
NR_DL_FRAME_PARMS *frame_parms);
NR_DL_FRAME_PARMS *frame_parms
#ifdef FLT16_MAX
,int use_fp16
#endif
);
/*!
\fn int nr_generate_sss
@@ -69,7 +73,11 @@ int nr_generate_sss(c16_t *txdataF,
int16_t amp,
uint8_t ssb_start_symbol,
nfapi_nr_config_request_scf_t *config,
NR_DL_FRAME_PARMS *frame_parms);
NR_DL_FRAME_PARMS *frame_parms
#ifdef FLT16_MAX
,int use_fp16
#endif
);
/*!
\fn void nr_generate_pbch_dmrs
@@ -106,9 +114,9 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB,
void nr_init_pbch_interleaver(uint8_t *interleaver);
uint32_t nr_pbch_extra_byte_generation(int sfn, int n_hf, int ssb_index, int ssb_sc_offset, int Lmax);
NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB);
NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB,int use_gpu);
void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARMS *frame_parms);
void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARMS *frame_parms,int use_gpu);
/** \brief This function is the top-level entry point to PUSCH demodulation, after frequency-domain transformation and channel estimation. It performs
- RB extraction (signal and channel estimates)

View File

@@ -875,7 +875,11 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
csirs_config_pdu->scramb_id,
csirs_config_pdu->power_control_offset_ss,
csirs_config_pdu->cdm_type,
csi_info->csi_rs_generated_signal);
csi_info->csi_rs_generated_signal
#ifdef FLT16_MAX
,ue->use_fp16
#endif
);
csi_info->csi_rs_generated_signal_bits = log2_approx(AMP);

View File

@@ -24,6 +24,9 @@
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include "PHY/MODULATION/nr_modulation.h"
// #define SL_DEBUG
@@ -158,7 +161,11 @@ void sl_generate_and_map_psbch(c16_t *txF,
uint16_t re_offset,
uint16_t scaling_factor,
uint16_t symbol_size,
c16_t *psbch_dmrs)
c16_t *psbch_dmrs
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
uint64_t psbch_a_reversed = 0;
uint16_t num_psbch_modsym = 0, numsym = 0;
@@ -218,8 +225,14 @@ void sl_generate_and_map_psbch(c16_t *txF,
#endif
/// 38.211 QPSK modulation
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(encoder_output, num_psbch_modsym * mod_order, mod_order, NULL,(_Float16 *)psbch_modsym);
else
nr_modulation(encoder_output, num_psbch_modsym * mod_order, mod_order, (int16_t *)psbch_modsym,NULL);
#else
nr_modulation(encoder_output, num_psbch_modsym * mod_order, mod_order, (int16_t *)psbch_modsym);
#endif
// RE MApping of PSBCH and PSBCH DMRS
int index = 0, dmrs_index = 0;
const int numre = SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;
@@ -363,7 +376,11 @@ void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx, sl_nr_
struct complex16 *psbch_dmrs = &sl_ue_phy_params->init_params.psbch_dmrs_modsym[slss_id][0];
sl_generate_and_map_psbch(txF, &psbch_payload, slss_id, sl_fp->Ncp, re_offset, scaling_factor, symbol_size, psbch_dmrs);
sl_generate_and_map_psbch(txF, &psbch_payload, slss_id, sl_fp->Ncp, re_offset, scaling_factor, symbol_size, psbch_dmrs
#ifdef FLT16_MAX
,UE->use_fp16
#endif
);
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: txdataF Prepared\n");

View File

@@ -35,6 +35,9 @@
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include "PHY/MODULATION/nr_modulation.h"
#include "PHY/MODULATION/modulation_common.h"
#include "common/utils/assertions.h"
@@ -459,6 +462,31 @@ static void dmrs_amp_mult(const uint32_t dmrs_port,
}
}
#ifdef FLT16_MAX
static void dmrs_amp_mult_fp16(const uint32_t dmrs_port,
const int Wt,
const int Wf[2],
const cf16_t *mod_dmrs,
cf16_t *mod_dmrs_out,
const uint32_t n_dmrs,
const pusch_dmrs_type_t dmrs_type,
const unsigned int num_cdm_groups_no_data)
{
_Float16 beta_dmrs_pusch = (_Float16)get_beta_dmrs(num_cdm_groups_no_data, dmrs_type == pusch_dmrs_type2);
/* short array that hold amplitude for k_prime = 0 and k_prime = 1 */
int32_t alpha_dmrs[2] __attribute((aligned(16)));
for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) {
alpha_dmrs[i] = Wf[i] * Wt * beta_dmrs_pusch;
}
/* multiply amplitude with complex DMRS vector */
for (int_fast16_t i = 0; i < n_dmrs; i++) {
mod_dmrs_out[i].r= mod_dmrs[i].r * alpha_dmrs[i % 2];
mod_dmrs_out[i].i= mod_dmrs[i].i * alpha_dmrs[i % 2];
}
}
#endif
/*
Map ULSCH data and DMRS in all of the scheduled symbols and PRBs
*/
@@ -466,7 +494,11 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
const unsigned int slot,
const c16_t *dmrs_seq,
const c16_t *data,
c16_t *out)
c16_t *out
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
// asign the function pointers
map_dmrs_func_t map_dmrs_ptr = NULL;
@@ -493,17 +525,38 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
if (dmrs_symbol) {
c16_t mod_dmrs[ALNARS_16_4(n_dmrs)] __attribute((aligned(16)));
if (p.transform_precoding == transformPrecoder_disabled) {
#ifdef FLT16_MAX
if (use_fp16) {
nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, NULL,(_Float16 *)mod_dmrs);
dmrs_amp_mult_fp16(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
}
else {
nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs,NULL);
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
}
#else
nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
#endif
} else {
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
}
} else if ((p.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && ptrs_symbol) {
AssertFatal(p.transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n");
c16_t mod_ptrs[ALNARS_16_4(p.nb_rb)] __attribute((aligned(16)));
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, p.nb_rb, DMRS_MOD_ORDER, NULL,(_Float16 *)mod_ptrs);
else {
nr_modulation(gold, p.nb_rb, DMRS_MOD_ORDER, (int16_t *)mod_ptrs,NULL);
const unsigned int beta_ptrs = 1; // temp value until power control is implemented
mult_complex_vector_real_scalar(mod_ptrs, beta_ptrs * AMP, mod_ptrs_amp, p.nb_rb);
}
#else
nr_modulation(gold, p.nb_rb, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
const unsigned int beta_ptrs = 1; // temp value until power control is implemented
mult_complex_vector_real_scalar(mod_ptrs, beta_ptrs * AMP, mod_ptrs_amp, p.nb_rb);
#endif
}
map_current_symbol(p,
dmrs_symbol,
@@ -1286,12 +1339,24 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
int max_num_re = Nl * number_of_symbols * nb_rb * NR_NB_SC_PER_RB;
c16_t d_mod[max_num_re] __attribute__((aligned(16)));
#ifdef FLT16_MAX
if (UE->use_fp16)
nr_modulation(scrambled_output, // assume one codeword for the moment
available_bits,
mod_order,
NULL,
(_Float16 *)d_mod);
else
nr_modulation(scrambled_output, // assume one codeword for the moment
available_bits,
mod_order,
(int16_t *)d_mod,NULL);
#else
nr_modulation(scrambled_output, // assume one codeword for the moment
available_bits,
mod_order,
(int16_t *)d_mod);
#endif
/////////////////////////ULSCH layer mapping/////////////////////////
const int sz = available_bits / mod_order / Nl;
@@ -1410,7 +1475,11 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
.delta = delta,
.num_cdm_no_data = cdm_grps_no_data};
map_symbols(params, slot, dmrs_seq, data, tx_precoding[nl]);
map_symbols(params, slot, dmrs_seq, data, tx_precoding[nl]
#ifdef FLT16_MAX
,UE->use_fp16
#endif
);
} // for (nl=0; nl < Nl; nl++)
@@ -1519,7 +1588,11 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
if (was_symbol_used[i] == false)
continue;
for (int ap = 0; ap < n_antenna_ports; ap++) {
apply_nr_rotation_TX(frame_parms, txdataF[ap], frame_parms->symbol_rotation[linktype], slot, N_RB, i, 1);
apply_nr_rotation_TX(frame_parms, txdataF[ap], frame_parms->symbol_rotation[linktype], slot, N_RB, i, 1
#ifdef FLT16_MAX
,UE->use_fp16,AMP
#endif
);
}
}
}

View File

@@ -39,6 +39,11 @@
#include "common/utils/utils.h"
#include "common/utils/LOG/log.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
#define simd_q15_t simde__m128i
#define shiftright_int16(a,shift) simde_mm_srai_epi16(a,shift)
#define set1_int16(a) simde_mm_set1_epi16(a)
@@ -244,6 +249,17 @@ extern "C" {
};
}
#ifdef __aarch64__
__attribute__((always_inline)) inline cf16_t cf16mulReal(const cf16_t a, const float16_t b)
{
return (cf16_t){.r = (float16_t)(a.r * b), .i = (float16_t)(a.i * b)};
}
#else
__attribute__((always_inline)) inline cf16_t cf16mulReal(const cf16_t a, const _Float16 b)
{
return (cf16_t){.r = (_Float16)(a.r * b), .i = (_Float16)(a.i * b)};
}
#endif
// On N complex numbers
// y.r += (x * alpha.r) >> 14
// y.i += (x * alpha.i) >> 14
@@ -970,6 +986,154 @@ void InitSinLUT(void);
// ret.i == sinus << 14
c16_t get_sin_cos(double phase);
#ifdef FLT16_MAX
// Interleaved input: [re0, im0, re1, im1, ...] as _Float16 (assumed to be -1...1
// Interleaved output: c16_t Q15 with truncation rounding
static inline void fp16_to_q15(const cf16_t *in_ri,
c16_t *out_q15,
int n_complex,
int16_t amp)
{
const int N = n_complex * 2;
int i = 0;
int16_t *out_q15_2 = (int16_t *)out_q15;
#if defined(__AVX512FP16__)
const _Float16 *in=(_Float16 *)in_ri;
const __m512h k = _mm512_set1_ph((_Float16)amp); // FP16 scale
for (; i + 32 <= N; i += 32) { // 32 halves per iter
__m512h h = _mm512_loadu_ph(in + i); // unaligned ok
__m512h hs = _mm512_mul_ph(h, k); // scale
__m512i q = _mm512_cvtph_epi16(hs); // trunc→i16, saturating
_mm512_storeu_si512((__m512i*)(out_q15_2 + i), q);
}
for (; i + 16 <= N; i += 16) { // 16 halves per iter
__m256h h = _mm256_loadu_ph(in + i); // unaligned ok
__m256h hs = _mm256_mul_ph(h, *(__m256h*)&k); // scale
__m256i q = _mm256_cvtph_epi16(hs); // trunc→i16, saturating
_mm256_storeu_si256((__m256i*)(out_q15_2 + i), q);
}
for (; i + 8 <= N; i += 8) { // 16 halves per iter
__m128h h = _mm_loadu_ph(in + i); // unaligned ok
__m128h hs = _mm_mul_ph(h, *(__m128h*)&k); // scale
__m128i q = _mm_cvtph_epi16(hs); // trunc→i16, saturating
_mm_storeu_si128((__m128i*)(out_q15_2 + i), q);
}
#elif defined(__aarch64__)
const float16_t *in=(float16_t *)in_ri;
const float16x8_t k = vdupq_n_f16((float16_t)amp);
for (; i + 8 <= N; i += 8) {
float16x8_t h = vld1q_f16((float16_t*)(in + i)); // 8 halves (4 complex)
float16x8_t hs = vmulq_f16(h, k); // scale to Q15 domain
int16x8_t q = vcvtq_s16_f16(hs); // truncate toward zero, saturate
vst1q_s16((int16_t*)(out_q15_2 + i), q);
}
#endif
for (; i < N; ++i) { // tail
float f = (float)in[i] * (float)amp;
int x = (int) (f > 0 ? floorf(f) : ceilf(f)); // trunc toward zero
if (x > 32767) x = 32767; // saturate
if (x < -32768) x = -32768;
out_q15_2[i] = (int16_t)x;
}
}
static inline void rotate_cpx_vector_fp16(const cf16_t *const x, const cf16_t *const alpha, cf16_t *y, uint32_t N)
{
uint32_t i=0;
#if defined(__aarch64__)
const float16x8_t zerosq=vdupq_n_f16(0.0f);
const float16x4_t zeros=vdup_n_f16(0.0f);
const uint32x4_t alpha16x8=vdupq_n_u32(*(uint32_t*)alpha);
for (; i + 4 <= N ; i+=4) {
float16x8_t x16x8 = vld1q_f16((float16_t*)(x + i));
float16x8_t y16x8 = vcmlaq_f16(zerosq,x16x8,*((float16x8_t*)&alpha16x8));
y16x8 = vcmlaq_rot90_f16(y16x8,x16x8,*((float16x8_t*)&alpha16x8));
vst1q_f16((float16_t*)(y + i),y16x8);
}
for (; i + 2 <= N ; i+=2) {
float16x4_t x16x4 = vld1_f16((float16_t*)(x + i));
float16x4_t y16x4 = vcmla_f16((float16x4_t)zeros,x16x4,*((float16x4_t*)&alpha16x8));
y16x4 = vcmla_rot90_f16(y16x4,x16x4,*((float16x4_t*)&alpha16x8));
vst1_f16((float16_t*)(y + i),y16x4);
}
#elif defined(__AVX512FP16__)
__m512h alpha512=_mm512_set1_pch(*(_Float16 _Complex*)alpha);
const __m512h alpha512c=_mm512_conj_pch(alpha512);
for (; i + 32 < N; i+=32) {
_mm512_storeu_ph((__m512h*)(y + i),_mm512_cmul_pch(_mm512_loadu_ph(x + i),alpha512c));
_mm512_storeu_ph((__m512h*)(y + i + 16),_mm512_cmul_pch(_mm512_loadu_ph(x + i + 16),alpha512c));
// if (i==0) { for (int j=0;j<2;j+=2) printf("%0.2f+(%0.2fj) ",(double)((_Float16*)&x512)[j],(double)((_Float16*)&x512)[j]); printf("\n");}
//if (i==0) { for (int j=0;j<32;j+=2) printf("%0.2f+(%0.2fj) ",(double)((_Float16*)&y512)[j],(double)((_Float16*)&y512)[j]); printf("\n");}
// _mm512_storeu_ph((__m512h*)(y + i),y512);
}
for (; i + 8 < N; i+=8)
_mm256_storeu_ph((__m256h*)(y + i),_mm256_cmul_pch( _mm256_loadu_ph(x + i),*(__m256h*)&alpha512c));
for (; i + 4 < N; i+=4)
_mm_storeu_ph((__m128h*)(y + i),_mm_cmul_pch(_mm_loadu_ph(x + i),*(__m128h*)&alpha512c));
/*
printf("y:");
for (int j=0;j<32;j+=2)
printf("%0.2f+(%0.2fj) ",(double)((_Float16*)y)[j],(double)((_Float16*)y)[j+1]);
printf("\n");*/
#else
AssertFatal(1==0,"No support for fp16 complex multiplication and FP16 is requested\n");
#endif
}
static inline void rotate_cpx_vector_fp16in_q15out(const cf16_t *const x, const cf16_t *const alpha, int16_t tx_amp, c16_t *y, uint32_t N)
{
uint32_t i=0;
#if defined(__aarch64__)
const float16x8_t zerosq=vdupq_n_f16(0.0f);
const float16x4_t zeros=vdup_n_f16(0.0f);
cf16_t alpha2;
alpha2.r = alpha->r * (float16_t)tx_amp;
alpha2.i = alpha->i * (float16_t)tx_amp;
const uint32x4_t alpha16x8=vdupq_n_u32(*(uint32_t*)&alpha2);
for (; i + 4 <= N ; i+=4) {
float16x8_t x16x8 = vld1q_f16((float16_t*)(x + i));
float16x8_t y16x8 = vcmlaq_f16(zerosq,x16x8,*((float16x8_t*)&alpha16x8));
y16x8 = vcmlaq_rot90_f16(y16x8,x16x8,*((float16x8_t*)&alpha16x8));
vst1q_s16((int16_t*)(y + i),vcvtq_s16_f16(y16x8));
}
for (; i + 2 <= N ; i+=2) {
float16x4_t x16x4 = vld1_f16((float16_t*)(x + i));
float16x4_t y16x4 = vcmla_f16((float16x4_t)zeros,x16x4,*((float16x4_t*)&alpha16x8));
y16x4 = vcmla_rot90_f16(y16x4,x16x4,*((float16x4_t*)&alpha16x8));
vst1_s16((int16_t*)(y + i),vcvt_s16_f16(y16x4));
}
#elif defined(__AVX512FP16__)
cf16_t alpha2;
alpha2.r = alpha->r * (_Float16)tx_amp;
alpha2.i = alpha->i * (_Float16)tx_amp;
__m512h alpha512=_mm512_set1_pch(*(_Float16 _Complex*)&alpha2);
const __m512h alpha512c=_mm512_conj_pch(alpha512);
for (; i + 32 < N; i+=32) {
_mm512_storeu_si512((__m512i*)(y + i),_mm512_cvtph_epi16(_mm512_cmul_pch(_mm512_loadu_ph(x + i),alpha512c)));
_mm512_storeu_si512((__m512i*)(y + i + 16),_mm512_cvtph_epi16(_mm512_cmul_pch(_mm512_loadu_ph(x + i + 16),alpha512c)));
// if (i==0) { for (int j=0;j<2;j+=2) printf("%0.2f+(%0.2fj) ",(double)((_Float16*)&x512)[j],(double)((_Float16*)&x512)[j]); printf("\n");}
//if (i==0) { for (int j=0;j<32;j+=2) printf("%0.2f+(%0.2fj) ",(double)((_Float16*)&y512)[j],(double)((_Float16*)&y512)[j]); printf("\n");}
// _mm512_storeu_ph((__m512h*)(y + i),y512);
}
for (; i + 8 < N; i+=8)
_mm256_storeu_si256((__m256i*)(y + i),_mm256_cvtph_epi16(_mm256_cmul_pch( _mm256_loadu_ph(x + i),*(__m256h*)&alpha512c)));
for (; i + 4 < N; i+=4)
_mm_storeu_si128((__m128i*)(y + i),_mm_cvtph_epi16(_mm_cmul_pch(_mm_loadu_ph(x + i),*(__m128h*)&alpha512c)));
/*
printf("y:");
for (int j=0;j<32;j+=2)
printf("%0.2f+(%0.2fj) ",(double)((_Float16*)y)[j],(double)((_Float16*)y)[j+1]);
printf("\n");*/
#else
AssertFatal(1==0,"No support for fp16 complex multiplication and FP16 is requested\n");
#endif
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -105,6 +105,9 @@ typedef struct {
uint8_t *b;
/// Pointers to transport block segments
uint8_t **c;
#ifdef ENABLE_CUDA
uint8_t *c_dev;
#endif
/// Interleaver outputs
uint8_t *f;
/// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.)
@@ -458,9 +461,11 @@ typedef struct PHY_VARS_gNB_s {
time_stats_t dlsch_resource_mapping_stats;
time_stats_t dlsch_precoding_stats;
time_stats_t tinput;
time_stats_t tinput_memcpy;
time_stats_t tprep;
time_stats_t tparity;
time_stats_t toutput;
time_stats_t tconcat;
time_stats_t dlsch_rate_matching_stats;
time_stats_t dlsch_interleaving_stats;
@@ -501,6 +506,8 @@ typedef struct PHY_VARS_gNB_s {
pthread_t L1_tx_thread;
int L1_tx_thread_core;
void *scopeData;
int use_gpu;
int use_fp16;
} PHY_VARS_gNB;
struct puschSymbolReqId {

View File

@@ -528,6 +528,8 @@ typedef struct PHY_VARS_NR_UE_s {
ntn_config_message_t* ntn_config_message;
pthread_t main_thread;
pthread_t stat_thread;
int use_gpu;
int use_fp16;
} PHY_VARS_NR_UE;
typedef struct {

View File

@@ -372,7 +372,11 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
nr_srs_info_t *nr_srs_info,
int16_t amp,
frame_t frame_number,
slot_t slot_number);
slot_t slot_number
#ifdef FLT16_MAX
,int use_fp16
#endif
);
void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
const csi_mapping_parms_t *phy_csi_parms,
const int16_t amp,
@@ -386,6 +390,10 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
const uint16_t scramb_id,
const uint8_t power_control_offset_ss,
const uint8_t cdm_type,
c16_t **dataF);
c16_t **dataF
#ifdef FLT16_MAX
,int use_fp16
#endif
);
#endif

View File

@@ -21,6 +21,10 @@
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
static void csi_rs_resource_mapping(c16_t **dataF,
int csi_rs_length,
int16_t mod_csi[][csi_rs_length >> 1],
@@ -94,27 +98,59 @@ static void get_modulated_csi_symbols(int symbols_per_slot,
int l0,
int l1,
int row,
int scramb_id)
int scramb_id
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
for (int lp = 0; lp <= lprime; lp++) {
int symb = l0;
const uint32_t *gold =
nr_gold_csi_rs(N_RB_DL, symbols_per_slot, slot, symb + lp, scramb_id);
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, NULL, (_Float16*)mod_csi[symb + lp]);
else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + lp],NULL);
#else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + lp]);
#endif
if ((row == 5) || (row == 7) || (row == 11) || (row == 13) || (row == 16)) {
const uint32_t *gold =
nr_gold_csi_rs(N_RB_DL, symbols_per_slot, slot, symb + 1, scramb_id);
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, NULL, (_Float16*)mod_csi[symb + 1]);
else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + 1],NULL);
#else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + 1]);
#endif
}
if ((row == 14) || (row == 13) || (row == 16) || (row == 17)) {
symb = l1;
const uint32_t *gold =
nr_gold_csi_rs(N_RB_DL, symbols_per_slot, slot, symb + lp, scramb_id);
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + lp]);
if ((row == 13) || (row == 16)) {
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, NULL, (_Float16*)mod_csi[symb + lp]);
else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + lp],NULL);
#else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + lp]);
#endif
if ((row == 13) || (row == 16)) {
const uint32_t *gold =
nr_gold_csi_rs(N_RB_DL, symbols_per_slot, slot, symb + 1, scramb_id);
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + 1]);
#ifdef FLT16_MAX
if (use_fp16)
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, NULL, (_Float16*)mod_csi[symb + 1]);
else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + 1],NULL);
#else
nr_modulation(gold, mod_length, DMRS_MOD_ORDER, mod_csi[symb + 1]);
#endif
}
}
}
@@ -574,7 +610,11 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
const uint16_t scramb_id,
const uint8_t power_control_offset_ss,
const uint8_t cdm_type,
c16_t **dataF)
c16_t **dataF
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
#ifdef NR_CSIRS_DEBUG
LOG_I(NR_PHY,
@@ -610,7 +650,11 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
symb_l0,
symb_l1,
row,
scramb_id);
scramb_id
#ifdef FLT16_MAX
,use_fp16
#endif
);
const uint32_t beta = get_csi_beta_amplitude(amp, power_control_offset_ss);
const double alpha = (phy_csi_parms->ports == 1) ? rho : 2 * rho;

View File

@@ -146,7 +146,11 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
nr_srs_info_t *nr_srs_info,
int16_t amp,
frame_t frame_number,
slot_t slot_number)
slot_t slot_number
#ifdef FLT16_MAX
,int use_fp16
#endif
)
{
uint8_t K_TC = 2 << nr_srs_info->comb_size;
/* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */
@@ -329,6 +333,14 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
LOG_I(NR_PHY, "(%d) \t%i\t%i\n", subcarrier_log, r_amp.r, r_amp.i);
#endif
#ifdef FLT16_MAX
if (use_fp16) {
cf16_t r_amp = {((_Float16)(r.r / sqrt_N_ap)),
((_Float16)(r.i / sqrt_N_ap))};
*(cf16_t*)&txdataF[p_index][symbol_offset + l_line_offset + subcarrier] = r_amp;
}
else
#endif
txdataF[p_index][symbol_offset + l_line_offset + subcarrier] = r_amp;
// Subcarrier increment

View File

@@ -30,6 +30,10 @@
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "PHY/INIT/nr_phy_init.h"
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
#include <float.h>
#include "PHY/MODULATION/nr_modulation.h"
#include "T.h"
#include "executables/nr-softmodem.h"
@@ -41,7 +45,6 @@
#include <stdint.h>
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
#include "PHY/log_tools.h"
//#define DEBUG_RXDATA
//#define SRS_IND_DEBUG
static void nr_fill_indication(PHY_VARS_gNB *gNB,
@@ -165,8 +168,16 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n
fp->symbols_per_slot,
bitmap);
nr_generate_pss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
nr_generate_sss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
nr_generate_pss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
nr_generate_sss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
uint16_t slots_per_hf = (fp->slots_per_frame) >> 1;
int n_hf = slot < slots_per_hf ? 0 : 1;
@@ -246,7 +257,12 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB,
csi_params->scramb_id,
csi_params->power_control_offset_ss,
csi_params->cdm_type,
gNB->common_vars.txdataF[beam_nb]);
gNB->common_vars.txdataF[beam_nb]
#ifdef FLT16_MAX
,gNB->use_fp16
#endif
);
}
void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
@@ -343,7 +359,11 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
slot,
fp->N_RB_DL,
0,
fp->Ncp == EXTENDED ? 12 : 14);
fp->Ncp == EXTENDED ? 12 : 14
#ifdef FLT16_MAX
,gNB->use_fp16,gNB->TX_AMP
#endif
);
}
T(T_GNB_PHY_DL_OUTPUT_SIGNAL,
T_INT(0),
@@ -1082,7 +1102,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
gNB->nr_srs_info[i],
AMP,
frame_rx,
slot_rx);
slot_rx,0);
}
stop_meas(&gNB->generate_srs_stats);
c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb];

View File

@@ -38,6 +38,7 @@
#include "PHY/defs_nr_UE.h"
#include "PHY/NR_REFSIG/dmrs_nr.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
#include "PHY/NR_REFSIG/ptrs_nr.h"
@@ -360,7 +361,11 @@ static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
ue->nr_srs_info,
AMP,
proc->frame_tx,
proc->nr_slot_tx);
proc->nr_slot_tx
#ifdef FLT16_MAX
,ue->use_fp16
#endif
);
return generated;
}

View File

@@ -517,7 +517,7 @@ int main(int argc, char **argv)
unsigned char output[nb_rb * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * NR_MAX_NB_LAYERS] __attribute__((aligned(64)));
bzero(output, sizeof(output));
if (input_fd == NULL) {
nr_dlsch_encoding(gNB, 1, dlsch, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
nr_dlsch_encoding(gNB, 1, dlsch, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
for (SNR = snr0; SNR < snr1 && !stop; SNR += snr_step) {

View File

@@ -311,8 +311,10 @@ void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config,
num_antenna_ports, pmi_pdu->num_ant_ports, pmi);
}
configmodule_interface_t *uniqCfg = NULL;
extern uint32_t use_gpu;
extern uint32_t use_fp16;
int main(int argc, char **argv)
{
stop = false;
@@ -408,7 +410,7 @@ int main(int argc, char **argv)
FILE *scg_fd=NULL;
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -1) {
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PQVI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -1) {
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
@@ -528,7 +530,14 @@ int main(int argc, char **argv)
print_perf=1;
cpu_meas_enabled = 1;
break;
case 'V':
use_fp16=1;
break;
case 'Q':
use_gpu=1;
break;
case 'I':
max_ldpc_iterations = atoi(optarg);
break;
@@ -680,6 +689,7 @@ int main(int argc, char **argv)
memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
gNB = RC.gNB[0];
gNB->use_fp16 = use_fp16;
gNB->ofdm_offset_divisor = UINT_MAX;
gNB->phase_comp = true; // we need to perform phase compensation, otherwise everything will fail
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
@@ -920,6 +930,7 @@ int main(int argc, char **argv)
PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE**));
PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*));
PHY_vars_UE_g[0][0] = UE;
printf("Copying gNB frame_parms to UE\n");
memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
UE->frame_parms.nb_antennas_rx = n_rx;
UE->frame_parms.nb_antenna_ports_gNB = n_tx;
@@ -1041,9 +1052,11 @@ int main(int argc, char **argv)
reset_meas(&gNB->dlsch_encoding_stats);
reset_meas(&gNB->dci_generation_stats);
reset_meas(&gNB->tinput);
reset_meas(&gNB->tinput_memcpy);
reset_meas(&gNB->tprep);
reset_meas(&gNB->tparity);
reset_meas(&gNB->toutput);
reset_meas(&gNB->tconcat);
reset_meas(&gNB->phase_comp_stats);
uint32_t errors_scrambling[16] = {0};
@@ -1135,7 +1148,7 @@ int main(int argc, char **argv)
1);
}
if (n_trials == 1)
printf("slot_offset %d, txdataF_offset %d \n", slot_offset, txdataF_offset);
printf("frame %d slot %d slot_offset %d, txdataF_offset %d \n", frame, slot, slot_offset, txdataF_offset);
//TODO: loop over slots
for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
@@ -1335,12 +1348,19 @@ int main(int argc, char **argv)
printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time");
printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time");
gNB->tinput.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->tinput,"DLSCH LDPC input processing time");
printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time");
gNB->tinput_memcpy.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->tinput_memcpy,"DLSCH LDPC input memcpy time");
gNB->tparity.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time");
gNB->toutput.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time");
gNB->dlsch_rate_matching_stats.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Matching time");
gNB->dlsch_interleaving_stats.trials = gNB->dlsch_encoding_stats.trials;
printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time");
printStatIndent3(&gNB->tconcat, "DLSCH Segment Concatenation 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");

View File

@@ -32,6 +32,8 @@
// Define signal handler to attempt graceful termination
bool stop = false;
uint32_t use_gpu=0;
uint32_t use_fp16=0;
void sigint_handler(int arg)
{

View File

@@ -1742,7 +1742,7 @@ int main(int argc, char *argv[])
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time");
printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time");
printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate matching time");
printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time");
printStatIndent(&gNB->rx_srs_stats,"RX SRS time");
printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time");