Commit a2613d56 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/ldpc_decoding_module_interface_rework'...

Merge remote-tracking branch 'origin/ldpc_decoding_module_interface_rework' into integration_2024_w50 (2952)

New LDPC coding library interface for decoding and encoding complete slots in one call to the library

Previous attempts to integrate LDPC decoding relying on offloading show
the limitation of the original code segment coding interface for the
library implementing LDPC coding. In order to perform the offload and
therefore the decoding in an optimal fashion, it is relevant to provide
the implementation with the broader amount of data possible per call,
which is a slot.  A previous MR related to T2 offload managed to offer
an interface for decoding transport blocks by modifying only
nr_ulsch_decoding.c. But this may not be sufficient for performing an
efficient decoding in any situation. Slots could be shared between
multiple transport blocks in case multiple UEs are connected to the RAN,
which makes the transport block size shrink and therefore degrades the
efficiency of the offloading.

This MR offers a broader interface with a gNB decoding entry point in
phy_procedures_nr_gNB.c. The file nr_ulsch_decoding.c now lets the
decoding library implement deinterleaving, rate-unmatching and decoding
for the slot. In gNB encoding and UE decoding and encoding as well,
tasks are partitioned in a similar fashion.

As it allows to feed the implementation with the broadest amount of data
possible, it allows to fit any coding solution in a library. This will
avoid further modification to OAI source code and addition of options to
select an implementation when integrating new decoding solutions. An
implementation of this interface will therefore be offered for every
existing decoding solution in OAI and solutions added in the future will
be provided as independent module code without any modification to the
core of OAI code.  The way to choose the decoding solution and to
configure it was also unified using configmodule. The library can be
chosen through the option --loader.ldpc.shlibversion. The slot coding
solutions shipped with this MR can be configured through configmodule
(e.g., T2 address and isolated cores).

This MR includes three coding implementations:

- A wrapper around segment decoding libraries for test purpose: libldpc.so
- A one shot slot coding and encoding with the T2 board: libldpc_t2.so
- A decoder on FPGA using the XDMA driver: libldpc_xdma.so

Improvements brought by this MR:

- Easy integration of a wider variety of LDPC coding solution at gNB and UE
- Easy selection of the LDPC coding solution (option --ldpc-offload-enable is kept for now but it can be ultimately removed)
- T2:
  * More efficient when many UEs are connected
  * Decoding and encoding in nr-uesoftmodem
parents deba36a5 7bf6f3f2
......@@ -485,26 +485,6 @@ target_link_libraries(params_libconfig PRIVATE config_internals ${libconfig_LIBR
add_library(shlib_loader OBJECT common/utils/load_module_shlib.c)
target_link_libraries(shlib_loader PRIVATE CONFIG_LIB)
##########################################################
# LDPC offload library - AMD T2 Accelerator Card
##########################################################
add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF)
if (ENABLE_LDPC_T2)
pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk=20.11.9)
find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS})
if (NOT PMD_T2)
message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)")
endif()
message(STATUS "T2 build: use ${PMD_T2}")
add_library(ldpc_t2 MODULE ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c)
set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API")
target_link_libraries(ldpc_t2 ${LIBDPDK_T2_LDFLAGS} ${PMD_T2})
endif()
##########################################################
include_directories ("${OPENAIR_DIR}/radio/COMMON")
##############################################################
......@@ -770,14 +750,6 @@ include_directories(${NFAPI_USER_DIR})
# Layer 1
#############################
set(PHY_TURBOSRC
${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c
${OPENAIR1_DIR}/PHY/CODING/3gpplte.c
${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c
${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c
${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c
${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder.c
)
set(PHY_POLARSRC
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_init.c
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c
......@@ -800,76 +772,16 @@ set(PHY_TURBOIF
${OPENAIR1_DIR}/PHY/CODING/coding_load.c
)
set(PHY_LDPC_ORIG_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
)
add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} )
target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS)
set(PHY_LDPC_OPTIM_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
)
add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} )
target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS)
set(PHY_LDPC_OPTIM8SEG_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
)
add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} )
target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS)
set(PHY_LDPC_OPTIM8SEGMULTI_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} )
target_link_libraries(ldpc PRIVATE ldpc_gen_HEADERS)
set(PHY_LDPC_CUDA_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
set(PHY_LDPC_CL_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
add_custom_target( nrLDPC_decoder_kernels_CL
COMMAND gcc ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc
SOURCES ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c
)
add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} )
target_link_libraries(ldpc_cl OpenCL)
add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL)
set(PHY_NR_CODINGIF
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c
)
##############################################
# Base CUDA setting
##############################################
add_boolean_option(ENABLE_LDPC_CUDA OFF "Build support for CUDA" OFF)
if (ENABLE_LDPC_CUDA)
find_package(CUDA REQUIRED)
SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;")
SET(CUDA_VERBOSE_BUILD ON)
cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC})
set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
if (NOT CUDA_FOUND)
message(FATAL_ERROR "no CUDA found")
endif()
endif()
add_library(coding MODULE ${PHY_TURBOSRC} )
set(PHY_NRLDPC_CODINGIF
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c
)
add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c)
set(PHY_SRC_COMMON
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
......@@ -1057,7 +969,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/TOOLS/simde_operations.c
${PHY_POLARSRC}
${PHY_SMALLBLOCKSRC}
${PHY_NR_CODINGIF}
${PHY_NRLDPC_CODINGIF}
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/srs_rx.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c
......@@ -1112,7 +1024,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/INIT/nr_init_ue.c
${PHY_POLARSRC}
${PHY_SMALLBLOCKSRC}
${PHY_NR_CODINGIF}
${PHY_NRLDPC_CODINGIF}
)
......@@ -2046,12 +1958,6 @@ if(E2_AGENT)
endif()
add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc)
if (ENABLE_LDPC_T2)
add_dependencies(nr-softmodem ldpc_t2)
endif()
# force the generation of ASN.1 so that we don't need to wait during the build
target_link_libraries(nr-softmodem PRIVATE
asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp)
......@@ -2104,12 +2010,6 @@ target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_m
target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB})
target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc )
if (ENABLE_LDPC_CUDA)
add_dependencies(nr-uesoftmodem ldpc_cuda)
add_dependencies(nr-softmodem ldpc_cuda)
endif()
# force the generation of ASN.1 so that we don't need to wait during the build
target_link_libraries(nr-uesoftmodem PRIVATE
asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp)
......@@ -2163,11 +2063,6 @@ add_executable(ldpctest
${PHY_NR_CODINGIF}
${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c
)
add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc)
if (ENABLE_LDPC_CUDA)
add_dependencies(ldpctest ldpc_cuda)
endif()
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}
......@@ -2264,10 +2159,6 @@ add_executable(nr_ulsim
${PHY_INTERFACE_DIR}/queue_t.c
)
if (ENABLE_LDPC_T2)
add_dependencies(nr_ulsim ldpc_t2)
endif()
target_link_libraries(nr_ulsim PRIVATE
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas
......@@ -2326,14 +2217,14 @@ if (${T_TRACER})
#all "add_library" definitions
ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap
params_libconfig oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_iqplayer
oai_eth_transpro oai_mobipass coding HASHTABLE UTIL OMG_SUMO
oai_eth_transpro oai_mobipass HASHTABLE UTIL OMG_SUMO
SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL
NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB
MISC_NFAPI_LTE_LIB MISC_NFAPI_NR_LIB
PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX
L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap
CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB
ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals nr_common)
dfts config_internals nr_common)
if (TARGET ${i})
add_dependencies(${i} generate_T)
endif()
......
......@@ -73,9 +73,9 @@ then
do
IS_NFAPI=`echo $FILE | grep -E -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext" || true`
IS_OAI_LICENCE_PRESENT=`grep -E -c "OAI Public License" $FILE || true`
IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause" $FILE || true`
IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause|License-Identifier: BSD-3-Clause" $FILE || true`
IS_MIT_LICENCE_PRESENT=`grep -E -c "MIT License" $FILE || true`
IS_EXCEPTION=`echo $FILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h" || true`
IS_EXCEPTION=`echo $FILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h" || true`
if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] && [ $IS_MIT_LICENCE_PRESENT -eq 0 ]
then
if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ]
......@@ -184,9 +184,9 @@ do
then
IS_NFAPI=`echo $FULLFILE | grep -E -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext" || true`
IS_OAI_LICENCE_PRESENT=`grep -E -c "OAI Public License" $FULLFILE || true`
IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause" $FULLFILE || true`
IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause|License-Identifier: BSD-3-Clause" $FULLFILE || true`
IS_MIT_LICENCE_PRESENT=`grep -E -c "MIT License" $FULLFILE || true`
IS_EXCEPTION=`echo $FULLFILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h" || true`
IS_EXCEPTION=`echo $FULLFILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h" || true`
if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] && [ $IS_MIT_LICENCE_PRESENT -eq 0 ]
then
if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ]
......
......@@ -45,7 +45,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>100</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010121">
......@@ -63,7 +63,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>150</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010131">
......@@ -81,7 +81,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>250</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010211">
......@@ -99,7 +99,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>150</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010221">
......@@ -117,7 +117,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>350</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010231">
......@@ -135,7 +135,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>550</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010311">
......@@ -153,7 +153,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>250</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010321">
......@@ -171,7 +171,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>650</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="010331">
......@@ -189,7 +189,7 @@
<always_exec>true</always_exec>
<physim_test>nr_ulsim</physim_test>
<physim_time_threshold>1100</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
</testCaseList>
......@@ -46,7 +46,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>100</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000121">
......@@ -64,7 +64,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>100</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000131">
......@@ -82,7 +82,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>200</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000211">
......@@ -100,7 +100,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>150</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000221">
......@@ -118,7 +118,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>250</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000231">
......@@ -136,7 +136,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>400</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000311">
......@@ -154,7 +154,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>200</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000321">
......@@ -172,7 +172,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>500</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000331">
......@@ -190,7 +190,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>500</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000411">
......@@ -208,7 +208,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>200</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000421">
......@@ -226,7 +226,7 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>300</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
<testCase id="000431">
......@@ -244,6 +244,6 @@
<always_exec>true</always_exec>
<physim_test>nr_dlsim</physim_test>
<physim_time_threshold>450</physim_time_threshold>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12</physim_run_args>
</testCase>
</testCaseList>
......@@ -46,7 +46,7 @@ BUILD_DOXYGEN=0
DISABLE_HARDWARE_DEPENDENCY="False"
CMAKE_BUILD_TYPE="RelWithDebInfo"
CMAKE_CMD="$CMAKE"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 websrv oai_iqplayer imscope"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 ldpc_xdma websrv oai_iqplayer imscope"
TARGET_LIST=""
BUILD_TOOL_OPT="-j$(nproc)"
......
......@@ -74,11 +74,6 @@ If DPDK library was installed into custom path, you have to point to the right d
```
export PKG_CONFIG_PATH=/opt/dpdk-t2/lib64/pkgconfig/:$PKG_CONFIG_PATH
```
## Setup of T2-related DPDK EAL parameters
To configure T2-related DPDK Environment Abstraction Layer (EAL) parameters, you can set the following parameters via the command line:
- `ldpc_offload.dpdk_dev` - **mandatory** parameter, specifies PCI address of the T2 card. PCI address of the T2 card can be detected by `lspci | grep "Xilinx"` command.
- `ldpc_offload.dpdk_cores_list` - CPU cores assigned to DPDK for T2 processing, by default set to *11-12*. Ensure that the CPU cores specified in *ldpc_offload.dpdk_cores_list* are available and not used by other processes to avoid conflicts.
- `ldpc_offload.dpdk_prefix` - DPDK shared data file prefix, by default set to *b6*
# OAI Build
OTA deployment is precisely described in the following tutorial:
......@@ -106,14 +101,35 @@ Shared object file *libldpc_t2.so* is created during the compilation. This objec
*Required poll mode driver has to be present on the host machine and required DPDK version has to be installed on the host, prior to the build of OAI*
# Setup of T2-related DPDK EAL parameters
To configure T2-related DPDK Environment Abstraction Layer (EAL) parameters, you can set the following parameters via the command line of PHY simulators or softmodem:
- `nrLDPC_coding_t2.dpdk_dev` - **mandatory** parameter, specifies PCI address of the T2 card. PCI address of the T2 card can be detected by `lspci | grep "Xilinx"` command.
- `nrLDPC_coding_t2.dpdk_core_list` - **mandatory** parameter, specifies CPU cores assigned to DPDK for T2 processing. Ensure that the CPU cores specified in *nrLDPC_coding_t2.dpdk_core_list* are available and not used by other processes to avoid conflicts.
- `nrLDPC_coding_t2.dpdk_prefix` - DPDK shared data file prefix, by default set to *b6*.
**Note:** These parameters can also be provided in a configuration file:
```
nrLDPC_coding_t2 : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};
loader : {
ldpc : {
shlibversion : "_t2";
};
};
```
# 5G PHY simulators
## nr_ulsim test
Offload of the channel decoding to the T2 card is in nr_ulsim specified by *-o* option. Example command for running nr_ulsim with LDPC decoding offload to the T2 card:
Offload of the channel decoding to the T2 card is in nr_ulsim specified by *--loader.ldpc.shlibversion _t2* option. Example command for running nr_ulsim with LDPC decoding offload to the T2 card:
```
cd ~/openairinterface5g
source oaienv
cd cmake_targets/ran_build/build
sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 -o --ldpc_offload.dpdk_dev 01:00.0
sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1
```
## nr_dlsim test
Offload of the channel encoding to the AMD Xilinx T2 card is in nr_dlsim specified by *-c* option. Example command for running nr_dlsim with LDPC encoding offload to the T2 card:
......@@ -121,18 +137,18 @@ Offload of the channel encoding to the AMD Xilinx T2 card is in nr_dlsim specifi
cd ~/openairinterface5g
source oaienv
cd cmake_targets/ran_build/build
sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 -c --ldpc_offload.dpdk_dev 01:00.0
sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1
```
# OTA test
Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--ldpc-offload-enable* option.
Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--loader.ldpc.shlibversion _t2* option.
## Run OAI gNB with USRP B210
```
cd ~/openairinterface5g
source oaienv
cd cmake_targets/ran_build/build
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --ldpc-offload-enable --ldpc_offload.dpdk_dev 01:00.0
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1
```
# Limitations
......
# LDPC offload with the XDMA driver
[TOC]
This documentation aims to provide a tutorial for using Xilinx PCIe-XDMA based FPGA LDPC decoding within OAI. LDPC decoding is offloaded to FPGA.
## XDMA Driver Build & Install
- Get XDMA driver source
```bash
git clone https://github.com/Xilinx/dma_ip_drivers.git
cd dma_ip_drivers/XDMA/linux-kernel
```
The *xdma_driver* directory contains the following:
```bash
dma_ip_drivers/XDMA/linux-kernel/
├── COPYING
├── include
├── LICENSE
├── readme.txt
├── RELEASE
├── tests
├── tools
└── xdma
```
Before building the driver, ensure that your system recognizes the Xilinx device. You can check this using the `lspci` command:
```bash
$ lspci | grep Xilinx
01:00.0 Serial controller: Xilinx Corporation Device 8038
```
Building and Installing the Driver
```bash
cd ~/dma_ip_drivers/XDMA/linux-kernel/xdma
make clean
make
# install to make the driver loading automatically at system startup
sudo make install
```
Load the Driver
```bash
cd ~/dma_ip_drivers/XDMA/linux-kernel/tests
sudo ./load_driver.sh
```
## OAI Build
```bash
# Get openairinterface5g source code
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
cd ~/openairinterface5g
# Install OAI dependencies
cd ~/openairinterface5g/cmake_targets
./build_oai -I
# Build OAI gNB & UE
cd ~/openairinterface5g
source oaienv
cd cmake_targets
./build_oai --ninja -w SIMU --gNB --nrUE -P --build-lib "ldpc_xdma" -C -c
```
Shared object file *libldpc_xdma.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using `--build-lib ldpc_xdma`.
## 5G PHY simulators
The simulated test uses the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface. Additionally, the option `--nrLDPC_coding_xdma.num_threads_prepare` is used to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts.
Another way to activate the feature is to add the `xdma.conf` file with the following content:
```
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};
```
and use option `-O xdma.conf`.
### nr_ulsim test
Example command for running nr_ulsim with LDPC decoding offload to the FPGA:
```bash
cd ~/openairinterface5g/cmake_targets/ran_build/build
sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
```
or
```
sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P -O xdma.conf
```
## Run
Both gNB and nrUE use the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface and `--nrLDPC_coding_xdma.num_threads_prepare` to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts.
Another way to activate the feature is to add the following content to the `.conf` file you want to use:
```
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};
```
and use option `-O *.conf`.
### gNB
Example command using rfsim:
```bash
cd ~/openairinterface5g/cmake_targets/ran_build/build
sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
```
or
```bash
sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf
```
if you have added the configuration to the `.conf` file.
### UE
Example command using rfsim:
```bash
cd ~/openairinterface5g/cmake_targets/ran_build/build
sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.serveraddr 10.201.1.100 --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2
```
or
```bash
sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.serveraddr 10.201.1.100
```
if you have added the configuration to the `.conf` file.
......@@ -403,7 +403,6 @@ void init_eNB_afterRU(void) {
for (inst=0; inst<RC.nb_nr_inst; inst++) {
gNB = RC.gNB[inst];
gNB->ldpc_offload_flag = get_softmodem_params()->ldpc_offload_flag;
phy_init_nr_gNB(gNB);
......
......@@ -42,6 +42,7 @@
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "openair1/PHY/MODULATION/nr_modulation.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/phy_vars_nr_ue.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
......@@ -216,7 +217,6 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
UE->rf_map.card = 0;
UE->rf_map.chain = CC_id + 0;
UE->max_ldpc_iterations = nrUE_params.max_ldpc_iterations;
UE->ldpc_offload_enable = nrUE_params.ldpc_offload_flag;
UE->UE_scan_carrier = nrUE_params.UE_scan_carrier;
UE->UE_fo_compensation = nrUE_params.UE_fo_compensation;
UE->if_freq = nrUE_params.if_freq;
......@@ -385,6 +385,7 @@ configmodule_interface_t *uniqCfg = NULL;
// A global var to reduce the changes size
ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0};
nrLDPC_coding_interface_t nrLDPC_coding_interface = {0};
int main(int argc, char **argv)
{
......@@ -424,10 +425,8 @@ int main(int argc, char **argv)
init_opt();
if (nrUE_params.ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
load_LDPClib(NULL, &ldpc_interface);
int ret_loader = load_nrLDPC_coding_interface(NULL, &nrLDPC_coding_interface);
AssertFatal(ret_loader == 0, "error loading LDPC library\n");
if (ouput_vcd) {
vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd");
......@@ -442,6 +441,8 @@ int main(int argc, char **argv)
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
PHY_vars_UE_g[inst][CC_id] = malloc(sizeof(*PHY_vars_UE_g[inst][CC_id]));
memset(PHY_vars_UE_g[inst][CC_id], 0, sizeof(*PHY_vars_UE_g[inst][CC_id]));
// All instances use the same coding interface
PHY_vars_UE_g[inst][CC_id]->nrLDPC_coding_interface = nrLDPC_coding_interface;
}
}
......
......@@ -39,7 +39,6 @@
{"dlsch-parallel", CONFIG_HLP_DLSCH_PARA, 0, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \
{"offset-divisor", CONFIG_HLP_OFFSET_DIV, 0, .uptr=&nrUE_params.ofdm_offset_divisor, .defuintval=8, TYPE_UINT32, 0}, \
{"max-ldpc-iterations", CONFIG_HLP_MAX_LDPC_ITERATIONS, 0, .iptr=&nrUE_params.max_ldpc_iterations, .defuintval=8, TYPE_UINT8, 0}, \
{"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&(nrUE_params.ldpc_offload_flag), .defintval=0, TYPE_INT, 0}, \
{"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, .iptr=&nrUE_params.vcdflag, .defintval=0, TYPE_INT, 0}, \
{"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&nrUE_params.uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \
{"reconfig-file", CONFIG_HLP_RE_CFG_FILE, 0, .strptr=&nrUE_params.reconfig_file, .defstrval="./reconfig.raw", TYPE_STRING, 0}, \
......@@ -85,7 +84,6 @@ typedef struct {
int nb_antennas_tx;
int N_RB_DL;
int ssb_start_subcarrier;
int ldpc_offload_flag;
double time_sync_P;
double time_sync_I;
int autonomous_ta;
......
......@@ -108,7 +108,6 @@ extern "C"
#define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n"
#define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence"
#define CONFIG_HLP_NOITTI "Do not start itti threads, call queue processing in place, inside the caller thread"
#define CONFIG_HLP_LDPC_OFFLOAD "Enable LDPC offload to AMD Xilinx T2 telco card\n"
#define CONFIG_HLP_SYNC_REF "UE acts a Sync Reference in Sidelink. 0-none 1-GNB 2-GNSS 4-localtiming\n"
#define CONFIG_HLP_TADV \
"Set RF board timing_advance to compensate fix delay inside the RF board between Rx and Tx timestamps (RF board internal " \
......@@ -142,7 +141,6 @@ extern "C"
#define EMULATE_L1 softmodem_params.emulate_l1
#define CONTINUOUS_TX softmodem_params.continuous_tx
#define SYNC_REF softmodem_params.sync_ref
#define LDPC_OFFLOAD_FLAG softmodem_params.ldpc_offload_flag
#define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
......@@ -182,7 +180,6 @@ extern int usrp_tx_thread;
{"continuous-tx", CONFIG_HLP_CONTINUOUS_TX, PARAMFLAG_BOOL, .iptr=&CONTINUOUS_TX, .defintval=0, TYPE_INT, 0}, \
{"disable-stats", CONFIG_HLP_STATS_DISABLE, PARAMFLAG_BOOL, .iptr=&stats_disabled, .defintval=0, TYPE_INT, 0}, \
{"no-itti-threads", CONFIG_HLP_NOITTI, PARAMFLAG_BOOL, .iptr=&softmodem_params.no_itti, .defintval=0, TYPE_INT, 0}, \
{"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&LDPC_OFFLOAD_FLAG, .defstrval=0, TYPE_INT, 0}, \
{"sync-ref", CONFIG_HLP_SYNC_REF, 0, .uptr=&SYNC_REF, .defintval=0, TYPE_UINT, 0}, \
{"A" , CONFIG_HLP_TADV, 0, .iptr=&softmodem_params.command_line_sample_advance,.defintval=0, TYPE_INT, 0}, \
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
......@@ -232,7 +229,6 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
// clang-format on
......@@ -321,7 +317,6 @@ typedef struct {
int continuous_tx;
uint32_t sync_ref;
int no_itti;
int ldpc_offload_flag;
int threequarter_fs;
} softmodem_params_t;
......
add_subdirectory(nr_phy_common)
add_subdirectory(TOOLS)
add_subdirectory(NR_TRANSPORT)
add_subdirectory(CODING)
add_library(coding MODULE
3gpplte_sse.c
3gpplte.c
3gpplte_turbo_decoder_sse_8bit.c
3gpplte_turbo_decoder_sse_16bit.c
3gpplte_turbo_decoder_avx2_16bit.c
3gpplte_turbo_decoder.c
)
set_target_properties(coding PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_library(ldpc_orig MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder.c
)
set_target_properties(ldpc_orig PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_optim MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder_optim.c
)
set_target_properties(ldpc_optim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_optim8seg MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder_optim8seg.c
)
set_target_properties(ldpc_optim8seg PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_optim8segmulti MODULE
nrLDPC_decoder/nrLDPC_decoder.c
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
set_target_properties(ldpc_optim8segmulti PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS)
add_custom_target(nrLDPC_decoder_kernels_CL
COMMAND gcc nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc
SOURCES nrLDPC_decoder/nrLDPC_decoder_CL.c
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(ldpc_cl MODULE
nrLDPC_decoder/nrLDPC_decoder_CL.c
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
set_target_properties(ldpc_cl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_cl PRIVATE OpenCL)
add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL)
##############################################
# Base CUDA setting
##############################################
add_boolean_option(ENABLE_LDPC_CUDA OFF "Build support for CUDA" OFF)
if (ENABLE_LDPC_CUDA)
find_package(CUDA REQUIRED)
if (NOT CUDA_FOUND)
message(FATAL_ERROR "no CUDA found")
endif()
SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;")
SET(CUDA_VERBOSE_BUILD ON)
cuda_add_library(ldpc_cuda MODULE
nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu
nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
)
set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti)
if (ENABLE_LDPC_CUDA)
add_dependencies(ldpctest ldpc_cuda)
endif()
add_subdirectory(nrLDPC_coding)
# LDPC coder/decoder implementation
The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time.
# LDPC coding implementation
The LDPC encoder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md).
Two types of library are available with two different interfaces. There are libraries implementing the encoder and decoder of code segments and libraries implementing the encoder and decoder of slots.
## Selecting the LDPC library at run time
## LDPC slot coding
The interface of the library is defined in [nrLDPC_coding_interface.h](file://../nrLDPC_coding/nrLDPC_coding_interface.h).
The code loading the LDPC library is in [nrLDPC_coding_interface_load.c](file://../nrLDPC_coding/nrLDPC_coding_interface_load.c), in function `load_nrLDPC_coding_interface`, which must be called at init time.
By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below:
### Selecting the LDPC library at run time
By default the function `int load_nrLDPC_coding_interface(void)` looks for `libldpc.so`.\
This default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below:
#### Examples of ldpc shared lib selection when running nr softmodem's:
loading `libldpc_optim8seg.so` instead of `libldpc.so`:
loading default `libldpc.so`:
```
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5
.......................
[CONFIG] loader.ldpc.shlibversion set to default value ""
[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (2 to default value)
shlib_path libldpc.so
[LOADER] library libldpc.so successfully loaded
........................
```
`libldpc.so` has its decoder implemented in [nrLDPC_coding_segment_decoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c).\
Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c).
*Note: The segment coding library `libldpc.so` is an adaptation layer between the slot coding interface and a segment coding library.*
*The segment coding library is `libldpc_optim8segmulti.so` by default but it can be chosen with option `--nrLDPC_coding_segment.segment_shlibversion` followed by the library version - like with `--loader.ldpc.shlibversion` in the slot coding case -*
loading `libldpc_t2.so` instead of `libldpc.so`:
`make ldpc_t2`
This command creates the `libldpc_t2.so` shared library.
```
Building C object CMakeFiles/ldpc_t2.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c.o
Linking C shared module libldpc_t2.so
```
At runtime, to successfully use the T2 board, you need to install vendor specific drivers and tools.\
Please refer to the dedicated documentation at [LDPC_T2_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_T2_OFFLOAD_SETUP.md).
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1`
```
.......................
[CONFIG] loader.ldpc.shlibversion set to default value ""
[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
[CONFIG] shlibversion set to _t2 from command line
[CONFIG] loader.ldpc 1 options set from command line
shlib_path libldpc_t2.so
[LOADER] library libldpc_t2.so successfully loaded
........................
```
`libldpc_t2.so` has its decoder and its encoder implemented in [nrLDPC_coding_t2.c](file://../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c).
loading `libldpc_xdma.so` instead of `libldpc.so`:
`make ldpc_xdma` or `ninja ldpc_xdma`
This command creates the `libldpc_xdma.so` shared library.
```
ninja ldpc_xdma
[2/2] Linking C shared module libldpc_xdma.so
```
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg
At runtime, to successfully use the xdma, you need to install vendor specific drivers and tools.\
Please refer to the dedicated documentation at [LDPC_XDMA_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_XDMA_OFFLOAD_SETUP.md).
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2`
```
.......................
[CONFIG] loader.ldpc.shlibversion set to default value ""
[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
[CONFIG] shlibversion set to _optim8seg from command line
[CONFIG] shlibversion set to _xdma from command line
[CONFIG] loader.ldpc 1 options set from command line
shlib_path libldpc_xdma.so
[LOADER] library libldpc_xdma.so successfully loaded
........................
```
`libldpc_xdma.so` has its decoder implemented in [nrLDPC_coding_xdma.c](file://../nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c).\
Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c).
*Note: `libldpc_xdma.so` relies on a segment coding library for encoding.*
*The segment coding library is `libldpc.so` by default but it can be chosen with option `--nrLDPC_coding_xdma.encoder_shlibversion` followed by the library version - like with `--loder.ldpc.shlibversion` in the segment coding case above -*
#### Examples of ldpc shared lib selection when running ldpctest:
Slot coding libraries cannot be used yet within ldpctest.
But they can be used within nr_ulsim, nr_dlsim, nr_ulschsim and nr_dlschsim.\
In these PHY simulators, using the slot coding libraries is enabled in the exact same way as in nr-softmodem.
### LDPC libraries
Libraries implementing the slotwise LDPC coding must be named `libldpc<_version>.so`. They must implement four functions: `nrLDPC_coding_init`, `nrLDPC_coding_shutdown`, `nrLDPC_coding_decoder` and `nrLDPC_coding_encoder`. The prototypes for these functions is defined in [nrLDPC_coding_interface.h](file://../nrLDPC_coding/nrLDPC_coding_interface.h).
`libldpc.so` is completed.
`libldpc_t2.so` is completed.
`libldpc_xdma.so` is completed.
## LDPC segment coding
The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h).
The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time.
### Selecting the LDPC library at run time
By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below:
#### Examples of ldpc shared lib selection when running nr softmodem's:
loading `libldpc_optim8seg.so` instead of `libldpc_optim8segmulti.so`:
```
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _optim8seg
.......................
[CONFIG] nrLDPC_coding_segment.segment_shlibversion set to default value "_optim8segmulti"
[LIBCONFIG] nrLDPC_coding_segment: 1/1 parameters successfully set, (0 to default value)
[CONFIG] segment_shlibversion set to _optim8seg from command line
[CONFIG] nrLDPC_coding_segment 1 options set from command line
[LOADER] library libldpc_optim8seg.so successfully loaded
........................
```
......@@ -46,7 +159,7 @@ Built target ldpc_cl
At runtime, to successfully use hardware acceleration via OpenCL, you need to install vendor specific packages which deliver the required drivers and tools to make use of their GPU (Nvidia, Intel...) , fpga (Xilinx, Intel) or CPU (Intel, AMD, ARM...) through OpenCL.
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _cl`
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --nrLDPC_coding_segment.segment_shlibversion _cl`
```
------------------------------------------------
......@@ -81,12 +194,12 @@ At runtime, to successfully use hardware acceleration via OpenCL, you need to in
-----------------------------------------------------------------
```
`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --loader.ldpc.shlibversion _cl --log_config.hw_log_level info`
`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _cl --log_config.hw_log_level info`
```
............................................................
[CONFIG] shlibversion set to _cl from command line
[CONFIG] loader.ldpc 1 options set from command line
[CONFIG] segment_shlibversion set to _cl from command line
[CONFIG] nrLDPC_coding_segment 1 options set from command line
[LOADER] library libldpc_cl.so successfully loaded
[HW] Platform 0, OpenCL profile FULL_PROFILE
[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX
......@@ -118,7 +231,7 @@ At runtime, to successfully use hardware acceleration via OpenCL, you need to in
------------------------------------------------------------
```
A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v`option, which can be used to specify the version of the ldpc shared library to be used.
A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v` option, which can be used to specify the version of the ldpc shared library to be used.
#### Examples of ldpc shared lib selection when running ldpctest:
......
......@@ -403,7 +403,7 @@ int main(int argc, char *argv[])
{
short block_length=8448; // decoder supports length: 1201 -> 1280, 2401 -> 2560
// default to check output inside ldpc, the NR version checks the outer CRC defined by 3GPP
char *ldpc_version = NULL;
char *ldpc_version = "_optim8segmulti";
/* version of the ldpc decoder library to use (XXX suffix to use when loading libldpc_XXX.so */
short max_iterations=5;
int n_segments=1;
......
add_subdirectory(nrLDPC_coding_segment)
add_subdirectory(nrLDPC_coding_xdma)
add_subdirectory(nrLDPC_coding_t2)
/*
* 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 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h
* \brief interface for libraries implementing coding/decoding algorithms
*/
#include "PHY/defs_gNB.h"
#ifndef __NRLDPC_CODING_INTERFACE__H__
#define __NRLDPC_CODING_INTERFACE__H__
/**
* \typedef nrLDPC_segment_decoding_parameters_t
* \struct nrLDPC_segment_decoding_parameters_s
* \brief decoding parameter of segments
* \var E input llr segment size
* \var R code rate indication
* \var llr segment input llr array
* \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2)
* \var d_to_be_cleared
* pointer to the flag used to clear d properly
* when true, clear d after rate dematching
* \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2)
* \var decodeSuccess
* flag indicating that the decoding of the segment was successful
* IT MUST BE FILLED BY THE IMPLEMENTATION
* \var ts_deinterleave deinterleaving time stats
* \var ts_rate_unmatch rate unmatching time stats
* \var ts_ldpc_decode decoding time stats
*/
typedef struct nrLDPC_segment_decoding_parameters_s{
int E;
uint8_t R;
short *llr;
int16_t *d;
bool *d_to_be_cleared;
uint8_t *c;
bool decodeSuccess;
time_stats_t ts_deinterleave;
time_stats_t ts_rate_unmatch;
time_stats_t ts_ldpc_decode;
} nrLDPC_segment_decoding_parameters_t;
/**
* \typedef nrLDPC_TB_decoding_parameters_t
* \struct nrLDPC_TB_decoding_parameters_s
* \brief decoding parameter of transport blocks
* \var harq_unique_pid unique id of the HARQ process
* WARNING This id should be unique in the whole instance
* among the active HARQ processes for the duration of the process
* \var processedSegments
* pointer to the number of succesfully decoded segments
* it initially holds the total number of segments decoded after the previous HARQ round
* it finally holds the total number of segments decoded after the current HARQ round
* \var nb_rb number of resource blocks
* \var Qm modulation order
* \var mcs MCS
* \var nb_layers number of layers
* \var BG LDPC base graph id
* \var rv_index redundancy version of the current HARQ round
* \var max_ldpc_iterations maximum number of LDPC iterations
* \var abort_decode pointer to decode abort flag
* \var G Available radio resource bits
* \var tbslbrm Transport block size LBRM
* \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1)
* \var K Code block size at decoder output
* \var Z lifting size
* \var F filler bits size
* \var C number of segments
* \var segments array of segments parameters
*/
typedef struct nrLDPC_TB_decoding_parameters_s{
uint32_t harq_unique_pid;
uint32_t *processedSegments;
uint16_t nb_rb;
uint8_t Qm;
uint8_t mcs;
uint8_t nb_layers;
uint8_t BG;
uint8_t rv_index;
uint8_t max_ldpc_iterations;
decode_abort_t *abort_decode;
uint32_t G;
uint32_t tbslbrm;
uint32_t A;
uint32_t K;
uint32_t Z;
uint32_t F;
uint32_t C;
nrLDPC_segment_decoding_parameters_t *segments;
} nrLDPC_TB_decoding_parameters_t;
/**
* \typedef nrLDPC_slot_decoding_parameters_t
* \struct nrLDPC_slot_decoding_parameters_s
* \brief decoding parameter of slot
* \var frame frame index
* \var slot slot index
* \var nb_TBs number of transport blocks
* \var threadPool pointer to the thread pool
* The thread pool can be used by the implementation
* in order to launch jobs internally
* DEQUEUING THE JOBS IS DONE WITHIN THE IMPLEMENTATION
* \var TBs array of TBs decoding parameters
*/
typedef struct nrLDPC_slot_decoding_parameters_s{
int frame;
int slot;
int nb_TBs;
tpool_t *threadPool;
nrLDPC_TB_decoding_parameters_t *TBs;
} nrLDPC_slot_decoding_parameters_t;
/**
* \typedef nrLDPC_segment_encoding_parameters_t
* \struct nrLDPC_segment_encoding_parameters_s
* \brief encoding parameter of segments
* \var E input llr segment size
* \var output input llr segment array
* \var c Pointers to code blocks before LDPC encoding (38.212 V15.4.0 section 5.2.2)
* flag indicating that the decoding of the segment was successful
* IT MUST BE FILLED BY THE IMPLEMENTATION
* \var ts_interleave interleaving time stats
* \var ts_rate_match rate matching time stats
* \var ts_ldpc_encode encoding time stats
*/
typedef struct nrLDPC_segment_encoding_parameters_s{
int E;
unsigned char *output;
uint8_t *c;
time_stats_t ts_interleave;
time_stats_t ts_rate_match;
time_stats_t ts_ldpc_encode;
} nrLDPC_segment_encoding_parameters_t;
/**
* \typedef nrLDPC_TB_encoding_parameters_t
* \struct nrLDPC_TB_encoding_parameters_s
* \brief encoding parameter of transport blocks
* \var harq_unique_pid unique id of the HARQ process
* WARNING This id should be unique in the whole instance
* among the active HARQ processes for the duration of the process
* \var nb_rb number of resource blocks
* \var Qm modulation order
* \var mcs MCS
* \var nb_layers number of layers
* \var BG LDPC base graph id
* \var rv_index
* \var G Available radio resource bits
* \var tbslbrm Transport block size LBRM
* \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1)
* \var Kb Code block size divided by lifting size
* \var K Code block size at input of encoder
* \var Z lifting size
* \var F filler bits size
* \var C number of segments
* \var segments array of segments parameters
*/
typedef struct nrLDPC_TB_encoding_parameters_s{
uint32_t harq_unique_pid;
uint16_t nb_rb;
uint8_t Qm;
uint8_t mcs;
uint8_t nb_layers;
uint8_t BG;
uint8_t rv_index;
uint32_t G;
uint32_t tbslbrm;
uint32_t A;
uint32_t Kb;
uint32_t K;
uint32_t Z;
uint32_t F;
uint32_t C;
nrLDPC_segment_encoding_parameters_t *segments;
} nrLDPC_TB_encoding_parameters_t;
/**
* \typedef nrLDPC_slot_encoding_parameters_t
* \struct nrLDPC_slot_encoding_parameters_s
* \brief encoding parameter of slot
* \var frame frame index
* \var slot slot index
* \var nb_TBs number of transport blocks
* \var threadPool pointer to the thread pool
* The thread pool can be used by the implementation
* in order to launch jobs internally
* DEQUEUING THE JOBS IS DONE WITHIN THE IMPLEMENTATION
* \var tinput pointer to the input timer struct
* \var tprep pointer to the preparation timer struct
* \var tparity pointer to the parity timer struct
* \var toutput pointer to the output timer struct
* \var TBs array of TBs decoding parameters
*/
typedef struct nrLDPC_slot_encoding_parameters_s{
int frame;
int slot;
int nb_TBs;
tpool_t *threadPool;
time_stats_t *tinput;
time_stats_t *tprep;
time_stats_t *tparity;
time_stats_t *toutput;
nrLDPC_TB_encoding_parameters_t *TBs;
} nrLDPC_slot_encoding_parameters_t;
typedef int32_t(nrLDPC_coding_init_t)(void);
typedef int32_t(nrLDPC_coding_shutdown_t)(void);
/**
* \brief slot decoding function interface
* \param nrLDPC_slot_decoding_parameters pointer to the structure holding the parameters necessary for decoding
*/
typedef int32_t(nrLDPC_coding_decoder_t)(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters);
/**
* \brief slot encoding function interface
* \param nrLDPC_slot_encoding_parameters pointer to the structure holding the parameters necessary for encoding
*/
typedef int32_t(nrLDPC_coding_encoder_t)(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters);
typedef struct nrLDPC_coding_interface_s {
nrLDPC_coding_init_t *nrLDPC_coding_init;
nrLDPC_coding_shutdown_t *nrLDPC_coding_shutdown;
nrLDPC_coding_decoder_t *nrLDPC_coding_decoder;
nrLDPC_coding_encoder_t *nrLDPC_coding_encoder;
} nrLDPC_coding_interface_t;
int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *interface);
int free_nrLDPC_coding_interface(nrLDPC_coding_interface_t *interface);
#endif
/*
* 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 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c
* \brief load library implementing coding/decoding algorithms
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <stdlib.h>
#include <malloc.h>
#include "assertions.h"
#include "common/utils/LOG/log.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
/* arguments used when called from phy simulators exec's which do not use the config module */
/* arg is used to initialize the config module so that the loader works as expected */
char *arguments_phy_simulators[64]={"ldpctest",NULL};
int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *itf)
{
char *ptr = (char *)config_get_if();
char libname[64] = "ldpc";
if (ptr == NULL) { // phy simulators, config module possibly not loaded
uniqCfg = load_configmodule(1, arguments_phy_simulators, CONFIG_ENABLECMDLINEONLY);
logInit();
}
/* function description array, to be used when loading the encoding/decoding shared lib */
loader_shlibfunc_t shlib_fdesc[] = {{.fname = "nrLDPC_coding_init"},
{.fname = "nrLDPC_coding_shutdown"},
{.fname = "nrLDPC_coding_decoder"},
{.fname = "nrLDPC_coding_encoder"}};
int ret;
ret = load_module_version_shlib(libname, version, shlib_fdesc, sizeofArray(shlib_fdesc), NULL);
if(ret < 0){
LOG_D(PHY, "NR ULSCH decoding module unavailable");
return ret;
}
itf->nrLDPC_coding_init = (nrLDPC_coding_init_t *)shlib_fdesc[0].fptr;
itf->nrLDPC_coding_shutdown = (nrLDPC_coding_shutdown_t *)shlib_fdesc[1].fptr;
itf->nrLDPC_coding_decoder = (nrLDPC_coding_decoder_t *)shlib_fdesc[2].fptr;
itf->nrLDPC_coding_encoder = (nrLDPC_coding_encoder_t *)shlib_fdesc[3].fptr;
AssertFatal(itf->nrLDPC_coding_init() == 0, "error starting LDPC library %s %s\n", libname, version);
return 0;
}
int free_nrLDPC_coding_interface(nrLDPC_coding_interface_t *interface)
{
return interface->nrLDPC_coding_shutdown();
}
add_library(ldpc MODULE
nrLDPC_coding_segment_decoder.c
nrLDPC_coding_segment_encoder.c
${PHY_NR_CODINGIF}
)
set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(nr-softmodem ldpc)
add_dependencies(nr-uesoftmodem ldpc)
add_dependencies(nr_ulsim ldpc)
add_dependencies(nr_ulschsim ldpc)
add_dependencies(nr_dlsim ldpc)
add_dependencies(nr_dlschsim ldpc)
add_dependencies(ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti)
if (ENABLE_LDPC_CUDA)
add_dependencies(ldpc ldpc_cuda)
endif()
/*
* 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_decoder.c
* \brief Top-level routines for decoding LDPC transport channels
*/
// [from gNB coding]
#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_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_ulsch.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
#include "SCHED_NR/sched_nr.h"
#include "SCHED_NR/fapi_nr_l1.h"
#include "defs.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "common/utils/LOG/log.h"
#include <stdalign.h>
#include <stdint.h>
#include <syscall.h>
#include <time.h>
//#define gNB_DEBUG_TRACE
#define OAI_LDPC_DECODER_MAX_NUM_LLR 27000 //26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
//#define DEBUG_CRC
#ifdef DEBUG_CRC
#define PRINT_CRC_CHECK(a) a
#else
#define PRINT_CRC_CHECK(a)
#endif
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
/**
* \typedef nrLDPC_decoding_parameters_t
* \struct nrLDPC_decoding_parameters_s
* \brief decoding parameter of transport blocks
* \var decoderParms decoder parameters
* \var Qm modulation order
* \var Kc size of base graph input
* \var rv_index
* \var max_number_iterations maximum number of LDPC iterations
* \var abort_decode pointer to decode abort flag
* \var tbslbrm transport block size LBRM in bytes
* \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1)
* \var K Code block size at decoder output
* \var Z lifting size
* \var F filler bits size
* \var r segment index in TB
* \var E input llr segment size
* \var C number of segments
* \var llr input llr segment array
* \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2)
* \var d_to_be_cleared
* pointer to the flag used to clear d properly
* when true, clear d after rate dematching
* \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2)
* \var decodeSuccess pointer to the flag indicating that the decoding of the segment was successful
* \var ans pointer to task answer used by the thread pool to detect task completion
* \var p_ts_deinterleave pointer to deinterleaving time stats
* \var p_ts_rate_unmatch pointer to rate unmatching time stats
* \var p_ts_ldpc_decode pointer to decoding time stats
*/
typedef struct nrLDPC_decoding_parameters_s{
t_nrLDPC_dec_params decoderParms;
uint8_t Qm;
uint8_t Kc;
uint8_t rv_index;
decode_abort_t *abort_decode;
uint32_t tbslbrm;
uint32_t A;
uint32_t K;
uint32_t Z;
uint32_t F;
uint32_t C;
int E;
short *llr;
int16_t *d;
bool *d_to_be_cleared;
uint8_t *c;
bool *decodeSuccess;
task_ans_t *ans;
time_stats_t *p_ts_deinterleave;
time_stats_t *p_ts_rate_unmatch;
time_stats_t *p_ts_ldpc_decode;
} nrLDPC_decoding_parameters_t;
// Global var to limit the rework of the dirty legacy code
ldpc_interface_t ldpc_interface_segment;
static void nr_process_decode_segment(void *arg)
{
nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg;
t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms;
const int Kr = rdata->K;
const int Kr_bytes = Kr >> 3;
const int K_bits_F = Kr - rdata->F;
const int A = rdata->A;
const int E = rdata->E;
const int Qm = rdata->Qm;
const int rv_index = rdata->rv_index;
const uint8_t kc = rdata->Kc;
short *ulsch_llr = rdata->llr;
int8_t llrProcBuf[OAI_LDPC_DECODER_MAX_NUM_LLR] __attribute__((aligned(32)));
t_nrLDPC_time_stats procTime = {0};
t_nrLDPC_time_stats *p_procTime = &procTime;
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// nr_deinterleaving_ldpc ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// ulsch_llr =====> ulsch_harq->e //////////////////////////////
start_meas(rdata->p_ts_deinterleave);
/// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1)
int16_t harq_e[E];
nr_deinterleaving_ldpc(E, Qm, harq_e, ulsch_llr);
//////////////////////////////////////////////////////////////////////////////////////////
stop_meas(rdata->p_ts_deinterleave);
start_meas(rdata->p_ts_rate_unmatch);
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// nr_rate_matching_ldpc_rx ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
///////////////////////// ulsch_harq->e =====> ulsch_harq->d /////////////////////////
if (nr_rate_matching_ldpc_rx(rdata->tbslbrm,
p_decoderParms->BG,
p_decoderParms->Z,
rdata->d,
harq_e,
rdata->C,
rv_index,
*rdata->d_to_be_cleared,
E,
rdata->F,
Kr - rdata->F - 2 * (p_decoderParms->Z))
== -1) {
stop_meas(rdata->p_ts_rate_unmatch);
LOG_E(PHY, "nrLDPC_coding_segment_decoder.c: Problem in rate_matching\n");
// Task completed
completed_task_ans(rdata->ans);
return;
}
stop_meas(rdata->p_ts_rate_unmatch);
*rdata->d_to_be_cleared = false;
memset(rdata->c, 0, Kr_bytes);
p_decoderParms->crc_type = crcType(rdata->C, A);
p_decoderParms->E = lenWithCrc(rdata->C, A);
// set first 2*Z_c bits to zeros
int16_t z[68 * 384 + 16] __attribute__((aligned(16)));
start_meas(rdata->p_ts_ldpc_decode);
memset(z, 0, 2 * rdata->Z * sizeof(*z));
// set Filler bits
memset(z + K_bits_F, 127, rdata->F * sizeof(*z));
// Move coded bits before filler bits
memcpy(z + 2 * rdata->Z, rdata->d, (K_bits_F - 2 * rdata->Z) * sizeof(*z));
// skip filler bits
memcpy(z + Kr, rdata->d + (Kr - 2 * rdata->Z), (kc * rdata->Z - Kr) * sizeof(*z));
// Saturate coded bits before decoding into 8 bits values
simde__m128i *pv = (simde__m128i *)&z;
int8_t l[68 * 384 + 16] __attribute__((aligned(16)));
simde__m128i *pl = (simde__m128i *)&l;
for (int i = 0, j = 0; j < ((kc * rdata->Z) >> 4) + 1; i += 2, j++) {
pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// nrLDPC_decoder /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// pl =====> llrProcBuf //////////////////////////////////
int decodeIterations =
ldpc_interface_segment.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode);
if (decodeIterations <= p_decoderParms->numMaxIter) {
memcpy(rdata->c,llrProcBuf, Kr>>3);
*rdata->decodeSuccess = true;
} else {
*rdata->decodeSuccess = false;
}
stop_meas(rdata->p_ts_ldpc_decode);
// Task completed
completed_task_ans(rdata->ans);
}
int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int pusch_id, thread_info_tm_t *t_info)
{
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id];
*nrLDPC_TB_decoding_parameters->processedSegments = 0;
t_nrLDPC_dec_params decParams = {.check_crc = check_crc};
decParams.BG = nrLDPC_TB_decoding_parameters->BG;
decParams.Z = nrLDPC_TB_decoding_parameters->Z;
decParams.numMaxIter = nrLDPC_TB_decoding_parameters->max_ldpc_iterations;
decParams.outMode = 0;
for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) {
nrLDPC_decoding_parameters_t *rdata = &((nrLDPC_decoding_parameters_t *)t_info->buf)[t_info->len];
DevAssert(t_info->len < t_info->cap);
rdata->ans = &t_info->ans[t_info->len];
t_info->len += 1;
decParams.R = nrLDPC_TB_decoding_parameters->segments[r].R;
decParams.setCombIn = !nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared;
rdata->decoderParms = decParams;
rdata->llr = nrLDPC_TB_decoding_parameters->segments[r].llr;
rdata->Kc = decParams.BG == 2 ? 52 : 68;
rdata->C = nrLDPC_TB_decoding_parameters->C;
rdata->E = nrLDPC_TB_decoding_parameters->segments[r].E;
rdata->A = nrLDPC_TB_decoding_parameters->A;
rdata->Qm = nrLDPC_TB_decoding_parameters->Qm;
rdata->K = nrLDPC_TB_decoding_parameters->K;
rdata->Z = nrLDPC_TB_decoding_parameters->Z;
rdata->F = nrLDPC_TB_decoding_parameters->F;
rdata->rv_index = nrLDPC_TB_decoding_parameters->rv_index;
rdata->tbslbrm = nrLDPC_TB_decoding_parameters->tbslbrm;
rdata->abort_decode = nrLDPC_TB_decoding_parameters->abort_decode;
rdata->d = nrLDPC_TB_decoding_parameters->segments[r].d;
rdata->d_to_be_cleared = nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared;
rdata->c = nrLDPC_TB_decoding_parameters->segments[r].c;
rdata->decodeSuccess = &nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess;
rdata->p_ts_deinterleave = &nrLDPC_TB_decoding_parameters->segments[r].ts_deinterleave;
rdata->p_ts_rate_unmatch = &nrLDPC_TB_decoding_parameters->segments[r].ts_rate_unmatch;
rdata->p_ts_ldpc_decode = &nrLDPC_TB_decoding_parameters->segments[r].ts_ldpc_decode;
task_t t = {.func = &nr_process_decode_segment, .args = rdata};
pushTpool(nrLDPC_slot_decoding_parameters->threadPool, t);
LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r);
}
return nrLDPC_TB_decoding_parameters->C;
}
int32_t nrLDPC_coding_init(void){
char *segment_shlibversion = NULL;
paramdef_t LoaderParams[] = {
{"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL}
};
config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_segment");
load_LDPClib(segment_shlibversion, &ldpc_interface_segment);
return 0;
}
int32_t nrLDPC_coding_shutdown(void){
free_LDPClib(&ldpc_interface_segment);
return 0;
}
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){
int nbSegments = 0;
for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) {
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id];
nbSegments += nrLDPC_TB_decoding_parameters->C;
}
nrLDPC_decoding_parameters_t arr[nbSegments];
task_ans_t ans[nbSegments];
memset(ans, 0, nbSegments * sizeof(task_ans_t));
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbSegments, .ans = ans};
int nbDecode = 0;
for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) {
nbDecode += nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters, pusch_id, &t_info);
}
DevAssert(nbDecode == t_info.len);
// Execute thread poool tasks
join_task_ans(t_info.ans, t_info.len);
for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) {
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id];
for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) {
if (nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess) {
*nrLDPC_TB_decoding_parameters->processedSegments = *nrLDPC_TB_decoding_parameters->processedSegments + 1;
}
}
}
return 0;
}
/*
* 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 "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 ldpc_interface_t ldpc_interface_segment;
typedef struct ldpc8blocks_args_s {
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters;
encoder_implemparams_t impp;
} ldpc8blocks_args_t;
static void ldpc8blocks_coding_segment(void *p)
{
ldpc8blocks_args_t *args = (ldpc8blocks_args_t *)p;
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = args->nrLDPC_TB_encoding_parameters;
encoder_implemparams_t *impp = &args->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 Kr %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!
uint8_t tmp[8][68 * 384]__attribute__((aligned(32)));
uint8_t *d[impp->n_segments];
for (int rr=impp->macro_num*8, i=0; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++,i++ )
d[rr] = tmp[i];
uint8_t *c[nrLDPC_TB_encoding_parameters->C];
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->macro_num*8].ts_ldpc_encode);
ldpc_interface_segment.LDPCencoder(c, d, impp);
stop_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num*8].ts_ldpc_encode);
// Compute where to place in output buffer that is concatenation of all segments
uint32_t r_offset=0;
for (int i=0; i < impp->macro_num*8; i++ )
r_offset+=nrLDPC_TB_encoding_parameters->segments[i].E;
for (int rr=impp->macro_num*8; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++ ) {
if (impp->F>0) {
// writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212
memset(&d[rr][impp->K - impp->F - 2 * impp->Zc], NR_NULL, impp->F);
}
#ifdef DEBUG_LDPC_ENCODING
LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]);
#endif
uint32_t E = nrLDPC_TB_encoding_parameters->segments[rr].E;
LOG_D(NR_PHY,
"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb "
"%d,nrOfLayer %d)...\n",
rr,
impp->n_segments,
G,
E,
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;
uint8_t e[E];
bzero (e, E);
start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match);
nr_rate_matching_ldpc(Tbslbrm,
impp->BG,
impp->Zc,
d[rr],
e,
impp->n_segments,
impp->F,
impp->K - impp->F - 2 * impp->Zc,
nrLDPC_TB_encoding_parameters->rv_index,
E);
stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].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 segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, "
"nb_rb %d)...\n",
rr,
impp->n_segments,
G,
E,
impp->K,
impp->F,
impp->K - impp->F - 2 * impp->Zc,
mod_order,
nb_rb);
}
#ifdef DEBUG_LDPC_ENCODING
for (int i =0; i<16; i++)
printf("output ratematching e[%d]= %d r_offset %u\n", i,e[i], r_offset);
#endif
start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave);
nr_interleaving_ldpc(E,
mod_order,
e,
impp->output+r_offset);
stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave);
#ifdef DEBUG_LDPC_ENCODING
for (int i =0; i<16; i++)
printf("output interleaving f[%d]= %d r_offset %u\n", i,impp->output[i+r_offset], r_offset);
if (r==impp->n_segments-1)
write_output("enc_output.m","enc",impp->output,G,1,4);
#endif
r_offset += E;
}
// Task running in // completed
completed_task_ans(impp->ans);
}
static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int dlsch_id, thread_info_tm_t *t_info)
{
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
encoder_implemparams_t impp = {0};
impp.n_segments = nrLDPC_TB_encoding_parameters->C;
impp.tinput = nrLDPC_slot_encoding_parameters->tinput;
impp.tprep = nrLDPC_slot_encoding_parameters->tprep;
impp.tparity = nrLDPC_slot_encoding_parameters->tparity;
impp.toutput = nrLDPC_slot_encoding_parameters->toutput;
impp.Kb = nrLDPC_TB_encoding_parameters->Kb;
impp.Zc = nrLDPC_TB_encoding_parameters->Z;
NR_DL_gNB_HARQ_t harq;
impp.harq = &harq;
impp.BG = nrLDPC_TB_encoding_parameters->BG;
impp.output = nrLDPC_TB_encoding_parameters->segments->output;
impp.K = nrLDPC_TB_encoding_parameters->K;
impp.F = nrLDPC_TB_encoding_parameters->F;
size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1));
for (int j = 0; j < n_seg; j++) {
ldpc8blocks_args_t *perJobImpp = &((ldpc8blocks_args_t *)t_info->buf)[t_info->len];
DevAssert(t_info->len < t_info->cap);
impp.ans = &t_info->ans[t_info->len];
t_info->len += 1;
impp.macro_num = j;
perJobImpp->impp = impp;
perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters;
task_t t = {.func = ldpc8blocks_coding_segment, .args = perJobImpp};
pushTpool(nrLDPC_slot_encoding_parameters->threadPool, t);
}
return n_seg;
}
int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
int 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];
size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1));
nbTasks += n_seg;
}
ldpc8blocks_args_t arr[nbTasks];
task_ans_t ans[nbTasks];
memset(ans, 0, nbTasks * sizeof(task_ans_t));
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbTasks, .ans = ans};
int nbEncode = 0;
for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) {
nbEncode += nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info);
}
DevAssert(nbEncode == t_info.len);
// Execute thread poool tasks
join_task_ans(ans, nbEncode);
return 0;
}
##########################################################
# LDPC offload library - AMD T2 Accelerator Card
##########################################################
add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF)
if (ENABLE_LDPC_T2)
pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk=20.11.9)
find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS})
if (NOT PMD_T2)
message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)")
endif()
message(STATUS "T2 build: use ${PMD_T2}")
add_library(ldpc_t2 MODULE nrLDPC_coding_t2.c)
set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API")
set_target_properties(ldpc_t2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2})
add_dependencies(nr-softmodem ldpc_t2)
add_dependencies(nr-uesoftmodem ldpc_t2)
add_dependencies(nr_ulsim ldpc_t2)
add_dependencies(nr_ulschsim ldpc_t2)
add_dependencies(nr_dlsim ldpc_t2)
add_dependencies(nr_dlschsim ldpc_t2)
endif()
......@@ -2,43 +2,32 @@
* Copyright(c) 2017 Intel Corporation
*/
/*!\file nrLDPC_decoder_offload.c
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c
* \note: based on testbbdev test_bbdev_perf.c functions. Harq buffer offset added.
* \mbuf and mempool allocated at the init step, LDPC parameters updated from OAI.
*/
#include <stdint.h>
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h"
#include "PHY/sse_intrin.h"
#include "nrLDPCdecoder_defs.h"
#include "nrLDPC_types.h"
#include "nrLDPC_init.h"
#include "nrLDPC_mPass.h"
#include "nrLDPC_cnProc.h"
#include "nrLDPC_bnProc.h"
#include <common/utils/LOG/log.h>
#define NR_LDPC_ENABLE_PARITY_CHECK
#ifdef NR_LDPC_DEBUG_MODE
#include "nrLDPC_tools/nrLDPC_debug.h"
#endif
#include "openair1/PHY/CODING/nrLDPC_extern.h"
#include <stdint.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <rte_eal.h>
#include <rte_common.h>
#include <rte_string_fns.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_pdump.h>
#include "nrLDPC_offload.h"
#include <math.h>
#include <rte_dev.h>
#include <rte_launch.h>
......@@ -60,6 +49,8 @@
#define HARQ_INCR 32768
/* Headroom for filler LLRs insertion in HARQ buffer */
#define FILLER_HEADROOM 1024
/* Number of segments that could be stored in HARQ combined buffers */
#define HARQ_CODEBLOCK_ID_MAX (16 << 5)
pthread_mutex_t encode_mutex;
pthread_mutex_t decode_mutex;
......@@ -119,10 +110,9 @@ struct thread_params {
uint8_t dev_id;
uint16_t queue_id;
uint32_t lcore_id;
struct nrLDPCoffload_params *p_offloadParams;
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters;
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters;
uint8_t iter_count;
uint8_t *p_out;
uint8_t ulsch_id;
rte_atomic16_t nb_dequeued;
rte_atomic16_t processing_status;
rte_atomic16_t burst_sz;
......@@ -131,6 +121,24 @@ struct thread_params {
struct rte_bbdev_enc_op *enc_ops[MAX_BURST];
};
static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) {
uint16_t nb_segments = 0;
for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h)
{
nb_segments+=nrLDPC_slot_decoding_parameters->TBs[h].C;
}
return nb_segments;
}
static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) {
uint16_t nb_segments = 0;
for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h)
{
nb_segments+=nrLDPC_slot_encoding_parameters->TBs[h].C;
}
return nb_segments;
}
// DPDK BBDEV copy
static inline void
mbuf_reset(struct rte_mbuf *m)
......@@ -179,7 +187,11 @@ static int create_mempools(struct active_device *ad, int socket_id, uint16_t num
ops_pool_size, OPS_CACHE_SIZE, socket_id);
if ((ad->bbdev_dec_op_pool == NULL) || (ad->bbdev_enc_op_pool == NULL))
AssertFatal(1 == 0, "ERROR Failed to create %u items ops pool for dev %u on socket %d.", ops_pool_size, ad->dev_id, socket_id);
AssertFatal(1 == 0,
"ERROR Failed to create %u items ops pool for dev %u on socket %d.",
ops_pool_size,
ad->dev_id,
socket_id);
/* Inputs */
mbuf_pool_size = optimal_mempool_size(ops_pool_size * nb_segments);
......@@ -187,9 +199,9 @@ static int create_mempools(struct active_device *ad, int socket_id, uint16_t num
ad->in_mbuf_pool = rte_pktmbuf_pool_create("in_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id);
AssertFatal(ad->in_mbuf_pool != NULL,
"ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %d.",
mbuf_pool_size,
ad->dev_id,
socket_id);
mbuf_pool_size,
ad->dev_id,
socket_id);
/* Hard outputs */
data_room_size = RTE_MAX(out_buff_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE);
......@@ -329,7 +341,7 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info)
for (queue_id = 0; queue_id < nb_queues; ++queue_id) {
ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf);
if (ret == 0) {
printf("Found LDCP encoding queue (id=%d) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id);
printf("Found LDCP encoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id);
qconf.priority++;
ad->enc_queue = queue_id;
ad->queue_ids[queue_id] = queue_id;
......@@ -343,7 +355,7 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info)
for (queue_id++; queue_id < nb_queues; ++queue_id) {
ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf);
if (ret == 0) {
printf("Found LDCP decoding queue (id=%d) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id);
printf("Found LDCP decoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id);
qconf.priority++;
ad->dec_queue = queue_id;
ad->queue_ids[queue_id] = queue_id;
......@@ -358,52 +370,55 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info)
// based on DPDK BBDEV init_op_data_objs
static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs,
uint8_t *input,
t_nrLDPCoffload_params *offloadParams,
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters,
struct rte_mempool *mbuf_pool,
const uint16_t n,
enum op_data_type op_type,
uint16_t min_alignment)
{
bool large_input = false;
for (int i = 0; i < n; ++i) {
uint32_t data_len = offloadParams->perCB[i].E_cb;
char *data;
struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
AssertFatal(m_head != NULL,
"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
op_type,
n,
mbuf_pool->size);
if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) {
printf("Warning: Larger input size than DPDK mbuf %u\n", data_len);
large_input = true;
}
bufs[i].data = m_head;
bufs[i].offset = 0;
bufs[i].length = 0;
if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) {
if ((op_type == DATA_INPUT) && large_input) {
/* Allocate a fake overused mbuf */
data = rte_malloc(NULL, data_len, 0);
AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len);
memcpy(data, &input[i * LDPC_MAX_CB_SIZE], data_len);
m_head->buf_addr = data;
m_head->buf_iova = rte_malloc_virt2iova(data);
m_head->data_off = 0;
m_head->data_len = data_len;
} else {
rte_pktmbuf_reset(m_head);
data = rte_pktmbuf_append(m_head, data_len);
AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type);
AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment),
"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
data,
min_alignment);
rte_memcpy(data, &input[i * LDPC_MAX_CB_SIZE], data_len);
uint16_t j = 0;
for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) {
for (uint16_t i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) {
uint32_t data_len = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E;
char *data;
struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
AssertFatal(m_head != NULL,
"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
op_type,
nb_segments_decoding(nrLDPC_slot_decoding_parameters),
mbuf_pool->size);
if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) {
printf("Warning: Larger input size than DPDK mbuf %u\n", data_len);
large_input = true;
}
bufs[i].length += data_len;
bufs[j].data = m_head;
bufs[j].offset = 0;
bufs[j].length = 0;
if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) {
if ((op_type == DATA_INPUT) && large_input) {
/* Allocate a fake overused mbuf */
data = rte_malloc(NULL, data_len, 0);
AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len);
memcpy(data, &input[j * LDPC_MAX_CB_SIZE], data_len);
m_head->buf_addr = data;
m_head->buf_iova = rte_malloc_virt2iova(data);
m_head->data_off = 0;
m_head->data_len = data_len;
} else {
rte_pktmbuf_reset(m_head);
data = rte_pktmbuf_append(m_head, data_len);
AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type);
AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment),
"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
data,
min_alignment);
rte_memcpy(data, &input[j * LDPC_MAX_CB_SIZE], data_len);
}
bufs[j].length += data_len;
}
++j;
}
}
return 0;
......@@ -411,59 +426,62 @@ static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs,
// based on DPDK BBDEV init_op_data_objs
static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs,
uint8_t **input_enc,
t_nrLDPCoffload_params *offloadParams,
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters,
struct rte_mbuf *m_head,
struct rte_mempool *mbuf_pool,
const uint16_t n,
enum op_data_type op_type,
uint16_t min_alignment)
{
bool large_input = false;
for (int i = 0; i < n; ++i) {
uint32_t data_len = offloadParams->Kr;
char *data;
struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
AssertFatal(m_head != NULL,
"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
op_type,
n,
mbuf_pool->size);
if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) {
printf("Warning: Larger input size than DPDK mbuf %u\n", data_len);
large_input = true;
}
bufs[i].data = m_head;
bufs[i].offset = 0;
bufs[i].length = 0;
if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) {
if ((op_type == DATA_INPUT) && large_input) {
/* Allocate a fake overused mbuf */
data = rte_malloc(NULL, data_len, 0);
AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len);
memcpy(data, &input_enc[0], data_len);
m_head->buf_addr = data;
m_head->buf_iova = rte_malloc_virt2iova(data);
m_head->data_off = 0;
m_head->data_len = data_len;
} else {
rte_pktmbuf_reset(m_head);
data = rte_pktmbuf_append(m_head, data_len);
AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type);
AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment),
"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
data,
min_alignment);
rte_memcpy(data, input_enc[i], data_len);
uint16_t j = 0;
for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) {
for (int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) {
uint32_t data_len = (nrLDPC_slot_encoding_parameters->TBs[h].K - nrLDPC_slot_encoding_parameters->TBs[h].F + 7) / 8;
char *data;
struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
AssertFatal(m_head != NULL,
"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
op_type,
nb_segments_encoding(nrLDPC_slot_encoding_parameters),
mbuf_pool->size);
if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) {
printf("Warning: Larger input size than DPDK mbuf %u\n", data_len);
large_input = true;
}
bufs[i].length += data_len;
bufs[j].data = m_head;
bufs[j].offset = 0;
bufs[j].length = 0;
if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) {
if ((op_type == DATA_INPUT) && large_input) {
/* Allocate a fake overused mbuf */
data = rte_malloc(NULL, data_len, 0);
AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len);
memcpy(data, nrLDPC_slot_encoding_parameters->TBs[h].segments[i].c, data_len);
m_head->buf_addr = data;
m_head->buf_iova = rte_malloc_virt2iova(data);
m_head->data_off = 0;
m_head->data_len = data_len;
} else {
rte_pktmbuf_reset(m_head);
data = rte_pktmbuf_append(m_head, data_len);
AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type);
AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment),
"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
data,
min_alignment);
rte_memcpy(data, nrLDPC_slot_encoding_parameters->TBs[h].segments[i].c, data_len);
}
bufs[j].length += data_len;
}
++j;
}
}
return 0;
}
// DPDK BBEV copy
static int allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len, const int socket)
{
......@@ -507,111 +525,140 @@ free_buffers(struct active_device *ad, struct test_op_params *op_params)
}
// based on DPDK BBDEV copy_reference_ldpc_dec_op
static void set_ldpc_dec_op(struct rte_bbdev_dec_op **ops,
unsigned int start_idx,
struct data_buffers *bufs,
uint8_t ulsch_id,
t_nrLDPCoffload_params *p_offloadParams)
static void
set_ldpc_dec_op(struct rte_bbdev_dec_op **ops,
unsigned int start_idx,
struct data_buffers *bufs,
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters)
{
unsigned int h;
unsigned int i;
for (i = 0; i < p_offloadParams->C; ++i) {
ops[i]->ldpc_dec.cb_params.e = p_offloadParams->perCB[i].E_cb;
ops[i]->ldpc_dec.basegraph = p_offloadParams->BG;
ops[i]->ldpc_dec.z_c = p_offloadParams->Z;
ops[i]->ldpc_dec.q_m = p_offloadParams->Qm;
ops[i]->ldpc_dec.n_filler = p_offloadParams->F;
ops[i]->ldpc_dec.n_cb = p_offloadParams->n_cb;
ops[i]->ldpc_dec.iter_max = p_offloadParams->numMaxIter;
ops[i]->ldpc_dec.rv_index = p_offloadParams->rv;
ops[i]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE |
RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE |
RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE |
RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE;
if (p_offloadParams->setCombIn) {
ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE;
}
if (p_offloadParams->C > 1) {
ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP;
ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK;
unsigned int j = 0;
for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){
for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) {
ops[j]->ldpc_dec.cb_params.e = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E;
ops[j]->ldpc_dec.basegraph = nrLDPC_slot_decoding_parameters->TBs[h].BG;
ops[j]->ldpc_dec.z_c = nrLDPC_slot_decoding_parameters->TBs[h].Z;
ops[j]->ldpc_dec.q_m = nrLDPC_slot_decoding_parameters->TBs[h].Qm;
ops[j]->ldpc_dec.n_filler = nrLDPC_slot_decoding_parameters->TBs[h].F;
ops[j]->ldpc_dec.n_cb = (nrLDPC_slot_decoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_decoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_decoding_parameters->TBs[h].Z);
ops[j]->ldpc_dec.iter_max = nrLDPC_slot_decoding_parameters->TBs[h].max_ldpc_iterations;
ops[j]->ldpc_dec.rv_index = nrLDPC_slot_decoding_parameters->TBs[h].rv_index;
ops[j]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE |
RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE |
RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE |
RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE;
if (*nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared) {
*nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared = false;
*nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = 0;
} else {
ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE;
}
if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) {
ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP;
ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK;
}
ops[j]->ldpc_dec.code_block_mode = 1;
ops[j]->ldpc_dec.harq_combined_input.offset = (((nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) % HARQ_CODEBLOCK_ID_MAX) + i) * LDPC_MAX_CB_SIZE;
ops[j]->ldpc_dec.harq_combined_output.offset = (((nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) % HARQ_CODEBLOCK_ID_MAX) + i) * LDPC_MAX_CB_SIZE;
if (bufs->hard_outputs != NULL)
ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + j];
if (bufs->inputs != NULL)
ops[j]->ldpc_dec.input = bufs->inputs[start_idx + j];
if (bufs->soft_outputs != NULL)
ops[j]->ldpc_dec.soft_output = bufs->soft_outputs[start_idx + j];
if (bufs->harq_inputs != NULL)
ops[j]->ldpc_dec.harq_combined_input = bufs->harq_inputs[start_idx + j];
if (bufs->harq_outputs != NULL)
ops[j]->ldpc_dec.harq_combined_output = bufs->harq_outputs[start_idx + j];
++j;
}
ops[i]->ldpc_dec.code_block_mode = 1;
ops[i]->ldpc_dec.harq_combined_input.offset = ulsch_id * NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE + i * LDPC_MAX_CB_SIZE;
ops[i]->ldpc_dec.harq_combined_output.offset = ulsch_id * NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE + i * LDPC_MAX_CB_SIZE;
if (bufs->hard_outputs != NULL)
ops[i]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + i];
if (bufs->inputs != NULL)
ops[i]->ldpc_dec.input = bufs->inputs[start_idx + i];
if (bufs->soft_outputs != NULL)
ops[i]->ldpc_dec.soft_output = bufs->soft_outputs[start_idx + i];
if (bufs->harq_inputs != NULL)
ops[i]->ldpc_dec.harq_combined_input = bufs->harq_inputs[start_idx + i];
if (bufs->harq_outputs != NULL)
ops[i]->ldpc_dec.harq_combined_output = bufs->harq_outputs[start_idx + i];
}
}
// based on DPDK BBDEV copy_reference_ldpc_enc_op
static void set_ldpc_enc_op(struct rte_bbdev_enc_op **ops,
unsigned int start_idx,
struct rte_bbdev_op_data *inputs,
struct rte_bbdev_op_data *outputs,
t_nrLDPCoffload_params *p_offloadParams)
static void
set_ldpc_enc_op(struct rte_bbdev_enc_op **ops,
unsigned int start_idx,
struct rte_bbdev_op_data *inputs,
struct rte_bbdev_op_data *outputs,
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
for (int i = 0; i < p_offloadParams->C; ++i) {
ops[i]->ldpc_enc.cb_params.e = p_offloadParams->perCB[i].E_cb;
ops[i]->ldpc_enc.basegraph = p_offloadParams->BG;
ops[i]->ldpc_enc.z_c = p_offloadParams->Z;
ops[i]->ldpc_enc.q_m = p_offloadParams->Qm;
ops[i]->ldpc_enc.n_filler = p_offloadParams->F;
ops[i]->ldpc_enc.n_cb = p_offloadParams->n_cb;
ops[i]->ldpc_enc.rv_index = p_offloadParams->rv;
ops[i]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH;
ops[i]->ldpc_enc.code_block_mode = 1;
ops[i]->ldpc_enc.output = outputs[start_idx + i];
ops[i]->ldpc_enc.input = inputs[start_idx + i];
unsigned int h;
unsigned int i;
unsigned int j = 0;
for (h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){
for (i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) {
ops[j]->ldpc_enc.cb_params.e = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E;
ops[j]->ldpc_enc.basegraph = nrLDPC_slot_encoding_parameters->TBs[h].BG;
ops[j]->ldpc_enc.z_c = nrLDPC_slot_encoding_parameters->TBs[h].Z;
ops[j]->ldpc_enc.q_m = nrLDPC_slot_encoding_parameters->TBs[h].Qm;
ops[j]->ldpc_enc.n_filler = nrLDPC_slot_encoding_parameters->TBs[h].F;
ops[j]->ldpc_enc.n_cb = (nrLDPC_slot_encoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_encoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_encoding_parameters->TBs[h].Z);
if (nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm != 0) {
uint32_t Nref = 3 * nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm / (2 * nrLDPC_slot_encoding_parameters->TBs[h].C);
ops[j]->ldpc_enc.n_cb = min(ops[j]->ldpc_enc.n_cb, Nref);
}
ops[j]->ldpc_enc.rv_index = nrLDPC_slot_encoding_parameters->TBs[h].rv_index;
ops[j]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH;
ops[j]->ldpc_enc.code_block_mode = 1;
ops[j]->ldpc_enc.output = outputs[start_idx + j];
ops[j]->ldpc_enc.input = inputs[start_idx + j];
++j;
}
}
}
static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, const uint16_t n, const int vector_mask, uint8_t *p_out)
static int
retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops,
const int vector_mask,
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters)
{
struct rte_bbdev_op_data *hard_output;
uint16_t data_len = 0;
struct rte_mbuf *m;
unsigned int i;
char *data;
int offset = 0;
for (i = 0; i < n; ++i) {
hard_output = &ops[i]->ldpc_dec.hard_output;
m = hard_output->data;
data_len = rte_pktmbuf_data_len(m) - hard_output->offset;
data = m->buf_addr;
memcpy(&p_out[offset], data + m->data_off, data_len);
offset += data_len;
rte_pktmbuf_free(ops[i]->ldpc_dec.hard_output.data);
rte_pktmbuf_free(ops[i]->ldpc_dec.input.data);
unsigned int h;
unsigned int i;
unsigned int j = 0;
for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){
for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) {
hard_output = &ops[j]->ldpc_dec.hard_output;
m = hard_output->data;
data_len = rte_pktmbuf_data_len(m) - hard_output->offset;
data = m->buf_addr;
memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data + m->data_off, data_len);
rte_pktmbuf_free(ops[j]->ldpc_dec.hard_output.data);
rte_pktmbuf_free(ops[j]->ldpc_dec.input.data);
++j;
}
}
return 0;
}
static int retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, const uint16_t n, uint8_t *p_out, nrLDPC_params_per_cb_t *perCB)
static int
retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops,
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
int offset = 0;
for (int i = 0; i < n; ++i) {
struct rte_bbdev_op_data *output = &ops[i]->ldpc_enc.output;
struct rte_mbuf *m = output->data;
uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset;
uint8_t *out = &p_out[offset];
const char *data = m->buf_addr + m->data_off;
const char *end = data + data_len;
while (data < end) {
uint8_t byte = *data++; // get the current byte
for (int bit = 7; bit >= 0; --bit) {
*out++ = (byte >> bit) & 1; // extract each bit
unsigned int j = 0;
for (unsigned int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){
for (unsigned int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) {
struct rte_bbdev_op_data *output = &ops[j]->ldpc_enc.output;
struct rte_mbuf *m = output->data;
uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset;
uint8_t *out = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].output;
const char *data = m->buf_addr + m->data_off;
const char *end = data + data_len;
while (data < end) {
uint8_t byte = *data++; // get the current byte
for (int bit = 7; bit >= 0; --bit) {
*out++ = (byte >> bit) & 1; // extract each bit
}
}
rte_pktmbuf_free(m);
rte_pktmbuf_free(ops[j]->ldpc_enc.input.data);
++j;
}
offset += perCB[i].E_cb;
rte_pktmbuf_free(m);
rte_pktmbuf_free(ops[i]->ldpc_enc.input.data);
}
return 0;
}
......@@ -629,7 +676,7 @@ static int init_test_op_params(struct test_op_params *op_params,
ret = rte_bbdev_dec_op_alloc_bulk(ops_mp, &op_params->ref_dec_op, num_to_process);
op_params->mp_dec = ops_mp;
} else {
ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, num_to_process);
ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, 1);
op_params->mp_enc = ops_mp;
}
......@@ -646,29 +693,31 @@ static int
pmd_lcore_ldpc_dec(void *arg)
{
struct thread_params *tp = arg;
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters = tp->nrLDPC_slot_decoding_parameters;
uint16_t enq, deq;
int time_out = 0;
const uint16_t queue_id = tp->queue_id;
const uint16_t num_segments = tp->p_offloadParams->C;
struct rte_bbdev_dec_op *ops_enq[num_segments];
struct rte_bbdev_dec_op *ops_deq[num_segments];
uint8_t ulsch_id = tp->ulsch_id;
const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters);
struct rte_bbdev_dec_op **ops_enq;
struct rte_bbdev_dec_op **ops_deq;
ops_enq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE);
ops_deq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE);
struct data_buffers *bufs = NULL;
int i, ret;
uint16_t h, i, j;
int ret;
struct rte_bbdev_info info;
uint16_t num_to_enq;
uint8_t *p_out = tp->p_out;
t_nrLDPCoffload_params *p_offloadParams = tp->p_offloadParams;
AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST);
rte_bbdev_info_get(tp->dev_id, &info);
bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
rte_pause();
ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp_dec, ops_enq, num_segments);
AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments);
set_ldpc_dec_op(ops_enq, 0, bufs, ulsch_id, p_offloadParams);
set_ldpc_dec_op(ops_enq, 0, bufs, nrLDPC_slot_decoding_parameters);
for (enq = 0, deq = 0; enq < num_segments;) {
num_to_enq = num_segments;
......@@ -686,19 +735,45 @@ pmd_lcore_ldpc_dec(void *arg)
DevAssert(time_out <= TIME_OUT_POLL);
}
if (deq == enq) {
ret = retrieve_ldpc_dec_op(ops_deq, tp->op_params->vector_mask, nrLDPC_slot_decoding_parameters);
AssertFatal(ret == 0, "LDPC offload decoder failed!");
tp->iter_count = 0;
/* get the max of iter_count for all dequeued ops */
for (i = 0; i < num_segments; ++i) {
uint8_t *status = tp->p_offloadParams->perCB[i].p_status_cb;
tp->iter_count = RTE_MAX(ops_enq[i]->ldpc_dec.iter_count, tp->iter_count);
*status = ops_enq[i]->status;
j = 0;
for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){
for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) {
bool *status = &nrLDPC_slot_decoding_parameters->TBs[h].segments[i].decodeSuccess;
tp->iter_count = RTE_MAX(ops_enq[j]->ldpc_dec.iter_count, tp->iter_count);
// Check if CRC is available otherwise rely on ops_enq[j]->status to detect decoding success
// CRC is NOT available if the CRC type is 24_B which is when C is greater than 1
if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) {
*status = (ops_enq[j]->status == 0);
} else {
uint8_t *decoded_bytes = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c;
uint8_t crc_type = crcType(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A);
uint32_t len_with_crc = lenWithCrc(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A);
*status = check_crc(decoded_bytes, len_with_crc, crc_type);
}
if (*status) {
*nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments + 1;
}
++j;
}
}
ret = retrieve_ldpc_dec_op(ops_deq, num_segments, tp->op_params->vector_mask, p_out);
AssertFatal(ret == 0, "LDPC offload decoder failed!");
}
rte_bbdev_dec_op_free_bulk(ops_enq, num_segments);
// Return the max number of iterations accross all segments
rte_free(ops_enq);
rte_free(ops_deq);
// Return the worst decoding number of iterations for all segments
return tp->iter_count;
}
......@@ -706,19 +781,19 @@ pmd_lcore_ldpc_dec(void *arg)
static int pmd_lcore_ldpc_enc(void *arg)
{
struct thread_params *tp = arg;
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters = tp->nrLDPC_slot_encoding_parameters;
uint16_t enq, deq;
int time_out = 0;
const uint16_t queue_id = tp->queue_id;
const uint16_t num_segments = tp->p_offloadParams->C;
tp->op_params->num_to_process = num_segments;
struct rte_bbdev_enc_op *ops_enq[num_segments];
struct rte_bbdev_enc_op *ops_deq[num_segments];
const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters);
struct rte_bbdev_enc_op **ops_enq;
struct rte_bbdev_enc_op **ops_deq;
ops_enq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE);
ops_deq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE);
struct rte_bbdev_info info;
int ret;
struct data_buffers *bufs = NULL;
uint16_t num_to_enq;
uint8_t *p_out = tp->p_out;
t_nrLDPCoffload_params *p_offloadParams = tp->p_offloadParams;
AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST);
......@@ -729,7 +804,7 @@ static int pmd_lcore_ldpc_enc(void *arg)
ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp_enc, ops_enq, num_segments);
AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments);
set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, p_offloadParams);
set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_encoding_parameters);
for (enq = 0, deq = 0; enq < num_segments;) {
num_to_enq = num_segments;
if (unlikely(num_segments - enq < num_to_enq))
......@@ -744,18 +819,19 @@ static int pmd_lcore_ldpc_enc(void *arg)
DevAssert(time_out <= TIME_OUT_POLL);
}
ret = retrieve_ldpc_enc_op(ops_deq, num_segments, p_out, tp->p_offloadParams->perCB);
ret = retrieve_ldpc_enc_op(ops_deq, nrLDPC_slot_encoding_parameters);
AssertFatal(ret == 0, "Failed to retrieve LDPC encoding op!");
rte_bbdev_enc_op_free_bulk(ops_enq, num_segments);
rte_free(ops_enq);
rte_free(ops_deq);
return ret;
}
// based on DPDK BBDEV throughput_pmd_lcore_dec
int start_pmd_dec(struct active_device *ad,
struct test_op_params *op_params,
t_nrLDPCoffload_params *p_offloadParams,
uint8_t ulsch_id,
uint8_t *p_out)
nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters)
{
int ret;
unsigned int lcore_id, used_cores = 0;
......@@ -764,7 +840,7 @@ int start_pmd_dec(struct active_device *ad,
num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores;
/* Allocate memory for thread parameters structure */
struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE);
AssertFatal(t_params != NULL,
AssertFatal(t_params != 0,
"Failed to alloc %zuB for t_params",
RTE_ALIGN(sizeof(struct thread_params) * num_lcores, RTE_CACHE_LINE_SIZE));
rte_atomic16_set(&op_params->sync, SYNC_WAIT);
......@@ -774,9 +850,7 @@ int start_pmd_dec(struct active_device *ad,
t_params[0].op_params = op_params;
t_params[0].queue_id = ad->dec_queue;
t_params[0].iter_count = 0;
t_params[0].p_out = p_out;
t_params[0].p_offloadParams = p_offloadParams;
t_params[0].ulsch_id = ulsch_id;
t_params[0].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters;
used_cores++;
// For now, we never enter here, we don't use the DPDK thread pool
RTE_LCORE_FOREACH_WORKER(lcore_id) {
......@@ -787,9 +861,7 @@ int start_pmd_dec(struct active_device *ad,
t_params[used_cores].op_params = op_params;
t_params[used_cores].queue_id = ad->queue_ids[used_cores];
t_params[used_cores].iter_count = 0;
t_params[used_cores].p_out = p_out;
t_params[used_cores].p_offloadParams = p_offloadParams;
t_params[used_cores].ulsch_id = ulsch_id;
t_params[used_cores].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters;
rte_eal_remote_launch(pmd_lcore_ldpc_dec, &t_params[used_cores++], lcore_id);
}
rte_atomic16_set(&op_params->sync, SYNC_START);
......@@ -804,8 +876,7 @@ int start_pmd_dec(struct active_device *ad,
// based on DPDK BBDEV throughput_pmd_lcore_enc
int32_t start_pmd_enc(struct active_device *ad,
struct test_op_params *op_params,
t_nrLDPCoffload_params *p_offloadParams,
uint8_t *p_out)
nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
unsigned int lcore_id, used_cores = 0;
uint16_t num_lcores;
......@@ -818,8 +889,7 @@ int32_t start_pmd_enc(struct active_device *ad,
t_params[0].op_params = op_params;
t_params[0].queue_id = ad->enc_queue;
t_params[0].iter_count = 0;
t_params[0].p_out = p_out;
t_params[0].p_offloadParams = p_offloadParams;
t_params[0].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters;
used_cores++;
// For now, we never enter here, we don't use the DPDK thread pool
RTE_LCORE_FOREACH_WORKER(lcore_id) {
......@@ -830,6 +900,7 @@ int32_t start_pmd_enc(struct active_device *ad,
t_params[used_cores].op_params = op_params;
t_params[used_cores].queue_id = ad->queue_ids[1];
t_params[used_cores].iter_count = 0;
t_params[used_cores].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters;
rte_eal_remote_launch(pmd_lcore_ldpc_enc, &t_params[used_cores++], lcore_id);
}
rte_atomic16_set(&op_params->sync, SYNC_START);
......@@ -843,7 +914,7 @@ struct test_op_params *op_params = NULL;
struct rte_mbuf *m_head[DATA_NUM_TYPES];
// OAI CODE
int32_t LDPCinit()
int32_t nrLDPC_coding_init()
{
pthread_mutex_init(&encode_mutex, NULL);
pthread_mutex_init(&decode_mutex, NULL);
......@@ -851,16 +922,17 @@ int32_t LDPCinit()
int dev_id = 0;
struct rte_bbdev_info info;
struct active_device *ad = active_devs;
char *dpdk_dev = NULL; // PCI address of the card
char *dpdk_dev = NULL; //PCI address of the card
char *dpdk_core_list = NULL; // cores used by DPDK for T2
char *dpdk_file_prefix = NULL;
paramdef_t LoaderParams[] = {
{"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL},
{"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = "11-12", TYPE_STRING, 0, NULL},
{"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL}
{"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL},
{"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = NULL, TYPE_STRING, 0, NULL},
{"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL}
};
config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "ldpc_offload");
AssertFatal(dpdk_dev != NULL, "ldpc_offload.dpdk_dev was not provided");
config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_t2");
AssertFatal(dpdk_dev!=NULL, "nrLDPC_coding_t2.dpdk_dev was not provided");
AssertFatal(dpdk_core_list!=NULL, "nrLDPC_coding_t2.dpdk_core_list was not provided");
char *argv_re[] = {"bbdev", "-a", dpdk_dev, "-l", dpdk_core_list, "--file-prefix", dpdk_file_prefix, "--"};
// EAL initialization, if already initialized (init in xran lib) try to probe DPDK device
ret = rte_eal_init(sizeofArray(argv_re), argv_re);
......@@ -875,9 +947,9 @@ int32_t LDPCinit()
rte_bbdev_info_get(0, &info);
// Set number of queues based on number of initialized cores (-l option) and driver
// capabilities
AssertFatal(add_dev(dev_id, &info) == 0, "Failed to setup bbdev");
AssertFatal(rte_bbdev_stats_reset(dev_id) == 0, "Failed to reset stats of bbdev %d", dev_id);
AssertFatal(rte_bbdev_start(dev_id) == 0, "Failed to start bbdev %d", dev_id);
AssertFatal(add_dev(dev_id, &info)== 0, "Failed to setup bbdev");
AssertFatal(rte_bbdev_stats_reset(dev_id) == 0, "Failed to reset stats of bbdev %u", dev_id);
AssertFatal(rte_bbdev_start(dev_id) == 0, "Failed to start bbdev %u", dev_id);
//the previous calls have populated this global variable (beurk)
// One more global to remove, not thread safe global op_params
......@@ -904,7 +976,7 @@ int32_t LDPCinit()
return 0;
}
int32_t LDPCshutdown()
int32_t nrLDPC_coding_shutdown()
{
struct active_device *ad = active_devs;
int dev_id = 0;
......@@ -919,32 +991,23 @@ int32_t LDPCshutdown()
return 0;
}
int32_t LDPCdecoder(struct nrLDPC_dec_params *p_decParams,
uint8_t harq_pid,
uint8_t ulsch_id,
uint8_t C,
int8_t *p_llr,
int8_t *p_out,
t_nrLDPC_time_stats *p_profiler,
decode_abort_t *ab)
{
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){
pthread_mutex_lock(&decode_mutex);
uint16_t num_blocks = 0;
for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){
num_blocks += nrLDPC_slot_decoding_parameters->TBs[h].C;
}
uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
/* It is not unlikely that l_ol becomes big enough to overflow the stack
* If you observe this behavior then move it to the heap
* Then you would better do a persistent allocation to limit the overhead
*/
uint8_t l_ol[num_blocks * LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
// hardcoded we use first device
struct active_device *ad = active_devs;
t_nrLDPCoffload_params offloadParams = {.n_cb = (p_decParams->BG == 1) ? (66 * p_decParams->Z) : (50 * p_decParams->Z),
.BG = p_decParams->BG,
.Z = p_decParams->Z,
.rv = p_decParams->rv,
.F = p_decParams->F,
.Qm = p_decParams->Qm,
.numMaxIter = p_decParams->numMaxIter,
.C = C,
.setCombIn = p_decParams->setCombIn};
for (int r = 0; r < C; r++) {
offloadParams.perCB[r].E_cb = p_decParams->perCB[r].E_cb;
offloadParams.perCB[r].p_status_cb = &(p_decParams->perCB[r].status_cb);
}
struct rte_bbdev_info info;
int ret;
rte_bbdev_info_get(ad->dev_id, &info);
......@@ -962,50 +1025,48 @@ int32_t LDPCdecoder(struct nrLDPC_dec_params *p_decParams,
&op_params->q_bufs[socket_id][queue_id].hard_outputs,
&op_params->q_bufs[socket_id][queue_id].harq_inputs,
&op_params->q_bufs[socket_id][queue_id].harq_outputs};
int offset = 0;
for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){
for (int r = 0; r < nrLDPC_slot_decoding_parameters->TBs[h].C; r++) {
memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t));
simde__m128i *pv_ol128 = (simde__m128i *)z_ol;
simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset];
int kc = nrLDPC_slot_decoding_parameters->TBs[h].BG == 2 ? 52 : 68;
for (int i = 0, j = 0; j < ((kc * nrLDPC_slot_decoding_parameters->TBs[h].Z) >> 4) + 1; i += 2, j++) {
pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]);
}
offset += LDPC_MAX_CB_SIZE;
}
}
for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) {
ret = allocate_buffers_on_socket(queue_ops[type], C * sizeof(struct rte_bbdev_op_data), socket_id);
ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id);
AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs");
ret = init_op_data_objs_dec(*queue_ops[type],
(uint8_t *)p_llr,
&offloadParams,
l_ol,
nrLDPC_slot_decoding_parameters,
mbuf_pools[type],
C,
type,
info.drv.min_alignment);
AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs");
}
ret = start_pmd_dec(ad, op_params, &offloadParams, ulsch_id, (uint8_t *)p_out);
ret = start_pmd_dec(ad, op_params, nrLDPC_slot_decoding_parameters);
if (ret < 0) {
printf("Couldn't start pmd dec\n");
pthread_mutex_unlock(&decode_mutex);
return (p_decParams->numMaxIter);
LOG_E(PHY, "Couldn't start pmd dec\n");
}
pthread_mutex_unlock(&decode_mutex);
return ret;
return 0;
}
int32_t LDPCencoder(unsigned char **input, unsigned char **output, encoder_implemparams_t *impp)
int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
pthread_mutex_lock(&encode_mutex);
// hardcoded to use the first found board
struct active_device *ad = active_devs;
int ret;
uint32_t Nref = 0;
t_nrLDPCoffload_params offloadParams = {.n_cb = (impp->BG == 1) ? (66 * impp->Zc) : (50 * impp->Zc),
.BG = impp->BG,
.Z = impp->Zc,
.rv = impp->rv,
.F = impp->F,
.Qm = impp->Qm,
.C = impp->n_segments,
.Kr = (impp->K - impp->F + 7) / 8};
for (int r = 0; r < impp->n_segments; r++) {
offloadParams.perCB[r].E_cb = impp->perCB[r].E_cb;
}
if (impp->Tbslbrm != 0) {
Nref = 3 * impp->Tbslbrm / (2 * impp->n_segments);
offloadParams.n_cb = min(offloadParams.n_cb, Nref);
}
struct rte_bbdev_info info;
rte_bbdev_info_get(ad->dev_id, &info);
int socket_id = GET_SOCKET(info.socket_id);
......@@ -1022,20 +1083,23 @@ int32_t LDPCencoder(unsigned char **input, unsigned char **output, encoder_imple
&op_params->q_bufs[socket_id][queue_id].hard_outputs,
&op_params->q_bufs[socket_id][queue_id].harq_inputs,
&op_params->q_bufs[socket_id][queue_id].harq_outputs};
uint16_t num_blocks = 0;
for(uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){
num_blocks += nrLDPC_slot_encoding_parameters->TBs[h].C;
}
for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) {
ret = allocate_buffers_on_socket(queue_ops[type], impp->n_segments * sizeof(struct rte_bbdev_op_data), socket_id);
ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id);
AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs");
ret = init_op_data_objs_enc(*queue_ops[type],
input,
&offloadParams,
nrLDPC_slot_encoding_parameters,
m_head[type],
mbuf_pools[type],
impp->n_segments,
type,
info.drv.min_alignment);
AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs");
}
ret = start_pmd_enc(ad, op_params, &offloadParams, *output);
ret = start_pmd_enc(ad, op_params, nrLDPC_slot_encoding_parameters);
pthread_mutex_unlock(&encode_mutex);
return ret;
}
##########################################################
# LDPC offload library - XDMA
##########################################################
add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF)
if (ENABLE_LDPC_XDMA)
add_library(ldpc_xdma MODULE
nrLDPC_coding_xdma_offload.c
nrLDPC_coding_xdma.c
../nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
../../nrLDPC_load.c
)
set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(nr-softmodem ldpc_xdma)
add_dependencies(nr-uesoftmodem ldpc_xdma)
add_dependencies(nr_ulsim ldpc_xdma)
add_dependencies(nr_ulschsim ldpc_xdma)
add_dependencies(nr_dlsim ldpc_xdma)
add_dependencies(nr_dlschsim ldpc_xdma)
add_dependencies(ldpc_xdma ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti)
if (ENABLE_LDPC_CUDA)
add_dependencies(ldpc_xdma ldpc_cuda)
endif()
endif()
/*
* 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_xdma/nrLDPC_coding_xdma.c
* \brief Top-level routines for decoding LDPC (ULSCH) transport channels
* decoding implemented using a FEC IP core on FPGA through XDMA driver
*/
// [from gNB coding]
#include <syscall.h>
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/coding_extern.h"
#include "PHY/CODING/lte_interleaver_inline.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_ulsch.h"
#include "PHY/defs_gNB.h"
#include "SCHED_NR/fapi_nr_l1.h"
#include "SCHED_NR/sched_nr.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "defs.h"
// #define DEBUG_ULSCH_DECODING
// #define gNB_DEBUG_TRACE
#define OAI_UL_LDPC_MAX_NUM_LLR 27000 // 26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
// #define DEBUG_CRC
#ifdef DEBUG_CRC
#define PRINT_CRC_CHECK(a) a
#else
#define PRINT_CRC_CHECK(a)
#endif
// extern double cpuf;
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
// Global var to limit the rework of the dirty legacy code
ldpc_interface_t ldpc_interface_segment;
int num_threads_prepare_max = 0;
char *user_device = NULL;
char *enc_read_device = NULL;
char *enc_write_device = NULL;
char *dec_read_device = NULL;
char *dec_write_device = NULL;
/*!
* \typedef args_fpga_decode_prepare_t
* \struct args_fpga_decode_prepare_s
* \brief arguments structure for passing arguments to the nr_ulsch_FPGA_decoding_prepare_blocks function
*/
typedef struct args_fpga_decode_prepare_s {
nrLDPC_TB_decoding_parameters_t *TB_params; /*!< transport blocks parameters */
uint8_t *multi_indata; /*!< pointer to the head of the block destination array that is then passed to the FPGA decoding */
int no_iteration_ldpc; /*!< pointer to the number of iteration set by this function */
uint32_t r_first; /*!< index of the first block to be prepared within this function */
uint32_t r_span; /*!< number of blocks to be prepared within this function */
int r_offset; /*!< r index expressed in bits */
int input_CBoffset; /*!< */
int kc; /*!< */
int K_bits_F; /*!< */
task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */
} args_fpga_decode_prepare_t;
int32_t nrLDPC_coding_init(void);
int32_t nrLDPC_coding_shutdown(void);
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx);
// int32_t nrLDPC_coding_encoder(void);
int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params,
int frame_rx,
int slot_rx,
tpool_t *ldpc_threadPool);
void nr_ulsch_FPGA_decoding_prepare_blocks(void *args);
int32_t nrLDPC_coding_init(void)
{
char *encoder_shlibversion = NULL;
paramdef_t LoaderParams[] = {
{"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL},
{"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL},
{"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL},
{"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL},
{"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL},
{"dec_read_device", NULL, 0, .strptr = &dec_read_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_READ, TYPE_STRING, 0, NULL},
{"dec_write_device", NULL, 0, .strptr = &dec_write_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_WRITE, TYPE_STRING, 0, NULL}
};
config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_xdma");
AssertFatal(num_threads_prepare_max != 0, "nrLDPC_coding_xdma.num_threads_prepare was not provided");
load_LDPClib(encoder_shlibversion, &ldpc_interface_segment);
return 0;
}
int32_t nrLDPC_coding_shutdown(void)
{
free_LDPClib(&ldpc_interface_segment);
return 0;
}
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx)
{
int nbDecode = 0;
for (int ULSCH_id = 0; ULSCH_id < slot_params->nb_TBs; ULSCH_id++)
nbDecode += decoder_xdma(&slot_params->TBs[ULSCH_id], frame_rx, slot_rx, slot_params->threadPool);
return nbDecode;
}
/*
int32_t nrLDPC_coding_encoder(void)
{
return 0;
}
*/
int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params,
int frame_rx,
int slot_rx,
tpool_t *ldpc_threadPool)
{
const uint32_t Kr = TB_params->K;
const uint32_t Kr_bytes = Kr >> 3;
const int kc = TB_params->BG == 2 ? 52 : 68;
int r_offset = 0, offset = 0;
int K_bits_F = Kr - TB_params->F;
// FPGA parameter preprocessing
static uint8_t multi_indata[27000 * 25]; // FPGA input data
static uint8_t multi_outdata[1100 * 25]; // FPGA output data
int bg_len = TB_params->BG == 1 ? 22 : 10;
// Calc input CB offset
int input_CBoffset = TB_params->Z * kc * 8;
if ((input_CBoffset & 0x7F) == 0)
input_CBoffset = input_CBoffset / 8;
else
input_CBoffset = 16 * ((input_CBoffset / 128) + 1);
DecIFConf dec_conf = {0};
dec_conf.Zc = TB_params->Z;
dec_conf.BG = TB_params->BG;
dec_conf.max_iter = TB_params->max_ldpc_iterations;
dec_conf.numCB = TB_params->C;
// input soft bits length, Zc x 66 - length of filler bits
dec_conf.numChannelLls = (K_bits_F - 2 * TB_params->Z) + (kc * TB_params->Z - Kr);
// filler bits length
dec_conf.numFillerBits = TB_params->F;
dec_conf.max_schedule = 0;
dec_conf.SetIdx = 12;
dec_conf.nRows = (dec_conf.BG == 1) ? 46 : 42;
dec_conf.user_device = user_device;
dec_conf.enc_read_device = enc_read_device;
dec_conf.enc_write_device = enc_write_device;
dec_conf.dec_read_device = dec_read_device;
dec_conf.dec_write_device = dec_write_device;
int out_CBoffset = dec_conf.Zc * bg_len;
if ((out_CBoffset & 0x7F) == 0)
out_CBoffset = out_CBoffset / 8;
else
out_CBoffset = 16 * ((out_CBoffset / 128) + 1);
#ifdef LDPC_DATA
printf("\n------------------------\n");
printf("BG:\t\t%d\n", dec_conf.BG);
printf("TB_params->C: %d\n", TB_params->C);
printf("TB_params->K: %d\n", TB_params->K);
printf("TB_params->Z: %d\n", TB_params->Z);
printf("TB_params->F: %d\n", TB_params->F);
printf("numChannelLls:\t %d = (%d - 2 * %d) + (%d * %d - %d)\n",
dec_conf.numChannelLls,
K_bits_F,
TB_params->Z,
kc,
TB_params->Z,
Kr);
printf("numFillerBits:\t %d\n", TB_params->F);
printf("------------------------\n");
// ===================================
// debug mode
// ===================================
FILE *fptr_llr, *fptr_ldpc;
fptr_llr = fopen("../../../cmake_targets/log/ulsim_ldpc_llr.txt", "w");
fptr_ldpc = fopen("../../../cmake_targets/log/ulsim_ldpc_output.txt", "w");
// ===================================
#endif
int length_dec = lenWithCrc(TB_params->C, TB_params->A);
uint8_t crc_type = crcType(TB_params->C, TB_params->A);
int no_iteration_ldpc = 2;
uint32_t num_threads_prepare = 0;
// calculate required number of jobs
uint32_t r_while = 0;
while (r_while < TB_params->C) {
// calculate number of segments processed in the new job
uint32_t modulus = (TB_params->C - r_while) % (num_threads_prepare_max - num_threads_prepare);
uint32_t quotient = (TB_params->C - r_while) / (num_threads_prepare_max - num_threads_prepare);
uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1;
// saturate to be sure to not go above C
uint32_t r_span = TB_params->C - r_while < r_span_max ? TB_params->C - r_while : r_span_max;
// increment
num_threads_prepare++;
r_while += r_span;
}
args_fpga_decode_prepare_t arr[num_threads_prepare];
task_ans_t ans[num_threads_prepare];
memset(ans, 0, num_threads_prepare * sizeof(task_ans_t));
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = num_threads_prepare, .ans = ans};
// start the prepare jobs
uint32_t r_remaining = 0;
for (uint32_t r = 0; r < TB_params->C; r++) {
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
if (r_remaining == 0) {
// TODO: int nr_tti_rx = 0;
args_fpga_decode_prepare_t *args = &((args_fpga_decode_prepare_t *)t_info.buf)[t_info.len];
DevAssert(t_info.len < t_info.cap);
args->ans = &t_info.ans[t_info.len];
t_info.len += 1;
args->TB_params = TB_params;
args->multi_indata = multi_indata;
args->no_iteration_ldpc = no_iteration_ldpc;
args->r_first = r;
uint32_t modulus = (TB_params->C - r) % (num_threads_prepare_max - num_threads_prepare);
uint32_t quotient = (TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare);
uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1;
uint32_t r_span = TB_params->C - r < r_span_max ? TB_params->C - r : r_span_max;
args->r_span = r_span;
args->r_offset = r_offset;
args->input_CBoffset = input_CBoffset;
args->kc = kc;
args->K_bits_F = K_bits_F;
r_remaining = r_span;
task_t t = {.func = &nr_ulsch_FPGA_decoding_prepare_blocks, .args = args};
pushTpool(ldpc_threadPool, t);
LOG_D(PHY, "Added %d block(s) to prepare for decoding, in pipe: %d to %d\n", r_span, r, r + r_span - 1);
}
r_offset += segment_params->E;
offset += (Kr_bytes - (TB_params->F >> 3) - ((TB_params->C > 1) ? 3 : 0));
r_remaining -= 1;
}
// reset offset in order to properly fill the output array later
offset = 0;
DevAssert(num_threads_prepare == t_info.len);
// wait for the prepare jobs to complete
join_task_ans(t_info.ans, t_info.len);
for (uint32_t job = 0; job < num_threads_prepare; job++) {
args_fpga_decode_prepare_t *args = &arr[job];
if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations)
no_iteration_ldpc = TB_params->max_ldpc_iterations + 1;
}
// launch decode with FPGA
LOG_I(PHY, "Run the LDPC ------[FPGA version]------\n");
//==================================================================
// Xilinx FPGA LDPC decoding function -> nrLDPC_decoder_FPGA_PYM()
//==================================================================
start_meas(&TB_params->segments[0].ts_ldpc_decode);
nrLDPC_decoder_FPGA_PYM(&multi_indata[0], &multi_outdata[0], dec_conf);
// printf("Xilinx FPGA -> CB = %d\n", harq_process->C);
stop_meas(&TB_params->segments[0].ts_ldpc_decode);
*TB_params->processedSegments = 0;
for (uint32_t r = 0; r < TB_params->C; r++) {
// ------------------------------------------------------------
// --------------------- copy FPGA output ---------------------
// ------------------------------------------------------------
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
if (check_crc(multi_outdata, length_dec, crc_type)) {
#ifdef DEBUG_CRC
LOG_I(PHY, "Segment %d CRC OK\n", r);
#endif
no_iteration_ldpc = 2;
} else {
#ifdef DEBUG_CRC
LOG_I(PHY, "segment %d CRC NOK\n", r);
#endif
no_iteration_ldpc = TB_params->max_ldpc_iterations + 1;
}
for (int i = 0; i < out_CBoffset; i++) {
segment_params->c[i] = multi_outdata[i + r * out_CBoffset];
}
segment_params->decodeSuccess = (no_iteration_ldpc <= TB_params->max_ldpc_iterations);
if (segment_params->decodeSuccess) {
*TB_params->processedSegments = *TB_params->processedSegments + 1;
}
}
return 0;
}
/*!
* \fn nr_ulsch_FPGA_decoding_prepare_blocks(void *args)
* \brief prepare blocks for LDPC decoding on FPGA
*
* \param args pointer to the arguments of the function in a structure of type args_fpga_decode_prepare_t
*/
void nr_ulsch_FPGA_decoding_prepare_blocks(void *args)
{
// extract the arguments
args_fpga_decode_prepare_t *arguments = (args_fpga_decode_prepare_t *)args;
nrLDPC_TB_decoding_parameters_t *TB_params = arguments->TB_params;
uint8_t Qm = TB_params->Qm;
uint8_t BG = TB_params->BG;
uint8_t rv_index = TB_params->rv_index;
uint8_t max_ldpc_iterations = TB_params->max_ldpc_iterations;
uint32_t tbslbrm = TB_params->tbslbrm;
uint32_t Kr = TB_params->K;
uint32_t Z = TB_params->Z;
uint32_t F = TB_params->F;
uint32_t C = TB_params->C;
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[0];
short *ulsch_llr = segment_params->llr;
uint8_t *multi_indata = arguments->multi_indata;
int no_iteration_ldpc = arguments->no_iteration_ldpc;
uint32_t r_first = arguments->r_first;
uint32_t r_span = arguments->r_span;
int r_offset = arguments->r_offset;
int input_CBoffset = arguments->input_CBoffset;
int kc = arguments->kc;
int K_bits_F = arguments->K_bits_F;
int16_t z[68 * 384 + 16] __attribute__((aligned(16)));
simde__m128i *pv = (simde__m128i *)&z;
// the function processes r_span blocks starting from block at index r_first in ulsch_llr
for (uint32_t r = r_first; r < (r_first + r_span); r++) {
nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r];
// ----------------------- FPGA pre process ------------------------
simde__m128i ones = simde_mm_set1_epi8(255); // Generate a vector with all elements set to 255
simde__m128i *temp_multi_indata = (simde__m128i *)&multi_indata[r * input_CBoffset];
// -----------------------------------------------------------------
// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1)
int16_t harq_e[segment_params->E];
// -------------------------------------------------------------------------------------------
// deinterleaving
// -------------------------------------------------------------------------------------------
start_meas(&segment_params->ts_deinterleave);
nr_deinterleaving_ldpc(segment_params->E, Qm, harq_e, ulsch_llr + r_offset);
stop_meas(&segment_params->ts_deinterleave);
// -------------------------------------------------------------------------------------------
// dematching
// -------------------------------------------------------------------------------------------
start_meas(&segment_params->ts_rate_unmatch);
if (nr_rate_matching_ldpc_rx(tbslbrm,
BG,
Z,
segment_params->d,
harq_e,
C,
rv_index,
*segment_params->d_to_be_cleared,
segment_params->E,
F,
Kr - F - 2 * Z)
== -1) {
stop_meas(&segment_params->ts_rate_unmatch);
LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n");
no_iteration_ldpc = max_ldpc_iterations + 1;
arguments->no_iteration_ldpc = no_iteration_ldpc;
return;
} else {
stop_meas(&segment_params->ts_rate_unmatch);
}
*segment_params->d_to_be_cleared = false;
memset(segment_params->c, 0, Kr >> 3);
// set first 2*Z_c bits to zeros
memset(&z[0], 0, 2 * Z * sizeof(int16_t));
// set Filler bits
memset((&z[0] + K_bits_F), 127, F * sizeof(int16_t));
// Move coded bits before filler bits
memcpy((&z[0] + 2 * Z), segment_params->d, (K_bits_F - 2 * Z) * sizeof(int16_t));
// skip filler bits
memcpy((&z[0] + Kr), segment_params->d + (Kr - 2 * Z), (kc * Z - Kr) * sizeof(int16_t));
// Saturate coded bits before decoding into 8 bits values
for (int i = 0, j = 0; j < ((kc * Z) >> 4); i += 2, j++) {
temp_multi_indata[j] =
simde_mm_xor_si128(simde_mm_packs_epi16(pv[i], pv[i + 1]),
simde_mm_cmpeq_epi32(ones,
ones)); // Perform NOT operation and write the result to temp_multi_indata[j]
}
// the last bytes before reaching "kc * harq_process->Z" should not be written 128 bits at a time to avoid overwritting the
// following block in multi_indata
simde__m128i tmp =
simde_mm_xor_si128(simde_mm_packs_epi16(pv[2 * ((kc * Z) >> 4)], pv[2 * ((kc * Z) >> 4) + 1]),
simde_mm_cmpeq_epi32(ones,
ones)); // Perform NOT operation and write the result to temp_multi_indata[j]
uint8_t *tmp_p = (uint8_t *)&tmp;
for (int i = 0, j = ((kc * Z) & 0xfffffff0); j < kc * Z; i++, j++) {
multi_indata[r * input_CBoffset + j] = tmp_p[i];
}
r_offset += segment_params->E;
}
arguments->no_iteration_ldpc = no_iteration_ldpc;
}
/*
* Copyright (c) 2016-present, Xilinx, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license
* the terms of the BSD Licence are reported below:
*
* BSD License
*
* For Xilinx DMA IP software
*
* Copyright (c) 2016-present, Xilinx, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name Xilinx nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <byteswap.h>
#include <signal.h>
#include <ctype.h>
#include <termios.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include "xdma_diag.h"
#include "nrLDPC_coding_xdma_offload.h"
#include "common/utils/assertions.h"
typedef unsigned long long U64;
void* map_base;
int fd;
int fd_enc_write, fd_enc_read;
char *dev_enc_write, *dev_enc_read;
int fd_dec_write, fd_dec_read;
char *dev_dec_write, *dev_dec_read;
char allocated_write[24 * 1024] __attribute__((aligned(4096)));
char allocated_read[24 * 1024 * 3] __attribute__((aligned(4096)));
// dma_from_device.c
// [Start] #include "dma_utils.c" ===================================
/*
* man 2 write:
* On Linux, write() (and similar system calls) will transfer at most
* 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
* actually transferred. (This is true on both 32-bit and 64-bit
* systems.)
*/
#define RW_MAX_SIZE 0x7ffff000
int verbose = 0;
uint64_t getopt_integer(char* optarg)
{
int rc;
uint64_t value;
rc = sscanf(optarg, "0x%lx", &value);
if (rc <= 0)
rc = sscanf(optarg, "%lu", &value);
return value;
}
ssize_t read_to_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
{
ssize_t rc;
uint64_t count = 0;
char* buf = buffer;
off_t offset = base;
while (count < size) {
uint64_t bytes = size - count;
if (bytes > RW_MAX_SIZE)
bytes = RW_MAX_SIZE;
if (offset) {
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
perror("seek file");
return -EIO;
}
}
/* read data from file into memory buffer */
rc = read(fd, buf, bytes);
if (rc != bytes) {
fprintf(stderr, "%s, R off 0x%lx, 0x%lx != 0x%lx.\n", fname, count, rc, bytes);
perror("read file");
return -EIO;
}
count += bytes;
buf += bytes;
offset += bytes;
}
if (count != size) {
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
return -EIO;
}
return count;
}
ssize_t write_from_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
{
ssize_t rc;
uint64_t count = 0;
char* buf = buffer;
off_t offset = base;
while (count < size) {
uint64_t bytes = size - count;
if (bytes > RW_MAX_SIZE)
bytes = RW_MAX_SIZE;
if (offset) {
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
perror("seek file");
return -EIO;
}
}
/* write data to file from memory buffer */
rc = write(fd, buf, bytes);
if (rc != bytes) {
fprintf(stderr, "%s, W off 0x%lx, 0x%lx != 0x%lx.\n", fname, offset, rc, bytes);
perror("write file");
return -EIO;
}
count += bytes;
buf += bytes;
offset += bytes;
}
if (count != size) {
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
return -EIO;
}
return count;
}
// [End] #include "dma_utils.c" ===================================
int test_dma_enc_read(char* EncOut, EncIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = CB_PROCESS_NUMBER;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
mb = Confparam.kb_1 + kb;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
uint32_t OutDataNUM = Z_val * mb;
uint32_t Out_dwNumItems_p128;
uint32_t Out_dwNumItems;
if ((OutDataNUM & 0x7F) == 0)
Out_dwNumItems_p128 = OutDataNUM >> 5;
else
Out_dwNumItems_p128 = ((OutDataNUM >> 7) + 1) << 2;
Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num);
size = Out_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_ENC_OUT;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_enc_read < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_read, fd_enc_read);
perror("open device");
return -EINVAL;
}
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(dev_enc_read, fd_enc_read, EncOut, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
int test_dma_enc_write(char* data, EncIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = CB_PROCESS_NUMBER;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
mb = Confparam.kb_1 + kb;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
uint32_t InDataNUM = Z_val * kb;
uint32_t In_dwNumItems_p128;
uint32_t In_dwNumItems;
if ((InDataNUM & 0x7F) == 0)
In_dwNumItems_p128 = InDataNUM >> 5;
else
In_dwNumItems_p128 = ((InDataNUM >> 7) + 1) << 2;
In_dwNumItems = ((In_dwNumItems_p128 << 2) * CB_num);
size = In_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_ENC_IN;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_enc_write < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_write, fd_enc_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(dev_enc_write, fd_enc_write, data, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam)
int test_dma_dec_read(char* DecOut, DecIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = Confparam.CB_num;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
max_iter = 8;
sc_idx = 12;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data =
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
uint32_t OutDataNUM = Z_val * kb;
uint32_t Out_dwNumItems_p128;
uint32_t Out_dwNumItems;
if (CB_num & 0x01) // odd cb number
{
if ((OutDataNUM & 0xFF) == 0)
Out_dwNumItems_p128 = OutDataNUM;
else
Out_dwNumItems_p128 = 256 * ((OutDataNUM / 256) + 1);
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
} else {
if ((OutDataNUM & 0x7F) == 0)
Out_dwNumItems_p128 = OutDataNUM;
else
Out_dwNumItems_p128 = 128 * ((OutDataNUM / 128) + 1);
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
if ((Out_dwNumItems & 0x1f) != 0)
Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5;
}
size = Out_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_DEC_OUT;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_dec_read < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_read, fd_dec_read);
perror("open device");
return -EINVAL;
}
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(dev_dec_read, fd_dec_read, DecOut, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam)
int test_dma_dec_write(char* data, DecIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = Confparam.CB_num; // CB_PROCESS_NUMBER_Dec;//
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
max_iter = 8;
sc_idx = 12;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data =
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
uint32_t InDataNUM = Z_val * mb;
uint32_t In_dwNumItems_p128;
uint32_t In_dwNumItems;
InDataNUM = Z_val * mb * 8;
if ((InDataNUM & 0x7F) == 0)
In_dwNumItems_p128 = InDataNUM;
else
In_dwNumItems_p128 = 128 * ((InDataNUM / 128) + 1);
In_dwNumItems = (In_dwNumItems_p128 * CB_num) >> 3;
if ((In_dwNumItems & 0x1f) != 0)
In_dwNumItems = ((In_dwNumItems + 31) >> 5) << 5;
size = In_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_DEC_IN;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_dec_write < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_write, fd_dec_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(dev_dec_write, fd_dec_write, data, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
void test_dma_init(devices_t devices)
{
/* access width */
char* device2 = devices.user_device;
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
fflush(stdout);
/* map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
void* virt_addr;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
dev_enc_write = devices.enc_write_device;
dev_enc_read = devices.enc_read_device;
dev_dec_write = devices.dec_write_device;
dev_dec_read = devices.dec_read_device;
fd_enc_write = open(dev_enc_write, O_RDWR);
fd_enc_read = open(dev_enc_read, O_RDWR);
fd_dec_write = open(dev_dec_write, O_RDWR);
fd_dec_read = open(dev_dec_read, O_RDWR);
fflush(stdout);
}
void dma_reset(devices_t devices)
{
char* device2 = devices.user_device;
void* virt_addr;
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
close(fd_enc_write);
close(fd_enc_read);
close(fd_dec_write);
close(fd_dec_read);
close(fd);
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
fflush(stdout);
/* map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
dev_enc_write = devices.enc_write_device;
dev_enc_read = devices.enc_read_device;
dev_dec_write = devices.dec_write_device;
dev_dec_read = devices.dec_read_device;
fd_enc_write = open(dev_enc_write, O_RDWR);
fd_enc_read = open(dev_enc_read, O_RDWR);
fd_dec_write = open(dev_dec_write, O_RDWR);
fd_dec_read = open(dev_dec_read, O_RDWR);
fflush(stdout);
}
void test_dma_shutdown()
{
void* virt_addr;
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
close(fd_enc_write);
close(fd_enc_read);
close(fd_dec_write);
close(fd_dec_read);
close(fd);
}
// reg_rx.c
int nrLDPC_decoder_FPGA_PYM(uint8_t* buf_in, uint8_t* buf_out, DecIFConf dec_conf)
{
struct timespec ts_start0; // evaluate time from input setting to output setting including xdma
int Zc;
int nRows;
int baseGraph;
int CB_num;
DecIPConf Confparam;
int z_a, z_tmp;
int z_j = 0;
int input_CBoffset, output_CBoffset;
uint8_t i_LS;
devices_t devices = {
.user_device = dec_conf.user_device,
.enc_write_device = dec_conf.enc_write_device,
.enc_read_device = dec_conf.enc_read_device,
.dec_write_device = dec_conf.dec_write_device,
.dec_read_device = dec_conf.dec_read_device
};
static int init_flag = 0;
if (init_flag == 0) {
/*Init*/
test_dma_init(devices);
init_flag = 1;
} else {
dma_reset(devices);
}
clock_gettime(CLOCK_MONOTONIC, &ts_start0); // time start0
// LDPC input parameter
Zc = dec_conf.Zc; // shifting size
nRows = dec_conf.nRows; // number of Rows
baseGraph = dec_conf.BG; // base graph
CB_num = dec_conf.numCB; // 31 number of code block
// calc xdma LDPC parameter
// calc i_LS
if ((Zc % 15) == 0)
i_LS = 7;
else if ((Zc % 13) == 0)
i_LS = 6;
else if ((Zc % 11) == 0)
i_LS = 5;
else if ((Zc % 9) == 0)
i_LS = 4;
else if ((Zc % 7) == 0)
i_LS = 3;
else if ((Zc % 5) == 0)
i_LS = 2;
else if ((Zc % 3) == 0)
i_LS = 1;
else
i_LS = 0;
// calc z_a
if (i_LS == 0)
z_a = 2;
else
z_a = i_LS * 2 + 1;
// calc z_j
z_tmp = Zc / z_a;
while (z_tmp % 2 == 0) {
z_j = z_j + 1;
z_tmp = z_tmp / 2;
}
// calc CB_num and mb
Confparam.CB_num = CB_num;
if (baseGraph == 1)
Confparam.mb = 22 + nRows;
else
Confparam.mb = 10 + nRows;
// set BGSel, z_set, z_j
Confparam.BGSel = baseGraph;
Confparam.z_set = i_LS + 1;
Confparam.z_j = z_j;
// Calc input CB offset
input_CBoffset = Zc * Confparam.mb * 8;
if ((input_CBoffset & 0x7F) == 0)
input_CBoffset = input_CBoffset / 8;
else
input_CBoffset = 16 * ((input_CBoffset / 128) + 1);
// Calc output CB offset
output_CBoffset = Zc * (Confparam.mb - nRows);
if ((output_CBoffset & 0x7F) == 0)
output_CBoffset = output_CBoffset / 8;
else
output_CBoffset = 16 * ((output_CBoffset / 128) + 1);
// LDPC accelerator start
// write into accelerator
if (test_dma_dec_write((char *)buf_in, Confparam) != 0) {
exit(1);
printf("write exit!!\n");
}
// read output of accelerator
if (test_dma_dec_read((char *)buf_out, Confparam) != 0) {
exit(1);
printf("read exit!!\n");
}
return 0;
}
/*
* 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_xdma/nrLDPC_coding_xdma_offload.h
* \briefFPGA accelerator integrated into OAI (for one and multi code block)
* \author Sendren Xu, SY Yeh(fdragon), Hongming, Terng-Yin Hsu
* \date 2022-05-31
* \version 5.0
* \email: summery19961210@gmail.com
*/
#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_
#define __NRLDPC_CODING_XDMA_OFFLOAD__H_
#include <stdint.h>
#define DEVICE_NAME_DEFAULT_USER "/dev/xdma0_user"
#define DEVICE_NAME_DEFAULT_ENC_READ "/dev/xdma0_c2h_1"
#define DEVICE_NAME_DEFAULT_ENC_WRITE "/dev/xdma0_h2c_1"
#define DEVICE_NAME_DEFAULT_DEC_READ "/dev/xdma0_c2h_0"
#define DEVICE_NAME_DEFAULT_DEC_WRITE "/dev/xdma0_h2c_0"
/**
\brief LDPC input parameter
\param Zc shifting size
\param Rows
\param baseGraph base graph
\param CB_num number of code block
\param numChannelLlrs input soft bits length, Zc x 66 - length of filler bits
\param numFillerBits filler bits length
*/
typedef struct {
char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device;
unsigned char max_schedule;
unsigned char SetIdx;
int Zc;
unsigned char numCB;
unsigned char BG;
unsigned char max_iter;
int nRows;
int numChannelLls;
int numFillerBits;
} DecIFConf;
int nrLDPC_decoder_FPGA_PYM(uint8_t *buf_in, uint8_t *buf_out, DecIFConf dec_conf);
#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_
/*
* Copyright (c) 2016-present, Xilinx, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license
* the terms of the BSD Licence are reported below:
*
* BSD License
*
* For Xilinx DMA IP software
*
* Copyright (c) 2016-present, Xilinx, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name Xilinx nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MODULES_TXCTRL_INC_XDMA_DIAG_H_
#define MODULES_TXCTRL_INC_XDMA_DIAG_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned char max_schedule; // max_schedule = 0;
unsigned char mb; // mb = 32;
unsigned char CB_num; // id = CB_num;
unsigned char BGSel; // bg = 1;
unsigned char z_set; // z_set = 0;
unsigned char z_j; // z_j = 6;
unsigned char max_iter; // max_iter = 8;
unsigned char SetIdx; // sc_idx = 12;
} DecIPConf;
typedef struct {
int SetIdx;
int NumCBSegm;
int PayloadLen;
int Z;
int z_set;
int z_j;
int Kbmax;
int BGSel;
unsigned mb;
unsigned char CB_num;
unsigned char kb_1;
} EncIPConf;
typedef struct {
char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device;
} devices_t;
/* ltoh: little to host */
/* htol: little to host */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ltohl(x) (x)
#define ltohs(x) (x)
#define htoll(x) (x)
#define htols(x) (x)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define ltohl(x) __bswap_32(x)
#define ltohs(x) __bswap_16(x)
#define htoll(x) __bswap_32(x)
#define htols(x) __bswap_16(x)
#endif
#define MAP_SIZE (32 * 1024UL)
#define MAP_MASK (MAP_SIZE - 1)
#define SIZE_DEFAULT (32)
#define COUNT_DEFAULT (1)
#define OFFSET_DEC_IN 0x0000
#define OFFSET_DEC_OUT 0x0004
#define OFFSET_ENC_IN 0x0008
#define OFFSET_ENC_OUT 0x000c
#define OFFSET_RESET 0x0020
#define PCIE_OFF 0x0030
#define CB_PROCESS_NUMBER 24 // add by JW
#define CB_PROCESS_NUMBER_Dec 24
// dma_from_device.c
int test_dma_enc_read(char *EncOut, EncIPConf Confparam);
int test_dma_enc_write(char *data, EncIPConf Confparam);
int test_dma_dec_read(char *DecOut, DecIPConf Confparam);
int test_dma_dec_write(char *data, DecIPConf Confparam);
void test_dma_init(devices_t devices);
void test_dma_shutdown();
void dma_reset(devices_t devices);
#ifdef __cplusplus
}
#endif
#endif
......@@ -78,15 +78,6 @@ typedef enum nrLDPC_outMode {
nrLDPC_outMode_LLRINT8 /**< Single LLR value per int8_t output */
} e_nrLDPC_outMode;
/**
Structure containing LDPC parameters per CB
*/
typedef struct nrLDPC_params_per_cb {
uint32_t E_cb;
uint8_t status_cb;
uint8_t* p_status_cb;
} nrLDPC_params_per_cb_t;
/**
Structure containing LDPC decoder parameters.
*/
......@@ -94,35 +85,14 @@ typedef struct nrLDPC_dec_params {
uint8_t BG; /**< Base graph */
uint16_t Z; /**< Lifting size */
uint8_t R; /**< Decoding rate: Format 15,13,... for code rates 1/5, 1/3,... */
uint16_t F; /**< Filler bits */
uint8_t Qm; /**< Modulation */
uint8_t rv;
uint8_t numMaxIter; /**< Maximum number of iterations */
int E;
e_nrLDPC_outMode outMode; /**< Output format */
int crc_type;
int (*check_crc)(uint8_t* decoded_bytes, uint32_t n, uint8_t crc_type);
uint8_t setCombIn;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
} t_nrLDPC_dec_params;
/**
Structure containing LDPC offload parameters.
*/
typedef struct nrLDPCoffload_params {
uint8_t BG; /**< Base graph */
uint16_t Z;
uint16_t Kr;
uint8_t rv;
uint16_t n_cb;
uint16_t F; /**< Filler bits */
uint8_t Qm; /**< Modulation */
uint8_t C;
uint8_t numMaxIter;
uint8_t setCombIn;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
} t_nrLDPCoffload_params;
/**
Structure containing LDPC decoder processing time statistics.
*/
......
......@@ -57,13 +57,6 @@ typedef struct {
uint32_t K;
/// Number of "Filler" bits
uint32_t F;
/// Modulation order
uint8_t Qm;
uint32_t Tbslbrm;
unsigned int G;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
// Redundancy version index
uint8_t rv;
task_ans_t *ans;
} encoder_implemparams_t;
......
......@@ -26,6 +26,7 @@
#include "PHY/defs_gNB.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
......@@ -40,6 +41,7 @@
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "SCHED_NR/fapi_nr_l1.h"
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
#include <string.h>
int l1_north_init_gNB()
{
......@@ -96,9 +98,6 @@ void reset_active_stats(PHY_VARS_gNB *gNB, int frame)
}
}
// A global var to reduce the changes size
ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0};
void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
{
// shortcuts
......@@ -134,15 +133,11 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
nr_init_fde(); // Init array for frequency equalization of transform precoding of PUSCH
load_LDPClib(NULL, &ldpc_interface);
int ret_loader = load_nrLDPC_coding_interface(NULL, &gNB->nrLDPC_coding_interface);
AssertFatal(ret_loader == 0, "error loading LDPC library\n");
pthread_mutex_init(&gNB->UL_INFO.crc_rx_mutex, NULL);
if (gNB->ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
else
load_LDPClib(NULL, &ldpc_interface);
gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB;
init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table);
......
......@@ -358,6 +358,7 @@ void free_nr_ue_dl_harq(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PROCESSES
free_and_zero(harq_list[j][i].c[r]);
free_and_zero(harq_list[j][i].d[r]);
}
free_and_zero(harq_list[j][i].b);
free_and_zero(harq_list[j][i].c);
free_and_zero(harq_list[j][i].d);
}
......@@ -408,6 +409,7 @@ void nr_init_dl_harq_processes(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PR
memset(harq_list[j] + i, 0, sizeof(NR_DL_UE_HARQ_t));
init_downlink_harq_status(harq_list[j] + i);
harq_list[j][i].b = malloc16_clear(a_segments * 1056);
harq_list[j][i].c = malloc16(a_segments*sizeof(uint8_t *));
harq_list[j][i].d = malloc16(a_segments*sizeof(int16_t *));
const int sz=5*8448*sizeof(int16_t);
......
......@@ -65,6 +65,67 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats;
time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats;
size_t size_output = 0;
for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
LOG_D(PHY,"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
rel15->BWPStart,rel15->BWPSize,rel15->rbStart,rel15->rbSize);
const int Qm = rel15->qamModOrder[0];
/* PTRS */
uint16_t dlPtrsSymPos = 0;
int n_ptrs = 0;
uint32_t ptrsSymbPerSlot = 0;
if(rel15->pduBitmap & 0x1) {
set_ptrs_symb_idx(&dlPtrsSymPos,
rel15->NrOfSymbols,
rel15->StartSymbolIndex,
1 << rel15->PTRSTimeDensity,
rel15->dlDmrsSymbPos);
n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity;
ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols);
}
harq->unav_res = ptrsSymbPerSlot * n_ptrs;
/// CRC, coding, interleaving and rate matching
AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
/* output and its parts for each dlsch should be aligned on 64 bytes
* => size_output is a sum of parts sizes rounded up to a multiple of 64
*/
size_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
size_output += (size_output_tb + 63 - ((size_output_tb + 63) % 64));
}
unsigned char output[size_output] __attribute__((aligned(64)));
bzero(output, size_output);
size_t offset_output = 0;
start_meas(dlsch_encoding_stats);
if (nr_dlsch_encoding(gNB,
msgTx,
frame,
slot,
frame_parms,
output,
tinput,
tprep,
tparity,
toutput,
dlsch_rate_matching_stats,
dlsch_interleaving_stats,
dlsch_segmentation_stats) == -1) {
return;
}
stop_meas(dlsch_encoding_stats);
for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
......@@ -100,45 +161,24 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
}
harq->unav_res = ptrsSymbPerSlot * n_ptrs;
/// CRC, coding, interleaving and rate matching
AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers] __attribute__((aligned(64)));
bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers);
start_meas(dlsch_encoding_stats);
if (nr_dlsch_encoding(gNB,
frame,
slot,
harq,
frame_parms,
output,
tinput,
tprep,
tparity,
toutput,
dlsch_rate_matching_stats,
dlsch_interleaving_stats,
dlsch_segmentation_stats) == -1)
return;
stop_meas(dlsch_encoding_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH encoding:\nPayload:\n");
for (int i=0; i<harq->B>>7; i++) {
for (int j=0; j<16; j++)
printf("0x%02x\t", harq->pdu[(i<<4)+j]);
for (int i = 0; i < (harq->B>>3); i += 16) {
for (int j=0; j < 16; j++)
printf("0x%02x\t", harq->pdu[i + j]);
printf("\n");
}
printf("\nEncoded payload:\n");
for (int i=0; i<encoded_length>>3; i++) {
for (int j=0; j<8; j++)
printf("%d", output[(i<<3)+j]);
for (int i = 0; i < encoded_length; i += 8) {
for (int j = 0; j < 8; j++)
printf("%d", output[offset_output + i + j]);
printf("\t");
}
printf("\n");
#endif
if (IS_SOFTMODEM_DLSIM)
memcpy(harq->f, output, encoded_length);
memcpy(harq->f, &output[offset_output], encoded_length);
c16_t mod_symbs[rel15->NrOfCodewords][encoded_length];
for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
......@@ -147,7 +187,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
uint32_t scrambled_output[(encoded_length>>5)+4]; // modulator acces by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
if ( encoded_length > rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers) abort();
nr_pdsch_codeword_scrambling(output, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
nr_pdsch_codeword_scrambling(&output[offset_output], encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
#ifdef DEBUG_DLSCH
printf("PDSCH scrambling:\n");
......@@ -176,6 +216,12 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
}
/// Resource mapping
/* output and its parts for each dlsch should be aligned on 64 bytes
* => offset_output should remain a multiple of 64 with enough offset to fit each dlsch
*/
uint32_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
offset_output += (size_output_tb + 63) & ~63;
// Non interleaved VRB to PRB mapping
uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart+rel15->BWPStart)*NR_NB_SC_PER_RB;
if (start_sc >= frame_parms->ofdm_symbol_size)
......
......@@ -44,18 +44,18 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
int slot);
int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
int frame,
uint8_t slot,
NR_DL_gNB_HARQ_t *harq,
NR_DL_FRAME_PARMS* frame_parms,
unsigned char * output,
time_stats_t *tinput,
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);
processingData_L1tx_t *msgTx,
int frame,
uint8_t slot,
NR_DL_FRAME_PARMS *frame_parms,
unsigned char *output,
time_stats_t *tinput,
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);
void nr_emulate_dlsch_payload(uint8_t* payload, uint16_t size);
......
......@@ -19,21 +19,15 @@
* contact@openairinterface.org
*/
/*! \file PHY/LTE_TRANSPORT/dlsch_coding.c
/*! \file PHY/NR_TRANSPORT/nr_dlsch_coding_slot.c
* \brief Top-level routines for implementing LDPC-coded (DLSCH) transport channels from 38-212, 15.2
* \author H.Wang
* \date 2018
* \version 0.1
* \company Eurecom
* \email:
* \note
* \warning
*/
#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"
......@@ -117,130 +111,10 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB)
return(dlsch);
}
static void ldpc8blocks(void *p)
{
encoder_implemparams_t *impp=(encoder_implemparams_t *) p;
NR_DL_gNB_HARQ_t *harq = (NR_DL_gNB_HARQ_t *)impp->harq;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
uint8_t mod_order = rel15->qamModOrder[0];
uint16_t nb_rb = rel15->rbSize;
uint8_t nb_symb_sch = rel15->NrOfSymbols;
uint16_t length_dmrs = get_num_dmrs(rel15->dlDmrsSymbPos);
uint32_t A = rel15->TBSize[0]<<3;
uint8_t nb_re_dmrs;
if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1)
nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
else
nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
unsigned int G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, harq->unav_res, mod_order, rel15->nrOfLayers);
LOG_D(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n",
A,impp->K,G, nb_rb,nb_symb_sch,nb_re_dmrs,length_dmrs,(int)mod_order);
// nrLDPC_encoder output is in "d"
// let's make this interface happy!
uint8_t tmp[8][68 * 384]__attribute__((aligned(32)));
uint8_t *d[impp->n_segments];
for (int rr=impp->macro_num*8, i=0; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++,i++ )
d[rr] = tmp[i];
ldpc_interface.LDPCencoder(harq->c, d, impp);
// Compute where to place in output buffer that is concatenation of all segments
uint32_t r_offset=0;
for (int i=0; i < impp->macro_num*8; i++ )
r_offset+=nr_get_E(G, impp->n_segments, mod_order, rel15->nrOfLayers, i);
for (int rr=impp->macro_num*8; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++ ) {
if (impp->F>0) {
// writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212
memset(&d[rr][impp->K - impp->F - 2 * impp->Zc], NR_NULL, impp->F);
}
#ifdef DEBUG_DLSCH_CODING
LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]);
#endif
uint32_t E = nr_get_E(G, impp->n_segments, mod_order, rel15->nrOfLayers, rr);
//#ifdef DEBUG_DLSCH_CODING
LOG_D(NR_PHY,
"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb "
"%d,nrOfLayer %d)...\n",
rr,
impp->n_segments,
G,
E,
impp->F,
impp->K - impp->F - 2 * impp->Zc,
mod_order,
nb_rb,
rel15->nrOfLayers);
uint32_t Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
uint8_t e[E];
bzero (e, E);
nr_rate_matching_ldpc(Tbslbrm,
impp->BG,
impp->Zc,
d[rr],
e,
impp->n_segments,
impp->F,
impp->K - impp->F - 2 * impp->Zc,
rel15->rvIndex[0],
E);
if (impp->K - impp->F - 2 * impp->Zc > E) {
LOG_E(PHY,
"dlsch coding A %d Kr %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n",
A,
impp->K,
G,
nb_rb,
nb_symb_sch,
nb_re_dmrs,
length_dmrs,
(int)mod_order);
LOG_E(NR_PHY,
"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, "
"nb_rb %d)...\n",
rr,
impp->n_segments,
G,
E,
impp->K,
impp->F,
impp->K - impp->F - 2 * impp->Zc,
mod_order,
nb_rb);
}
#ifdef DEBUG_DLSCH_CODING
for (int i =0; i<16; i++)
printf("output ratematching e[%d]= %d r_offset %u\n", i,e[i], r_offset);
#endif
nr_interleaving_ldpc(E,
mod_order,
e,
impp->output+r_offset);
#ifdef DEBUG_DLSCH_CODING
for (int i =0; i<16; i++)
printf("output interleaving f[%d]= %d r_offset %u\n", i,impp->output[i+r_offset], r_offset);
if (r==impp->n_segments-1)
write_output("enc_output.m","enc",impp->output,G,1,4);
#endif
r_offset += E;
}
// Task running in // completed
completed_task_ans(impp->ans);
}
int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
processingData_L1tx_t *msgTx,
int frame,
uint8_t slot,
NR_DL_gNB_HARQ_t *harq,
NR_DL_FRAME_PARMS *frame_parms,
unsigned char *output,
time_stats_t *tinput,
......@@ -251,145 +125,195 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats)
{
encoder_implemparams_t impp;
impp.output=output;
unsigned int crc=1;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
impp.Zc = harq->Z;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN);
uint32_t A = rel15->TBSize[0]<<3;
unsigned char *a=harq->pdu;
if (rel15->rnti != SI_RNTI) {
ws_trace_t tmp = {.nr = true,
.direction = DIRECTION_DOWNLINK,
.pdu_buffer = a,
.pdu_buffer_size = rel15->TBSize[0],
.ueid = 0,
.rntiType = WS_C_RNTI,
.rnti = rel15->rnti,
.sysFrame = frame,
.subframe = slot,
.harq_pid = 0, // difficult to find the harq pid here
.oob_event = 0,
.oob_event_value = 0};
trace_pdu(&tmp);
}
NR_gNB_PHY_STATS_t *phy_stats = NULL;
if (rel15->rnti != 0xFFFF)
phy_stats = get_phy_stats(gNB, rel15->rnti);
nrLDPC_TB_encoding_parameters_t TBs[msgTx->num_pdsch_slot];
memset(TBs, 0, sizeof(TBs));
nrLDPC_slot_encoding_parameters_t slot_parameters = {
.frame = frame,
.slot = slot,
.nb_TBs = msgTx->num_pdsch_slot,
.threadPool = &gNB->threadPool,
.tinput = tinput,
.tprep = tprep,
.tparity = tparity,
.toutput = toutput,
.TBs = TBs
};
int num_segments = 0;
for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
unsigned int crc=1;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
uint32_t A = rel15->TBSize[0]<<3;
unsigned char *a=harq->pdu;
if (rel15->rnti != SI_RNTI) {
ws_trace_t tmp = {.nr = true,
.direction = DIRECTION_DOWNLINK,
.pdu_buffer = a,
.pdu_buffer_size = rel15->TBSize[0],
.ueid = 0,
.rntiType = WS_C_RNTI,
.rnti = rel15->rnti,
.sysFrame = frame,
.subframe = slot,
.harq_pid = 0, // difficult to find the harq pid here
.oob_event = 0,
.oob_event_value = 0};
trace_pdu(&tmp);
}
if (phy_stats) {
phy_stats->frame = frame;
phy_stats->dlsch_stats.total_bytes_tx += rel15->TBSize[0];
phy_stats->dlsch_stats.current_RI = rel15->nrOfLayers;
phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0];
}
NR_gNB_PHY_STATS_t *phy_stats = NULL;
if (rel15->rnti != 0xFFFF)
phy_stats = get_phy_stats(gNB, rel15->rnti);
int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers*1056;
int B;
if (A > NR_MAX_PDSCH_TBS) {
// Add 24-bit crc (polynomial A) to payload
crc = crc24a(a,A)>>8;
a[A>>3] = ((uint8_t *)&crc)[2];
a[1+(A>>3)] = ((uint8_t *)&crc)[1];
a[2+(A>>3)] = ((uint8_t *)&crc)[0];
//printf("CRC %x (A %d)\n",crc,A);
//printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]);
B = A + 24;
// harq->b = a;
AssertFatal((A / 8) + 4 <= max_bytes,
"A %d is too big (A/8+4 = %d > %d)\n",
A,
(A / 8) + 4,
max_bytes);
memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes?
} else {
// Add 16-bit crc (polynomial A) to payload
crc = crc16(a,A)>>16;
a[A>>3] = ((uint8_t *)&crc)[1];
a[1+(A>>3)] = ((uint8_t *)&crc)[0];
//printf("CRC %x (A %d)\n",crc,A);
//printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]);
B = A + 16;
// harq->b = a;
AssertFatal((A / 8) + 3 <= max_bytes,
"A %d is too big (A/8+3 = %d > %d)\n",
A,
(A / 8) + 3,
max_bytes);
memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc
}
if (phy_stats) {
phy_stats->frame = frame;
phy_stats->dlsch_stats.total_bytes_tx += rel15->TBSize[0];
phy_stats->dlsch_stats.current_RI = rel15->nrOfLayers;
phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0];
}
impp.BG = rel15->maintenance_parms_v3.ldpcBaseGraph;
int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers*1056;
int B;
if (A > NR_MAX_PDSCH_TBS) {
// Add 24-bit crc (polynomial A) to payload
crc = crc24a(a,A)>>8;
a[A>>3] = ((uint8_t *)&crc)[2];
a[1+(A>>3)] = ((uint8_t *)&crc)[1];
a[2+(A>>3)] = ((uint8_t *)&crc)[0];
//printf("CRC %x (A %d)\n",crc,A);
//printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]);
B = A + 24;
// harq->b = a;
AssertFatal((A / 8) + 4 <= max_bytes,
"A %d is too big (A/8+4 = %d > %d)\n",
A,
(A / 8) + 4,
max_bytes);
memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes?
} else {
// Add 16-bit crc (polynomial A) to payload
crc = crc16(a,A)>>16;
a[A>>3] = ((uint8_t *)&crc)[1];
a[1+(A>>3)] = ((uint8_t *)&crc)[0];
//printf("CRC %x (A %d)\n",crc,A);
//printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]);
B = A + 16;
// harq->b = a;
AssertFatal((A / 8) + 3 <= max_bytes,
"A %d is too big (A/8+3 = %d > %d)\n",
A,
(A / 8) + 3,
max_bytes);
memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc
}
start_meas(dlsch_segmentation_stats);
impp.Kb = nr_segmentation(harq->b, harq->c, B, &impp.n_segments, &impp.K, &impp.Zc, &impp.F, impp.BG);
stop_meas(dlsch_segmentation_stats);
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id];
// The harq_pid is not unique among the active HARQ processes in the instance so we use dlsch_id instead
TB_parameters->harq_unique_pid = dlsch_id;
TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph;
TB_parameters->Z = harq->Z;
TB_parameters->A = A;
start_meas(dlsch_segmentation_stats);
TB_parameters->Kb = nr_segmentation(harq->b,
harq->c,
B,
&TB_parameters->C,
&TB_parameters->K,
&TB_parameters->Z,
&TB_parameters->F,
TB_parameters->BG);
stop_meas(dlsch_segmentation_stats);
if (TB_parameters->C>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B);
return(-1);
}
num_segments += TB_parameters->C;
if (impp.n_segments>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B);
return(-1);
}
for (int r=0; r<impp.n_segments; r++) {
//d_tmp[r] = &harq->d[r][0];
//channel_input[r] = &harq->d[r][0];
#ifdef DEBUG_DLSCH_CODING
LOG_D(PHY,"Encoder: B %d F %d \n",harq->B, impp.F);
LOG_D(PHY,"start ldpc encoder segment %d/%d\n",r,impp.n_segments);
LOG_D(PHY,"input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2],harq->c[r][3], harq->c[r][4]);
for (int cnt =0 ; cnt < 22*(*impp.Zc)/8; cnt ++) {
LOG_D(PHY,"%d ", harq->c[r][cnt]);
}
nrLDPC_segment_encoding_parameters_t segments[num_segments];
memset(segments, 0, sizeof(segments));
size_t segments_offset = 0;
size_t dlsch_offset = 0;
for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) {
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
LOG_D(PHY,"\n");
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id];
#ifdef DEBUG_DLSCH_CODING
for (int r = 0; r < TB_parameters->C; r++) {
LOG_D(PHY, "Encoder: B %d F %d \n", harq->B, TB_parameters->F);
LOG_D(PHY, "start ldpc encoder segment %d/%d\n", r, TB_parameters->C);
LOG_D(PHY, "input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2], harq->c[r][3], harq->c[r][4]);
for (int cnt = 0; cnt < 22 * (TB_parameters->Z) / 8; cnt++) {
LOG_D(PHY, "%d ", harq->c[r][cnt]);
}
LOG_D(PHY, "\n");
}
#endif
//ldpc_encoder_orig((unsigned char*)harq->c[r],harq->d[r],*Zc,Kb,Kr,BG,0);
//ldpc_encoder_optim((unsigned char*)harq->c[r],(unsigned char*)&harq->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL);
}
impp.tprep = tprep;
impp.tinput = tinput;
impp.tparity = tparity;
impp.toutput = toutput;
impp.harq = harq;
if (gNB->ldpc_offload_flag) {
impp.Qm = rel15->qamModOrder[0];
impp.Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
impp.rv = rel15->rvIndex[0];
TB_parameters->nb_rb = rel15->rbSize;
TB_parameters->Qm = rel15->qamModOrder[0];
TB_parameters->mcs = rel15->mcsIndex[0];
TB_parameters->nb_layers = rel15->nrOfLayers;
TB_parameters->rv_index = rel15->rvIndex[0];
int nb_re_dmrs =
(rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData);
impp.G = nr_get_G(rel15->rbSize,
rel15->NrOfSymbols,
nb_re_dmrs,
get_num_dmrs(rel15->dlDmrsSymbPos),
harq->unav_res,
rel15->qamModOrder[0],
rel15->nrOfLayers);
for (int r = 0; r < impp.n_segments; r++) {
impp.perCB[r].E_cb = nr_get_E(impp.G, impp.n_segments, impp.Qm, rel15->nrOfLayers, r);
}
ldpc_interface_offload.LDPCencoder(harq->c, &impp.output, &impp);
} else {
size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1));
encoder_implemparams_t arr[n_seg];
task_ans_t ans[n_seg];
memset(ans, 0, n_seg * sizeof(task_ans_t));
for (int j = 0; j < n_seg; j++) {
encoder_implemparams_t *perJobImpp = &arr[j];
*perJobImpp = impp;
perJobImpp->macro_num = j;
perJobImpp->ans = &ans[j];
task_t t = {.func = ldpc8blocks, .args = perJobImpp};
pushTpool(&gNB->threadPool, t);
TB_parameters->G = nr_get_G(rel15->rbSize,
rel15->NrOfSymbols,
nb_re_dmrs,
get_num_dmrs(rel15->dlDmrsSymbPos),
harq->unav_res,
rel15->qamModOrder[0],
rel15->nrOfLayers);
TB_parameters->tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
TB_parameters->segments = &segments[segments_offset];
size_t r_offset = 0;
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
segment_parameters->c = harq->c[r];
segment_parameters->E = nr_get_E(TB_parameters->G,
TB_parameters->C,
TB_parameters->Qm,
rel15->nrOfLayers,
r);
segment_parameters->output = &output[dlsch_offset + r_offset];
r_offset += segment_parameters->E;
reset_meas(&segment_parameters->ts_interleave);
reset_meas(&segment_parameters->ts_rate_match);
reset_meas(&segment_parameters->ts_ldpc_encode);
}
join_task_ans(ans, n_seg);
segments_offset += TB_parameters->C;
/* output and its parts for each dlsch should be aligned on 64 bytes
* => dlsch_offset should remain a multiple of 64 with enough offset to fit each dlsch
*/
const size_t dlsch_size = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers;
dlsch_offset += (dlsch_size + 63 - ((dlsch_size + 63) % 64));
}
gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_OUT);
return 0;
}
......@@ -42,28 +42,23 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t *ulsch, uint16_t N_RB_UL);
NR_gNB_ULSCH_t new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL);
/*! \brief Perform PUSCH decoding. TS 38.212 V15.4.0 subclause 6.2
/*! \brief Perform PUSCH decoding for the whole current received TTI. TS 38.212 V15.4.0 subclause 6.2
@param phy_vars_gNB, Pointer to PHY data structure for gNB
@param UE_id, ID of UE transmitting this PUSCH
@param ulsch_llr, Pointer to received llr in ulsch
@param frame_parms, Pointer to frame descriptor structure
@param nb_symb_sch, number of symbols used in the uplink shared channel
@param nb_re_dmrs, number of DMRS resource elements in one RB
@param frame, current received frame
@param nr_tti_rx, current received TTI
@param harq_pid, harq process id
@param is_crnti
@param G
@param ULSCH_ids, array of ULSCH ids
@param nb_pusch, number of uplink shared channels
*/
int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
uint8_t UE_id,
short *ulsch_llr,
NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *pusch_pdu,
uint32_t frame,
uint8_t nr_tti_rx,
uint8_t harq_pid,
uint32_t G,
thread_info_tm_t *t_info);
uint32_t *G,
uint8_t *ULSCH_ids,
int nb_pusch);
/*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1
@param llr, Pointer to llr bits
......
......@@ -19,15 +19,8 @@
* contact@openairinterface.org
*/
/*! \file PHY/NR_TRANSPORT/nr_ulsch_decoding.c
/*! \file PHY/NR_TRANSPORT/nr_ulsch_decoding_slot.c
* \brief Top-level routines for decoding LDPC (ULSCH) transport channels from 38.212, V15.4.0 2018-12
* \author Ahmed Hussein
* \date 2019
* \version 0.1
* \company Fraunhofer IIS
* \email: ahmed.hussein@iis.fraunhofer.de
* \note
* \warning
*/
......@@ -36,6 +29,7 @@
#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_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
......@@ -50,10 +44,6 @@
//#define DEBUG_ULSCH_DECODING
//#define gNB_DEBUG_TRACE
#include <stdint.h>
#include <time.h>
#include <stdalign.h>
#define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
//#define DEBUG_CRC
#ifdef DEBUG_CRC
......@@ -123,361 +113,215 @@ NR_gNB_ULSCH_t new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL)
return(ulsch);
}
static void nr_processULSegment(void *arg)
int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
NR_DL_FRAME_PARMS *frame_parms,
uint32_t frame,
uint8_t nr_tti_rx,
uint32_t *G,
uint8_t *ULSCH_ids,
int nb_pusch)
{
ldpcDecode_t *rdata = (ldpcDecode_t *)arg;
NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms;
const int Kr = ulsch_harq->K;
const int Kr_bytes = Kr >> 3;
const int K_bits_F = Kr - ulsch_harq->F;
const int r = rdata->segment_r;
const int A = rdata->A;
const int E = rdata->E;
const int Qm = rdata->Qm;
const int rv_index = rdata->rv_index;
const int r_offset = rdata->r_offset;
const uint8_t kc = rdata->Kc;
short *ulsch_llr = rdata->ulsch_llr;
const int max_ldpc_iterations = p_decoderParms->numMaxIter;
int8_t llrProcBuf[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__((aligned(32)));
t_nrLDPC_time_stats procTime = {0};
t_nrLDPC_time_stats *p_procTime = &procTime;
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// nr_deinterleaving_ldpc ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// ulsch_llr =====> ulsch_harq->e //////////////////////////////
/// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1)
int16_t harq_e[E];
nr_deinterleaving_ldpc(E, Qm, harq_e, ulsch_llr + r_offset);
// for (int i =0; i<16; i++)
// printf("rx output deinterleaving w[%d]= %d r_offset %d\n", i,ulsch_harq->w[r][i], r_offset);
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// nr_rate_matching_ldpc_rx ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
///////////////////////// ulsch_harq->e =====> ulsch_harq->d /////////////////////////
if (nr_rate_matching_ldpc_rx(rdata->tbslbrm,
p_decoderParms->BG,
p_decoderParms->Z,
ulsch_harq->d[r],
harq_e,
ulsch_harq->C,
rv_index,
ulsch_harq->d_to_be_cleared[r],
E,
ulsch_harq->F,
Kr - ulsch_harq->F - 2 * (p_decoderParms->Z))
== -1) {
LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n");
rdata->decodeIterations = max_ldpc_iterations + 1;
set_abort(&ulsch_harq->abort_decode, true);
// Task completed
completed_task_ans(rdata->ans);
return;
}
ulsch_harq->d_to_be_cleared[r] = false;
memset(ulsch_harq->c[r], 0, Kr_bytes);
p_decoderParms->crc_type = crcType(ulsch_harq->C, A);
p_decoderParms->E = lenWithCrc(ulsch_harq->C, A);
// set first 2*Z_c bits to zeros
int16_t z[68 * 384 + 16] __attribute__((aligned(16)));
memset(z, 0, 2 * ulsch_harq->Z * sizeof(*z));
// set Filler bits
memset(z + K_bits_F, 127, ulsch_harq->F * sizeof(*z));
// Move coded bits before filler bits
memcpy(z + 2 * ulsch_harq->Z, ulsch_harq->d[r], (K_bits_F - 2 * ulsch_harq->Z) * sizeof(*z));
// skip filler bits
memcpy(z + Kr, ulsch_harq->d[r] + (Kr - 2 * ulsch_harq->Z), (kc * ulsch_harq->Z - Kr) * sizeof(*z));
// Saturate coded bits before decoding into 8 bits values
simde__m128i *pv = (simde__m128i *)&z;
int8_t l[68 * 384 + 16] __attribute__((aligned(16)));
simde__m128i *pl = (simde__m128i *)&l;
for (int i = 0, j = 0; j < ((kc * ulsch_harq->Z) >> 4) + 1; i += 2, j++) {
pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// nrLDPC_decoder /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// pl =====> llrProcBuf //////////////////////////////////
rdata->decodeIterations =
ldpc_interface.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, &ulsch_harq->abort_decode);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING, 1);
if (rdata->decodeIterations <= p_decoderParms->numMaxIter)
memcpy(ulsch_harq->c[r],llrProcBuf, Kr>>3);
nrLDPC_TB_decoding_parameters_t TBs[nb_pusch];
memset(TBs, 0, sizeof(TBs));
nrLDPC_slot_decoding_parameters_t slot_parameters = {
.frame = frame,
.slot = nr_tti_rx,
.nb_TBs = nb_pusch,
.threadPool = &phy_vars_gNB->threadPool,
.TBs = TBs
};
// Task completed
completed_task_ans(rdata->ans);
}
int max_num_segments = 0;
int decode_offload(PHY_VARS_gNB *phy_vars_gNB,
uint8_t ULSCH_id,
short *ulsch_llr,
nfapi_nr_pusch_pdu_t *pusch_pdu,
t_nrLDPC_dec_params *decParams,
uint8_t harq_pid,
uint32_t G)
{
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
int16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
int8_t l_ol[NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
const int kc = decParams->BG == 2 ? 52 : 68;
uint32_t A = (harq_process->TBS) << 3;
const int Kr = harq_process->K;
const int Kr_bytes = Kr >> 3;
int8_t decodeIterations = 0;
int r_offset = 0;
int offset = 0;
// new data received, set processedSegments to 0
if (!decParams->setCombIn)
harq_process->processedSegments = 0;
for (int r = 0; r < harq_process->C; r++) {
decParams->perCB[r].E_cb = nr_get_E(G, harq_process->C, decParams->Qm, pusch_pdu->nrOfLayers, r);
memcpy(z_ol, ulsch_llr + r_offset, decParams->perCB[r].E_cb * sizeof(int16_t));
simde__m128i *pv_ol128 = (simde__m128i *)z_ol;
simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset];
for (int i = 0, j = 0; j < ((kc * harq_process->Z) >> 4) + 1; i += 2, j++) {
pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]);
}
decParams->F = harq_process->F;
r_offset += decParams->perCB[r].E_cb;
offset += LDPC_MAX_CB_SIZE;
}
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_gNB_PUSCH *pusch = &phy_vars_gNB->pusch_vars[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu;
int8_t p_outDec[harq_process->C * Kr_bytes];
memset(p_outDec, 0, sizeof(p_outDec));
decodeIterations =
ldpc_interface_offload.LDPCdecoder(decParams, harq_pid, ULSCH_id, harq_process->C, (int8_t *)l_ol, p_outDec, NULL, NULL);
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id];
if (decodeIterations < 0) {
LOG_E(PHY, "ulsch_decoding.c: Problem in LDPC decoder offload\n");
return -1;
}
TB_parameters->G = G[pusch_id];
int offset_b = 0;
for (int r = 0; r < harq_process->C; r++) {
if (decParams->perCB[r].status_cb == 0 || harq_process->C == 1) {
memcpy(harq_process->b + offset_b, &p_outDec[offset_b], Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
harq_process->processedSegments++;
if (!harq_process) {
LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n");
return -1;
}
offset_b += (Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
}
bool crc_valid = false;
// CRC check made by the T2, no need to perform CRC check for a single code block twice
if (harq_process->processedSegments == harq_process->C) {
crc_valid = check_crc(harq_process->b, lenWithCrc(1, A), crcType(1, A));
if (harq_process->C == 1 && !crc_valid) {
harq_process->processedSegments--;
// The harq_pid is not unique among the active HARQ processes in the instance so we use ULSCH_id instead
TB_parameters->harq_unique_pid = ULSCH_id;
// ------------------------------------------------------------------
TB_parameters->nb_rb = pusch_pdu->rb_size;
TB_parameters->Qm = pusch_pdu->qam_mod_order;
TB_parameters->mcs = pusch_pdu->mcs_index;
TB_parameters->nb_layers = pusch_pdu->nrOfLayers;
// ------------------------------------------------------------------
TB_parameters->processedSegments = &harq_process->processedSegments;
harq_process->TBS = pusch_pdu->pusch_data.tb_size;
TB_parameters->BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph;
TB_parameters->A = (harq_process->TBS) << 3;
NR_gNB_PHY_STATS_t *stats = get_phy_stats(phy_vars_gNB, ulsch->rnti);
if (stats) {
stats->frame = frame;
stats->ulsch_stats.round_trials[harq_process->round]++;
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
stats->ulsch_stats.power[aarx] = dB_fixed_x10(pusch->ulsch_power[aarx]);
stats->ulsch_stats.noise_power[aarx] = dB_fixed_x10(pusch->ulsch_noise_power[aarx]);
}
if (!harq_process->harq_to_be_cleared) {
stats->ulsch_stats.current_Qm = TB_parameters->Qm;
stats->ulsch_stats.current_RI = TB_parameters->nb_layers;
stats->ulsch_stats.total_bytes_tx += harq_process->TBS;
}
}
}
if (crc_valid) {
LOG_D(PHY, "ULSCH: Setting ACK for slot %d TBS %d\n", ulsch->slot, harq_process->TBS);
nr_fill_indication(phy_vars_gNB, ulsch->frame, ulsch->slot, ULSCH_id, harq_pid, 0, 0);
ulsch->active = false;
harq_process->round = 0;
} else {
uint8_t harq_pid = ulsch->harq_pid;
LOG_D(PHY,
"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d)\n",
phy_vars_gNB->Mod_id,
ulsch->frame,
ulsch->slot,
harq_pid,
ulsch->active,
harq_process->round,
harq_process->TBS);
nr_fill_indication(phy_vars_gNB, ulsch->frame, ulsch->slot, ULSCH_id, harq_pid, 1, 0);
ulsch->handled = 1;
decodeIterations = ulsch->max_ldpc_iterations + 1;
LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id);
}
ulsch->last_iteration_cnt = decodeIterations;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0);
return 0;
}
"ULSCH Decoding, harq_pid %d rnti %x TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, Coderate %f RV %d round %d new RX %d\n",
harq_pid,
ulsch->rnti,
TB_parameters->A,
TB_parameters->G,
TB_parameters->mcs,
TB_parameters->nb_layers,
TB_parameters->nb_rb,
TB_parameters->Qm,
pusch_pdu->target_code_rate / 10240.0f,
pusch_pdu->pusch_data.rv_index,
harq_process->round,
harq_process->harq_to_be_cleared);
// [hna] Perform nr_segmenation with input and output set to NULL to calculate only (C, K, Z, F)
nr_segmentation(NULL,
NULL,
lenWithCrc(1, TB_parameters->A), // size in case of 1 segment
&TB_parameters->C,
&TB_parameters->K,
&TB_parameters->Z, // [hna] Z is Zc
&TB_parameters->F,
TB_parameters->BG);
harq_process->C = TB_parameters->C;
harq_process->K = TB_parameters->K;
harq_process->Z = TB_parameters->Z;
harq_process->F = TB_parameters->F;
uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers; // number of segments to be allocated
if (TB_parameters->C > a_segments) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A);
return(-1);
}
if (TB_parameters->nb_rb != 273) {
a_segments = a_segments*TB_parameters->nb_rb;
a_segments = a_segments/273 +1;
}
if (TB_parameters->C > a_segments) {
LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments);
return -1;
}
max_num_segments = max(max_num_segments, TB_parameters->C);
#ifdef DEBUG_ULSCH_DECODING
printf("ulsch decoding nr segmentation Z %d\n", TB_parameters->Z);
if (!frame % 100)
printf("K %d C %d Z %d \n",
TB_parameters->K,
TB_parameters->C,
TB_parameters->Z);
printf("Segmentation: C %d, K %d\n",
TB_parameters->C,
TB_parameters->K);
#endif
TB_parameters->max_ldpc_iterations = ulsch->max_ldpc_iterations;
TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index;
TB_parameters->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes;
TB_parameters->abort_decode = &harq_process->abort_decode;
set_abort(&harq_process->abort_decode, false);
int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
uint8_t ULSCH_id,
short *ulsch_llr,
NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *pusch_pdu,
uint32_t frame,
uint8_t nr_tti_rx,
uint8_t harq_pid,
uint32_t G,
thread_info_tm_t *t_info)
{
if (!ulsch_llr) {
LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n");
return -1;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING, 1);
nrLDPC_segment_decoding_parameters_t segments[nb_pusch][max_num_segments];
memset(segments, 0, sizeof(segments));
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_gNB_PUSCH *pusch = &phy_vars_gNB->pusch_vars[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
short *ulsch_llr = phy_vars_gNB->pusch_vars[ULSCH_id].llr;
if (!harq_process) {
LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n");
return -1;
}
if (!ulsch_llr) {
LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n");
return -1;
}
// ------------------------------------------------------------------
const uint16_t nb_rb = pusch_pdu->rb_size;
const uint8_t Qm = pusch_pdu->qam_mod_order;
const uint8_t mcs = pusch_pdu->mcs_index;
const uint8_t n_layers = pusch_pdu->nrOfLayers;
// ------------------------------------------------------------------
harq_process->TBS = pusch_pdu->pusch_data.tb_size;
t_nrLDPC_dec_params decParams = {.check_crc = check_crc};
decParams.BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph;
const uint32_t A = (harq_process->TBS) << 3;
NR_gNB_PHY_STATS_t *stats = get_phy_stats(phy_vars_gNB, ulsch->rnti);
if (stats) {
stats->frame = frame;
stats->ulsch_stats.round_trials[harq_process->round]++;
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
stats->ulsch_stats.power[aarx] = dB_fixed_x10(pusch->ulsch_power[aarx]);
stats->ulsch_stats.noise_power[aarx] = dB_fixed_x10(pusch->ulsch_noise_power[aarx]);
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id];
TB_parameters->segments = segments[pusch_id];
uint32_t r_offset = 0;
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
segment_parameters->E = nr_get_E(TB_parameters->G,
TB_parameters->C,
TB_parameters->Qm,
TB_parameters->nb_layers,
r);
segment_parameters->R = nr_get_R_ldpc_decoder(TB_parameters->rv_index,
segment_parameters->E,
TB_parameters->BG,
TB_parameters->Z,
&harq_process->llrLen,
harq_process->round);
segment_parameters->llr = ulsch_llr + r_offset;
segment_parameters->d = harq_process->d[r];
segment_parameters->d_to_be_cleared = &harq_process->d_to_be_cleared[r];
segment_parameters->c = harq_process->c[r];
segment_parameters->decodeSuccess = false;
reset_meas(&segment_parameters->ts_deinterleave);
reset_meas(&segment_parameters->ts_rate_unmatch);
reset_meas(&segment_parameters->ts_ldpc_decode);
r_offset += segment_parameters->E;
}
if (!harq_process->harq_to_be_cleared) {
stats->ulsch_stats.current_Qm = Qm;
stats->ulsch_stats.current_RI = n_layers;
stats->ulsch_stats.total_bytes_tx += harq_process->TBS;
if (harq_process->harq_to_be_cleared) {
for (int r = 0; r < TB_parameters->C; r++) {
harq_process->d_to_be_cleared[r] = true;
}
harq_process->harq_to_be_cleared = false;
}
}
LOG_D(PHY,
"ULSCH Decoding, harq_pid %d rnti %x TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, Coderate %f RV %d round %d new RX %d\n",
harq_pid,
ulsch->rnti,
A,
G,
mcs,
n_layers,
nb_rb,
Qm,
pusch_pdu->target_code_rate / 10240.0f,
pusch_pdu->pusch_data.rv_index,
harq_process->round,
harq_process->harq_to_be_cleared);
// [hna] Perform nr_segmenation with input and output set to NULL to calculate only (C, K, Z, F)
nr_segmentation(NULL,
NULL,
lenWithCrc(1, A), // size in case of 1 segment
&harq_process->C,
&harq_process->K,
&harq_process->Z, // [hna] Z is Zc
&harq_process->F,
decParams.BG);
uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * n_layers; // number of segments to be allocated
if (harq_process->C > a_segments) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, A);
return(-1);
}
if (nb_rb != 273) {
a_segments = a_segments*nb_rb;
a_segments = a_segments/273 +1;
}
if (harq_process->C > a_segments) {
LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments);
return -1;
}
#ifdef DEBUG_ULSCH_DECODING
printf("ulsch decoding nr segmentation Z %d\n", harq_process->Z);
if (!frame % 100)
printf("K %d C %d Z %d \n", harq_process->K, harq_process->C, harq_process->Z);
printf("Segmentation: C %d, K %d\n",harq_process->C,harq_process->K);
#endif
decParams.Z = harq_process->Z;
decParams.numMaxIter = ulsch->max_ldpc_iterations;
decParams.Qm = Qm;
decParams.rv = pusch_pdu->pusch_data.rv_index;
decParams.outMode = 0;
decParams.setCombIn = !harq_process->harq_to_be_cleared;
if (harq_process->harq_to_be_cleared) {
for (int r = 0; r < harq_process->C; r++)
harq_process->d_to_be_cleared[r] = true;
harq_process->harq_to_be_cleared = false;
int ret_decoder = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
// post decode
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
nrLDPC_TB_decoding_parameters_t TB_parameters = TBs[pusch_id];
uint32_t offset = 0;
for (int r = 0; r < TB_parameters.C; r++) {
nrLDPC_segment_decoding_parameters_t nrLDPC_segment_decoding_parameters = TB_parameters.segments[r];
// Copy c to b in case of decoding success
if (nrLDPC_segment_decoding_parameters.decodeSuccess) {
memcpy(harq_process->b + offset, harq_process->c[r], (harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
} else {
LOG_D(PHY, "uplink segment error %d/%d\n", r, harq_process->C);
LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id);
}
offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
}
}
if (phy_vars_gNB->ldpc_offload_flag)
return decode_offload(phy_vars_gNB, ULSCH_id, ulsch_llr, pusch_pdu, &decParams, harq_pid, G);
harq_process->processedSegments = 0;
uint32_t offset = 0, r_offset = 0;
set_abort(&harq_process->abort_decode, false);
for (int r = 0; r < harq_process->C; r++) {
int E = nr_get_E(G, harq_process->C, Qm, n_layers, r);
ldpcDecode_t *rdata = &((ldpcDecode_t *)t_info->buf)[t_info->len];
DevAssert(t_info->len < t_info->cap);
rdata->ans = &t_info->ans[t_info->len];
t_info->len += 1;
decParams.R = nr_get_R_ldpc_decoder(pusch_pdu->pusch_data.rv_index,
E,
decParams.BG,
decParams.Z,
&harq_process->llrLen,
harq_process->round);
rdata->gNB = phy_vars_gNB;
rdata->ulsch_harq = harq_process;
rdata->decoderParms = decParams;
rdata->ulsch_llr = ulsch_llr;
rdata->Kc = decParams.BG == 2 ? 52 : 68;
rdata->harq_pid = harq_pid;
rdata->segment_r = r;
rdata->nbSegments = harq_process->C;
rdata->E = E;
rdata->A = A;
rdata->Qm = Qm;
rdata->r_offset = r_offset;
rdata->Kr_bytes = harq_process->K >> 3;
rdata->rv_index = pusch_pdu->pusch_data.rv_index;
rdata->offset = offset;
rdata->ulsch = ulsch;
rdata->ulsch_id = ULSCH_id;
rdata->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes;
task_t t = {.func = &nr_processULSegment, .args = rdata};
pushTpool(&phy_vars_gNB->threadPool, t);
LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r);
r_offset += E;
offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
}
return harq_process->C;
return ret_decoder;
}
......@@ -19,16 +19,8 @@
* contact@openairinterface.org
*/
/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
* \brief Top-level routines for decoding Turbo-coded (DLSCH) transport channels from 36-212, V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_decoding_slot.c
*/
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "PHY/defs_nr_UE.h"
......@@ -36,6 +28,7 @@
#include "PHY/phy_extern_nr_ue.h"
#include "PHY/CODING/coding_extern.h"
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "SCHED_NR_UE/defs.h"
#include "SIMULATION/TOOLS/sim.h"
......@@ -45,11 +38,6 @@
#include "openair1/PHY/TOOLS/phy_scope_interface.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
//#define ENABLE_PHY_PAYLOAD_DEBUG 1
#define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
//#define OAI_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX
static extended_kpi_ue kpiStructure = {0};
extended_kpi_ue* getKPIUE(void) {
......@@ -69,371 +57,302 @@ void nr_dlsch_unscrambling(int16_t *llr, uint32_t size, uint8_t q, uint32_t Nid,
nr_codeword_unscrambling(llr, size, q, Nid, n_RNTI);
}
static bool nr_ue_postDecode(PHY_VARS_NR_UE *phy_vars_ue,
ldpcDecode_ue_t *rdata,
bool last,
int b_size,
uint8_t b[b_size],
int *num_seg_ok,
const UE_nr_rxtx_proc_t *proc)
/*! \brief Prepare necessary parameters for nrLDPC_coding_interface
*/
uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t *dlsch,
int16_t **dlsch_llr,
uint8_t **b,
int *G,
int nb_dlsch,
uint8_t *DLSCH_ids)
{
NR_DL_UE_HARQ_t *harq_process = rdata->harq_process;
NR_UE_DLSCH_t *dlsch = (NR_UE_DLSCH_t *) rdata->dlsch;
int r = rdata->segment_r;
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_DEINTERLEAVING_STATS], &rdata->ts_deinterleave);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &rdata->ts_rate_unmatch);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &rdata->ts_ldpc_decode);
bool decodeSuccess = (rdata->decodeIterations < (1+dlsch->max_ldpc_iterations));
nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch];
memset(TBs, 0, sizeof(TBs));
nrLDPC_slot_decoding_parameters_t slot_parameters = {
.frame = proc->frame_rx,
.slot = proc->nr_slot_rx,
.nb_TBs = nb_dlsch,
.threadPool = &get_nrUE_params()->Tpool,
.TBs = TBs
};
int max_num_segments = 0;
for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) {
uint8_t DLSCH_id = DLSCH_ids[pdsch_id];
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
uint8_t dmrs_Type = dlsch_config->dmrsConfigType;
int harq_pid = dlsch_config->harq_process_nbr;
NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid];
AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type);
uint8_t nb_re_dmrs;
LOG_D(PHY, "Round %d RV idx %d\n", harq_process->DLround, dlsch->dlsch_config.rv);
if (dmrs_Type == NFAPI_NR_DMRS_TYPE1)
nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups;
else
nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups;
uint16_t dmrs_length = get_num_dmrs(dlsch_config->dlDmrsSymbPos);
if (!harq_process) {
LOG_E(PHY, "dlsch_decoding_slot.c: NULL harq_process pointer\n");
return dlsch[DLSCH_id].max_ldpc_iterations + 1;
}
if (decodeSuccess) {
memcpy(b+rdata->offset,
harq_process->c[r],
rdata->Kr_bytes - (harq_process->F>>3) -((harq_process->C>1)?3:0));
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id];
/* Neither harq_pid nor DLSCH_id are unique in the instance
* but their combination is.
* Since DLSCH_id < 2
* then 2 * harq_pid + DLSCH_id is unique.
*/
TB_parameters->harq_unique_pid = 2 * harq_pid + DLSCH_id;
// ------------------------------------------------------------------
TB_parameters->G = G[DLSCH_id];
TB_parameters->nb_rb = dlsch_config->number_rbs;
TB_parameters->Qm = dlsch_config->qamModOrder;
TB_parameters->mcs = dlsch_config->mcs;
TB_parameters->nb_layers = dlsch[DLSCH_id].Nl;
TB_parameters->BG = dlsch_config->ldpcBaseGraph;
TB_parameters->A = dlsch_config->TBS;
// ------------------------------------------------------------------
TB_parameters->processedSegments = &harq_process->processedSegments;
float Coderate = (float)dlsch->dlsch_config.targetCodeRate / 10240.0f;
LOG_D(
PHY,
"%d.%d DLSCH %d Decoding, harq_pid %d TBS %d G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d Qm %d "
"Coderate %f\n",
slot_parameters.frame,
slot_parameters.slot,
DLSCH_id,
harq_pid,
dlsch_config->TBS,
TB_parameters->G,
nb_re_dmrs,
dmrs_length,
TB_parameters->mcs,
TB_parameters->nb_layers,
dlsch_config->number_symbols,
TB_parameters->nb_rb,
TB_parameters->Qm,
Coderate);
(*num_seg_ok)++;
} else {
LOG_D(PHY, "DLSCH %d in error\n", rdata->dlsch_id);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN);
if (harq_process->first_rx == 1) {
// This is a new packet, so compute quantities regarding segmentation
nr_segmentation(NULL,
NULL,
lenWithCrc(1, TB_parameters->A), // We give a max size in case of 1 segment
&TB_parameters->C,
&TB_parameters->K,
&TB_parameters->Z, // [hna] Z is Zc
&TB_parameters->F,
TB_parameters->BG);
harq_process->C = TB_parameters->C;
harq_process->K = TB_parameters->K;
harq_process->Z = TB_parameters->Z;
harq_process->F = TB_parameters->F;
if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A);
return dlsch[DLSCH_id].max_ldpc_iterations + 1;
}
if (!last)
return false; // continue decoding
// all segments are done
kpiStructure.nb_total++;
kpiStructure.blockSize = dlsch->dlsch_config.TBS;
kpiStructure.dl_mcs = dlsch->dlsch_config.mcs;
kpiStructure.nofRBs = dlsch->dlsch_config.number_rbs;
harq_process->decodeResult = *num_seg_ok == harq_process->C;
if (harq_process->decodeResult && harq_process->C > 1) {
/* check global CRC */
int A = dlsch->dlsch_config.TBS;
// we have regrouped the transport block
if (!check_crc(b, lenWithCrc(1, A), crcType(1, A))) {
LOG_E(PHY,
" Frame %d.%d LDPC global CRC fails, but individual LDPC CRC succeeded. %d segs\n",
proc->frame_rx,
proc->nr_slot_rx,
harq_process->C);
harq_process->decodeResult = false;
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!slot_parameters.frame % 100))
LOG_I(PHY, "K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, TB_parameters->nb_layers);
// clear HARQ buffer
for (int i = 0; i < harq_process->C; i++)
memset(harq_process->d[i], 0, 5 * 8448 * sizeof(int16_t));
} else {
// This is not a new packet, so retrieve previously computed quantities regarding segmentation
TB_parameters->C = harq_process->C;
TB_parameters->K = harq_process->K;
TB_parameters->Z = harq_process->Z;
TB_parameters->F = harq_process->F;
}
}
max_num_segments = max(max_num_segments, TB_parameters->C);
if (harq_process->decodeResult) {
// We search only a reccuring OAI error that propagates all 0 packets with a 0 CRC, so we
const int sz = dlsch->dlsch_config.TBS / 8;
if (b[sz] == 0 && b[sz + 1] == 0) {
// do the check only if the 2 first bytes of the CRC are 0 (it can be CRC16 or CRC24)
int i = 0;
while (b[i] == 0 && i < sz)
i++;
if (i == sz) {
LOG_E(PHY,
"received all 0 pdu, consider it false reception, even if the TS 38.212 7.2.1 says only we should attach the "
"corresponding CRC, and nothing prevents to have a all 0 packet\n");
harq_process->decodeResult = false;
}
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT);
if (harq_process->decodeResult) {
LOG_D(PHY, "DLSCH received ok \n");
harq_process->status = SCH_IDLE;
dlsch->last_iteration_cnt = rdata->decodeIterations;
} else {
LOG_D(PHY, "DLSCH received nok \n");
kpiStructure.nb_nack++;
dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1;
}
return true; // end TB decoding
}
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD))
LOG_I(PHY, "Segmentation: C %d, K %d\n", harq_process->C, harq_process->K);
static void nr_processDLSegment(void *arg)
{
ldpcDecode_ue_t *rdata = (ldpcDecode_ue_t*) arg;
NR_UE_DLSCH_t *dlsch = rdata->dlsch;
NR_DL_UE_HARQ_t *harq_process= rdata->harq_process;
t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms;
int r = rdata->segment_r;
int E = rdata->E;
int Qm = rdata->Qm;
int r_offset = rdata->r_offset;
uint8_t kc = rdata->Kc;
uint32_t Tbslbrm = rdata->Tbslbrm;
short* dlsch_llr = rdata->dlsch_llr;
int8_t LDPCoutput[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__((aligned(32)));
int16_t z[68 * 384 + 16] __attribute__((aligned(16)));
int8_t l [68*384 + 16] __attribute__ ((aligned(16)));
const int Kr = harq_process->K;
const int K_bits_F = Kr - harq_process->F;
t_nrLDPC_time_stats procTime = {0};
//if we return before LDPC decoder run, the block is in error
rdata->decodeIterations = dlsch->max_ldpc_iterations + 1;
start_meas(&rdata->ts_deinterleave);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN);
int16_t w[E];
nr_deinterleaving_ldpc(E,
Qm,
w, // [hna] w is e
dlsch_llr+r_offset);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_OUT);
stop_meas(&rdata->ts_deinterleave);
start_meas(&rdata->ts_rate_unmatch);
/* LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,E %d, F %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n",
harq_pid,r, G,E,harq_process->F,
Kr*3,
harq_process->TBS,
Qm,
harq_process->nb_rb,
harq_process->Nl,
harq_process->rvidx,
harq_process->round); */
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN);
if (nr_rate_matching_ldpc_rx(Tbslbrm,
p_decoderParms->BG,
p_decoderParms->Z,
harq_process->d[r],
w,
harq_process->C,
dlsch->dlsch_config.rv,
harq_process->first_rx,
E,
harq_process->F,
Kr-harq_process->F-2*(p_decoderParms->Z))==-1) {
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT);
stop_meas(&rdata->ts_rate_unmatch);
LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n");
return;
TB_parameters->max_ldpc_iterations = dlsch[DLSCH_id].max_ldpc_iterations;
TB_parameters->rv_index = dlsch_config->rv;
TB_parameters->tbslbrm = dlsch_config->tbslbrm;
TB_parameters->abort_decode = &harq_process->abort_decode;
set_abort(&harq_process->abort_decode, false);
}
stop_meas(&rdata->ts_rate_unmatch);
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) {
LOG_D(PHY,"decoder input(segment %u) :",r);
for (int i=0; i<E; i++)
LOG_D(PHY,"%d : %d\n",i,harq_process->d[r][i]);
LOG_D(PHY,"\n");
}
{
start_meas(&rdata->ts_ldpc_decode);
//set first 2*Z_c bits to zeros
memset(z,0,2*harq_process->Z*sizeof(int16_t));
//set Filler bits
memset((z+K_bits_F),127,harq_process->F*sizeof(int16_t));
//Move coded bits before filler bits
memcpy((z+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t));
//skip filler bits
memcpy((z+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t));
//Saturate coded bits before decoding into 8 bits values
simde__m128i *pv = (simde__m128i*)&z;
simde__m128i *pl = (simde__m128i*)&l;
for (int i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) {
pl[j] = simde_mm_packs_epi16(pv[i],pv[i+1]);
nrLDPC_segment_decoding_parameters_t segments[nb_dlsch][max_num_segments];
memset(segments, 0, sizeof(segments));
bool d_to_be_cleared[nb_dlsch][max_num_segments];
memset(d_to_be_cleared, 0, sizeof(d_to_be_cleared));
for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) {
uint8_t DLSCH_id = DLSCH_ids[pdsch_id];
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
int harq_pid = dlsch_config->harq_process_nbr;
NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid];
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id];
TB_parameters->segments = segments[pdsch_id];
uint32_t r_offset = 0;
for (int r = 0; r < TB_parameters->C; r++) {
if (harq_process->first_rx == 1)
d_to_be_cleared[pdsch_id][r] = true;
else
d_to_be_cleared[pdsch_id][r] = false;
nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
segment_parameters->E = nr_get_E(TB_parameters->G,
TB_parameters->C,
TB_parameters->Qm,
TB_parameters->nb_layers,
r);
segment_parameters->R = nr_get_R_ldpc_decoder(TB_parameters->rv_index,
segment_parameters->E,
TB_parameters->BG,
TB_parameters->Z,
&harq_process->llrLen,
harq_process->DLround);
segment_parameters->llr = dlsch_llr[DLSCH_id] + r_offset;
segment_parameters->d = harq_process->d[r];
segment_parameters->d_to_be_cleared = &d_to_be_cleared[pdsch_id][r];
segment_parameters->c = harq_process->c[r];
segment_parameters->decodeSuccess = false;
reset_meas(&segment_parameters->ts_deinterleave);
reset_meas(&segment_parameters->ts_rate_unmatch);
reset_meas(&segment_parameters->ts_ldpc_decode);
r_offset += segment_parameters->E;
}
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_IN);
uint32_t A = dlsch->dlsch_config.TBS;
p_decoderParms->E = lenWithCrc(harq_process->C, A);
p_decoderParms->crc_type = crcType(harq_process->C, A);
rdata->decodeIterations =
ldpc_interface.LDPCdecoder(p_decoderParms, 0, 0, 0, l, LDPCoutput, &procTime, &harq_process->abort_decode);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_OUT);
if (rdata->decodeIterations <= dlsch->max_ldpc_iterations)
memcpy(harq_process->c[r], LDPCoutput, Kr >> 3);
stop_meas(&rdata->ts_ldpc_decode);
}
completed_task_ans(rdata->ans);
}
uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
const UE_nr_rxtx_proc_t *proc,
int eNB_id,
short *dlsch_llr,
NR_DL_FRAME_PARMS *frame_parms,
NR_UE_DLSCH_t *dlsch,
NR_DL_UE_HARQ_t *harq_process,
uint32_t frame,
uint16_t nb_symb_sch,
uint8_t nr_slot_rx,
uint8_t harq_pid,
int b_size,
uint8_t b[b_size],
int G)
{
uint32_t ret,offset;
uint32_t r,r_offset=0,Kr=8424,Kr_bytes;
t_nrLDPC_dec_params decParams;
decParams.check_crc = check_crc;
if (!harq_process) {
LOG_E(PHY,"dlsch_decoding.c: NULL harq_process pointer\n");
return(dlsch->max_ldpc_iterations + 1);
}
int ret_decoder = phy_vars_ue->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
// HARQ stats
LOG_D(PHY, "Round %d RV idx %d\n", harq_process->DLround, dlsch->dlsch_config.rv);
uint16_t nb_rb;// = 30;
uint8_t dmrs_Type = dlsch->dlsch_config.dmrsConfigType;
AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type);
uint8_t nb_re_dmrs;
if (dmrs_Type==NFAPI_NR_DMRS_TYPE1) {
nb_re_dmrs = 6*dlsch->dlsch_config.n_dmrs_cdm_groups;
} else {
nb_re_dmrs = 4*dlsch->dlsch_config.n_dmrs_cdm_groups;
if (ret_decoder != 0) {
return dlsch->max_ldpc_iterations + 1;
}
uint16_t dmrs_length = get_num_dmrs(dlsch->dlsch_config.dlDmrsSymbPos);
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN);
// post decode
for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) {
uint8_t DLSCH_id = DLSCH_ids[pdsch_id];
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
int harq_pid = dlsch_config->harq_process_nbr;
NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid];
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id];
uint32_t offset = 0;
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
if (segment_parameters->decodeSuccess) {
memcpy(b[DLSCH_id] + offset,
harq_process->c[r],
(harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
} else {
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
LOG_D(PHY, "frame=%d, slot=%d, first_rx=%d, rv_index=%d\n", proc->frame_rx, proc->nr_slot_rx, harq_process->first_rx, dlsch_config->rv);
LOG_D(PHY, "downlink segment error %d/%d\n", r, harq_process->C);
LOG_D(PHY, "DLSCH %d in error\n", DLSCH_id);
}
offset += (harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0);
//NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0];
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_DEINTERLEAVING_STATS], &segment_parameters->ts_deinterleave);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &segment_parameters->ts_rate_unmatch);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &segment_parameters->ts_ldpc_decode);
if (!dlsch_llr) {
LOG_E(PHY,"dlsch_decoding.c: NULL dlsch_llr pointer\n");
return(dlsch->max_ldpc_iterations + 1);
}
}
if (!frame_parms) {
LOG_E(PHY,"dlsch_decoding.c: NULL frame_parms pointer\n");
return(dlsch->max_ldpc_iterations + 1);
}
kpiStructure.nb_total++;
kpiStructure.blockSize = dlsch_config->TBS;
kpiStructure.dl_mcs = dlsch_config->mcs;
kpiStructure.nofRBs = dlsch_config->number_rbs;
nb_rb = dlsch->dlsch_config.number_rbs;
uint32_t A = dlsch->dlsch_config.TBS;
ret = dlsch->max_ldpc_iterations + 1;
dlsch->last_iteration_cnt = ret;
// target_code_rate is in 0.1 units
float Coderate = (float) dlsch->dlsch_config.targetCodeRate / 10240.0f;
decParams.BG = dlsch->dlsch_config.ldpcBaseGraph;
unsigned int kc = decParams.BG == 2 ? 52 : 68;
if (harq_process->first_rx == 1) {
// This is a new packet, so compute quantities regarding segmentation
nr_segmentation(NULL,
NULL,
lenWithCrc(1, A), // We give a max size in case of 1 segment
&harq_process->C,
&harq_process->K,
&harq_process->Z, // [hna] Z is Zc
&harq_process->F,
decParams.BG);
if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * dlsch->Nl) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, A);
return(-1);
harq_process->decodeResult = harq_process->processedSegments == harq_process->C;
if (harq_process->decodeResult && harq_process->C > 1) {
/* check global CRC */
int A = dlsch->dlsch_config.TBS;
// we have regrouped the transport block
if (!check_crc(b[DLSCH_id], lenWithCrc(1, A), crcType(1, A))) {
LOG_E(PHY,
" Frame %d.%d LDPC global CRC fails, but individual LDPC CRC succeeded. %d segs\n",
proc->frame_rx,
proc->nr_slot_rx,
harq_process->C);
harq_process->decodeResult = false;
}
}
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!frame%100))
LOG_I(PHY,"K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, dlsch->Nl);
// clear HARQ buffer
for (int i=0; i <harq_process->C; i++)
memset(harq_process->d[i],0,5*8448*sizeof(int16_t));
}
if (harq_process->decodeResult) {
// We search only a reccuring OAI error that propagates all 0 packets with a 0 CRC, so we
const int sz = dlsch->dlsch_config.TBS / 8;
if (b[DLSCH_id][sz] == 0 && b[DLSCH_id][sz + 1] == 0) {
// do the check only if the 2 first bytes of the CRC are 0 (it can be CRC16 or CRC24)
int i = 0;
while (b[DLSCH_id][i] == 0 && i < sz)
i++;
if (i == sz) {
LOG_E(PHY,
"received all 0 pdu, consider it false reception, even if the TS 38.212 7.2.1 says only we should attach the "
"corresponding CRC, and nothing prevents to have a all 0 packet\n");
harq_process->decodeResult = false;
}
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT);
decParams.Z = harq_process->Z;
decParams.numMaxIter = dlsch->max_ldpc_iterations;
decParams.outMode = 0;
r_offset = 0;
uint16_t a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * dlsch->Nl; //number of segments to be allocated
if (harq_process->decodeResult) {
LOG_D(PHY, "DLSCH received ok \n");
harq_process->status = SCH_IDLE;
dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations;
} else {
LOG_D(PHY, "DLSCH received nok \n");
kpiStructure.nb_nack++;
dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1;
}
if (nb_rb != 273) {
a_segments = a_segments*nb_rb;
a_segments = a_segments/273 +1;
}
uint8_t dmrs_Type = dlsch_config->dmrsConfigType;
uint8_t nb_re_dmrs;
if (dmrs_Type == NFAPI_NR_DMRS_TYPE1)
nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups;
else
nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups;
uint16_t dmrs_length = get_num_dmrs(dlsch_config->dlDmrsSymbPos);
float Coderate = (float)dlsch->dlsch_config.targetCodeRate / 10240.0f;
LOG_D(PHY,
"%d.%d DLSCH Decoded, harq_pid %d, round %d, result: %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d "
"nb_symb_sch %d "
"nb_rb %d Qm %d Coderate %f\n",
proc->frame_rx,
proc->nr_slot_rx,
harq_pid,
harq_process->DLround,
harq_process->decodeResult,
dlsch->dlsch_config.TBS,
dlsch->dlsch_config.TBS / 8,
G[DLSCH_id],
nb_re_dmrs,
dmrs_length,
dlsch->dlsch_config.mcs,
dlsch->Nl,
dlsch_config->number_symbols,
dlsch_config->number_rbs,
dlsch_config->qamModOrder,
Coderate);
if (harq_process->C > a_segments) {
LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments);
return((1+dlsch->max_ldpc_iterations));
}
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD))
LOG_I(PHY,"Segmentation: C %d, K %d\n",harq_process->C,harq_process->K);
Kr = harq_process->K;
Kr_bytes = Kr>>3;
offset = 0;
ldpcDecode_ue_t arr[harq_process->C];
task_ans_t ans[harq_process->C];
memset(ans, 0, harq_process->C * sizeof(task_ans_t));
set_abort(&harq_process->abort_decode, false);
for (r=0; r<harq_process->C; r++) {
//printf("start rx segment %d\n",r);
uint32_t E = nr_get_E(G, harq_process->C, dlsch->dlsch_config.qamModOrder, dlsch->Nl, r);
decParams.R = nr_get_R_ldpc_decoder(dlsch->dlsch_config.rv, E, decParams.BG, decParams.Z, &harq_process->llrLen, harq_process->DLround);
ldpcDecode_ue_t *rdata = &arr[r];
rdata->ans = &ans[r];
rdata->phy_vars_ue = phy_vars_ue;
rdata->harq_process = harq_process;
rdata->decoderParms = decParams;
rdata->dlsch_llr = dlsch_llr;
rdata->Kc = kc;
rdata->segment_r = r;
rdata->E = E;
rdata->Qm = dlsch->dlsch_config.qamModOrder;
rdata->r_offset = r_offset;
rdata->Kr_bytes = Kr_bytes;
rdata->rv_index = dlsch->dlsch_config.rv;
rdata->Tbslbrm = dlsch->dlsch_config.tbslbrm;
rdata->offset = offset;
rdata->dlsch = dlsch;
rdata->dlsch_id = harq_pid;
reset_meas(&rdata->ts_deinterleave);
reset_meas(&rdata->ts_rate_unmatch);
reset_meas(&rdata->ts_ldpc_decode);
task_t t = {.args = rdata, .func = nr_processDLSegment};
pushTpool(&get_nrUE_params()->Tpool, t);
LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r);
r_offset += E;
offset += (Kr_bytes - (harq_process->F>>3) - ((harq_process->C>1)?3:0));
//////////////////////////////////////////////////////////////////////////////////////////
}
int num_seg_ok = 0;
int nbDecode = harq_process->C;
if (nbDecode > 0) {
join_task_ans(ans, nbDecode);
for (size_t i = 0; i < nbDecode; ++i) {
nr_ue_postDecode(phy_vars_ue, &arr[i], i == nbDecode - 1, b_size, b, &num_seg_ok, proc);
}
}
LOG_D(PHY,
"%d.%d DLSCH Decoded, harq_pid %d, round %d, result: %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d "
"nb_symb_sch %d "
"nb_rb %d Qm %d Coderate %f\n",
frame,
nr_slot_rx,
harq_pid,
harq_process->DLround,
harq_process->decodeResult,
A,
A / 8,
G,
nb_re_dmrs,
dmrs_length,
dlsch->dlsch_config.mcs,
dlsch->Nl,
nb_symb_sch,
nb_rb,
dlsch->dlsch_config.qamModOrder,
Coderate);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_OUT);
ret = dlsch->last_iteration_cnt;
return(ret);
return dlsch[0].last_iteration_cnt;
}
......@@ -65,50 +65,51 @@ void nr_conjch0_mult_ch1(int *ch0,
unsigned short nb_rb,
unsigned char output_shift0);
/** \brief This is the top-level entry point for DLSCH decoding in UE. It should be replicated on several
threads (on multi-core machines) corresponding to different HARQ processes. The routine first
computes the segmentation information, followed by rate dematching and sub-block deinterleaving the of the
received LLRs computed by dlsch_demodulation for each transport block segment. It then calls the
turbo-decoding algorithm for each segment and stops after either after unsuccesful decoding of at least
one segment or correct decoding of all segments. Only the segment CRCs are check for the moment, the
overall CRC is ignored. Finally transport block reassembly is performed.
@param phy_vars_ue Pointer to ue variables
@param proc
@param eNB_id
@param dlsch_llr Pointer to LLR values computed by dlsch_demodulation
@param frame_parms Pointer to frame descriptor
@param dlsch Pointer to DLSCH descriptor
@param harq_process
@param frame Frame number
@param nb_symb_sch
@param nr_slot_rx Slot number
@param harq_pid
@param b_size
@param b
/** \brief This is the alternative top-level entry point for DLSCH decoding in UE.
It handles all the HARQ processes in only one call. The routine first
computes the segmentation information and then call LDPC decoder on the
received LLRs computed by dlsch_demodulation.
It stops after either unsuccesful decoding of at least
one segment or correct decoding of all segments. Only the segment CRCs are checked for the moment, the
overall CRC is ignored. Finally transport block reassembly is performed.
@param[in] phy_vars_ue Pointer to ue variables
@param[in] proc
@param[in] dlsch_llr Pointers to LLR values computed by dlsch_demodulation
@param[in] b
@param[in] G array of Gs
@param[in] nb_dlsch number of active downlink shared channels
@param[in] DLSCH_ids array of active downlink shared channels
@returns 0 on success, 1 on unsuccessful decoding
*/
uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
const UE_nr_rxtx_proc_t *proc,
int eNB_id,
short *dlsch_llr,
NR_DL_FRAME_PARMS *frame_parms,
NR_UE_DLSCH_t *dlsch,
NR_DL_UE_HARQ_t *harq_process,
uint32_t frame,
uint16_t nb_symb_sch,
uint8_t nr_slot_rx,
uint8_t harq_pid,
int b_size,
uint8_t b[b_size],
int G);
short **dlsch_llr,
uint8_t **b,
int *G,
int nb_dlsch,
uint8_t *DLSCH_ids);
/** \brief This is the alternative top-level entry point for ULSCH encoding in UE.
It handles all the HARQ processes in only one call. The routine first
computes the segmentation information, followed by LDPC encoding algorithm of the
Transport Block.
@param[in] phy_vars_ue pointer to ue variables
@param[in] ulsch Pointer to ULSCH descriptor
@param[in] frame frame index
@param[in] slot slot index
@param[in] G array of Gs
@param[in] nb_ulsch number of uplink shared channels
@param[in] ULSCH_ids array of uplink shared channel ids
@returns 0 on success, -1 on unsuccessful decoding
*/
int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
NR_UE_ULSCH_t *ulsch,
NR_DL_FRAME_PARMS* frame_parms,
uint8_t harq_pid,
uint32_t tb_size,
unsigned int G);
NR_UE_ULSCH_t *ulsch,
const uint32_t frame,
const uint8_t slot,
unsigned int *G,
int nb_ulsch,
uint8_t *ULSCH_ids);
/*! \brief Perform PUSCH scrambling. TS 38.211 V15.4.0 subclause 6.3.1.1
@param[in] in Pointer to input bits
......@@ -125,18 +126,23 @@ void nr_pusch_codeword_scrambling(uint8_t *in,
bool uci_on_pusch,
uint32_t* out);
/** \brief Perform the following functionalities:
/** \brief Alternative entry point to UE uplink shared channels procedures.
It handles all the HARQ processes in only one call.
Performs the following functionalities:
- encoding
- scrambling
- modulation
- transform precoding
@param[in] UE pointer to ue variables
@param[in] frame frame index
@param[in] slot slot index
@param[in] phy_data PHY layer informations
@param[in] c16_t
*/
void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
const unsigned char harq_pid,
const uint32_t frame,
const uint8_t slot,
const int gNB_id,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF);
......
......@@ -104,6 +104,8 @@ typedef struct {
uint8_t first_rx;
/// DLSCH status flag indicating
SCH_status_t status;
/// Pointer to the payload (38.212 V15.4.0 section 5.1)
uint8_t *b;
/// Pointers to transport block segments
uint8_t **c;
/// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15)
......@@ -126,6 +128,8 @@ typedef struct {
/// Last index of LLR buffer that contains information.
/// Used for computing LDPC decoder R
int llrLen;
/// Number of segments processed so far
uint32_t processedSegments;
decode_abort_t abort_decode;
} NR_DL_UE_HARQ_t;
......
......@@ -19,16 +19,8 @@
* contact@openairinterface.org
*/
/*! \file PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
* \brief Top-level routines for coding the ULSCH transport channel as described in 38.212 V15.4 2018-12
* \author Khalid Ahmed
* \date 2019
* \version 0.1
* \company Fraunhofer IIS
* \email: khalid.ahmed@iis.fraunhofer.de
* \note
* \warning
*/
/*! \file PHY/NR_UE_TRANSPORT/nr_ulsch_coding_slot.c
*/
#include "PHY/defs_UE.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
......@@ -36,54 +28,68 @@
#include "PHY/CODING/coding_extern.h"
#include "PHY/CODING/lte_interleaver_inline.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
#include "executables/nr-uesoftmodem.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
//#define DEBUG_ULSCH_CODING
int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
NR_UE_ULSCH_t *ulsch,
NR_DL_FRAME_PARMS* frame_parms,
uint8_t harq_pid,
uint32_t tb_size,
unsigned int G)
const uint32_t frame,
const uint8_t slot,
unsigned int *G,
int nb_ulsch,
uint8_t *ULSCH_ids)
{
start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN);
/////////////////////////parameters and variables initialization/////////////////////////
unsigned int crc = 1;
NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid];
uint16_t nb_rb = ulsch->pusch_pdu.rb_size;
uint32_t A = tb_size << 3;
uint32_t r_offset = 0;
// target_code_rate is in 0.1 units
float Coderate = (float) ulsch->pusch_pdu.target_code_rate / 10240.0f;
encoder_implemparams_t impp = {.n_segments = harq_process->C,
.macro_num = 0,
.K = harq_process->K,
.Kr = harq_process->K,
.Zc = harq_process->Z,
.BG = harq_process->BG,
.F = harq_process->F,
.rv = ulsch->pusch_pdu.pusch_data.rv_index,
.Qm = ulsch->pusch_pdu.qam_mod_order,
.tinput = NULL,
.tprep = NULL,
.tparity = NULL,
.toutput = NULL};
/////////////////////////////////////////////////////////////////////////////////////////
nrLDPC_TB_encoding_parameters_t TBs[nb_ulsch];
memset(TBs, 0, sizeof(TBs));
nrLDPC_slot_encoding_parameters_t slot_parameters = {
.frame = frame,
.slot = slot,
.nb_TBs = nb_ulsch,
.threadPool = &get_nrUE_params()->Tpool,
.tinput = NULL,
.tprep = NULL,
.tparity = NULL,
.toutput = NULL,
.TBs = TBs
};
int max_num_segments = 0;
for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id;
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id];
/* Neither harq_pid nor ULSCH_id are unique in the instance
* but their combination is.
* Since ULSCH_id < 2
* then 2 * harq_pid + ULSCH_id is unique.
*/
TB_parameters->harq_unique_pid = 2 * harq_pid + ULSCH_id;
/////////////////////////parameters and variables initialization/////////////////////////
unsigned int crc = 1;
NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid];
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch->pusch_pdu;
uint16_t nb_rb = pusch_pdu->rb_size;
uint32_t A = pusch_pdu->pusch_data.tb_size << 3;
uint8_t Qm = pusch_pdu->qam_mod_order;
// target_code_rate is in 0.1 units
float Coderate = (float)pusch_pdu->target_code_rate / 10240.0f;
LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, pusch_pdu->nrOfLayers);
LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G[pusch_id], Qm, Coderate);
LOG_D(NR_PHY, "harq_pid %d, pusch_data.new_data_indicator %d\n", harq_pid, pusch_pdu->pusch_data.new_data_indicator);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN);
LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, ulsch->pusch_pdu.nrOfLayers);
LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G, impp.Qm, Coderate);
LOG_D(NR_PHY, "harq_pid %d, pusch_data.new_data_indicator %d\n", harq_pid, ulsch->pusch_pdu.pusch_data.new_data_indicator);
if (ulsch->pusch_pdu.pusch_data.new_data_indicator) { // this is a new packet
#ifdef DEBUG_ULSCH_CODING
printf("encoding thinks this is a new packet \n");
#endif
///////////////////////// a---->| add CRC |---->b /////////////////////////
int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*ulsch->pusch_pdu.nrOfLayers*1056;
int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers * 1056;
int B;
if (A > NR_MAX_PDSCH_TBS) {
// Add 24-bit crc (polynomial A) to payload
......@@ -104,137 +110,90 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
///////////////////////// b---->| block segmentation |---->c /////////////////////////
harq_process->BG = ulsch->pusch_pdu.ldpcBaseGraph;
harq_process->BG = pusch_pdu->ldpcBaseGraph;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_IN);
start_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
impp.Kb = nr_segmentation(harq_process->payload_AB,
harq_process->c,
B,
&harq_process->C,
&harq_process->K,
&harq_process->Z,
&harq_process->F,
harq_process->BG);
stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
impp.n_segments = harq_process->C;
impp.K = harq_process->K;
impp.Kr = impp.K;
impp.Zc = harq_process->Z;
impp.F = harq_process->F;
impp.BG = harq_process->BG;
if (impp.n_segments > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * ulsch->pusch_pdu.nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B);
return(-1);
TB_parameters->Kb = nr_segmentation(harq_process->payload_AB,
harq_process->c,
B,
&harq_process->C,
&harq_process->K,
&harq_process->Z,
&harq_process->F,
harq_process->BG);
TB_parameters->C = harq_process->C;
TB_parameters->K = harq_process->K;
TB_parameters->Z = harq_process->Z;
TB_parameters->F = harq_process->F;
TB_parameters->BG = harq_process->BG;
if (TB_parameters->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B);
return (-1);
}
stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT);
#ifdef DEBUG_ULSCH_CODING
uint16_t Kr_bytes;
Kr_bytes = impp.Kr >> 3;
#endif
///////////////////////// c---->| LDCP coding |---->d ////////////////////////////////////
for (int r = 0; r < impp.n_segments; r++) {
#ifdef DEBUG_ULSCH_CODING
printf("Encoder: B %d F %d \n", B, impp.F);
printf("start ldpc encoder segment %d/%d\n", r, impp.n_segments);
printf("input %d %d %d %d %d \n", harq_process->c[r][0], harq_process->c[r][1], harq_process->c[r][2],harq_process->c[r][3], harq_process->c[r][4]);
for (int cnt = 0; cnt < 22 * impp.Zc / 8; cnt++) {
printf("%d ", harq_process->c[r][cnt]);
}
printf("\n");
#endif
max_num_segments = max(max_num_segments, TB_parameters->C);
TB_parameters->nb_rb = nb_rb;
TB_parameters->Qm = Qm;
TB_parameters->mcs = pusch_pdu->mcs_index;
TB_parameters->nb_layers = pusch_pdu->nrOfLayers;
TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index;
TB_parameters->G = G[pusch_id];
TB_parameters->tbslbrm = pusch_pdu->tbslbrm;
TB_parameters->A = A;
} // pusch_id
nrLDPC_segment_encoding_parameters_t segments[nb_ulsch][max_num_segments];
memset(segments, 0, sizeof(segments));
for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id;
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id];
NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid];
TB_parameters->segments = segments[pusch_id];
int r_offset = 0;
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
segment_parameters->c = harq_process->c[r];
segment_parameters->E = nr_get_E(TB_parameters->G,
TB_parameters->C,
TB_parameters->Qm,
TB_parameters->nb_layers,
r);
segment_parameters->output = harq_process->f + r_offset;
r_offset += segment_parameters->E;
reset_meas(&segment_parameters->ts_interleave);
reset_meas(&segment_parameters->ts_rate_match);
reset_meas(&segment_parameters->ts_ldpc_encode);
} // TB_parameters->C
} // pusch_id
///////////////////////// | LDCP coding | ////////////////////////////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
ue->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters);
for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) {
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id];
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_INTERLEAVING_STATS], &segment_parameters->ts_interleave);
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS], &segment_parameters->ts_rate_match);
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_LDPC_ENCODING_STATS], &segment_parameters->ts_ldpc_encode);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
}
if (ldpc_interface_offload.LDPCencoder) {
for (int j = 0; j < impp.n_segments; j++) {
impp.perCB[j].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
}
start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
ldpc_interface_offload.LDPCencoder(harq_process->c, &harq_process->f, &impp);
stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
} else {
if (ulsch->pusch_pdu.pusch_data.new_data_indicator) {
start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
for (int j = 0; j < (impp.n_segments / 8 + 1); j++) {
impp.macro_num = j;
impp.Kr = impp.K;
ldpc_interface.LDPCencoder(harq_process->c, harq_process->d, &impp);
}
stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT);
#ifdef DEBUG_ULSCH_CODING
write_output("ulsch_enc_input0.m", "enc_in0", &harq_process->c[0][0], Kr_bytes, 1, 4);
write_output("ulsch_enc_output0.m", "enc0", &harq_process->d[0][0], (3 * 8 * Kr_bytes) + 12, 1, 4);
#endif
}
///////////////////////////////////////////////////////////////////////////////
for (int r = 0; r < impp.n_segments; r++) { // looping over C segments
if (impp.F > 0) {
for (int k = impp.Kr - impp.F - 2 * impp.Zc; k < impp.Kr - 2 * impp.Zc; k++) {
harq_process->d[r][k] = NR_NULL;
}
}
LOG_D(PHY,
"Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb "
"%d, "
"rvidx %d)...\n",
r,
G,
impp.Kr * 3,
impp.Qm,
nb_rb,
ulsch->pusch_pdu.pusch_data.rv_index);
///////////////////////// d---->| Rate matching bit selection |---->e /////////////////////////
impp.perCB[r].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN);
start_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]);
if (nr_rate_matching_ldpc(ulsch->pusch_pdu.tbslbrm,
impp.BG,
impp.Zc,
harq_process->d[r],
harq_process->e + r_offset,
impp.n_segments,
impp.F,
impp.Kr - impp.F - 2 * impp.Zc,
impp.rv,
impp.perCB[r].E_cb)
== -1)
return -1;
stop_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_OUT);
#ifdef DEBUG_ULSCH_CODING
for (int i = 0; i < 16; i++)
printf("output ratematching e[%d]= %d r_offset %u\n", i, harq_process->e[i + r_offset], r_offset);
#endif
///////////////////////// e---->| Rate matching bit interleaving |---->f /////////////////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN);
start_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS);
nr_interleaving_ldpc(impp.perCB[r].E_cb, impp.Qm, harq_process->e + r_offset, harq_process->f + r_offset);
stop_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT);
#ifdef DEBUG_ULSCH_CODING
for (int i = 0; i < 16; i++)
printf("output interleaving f[%d]= %d r_offset %u\n", i, harq_process->f[i+r_offset], r_offset);
if (r == impp.n_segments - 1)
write_output("enc_output.m","enc", harq_process->f, G, 1, 4);
#endif
r_offset += impp.perCB[r].E_cb;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT);
stop_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS);
return(0);
return 0;
}
......@@ -462,65 +462,49 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
}
void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
const unsigned char harq_pid,
const uint32_t frame,
const uint8_t slot,
const int gNB_id,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF)
{
LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot);
int l_prime[2];
uint8_t nb_dmrs_re_per_rb;
int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id;
NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms;
if (UE->ul_harq_processes[harq_pid].ULstatus != ACTIVE)
return;
int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig
uint16_t number_dmrs_symbols = 0;
start_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
uint8_t ULSCH_ids[1];
unsigned int G[1];
uint8_t pusch_id = 0;
ULSCH_ids[pusch_id] = 0;
LOG_D(PHY, "nr_ue_ulsch_procedures_slot hard_id %d %d.%d prepare for coding\n", harq_pid, frame, slot);
NR_UE_ULSCH_t *ulsch_ue = &phy_data->ulsch;
NR_UL_UE_HARQ_t *harq_process_ul_ue = &UE->ul_harq_processes[harq_pid];
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch_ue->pusch_pdu;
uint32_t tb_size = pusch_pdu->pusch_data.tb_size;
AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 &&
pusch_pdu->pusch_uci.csi_part1_bit_length == 0 &&
pusch_pdu->pusch_uci.csi_part2_bit_length == 0,
"UCI on PUSCH not supported at PHY\n");
uint16_t number_dmrs_symbols = 0;
int start_symbol = pusch_pdu->start_symbol_index;
uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos;
uint16_t nb_rb = pusch_pdu->rb_size;
uint8_t number_of_symbols = pusch_pdu->nr_of_symbols;
uint8_t dmrs_type = pusch_pdu->dmrs_config_type;
uint16_t start_rb = pusch_pdu->rb_start;
uint16_t nb_rb = pusch_pdu->rb_size;
uint8_t Nl = pusch_pdu->nrOfLayers;
uint8_t mod_order = pusch_pdu->qam_mod_order;
uint16_t rnti = pusch_pdu->rnti;
uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data;
uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb+pusch_pdu->bwp_start)*NR_NB_SC_PER_RB;
if (start_sc >= frame_parms->ofdm_symbol_size)
start_sc -= frame_parms->ofdm_symbol_size;
ulsch_ue->Nid_cell = frame_parms->Nid_cell;
uint8_t dmrs_type = pusch_pdu->dmrs_config_type;
uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data;
uint8_t nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6 : 4) * cdm_grps_no_data;
int start_symbol = pusch_pdu->start_symbol_index;
uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos;
uint8_t mod_order = pusch_pdu->qam_mod_order;
uint8_t Nl = pusch_pdu->nrOfLayers;
uint32_t tb_size = pusch_pdu->pusch_data.tb_size;
uint16_t rnti = pusch_pdu->rnti;
for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) {
if((ul_dmrs_symb_pos >> i) & 0x01)
if ((ul_dmrs_symb_pos >> i) & 0x01)
number_dmrs_symbols += 1;
}
nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data;
LOG_D(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n",
rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb);
// TbD num_of_mod_symbols is set but never used
const uint32_t N_RE_prime = NR_NB_SC_PER_RB * number_of_symbols - nb_dmrs_re_per_rb * number_dmrs_symbols - N_PRB_oh;
harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb;
/////////////////////////PTRS parameters' initialization/////////////////////////
///////////
///////////////////////PTRS parameters' initialization///////////////////
unsigned int K_ptrs = 0, k_RE_ref = 0;
uint32_t unav_res = 0;
......@@ -531,32 +515,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
ulsch_ue->ptrs_symbols = 0;
set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols,
number_of_symbols,
start_symbol,
L_ptrs,
ul_dmrs_symb_pos);
set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, number_of_symbols, start_symbol, L_ptrs, ul_dmrs_symb_pos);
int n_ptrs = (nb_rb + K_ptrs - 1) / K_ptrs;
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ulsch_ue->ptrs_symbols,
start_symbol,
number_of_symbols);
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ulsch_ue->ptrs_symbols, start_symbol, number_of_symbols);
unav_res = n_ptrs * ptrsSymbPerSlot;
}
///////////
////////////////////////////////////////////////////////////////////
G[pusch_id] = nr_get_G(nb_rb, number_of_symbols, nb_dmrs_re_per_rb, number_dmrs_symbols, unav_res, mod_order, Nl);
/////////////////////////ULSCH coding/////////////////////////
///////////
unsigned int G = nr_get_G(nb_rb,
number_of_symbols,
nb_dmrs_re_per_rb,
number_dmrs_symbols,
unav_res,
mod_order,
Nl);
ws_trace_t tmp = {.nr = true,
.direction = DIRECTION_UPLINK,
.pdu_buffer = harq_process_ul_ue->payload_AB,
......@@ -571,19 +537,59 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
.oob_event_value = 0};
trace_pdu(&tmp);
if (nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, tb_size, G) == -1) {
/////////////////////////ULSCH coding/////////////////////////
if (nr_ulsch_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids) == -1) {
NR_UL_UE_HARQ_t *harq_process_ulsch = &UE->ul_harq_processes[harq_pid];
harq_process_ulsch->ULstatus = SCH_IDLE;
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
return;
}
///////////
////////////////////////////////////////////////////////////////////
LOG_D(PHY, "nr_ue_ulsch_procedures_slot hard_id %d %d.%d\n", harq_pid, frame, slot);
int l_prime[2];
NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms;
int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig
AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 && pusch_pdu->pusch_uci.csi_part1_bit_length == 0
&& pusch_pdu->pusch_uci.csi_part2_bit_length == 0,
"UCI on PUSCH not supported at PHY\n");
uint16_t start_rb = pusch_pdu->rb_start;
uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB;
if (start_sc >= frame_parms->ofdm_symbol_size)
start_sc -= frame_parms->ofdm_symbol_size;
ulsch_ue->Nid_cell = frame_parms->Nid_cell;
LOG_D(PHY,
"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d "
"cdmgrpsnodata %d "
"num_dmrs %d dmrs_re_per_rb %d\n",
rnti,
start_rb,
nb_rb,
mod_order,
Nl,
pusch_pdu->Tpmi,
pusch_pdu->bwp_start,
start_sc,
start_symbol,
number_of_symbols,
cdm_grps_no_data,
number_dmrs_symbols,
nb_dmrs_re_per_rb);
// TbD num_of_mod_symbols is set but never used
const uint32_t N_RE_prime = NR_NB_SC_PER_RB * number_of_symbols - nb_dmrs_re_per_rb * number_dmrs_symbols - N_PRB_oh;
harq_process_ul_ue->num_of_mod_symbols = N_RE_prime * nb_rb;
/////////////////////////ULSCH scrambling/////////////////////////
///////////
uint32_t available_bits = G;
uint32_t available_bits = G[pusch_id];
// +1 because size can be not modulo 4
uint32_t scrambled_output[available_bits / (8 * sizeof(uint32_t)) + 1];
memset(scrambled_output, 0, sizeof(scrambled_output));
......@@ -595,13 +601,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
false,
scrambled_output);
/////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////ULSCH modulation/////////////////////////
///////////
int max_num_re = Nl*number_of_symbols*nb_rb*NR_NB_SC_PER_RB;
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)));
nr_modulation(scrambled_output, // assume one codeword for the moment
......@@ -609,23 +611,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
mod_order,
(int16_t *)d_mod);
///////////
////////////////////////////////////////////////////////////////////////
/////////////////////////ULSCH layer mapping/////////////////////////
///////////
const int sz = available_bits / mod_order / Nl;
c16_t ulsch_mod[Nl][sz];
nr_ue_layer_mapping(d_mod, Nl, sz, ulsch_mod);
///////////
////////////////////////////////////////////////////////////////////////
//////////////////////// ULSCH transform precoding ////////////////////////
///////////
l_prime[0] = 0; // single symbol ap 0
......@@ -636,10 +629,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
memset(ulsch_mod_tp, 0, sizeof(ulsch_mod_tp));
if (pusch_pdu->transform_precoding == transformPrecoder_enabled) {
uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB;
uint32_t nb_re_pusch = nb_rb * NR_NB_SC_PER_RB;
uint32_t y_offset = 0;
uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2);
uint16_t num_dmrs_res_per_symbol = nb_rb * (NR_NB_SC_PER_RB / 2);
// Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol
int index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol);
......@@ -647,14 +639,16 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index];
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
AssertFatal(index >= 0,
"Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs "
"cannot be multiple "
"of any other primenumber other than 2,3,5\n");
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
LOG_D(PHY, "Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) {
if((ul_dmrs_symb_pos >> l) & 0x01)
if ((ul_dmrs_symb_pos >> l) & 0x01)
/* In the symbol with DMRS no data would be transmitted CDM groups is 2*/
continue;
......@@ -662,43 +656,35 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
y_offset = y_offset + nb_re_pusch;
LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset);
LOG_D(PHY, "Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset);
#ifdef DEBUG_PUSCH_MAPPING
printf("NR_ULSCH_UE: y_offset %u\t nb_re_pusch %u \t Symbol %d \t nb_rb %d \n",
y_offset, nb_re_pusch, l, nb_rb);
printf("NR_ULSCH_UE: y_offset %u\t nb_re_pusch %u \t Symbol %d \t nb_rb %d \n", y_offset, nb_re_pusch, l, nb_rb);
#endif
}
#ifdef DEBUG_DFT_IDFT
int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__((aligned(16)));
int offset = 0;
printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits,mod_order);
printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits, mod_order);
for (int ll = 0; ll < (available_bits/mod_order); ll++) {
for (int ll = 0; ll < (available_bits / mod_order); ll++) {
debug_symbols[ll] = ulsch_ue->ulsch_mod_tp[ll];
}
printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols,number_dmrs_symbols);
for (int ll = 0; ll < (number_of_symbols-number_dmrs_symbols); ll++) {
printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols, number_dmrs_symbols);
for (int ll = 0; ll < (number_of_symbols - number_dmrs_symbols); ll++) {
nr_idft(&debug_symbols[offset], nb_re_pusch);
offset = offset + nb_re_pusch;
}
LOG_M("preDFT_all_symbols.m", "UE_preDFT", ulsch_mod[0], number_of_symbols * nb_re_pusch, 1, 1);
LOG_M("postDFT_all_symbols.m", "UE_postDFT", ulsch_mod_tp, number_of_symbols * nb_re_pusch, 1, 1);
LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1);
LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1);
LOG_M("DEBUG_IDFT_SYMBOLS.m", "UE_Debug_IDFT", debug_symbols, number_of_symbols * nb_re_pusch, 1, 1);
LOG_M("UE_DMRS_SEQ.m", "UE_DMRS_SEQ", dmrs_seq, nb_re_pusch, 1, 1);
#endif
}
///////////
////////////////////////////////////////////////////////////////////////
/////////////////////////ULSCH RE mapping/////////////////////////
///////////
const int slot_sz = frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot;
c16_t tx_precoding[Nl][slot_sz];
......@@ -748,12 +734,13 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
} // for (nl=0; nl < Nl; nl++)
/////////////////////////ULSCH precoding/////////////////////////
///////////
/// Layer Precoding and Antenna port mapping
// ulsch_mod 0-3 are mapped on antenna ports
// The precoding info is supported by nfapi such as num_prgs, prg_size, prgs_list and pm_idx
// The same precoding matrix is applied on prg_size RBs, Thus
// pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1
// The Precoding matrix:
for (int ap = 0; ap < frame_parms->nb_antennas_tx; ap++) {
for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) {
......@@ -834,8 +821,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
NR_UL_UE_HARQ_t *harq_process_ulsch = NULL;
harq_process_ulsch = &UE->ul_harq_processes[harq_pid];
harq_process_ulsch->ULstatus = SCH_IDLE;
///////////
////////////////////////////////////////////////////////////////////////
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
}
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
......
......@@ -40,6 +40,7 @@
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/impl_defs_top.h"
#include "PHY/defs_common.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
#include "executables/rt_profiling.h"
......@@ -494,9 +495,10 @@ typedef struct PHY_VARS_gNB_s {
/// OFDM symbol offset divisor for UL
uint32_t ofdm_offset_divisor;
int ldpc_offload_flag;
/// NR LDPC coding related
nrLDPC_coding_interface_t nrLDPC_coding_interface;
int max_ldpc_iterations;
/// indicate the channel estimation technique in time domain
int chest_time;
/// indicate the channel estimation technique in freq domain
......
......@@ -98,6 +98,7 @@
#include "impl_defs_nr.h"
#include "time_meas.h"
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/TOOLS/tools_defs.h"
#include "common/platform_types.h"
#include "NR_UE_TRANSPORT/nr_transport_ue.h"
......@@ -494,9 +495,10 @@ typedef struct PHY_VARS_NR_UE_s {
/// N0 (used for abstraction)
double N0;
/// NR LDPC coding related
nrLDPC_coding_interface_t nrLDPC_coding_interface;
uint8_t max_ldpc_iterations;
int ldpc_offload_enable;
/// SRS variables
nr_srs_info_t *nr_srs_info;
......
......@@ -305,187 +305,144 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_TX + gNB->CC_id, 0);
}
static void nr_postDecode(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata)
static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, bool *ulsch_to_decode)
{
NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
NR_gNB_ULSCH_t *ulsch = rdata->ulsch;
int r = rdata->segment_r;
nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[rdata->ulsch_id].harq_process->ulsch_pdu;
bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter);
ulsch_harq->processedSegments++;
LOG_D(PHY,
"processing result of segment: %d, processed %d/%d, %s\n",
rdata->segment_r,
ulsch_harq->processedSegments,
rdata->nbSegments,
decodeSuccess ? "Decoded Successfully" : "Decoding Unsuccessful");
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
if (decodeSuccess) {
memcpy(ulsch_harq->b + rdata->offset, ulsch_harq->c[r], rdata->Kr_bytes - (ulsch_harq->F >> 3) - ((ulsch_harq->C > 1) ? 3 : 0));
int nb_pusch = 0;
for (uint8_t ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
if (ulsch_to_decode[ULSCH_id]) {
nb_pusch++;
}
}
} else {
LOG_D(PHY, "ULSCH %d in error\n", rdata->ulsch_id);
if (nb_pusch == 0) {
return 0;
}
//int dumpsig=0;
// if all segments are done
if (ulsch_harq->processedSegments == ulsch_harq->C) {
// When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the
// CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block
bool crc_valid = true;
if (ulsch_harq->C > 1) {
crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, rdata->A), crcType(1, rdata->A));
uint8_t ULSCH_ids[nb_pusch];
uint32_t G[nb_pusch];
int pusch_id = 0;
for (uint8_t ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
if (ulsch_to_decode[ULSCH_id]) {
ULSCH_ids[pusch_id] = ULSCH_id;
nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu;
uint16_t nb_re_dmrs;
uint16_t start_symbol = pusch_pdu->start_symbol_index;
uint16_t number_symbols = pusch_pdu->nr_of_symbols;
uint8_t number_dmrs_symbols = 0;
for (int l = start_symbol; l < start_symbol + number_symbols; l++)
number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01;
if (pusch_pdu->dmrs_config_type==pusch_dmrs_type1)
nb_re_dmrs = 6*pusch_pdu->num_dmrs_cdm_grps_no_data;
else
nb_re_dmrs = 4*pusch_pdu->num_dmrs_cdm_grps_no_data;
G[pusch_id] = nr_get_G(pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
gNB->ulsch[ULSCH_id].unav_res,
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
AssertFatal(G[pusch_id]>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n",
pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, dmrs symbol positions %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n",
pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
pusch_pdu->ul_dmrs_symb_pos,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
pusch_id++;
}
}
//----------------------------------------------------------
//--------------------- ULSCH decoding ---------------------
//----------------------------------------------------------
int ret_nr_ulsch_decoding =
nr_ulsch_decoding(gNB, frame_parms, frame_rx, slot_rx, G, ULSCH_ids, nb_pusch);
// CRC check per uplink shared channel
for (pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id];
NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process;
nfapi_nr_pusch_pdu_t *pusch_pdu = &ulsch_harq->ulsch_pdu;
bool crc_valid = false;
if (crc_valid && !check_abort(&ulsch_harq->abort_decode) && !gNB->pusch_vars[rdata->ulsch_id].DTX) {
// if all segments are done
if (ulsch_harq->processedSegments == ulsch_harq->C) {
if (ulsch_harq->C > 1) {
crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, (ulsch_harq->TBS) << 3), crcType(1, (ulsch_harq->TBS) << 3));
} else {
// When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the
// CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block
crc_valid = true;
}
}
if (crc_valid && !check_abort(&ulsch_harq->abort_decode) && !pusch->DTX) {
LOG_D(NR_PHY,
"[gNB %d] ULSCH %d: Setting ACK for SFN/SF %d.%d (rnti %x, pid %d, ndi %d, status %d, round %d, TBS %d, Max interation "
"(all seg) %d)\n",
gNB->Mod_id,
rdata->ulsch_id,
ULSCH_id,
ulsch->frame,
ulsch->slot,
ulsch->rnti,
rdata->harq_pid,
ulsch->harq_pid,
pusch_pdu->pusch_data.new_data_indicator,
ulsch->active,
ulsch_harq->round,
ulsch_harq->TBS,
rdata->decodeIterations);
nr_fill_indication(gNB, ulsch->frame, ulsch->slot, rdata->ulsch_id, rdata->harq_pid, 0, 0);
ulsch->max_ldpc_iterations);
nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 0, 0);
LOG_D(PHY, "ULSCH received ok \n");
ulsch->active = false;
ulsch_harq->round = 0;
//dumpsig=1;
ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure
} else {
LOG_D(PHY,
"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, "
"TBS %d) r %d\n",
"TBS %d)\n",
gNB->Mod_id,
ulsch->frame,
ulsch->slot,
rdata->harq_pid,
ulsch->harq_pid,
pusch_pdu->pusch_data.new_data_indicator,
ulsch->active,
ulsch_harq->round,
ulsch_harq->ulsch_pdu.pusch_data.rv_index,
ulsch_harq->ulsch_pdu.rb_start,
ulsch_harq->ulsch_pdu.rb_size,
ulsch_harq->TBS,
r);
nr_fill_indication(gNB, ulsch->frame, ulsch->slot, rdata->ulsch_id, rdata->harq_pid, 1, 0);
ulsch_harq->TBS);
nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 1, 0);
ulsch->handled = 1;
LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id);
// dumpsig=1;
LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id);
ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations + 1; // Setting to max_ldpc_iterations + 1 is sufficient given that this variable is only used for checking for failure
}
ulsch->last_iteration_cnt = rdata->decodeIterations;
/*
if (ulsch_harq->ulsch_pdu.mcs_index == 0 && dumpsig==1) {
int off = ((ulsch_harq->ulsch_pdu.rb_size&1) == 1)? 4:0;
LOG_M("rxsigF0.m","rxsF0",&gNB->common_vars.rxdataF[0][0][(ulsch_harq->slot%RU_RX_SLOT_DEPTH)*gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot],gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot,1,1);
LOG_M("rxsigF0_ext.m","rxsF0_ext",
&gNB->pusch_vars[0].rxdataF_ext[0][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("chestF0.m","chF0",
&gNB->pusch_vars[0].ul_ch_estimates[0][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1);
LOG_M("rxsigF0_comp.m","rxsF0_comp",
&gNB->pusch_vars[0].rxdataF_comp[0][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("rxsigF0_llr.m","rxsF0_llr",
&gNB->pusch_vars[0].llr[0],(ulsch_harq->ulsch_pdu.nr_of_symbols-1)*NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size *
ulsch_harq->ulsch_pdu.qam_mod_order,1,0); if (gNB->frame_parms.nb_antennas_rx > 1) {
LOG_M("rxsigF1_ext.m","rxsF0_ext",
&gNB->pusch_vars[0].rxdataF_ext[1][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("chestF1.m","chF1",
&gNB->pusch_vars[0].ul_ch_estimates[1][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1);
LOG_M("rxsigF1_comp.m","rxsF1_comp",
&gNB->pusch_vars[0].rxdataF_comp[1][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB *
ulsch_harq->ulsch_pdu.rb_size)),1,1);
}
exit(-1);
}
*/
ulsch->last_iteration_cnt = rdata->decodeIterations;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0);
}
}
static int nr_ulsch_procedures(PHY_VARS_gNB *gNB,
int frame_rx,
int slot_rx,
int ULSCH_id,
uint8_t harq_pid,
thread_info_tm_t *t_info)
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu;
uint16_t nb_re_dmrs;
uint16_t start_symbol = pusch_pdu->start_symbol_index;
uint16_t number_symbols = pusch_pdu->nr_of_symbols;
uint8_t number_dmrs_symbols = 0;
for (int l = start_symbol; l < start_symbol + number_symbols; l++)
number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01;
if (pusch_pdu->dmrs_config_type==pusch_dmrs_type1)
nb_re_dmrs = 6*pusch_pdu->num_dmrs_cdm_grps_no_data;
else
nb_re_dmrs = 4*pusch_pdu->num_dmrs_cdm_grps_no_data;
uint32_t G = nr_get_G(pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
gNB->ulsch[ULSCH_id].unav_res,
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
AssertFatal(G>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n",
pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, dmrs symbol positions %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n",
pusch_pdu->rb_size,
number_symbols,
nb_re_dmrs,
pusch_pdu->ul_dmrs_symb_pos,
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
pusch_pdu->qam_mod_order,
pusch_pdu->nrOfLayers);
//----------------------------------------------------------
//--------------------- ULSCH decoding ---------------------
//----------------------------------------------------------
/* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1
* (valid for unitary physical simulators). ULSCH processing lopp is then executed
* only once, which ensures exactly one start and stop of the ULSCH decoding time
* measurement per processed TB.*/
if (gNB->max_nb_pusch == 1)
start_meas(&gNB->ulsch_decoding_stats);
int const nbDecode = nr_ulsch_decoding(gNB,
ULSCH_id,
gNB->pusch_vars[ULSCH_id].llr,
frame_parms,
pusch_pdu,
frame_rx,
slot_rx,
harq_pid,
G,
t_info);
return nbDecode;
return ret_nr_ulsch_decoding;
}
void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, uint8_t harq_pid, uint8_t crc_flag, int dtx_flag)
{
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
......@@ -840,12 +797,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
}
}
ldpcDecode_t arr[64];
task_ans_t ans[64] = {0};
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = 64, .ans = ans};
// int64_t const t0 = time_now_ns();
int totalDecode = 0;
bool ulsch_to_decode[gNB->max_nb_pusch];
bzero((void *)ulsch_to_decode, sizeof(ulsch_to_decode));
for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process;
......@@ -937,25 +890,26 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
pusch_vars->DTX = 0;
}
ulsch_to_decode[ULSCH_id] = true;
stop_meas(&gNB->rx_pusch_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 0);
// LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1);
// LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 1);
int const tasks_added = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, &t_info);
if (tasks_added > 0)
totalDecode += tasks_added;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 0);
}
}
DevAssert(totalDecode == t_info.len);
/* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1
* (valid for unitary physical simulators). ULSCH processing lopp is then executed
* only once, which ensures exactly one start and stop of the ULSCH decoding time
* measurement per processed TB.*/
if (gNB->max_nb_pusch == 1)
start_meas(&gNB->ulsch_decoding_stats);
join_task_ans(t_info.ans, t_info.len);
for (int i = 0; i < t_info.len; ++i) {
nr_postDecode(gNB, &arr[i]);
int const ret_nr_ulsch_procedures = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ulsch_to_decode);
if (ret_nr_ulsch_procedures != 0) {
LOG_E(PHY,"Error in nr_ulsch_procedures, returned %d\n",ret_nr_ulsch_procedures);
}
/* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1
* (valid for unitary physical simulators). ULSCH processing loop is then executed
* only once, which ensures exactly one start and stop of the ULSCH decoding time
......
......@@ -271,7 +271,6 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
{
const int slot_tx = proc->nr_slot_tx;
const int frame_tx = proc->frame_tx;
const int gNB_id = proc->gNB_id;
AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n");
......@@ -288,12 +287,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
start_meas_nr_ue_phy(ue, PHY_PROC_TX);
const int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id;
if (ue->ul_harq_processes[harq_pid].ULstatus == ACTIVE) {
start_meas_nr_ue_phy(ue, PUSCH_PROC_STATS);
nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, gNB_id, phy_data, (c16_t **)&txdataF);
stop_meas_nr_ue_phy(ue, PUSCH_PROC_STATS);
}
nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF);
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF);
......@@ -685,23 +679,22 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls
return unav_res;
}
/*! \brief Process the whole DLSCH slot
*/
static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t dlsch[2],
int16_t *llr[2],
int G)
{
int16_t *llr[2]) {
if (dlsch[0].active == false) {
LOG_E(PHY, "DLSCH should be active when calling this function\n");
return true;
}
int gNB_id = proc->gNB_id;
bool dec = false;
int harq_pid = dlsch[0].dlsch_config.harq_process_nbr;
int frame_rx = proc->frame_rx;
int nr_slot_rx = proc->nr_slot_rx;
uint32_t ret = UINT32_MAX, ret1 = UINT32_MAX;
uint32_t ret = UINT32_MAX;
NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid];
NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid];
uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos);
......@@ -711,19 +704,21 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
uint8_t is_cw0_active = dl_harq0->status;
uint8_t is_cw1_active = dl_harq1->status;
int nb_dlsch = 0;
nb_dlsch += (is_cw0_active == ACTIVE) ? 1 : 0;
nb_dlsch += (is_cw1_active == ACTIVE) ? 1 : 0;
uint16_t nb_symb_sch = dlsch[0].dlsch_config.number_symbols;
uint8_t dmrs_type = dlsch[0].dlsch_config.dmrsConfigType;
uint8_t nb_re_dmrs;
if (dmrs_type==NFAPI_NR_DMRS_TYPE1) {
nb_re_dmrs = 6*dlsch[0].dlsch_config.n_dmrs_cdm_groups;
}
else {
nb_re_dmrs = 4*dlsch[0].dlsch_config.n_dmrs_cdm_groups;
if (dmrs_type == NFAPI_NR_DMRS_TYPE1) {
nb_re_dmrs = 6 * dlsch[0].dlsch_config.n_dmrs_cdm_groups;
} else {
nb_re_dmrs = 4 * dlsch[0].dlsch_config.n_dmrs_cdm_groups;
}
LOG_D(PHY,"AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx%1024, nr_slot_rx, harq_pid, is_cw0_active);
LOG_D(PHY,"AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx%1024, nr_slot_rx, harq_pid, is_cw1_active);
LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw0_active);
LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw1_active);
// exit dlsch procedures as there are no active dlsch
if (is_cw0_active != ACTIVE && is_cw1_active != ACTIVE) {
......@@ -735,44 +730,43 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
return false;
}
start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
nr_dlsch_unscrambling(llr[0], G, 0, dlsch[0].dlsch_config.dlDataScramblingId, dlsch[0].rnti);
stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
int G[2];
uint8_t DLSCH_ids[nb_dlsch];
int pdsch_id = 0;
uint8_t *p_b[2] = {NULL};
for (uint8_t DLSCH_id = 0; DLSCH_id < 2; DLSCH_id++) {
NR_DL_UE_HARQ_t *dl_harq = &ue->dl_harq_processes[DLSCH_id][harq_pid];
if (dl_harq->status != ACTIVE) continue;
start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
// create memory to store decoder output
int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated
int num_rb = dlsch[0].dlsch_config.number_rbs;
if (num_rb != 273) {
a_segments = a_segments*num_rb;
a_segments = (a_segments/273)+1;
DLSCH_ids[pdsch_id++] = DLSCH_id;
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
uint32_t unav_res = 0;
if (dlsch_config->pduBitmap & 0x1) {
uint16_t ptrsSymbPos = 0;
set_ptrs_symb_idx(&ptrsSymbPos, dlsch_config->number_symbols, dlsch_config->start_symbol, 1 << dlsch_config->PTRSTimeDensity,
dlsch_config->dlDmrsSymbPos);
int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity;
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols);
unav_res = n_ptrs * ptrsSymbPerSlot;
}
unav_res += compute_csi_rm_unav_res(dlsch_config);
G[DLSCH_id] = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[DLSCH_id].Nl);
start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
nr_dlsch_unscrambling(llr[DLSCH_id], G[DLSCH_id], 0, dlsch[DLSCH_id].dlsch_config.dlDataScramblingId, dlsch[DLSCH_id].rnti);
stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
p_b[DLSCH_id] = dl_harq->b;
}
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
__attribute__ ((aligned(32))) uint8_t p_b[dlsch_bytes];
ret = nr_dlsch_decoding(ue,
proc,
gNB_id,
llr[0],
&ue->frame_parms,
&dlsch[0],
dl_harq0,
frame_rx,
nb_symb_sch,
nr_slot_rx,
harq_pid,
dlsch_bytes,
p_b,
G);
LOG_T(PHY,"dlsch decoding, ret = %d\n", ret);
if(ret<ue->max_ldpc_iterations+1)
dec = true;
start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
ret = nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
if (ret < ue->max_ldpc_iterations + 1) dec = true;
int ind_type = -1;
switch(dlsch[0].rnti_type) {
switch (dlsch[0].rnti_type) {
case TYPE_RA_RNTI_:
ind_type = FAPI_NR_RX_PDU_TYPE_RAR;
break;
......@@ -791,75 +785,21 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
}
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, ind_type, ue, &dlsch[0], NULL, number_pdus, proc, NULL, p_b);
nr_fill_rx_indication(&rx_ind, ind_type, ue, &dlsch[0], NULL, number_pdus, proc, NULL, p_b[0]);
LOG_D(PHY, "DL PDU length in bits: %d, in bytes: %d \n", dlsch[0].dlsch_config.TBS, dlsch[0].dlsch_config.TBS / 8);
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
if (cpumeas(CPUMEAS_GETSTATE)) {
LOG_D(PHY,
" --> Unscrambling for CW0 %5.3f\n",
" --> Unscrambling %5.3f\n",
ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0));
LOG_D(PHY,
"AbsSubframe %d.%d --> LDPC Decoding for CW0 %5.3f\n",
"AbsSubframe %d.%d --> LDPC Decoding %5.3f\n",
frame_rx % 1024,
nr_slot_rx,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
}
if(is_cw1_active) {
// start ldpc decode for CW 1
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[1].dlsch_config;
uint32_t unav_res = 0;
if(dlsch_config->pduBitmap & 0x1) {
uint16_t ptrsSymbPos = 0;
set_ptrs_symb_idx(&ptrsSymbPos,
dlsch_config->number_symbols,
dlsch_config->start_symbol,
1 << dlsch_config->PTRSTimeDensity,
dlsch_config->dlDmrsSymbPos);
int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity;
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols);
unav_res = n_ptrs * ptrsSymbPerSlot;
}
start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
unav_res += compute_csi_rm_unav_res(dlsch_config);
G = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[1].Nl);
nr_dlsch_unscrambling(llr[1], G, 0, dlsch[1].dlsch_config.dlDataScramblingId, dlsch[1].rnti);
stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
ret1 = nr_dlsch_decoding(ue,
proc,
gNB_id,
llr[1],
&ue->frame_parms,
&dlsch[1],
dl_harq1,
frame_rx,
nb_symb_sch,
nr_slot_rx,
harq_pid,
dlsch_bytes,
p_b,
G);
LOG_T(PHY,"CW dlsch decoding, ret1 = %d\n", ret1);
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
if (cpumeas(CPUMEAS_GETSTATE)) {
LOG_D(PHY,
" --> Unscrambling for CW1 %5.3f\n",
ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0));
LOG_D(PHY,
"AbsSubframe %d.%d --> ldpc Decoding for CW1 %5.3f\n",
frame_rx % 1024,
nr_slot_rx,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
}
LOG_D(PHY, "harq_pid: %d, TBS expected dlsch1: %d \n", harq_pid, dlsch[1].dlsch_config.TBS);
}
// send to mac
// send to mac
if (ue->if_inst && ue->if_inst->dl_indication) {
ue->if_inst->dl_indication(&dl_indication);
}
......@@ -871,8 +811,18 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
}
if (ue->phy_sim_dlsch_b)
memcpy(ue->phy_sim_dlsch_b, p_b, dlsch_bytes);
int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * NR_MAX_NB_LAYERS; // number of segments to be allocated
int num_rb = dlsch[0].dlsch_config.number_rbs;
if (num_rb != 273) {
a_segments = a_segments * num_rb;
a_segments = (a_segments / 273) + 1;
}
uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment
if (ue->phy_sim_dlsch_b && is_cw0_active == ACTIVE)
memcpy(ue->phy_sim_dlsch_b, p_b[0], dlsch_bytes);
else if (ue->phy_sim_dlsch_b && is_cw1_active == ACTIVE)
memcpy(ue->phy_sim_dlsch_b, p_b[1], dlsch_bytes);
return dec;
}
......@@ -1146,8 +1096,9 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
start_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS);
if (ret_pdsch >= 0)
nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G);
if (ret_pdsch >= 0) {
nr_ue_dlsch_procedures(ue, proc, dlsch, llr);
}
else {
LOG_E(NR_PHY, "Demodulation impossible, internal error\n");
const int ack_nack_slot_and_frame =
......
......@@ -35,6 +35,7 @@
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/types.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/MODULATION/modulation_UE.h"
......@@ -380,7 +381,7 @@ int main(int argc, char **argv)
RC.gNB[0] = calloc(1, sizeof(PHY_VARS_gNB));
gNB = RC.gNB[0];
initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool");
initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool");
initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool");
//gNB_config = &gNB->gNB_config;
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
frame_parms->nb_antennas_tx = n_tx;
......@@ -430,6 +431,8 @@ int main(int argc, char **argv)
//nr_init_frame_parms_ue(&UE->frame_parms);
//init_nr_ue_transport(UE, 0);
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
NR_UE_DLSCH_t dlsch_ue[NR_MAX_NB_LAYERS > 4? 2:1] = {0};
int num_codeword = NR_MAX_NB_LAYERS > 4? 2:1;
nr_ue_dlsch_init(dlsch_ue, num_codeword, 5);
......@@ -513,7 +516,8 @@ int main(int argc, char **argv)
unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS] __attribute__((aligned(32)));
bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS);
if (input_fd == NULL) {
nr_dlsch_encoding(gNB, frame, slot, &dlsch->harq_process, frame_parms,output,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
msgDataTx.num_pdsch_slot = 1;
nr_dlsch_encoding(gNB, &msgDataTx, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
for (SNR = snr0; SNR < snr1; SNR += snr_step) {
......@@ -569,20 +573,18 @@ int main(int argc, char **argv)
}
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
__attribute__ ((aligned(32))) uint8_t b[dlsch_bytes];
uint8_t DLSCH_ids[1] = {0};
short *p_channel_output_fixed = channel_output_fixed;
uint8_t *p_b = b;
int available_bits_array[1] = { available_bits };
ret = nr_dlsch_decoding(UE,
&proc,
0,
channel_output_fixed,
&UE->frame_parms,
dlsch0_ue,
harq_process,
frame,
nb_symb_sch,
slot,
harq_pid,
dlsch_bytes,
b,
available_bits);
&p_channel_output_fixed,
&p_b,
available_bits_array,
1,
DLSCH_ids);
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0, VCD_FUNCTION_OUT);
......@@ -661,7 +663,10 @@ int main(int argc, char **argv)
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list);
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
abortTpool(&gNB->threadPool);
phy_free_nr_gNB(gNB);
free(RC.gNB[0]);
free(RC.gNB);
......
......@@ -47,7 +47,7 @@
#include "NR_ServingCellConfig.h"
#include "NR_SetupRelease.h"
#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/MODULATION/modulation_common.h"
#include "PHY/NR_REFSIG/ptrs_nr.h"
......@@ -297,7 +297,6 @@ int main(int argc, char **argv)
uint8_t n_tx=1,n_rx=1;
uint8_t round;
uint8_t num_rounds = 4;
int ldpc_offload_flag = 0;
char gNBthreads[128]="n";
channel_desc_t *gNB2UE;
......@@ -360,7 +359,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:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:c")) != -1) {
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:M:N:F:GR:d:PI: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' */
......@@ -412,10 +411,6 @@ int main(int argc, char **argv)
n_trials = atoi(optarg);
break;
case 'c':
ldpc_offload_flag = 1;
break;
case 's':
snr0 = atof(optarg);
printf("Setting SNR0 to %f\n",snr0);
......@@ -580,7 +575,6 @@ int main(int argc, char **argv)
//printf("-j Relative strength of second intefering gNB (in dB) - cell_id mod 3 = 2\n");
printf("-R N_RB_DL\n");
printf("-O oversampling factor (1,2,4,8,16)\n");
printf("-c ldpc offload flag\n");
printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n");
//printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
printf("-f raw file containing RRC configuration (generated by gNB)\n");
......@@ -640,7 +634,6 @@ int main(int argc, char **argv)
gNB = RC.gNB[0];
gNB->ofdm_offset_divisor = UINT_MAX;
gNB->ldpc_offload_flag = ldpc_offload_flag;
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)
frame_parms->nb_antennas_tx = n_tx;
......@@ -849,6 +842,7 @@ int main(int argc, char **argv)
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;
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
UE->max_ldpc_iterations = max_ldpc_iterations;
init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
......@@ -1337,8 +1331,7 @@ int main(int argc, char **argv)
free(UE->phy_sim_pdsch_dl_ch_estimates_ext);
free(UE->phy_sim_dlsch_b);
if (gNB->ldpc_offload_flag)
free_LDPClib(&ldpc_interface_offload);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
if (output_fd)
fclose(output_fd);
......
......@@ -33,6 +33,7 @@
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_gNB.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/MODULATION/modulation_eNB.h"
......@@ -90,28 +91,6 @@ void deref_sched_response(int _)
exit(1);
}
int nr_postDecode_sim(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata, int *nb_ok)
{
NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
int r = rdata->segment_r;
bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter);
ulsch_harq->processedSegments++;
if (decodeSuccess) {
memcpy(ulsch_harq->b+rdata->offset,
ulsch_harq->c[r],
rdata->Kr_bytes - (ulsch_harq->F>>3) -((ulsch_harq->C>1)?3:0));
}
// if all segments are done
if (rdata->nbSegments == ulsch_harq->processedSegments) {
return *nb_ok == rdata->nbSegments;
}
return 0;
}
nrUE_params_t nrUE_params;
nrUE_params_t *get_nrUE_params(void) {
......@@ -143,7 +122,6 @@ int main(int argc, char **argv)
NR_DL_FRAME_PARMS *frame_parms;
double sigma;
unsigned char qbits = 8;
int ret=0;
int loglvl = OAILOG_WARNING;
uint64_t SSB_positions=0x01;
uint16_t nb_symb_sch = 12;
......@@ -439,6 +417,7 @@ int main(int argc, char **argv)
UE->frame_parms.nb_antennas_tx = n_tx;
UE->frame_parms.nb_antennas_rx = 1;
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
//phy_init_nr_top(frame_parms);
if (init_nr_ue_signal(UE, 1) != 0) {
......@@ -448,6 +427,8 @@ int main(int argc, char **argv)
nr_init_ul_harq_processes(UE->ul_harq_processes, NR_MAX_ULSCH_HARQ_PROCESSES, UE->frame_parms.N_RB_UL, UE->frame_parms.nb_antennas_tx);
initFloatingCoresTpool(1, &nrUE_params.Tpool, false, "UE-tpool");
unsigned char harq_pid = 0;
unsigned int TBS = 8424;
unsigned int available_bits;
......@@ -530,7 +511,8 @@ int main(int argc, char **argv)
unsigned int G = available_bits;
if (input_fd == NULL) {
nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, TBS>>3, G);
uint8_t ULSCH_ids[] = {0};
nr_ulsch_encoding(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids);
}
printf("\n");
......@@ -594,21 +576,11 @@ int main(int argc, char **argv)
exit(-1);
#endif
ldpcDecode_t arr[16] = {0};
task_ans_t ans[16] = {0};
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .cap = 16, .len = 0, .ans = ans};
int nbDecode =
nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G, &t_info);
DevAssert(nbDecode > 0);
int nb_ok = 0;
join_task_ans(t_info.ans, t_info.len);
for (size_t i = 0; i < nbDecode; ++i) {
ret = nr_postDecode_sim(gNB, &arr[i], &nb_ok);
}
nbDecode = 0;
if (ret)
nr_ulsch_decoding(gNB, frame_parms, frame, subframe, &G, &UE_id, 1);
bool crc_valid = check_crc(harq_process_gNB->b, lenWithCrc(1, (harq_process_gNB->TBS) << 3), crcType(1, (harq_process_gNB->TBS) << 3));
if (!crc_valid) {
n_errors++;
}
}
printf("*****************************************\n");
......@@ -633,6 +605,8 @@ int main(int argc, char **argv)
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list);
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
term_nr_ue_signal(UE, 1);
free(UE);
......
......@@ -45,7 +45,7 @@
#include "NR_ReconfigurationWithSync.h"
#include "NR_ServingCellConfig.h"
#include "NR_UE-NR-Capability.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/MODULATION/nr_modulation.h"
#include "PHY/NR_REFSIG/dmrs_nr.h"
......@@ -212,7 +212,6 @@ int main(int argc, char *argv[])
double effRate;
double effTP;
float eff_tp_check = 100;
int ldpc_offload_flag = 0;
uint8_t max_rounds = 4;
int chest_type[2] = {0};
int enable_ptrs = 0;
......@@ -251,7 +250,7 @@ int main(int argc, char *argv[])
InitSinLUT();
int c;
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -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' */
......@@ -364,10 +363,6 @@ int main(int argc, char *argv[])
n_trials = atoi(optarg);
break;
case 'o':
ldpc_offload_flag = 1;
break;
case 'p':
extended_prefix_flag = 1;
break;
......@@ -531,7 +526,6 @@ int main(int argc, char *argv[])
printf("-k 3/4 sampling\n");
printf("-m MCS value\n");
printf("-n Number of trials to simulate\n");
printf("-o ldpc offload flag\n");
printf("-p Use extended prefix mode\n");
printf("-q MCS table\n");
printf("-r Number of allocated resource blocks for PUSCH\n");
......@@ -682,7 +676,6 @@ int main(int argc, char *argv[])
cfg->carrier_config.num_rx_ant.value = n_rx;
// nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,0,0x01);
gNB->ldpc_offload_flag = ldpc_offload_flag;
gNB->chest_freq = chest_type[0];
gNB->chest_time = chest_type[1];
......@@ -729,6 +722,7 @@ int main(int argc, char *argv[])
memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS));
UE->frame_parms.nb_antennas_tx = n_tx;
UE->frame_parms.nb_antennas_rx = 0;
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
if (init_nr_ue_signal(UE, 1) != 0) {
printf("Error at UE NR initialisation\n");
......@@ -751,6 +745,8 @@ int main(int argc, char *argv[])
UE_mac->if_module = nr_ue_if_module_init(0);
initFloatingCoresTpool(threadCnt, &nrUE_params.Tpool, false, "UE-tpool");
nr_ue_phy_config_request(&UE_mac->phy_config);
unsigned char harq_pid = 0;
......@@ -1596,8 +1592,8 @@ int main(int argc, char *argv[])
num_dmrs_cdm_grps_no_data);
free_MIB_NR(mib);
if (gNB->ldpc_offload_flag)
free_LDPClib(&ldpc_interface_offload);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
if (output_fd)
fclose(output_fd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment