Merge branch 'integration_2024_w50' into 'develop'
Integration: `2024.w50` Closes #753 See merge request oai/openairinterface5g!3166 * !3159 CI: Add FHI7.2 test with Metanoia RU * !3111 Enable USRP Tx thread in nrUE * !3144 UE data race fix * !3149 Fix several issues in ulsch_mmse_2layers * !3158 GTP: use direct call instead of ITTI * !3160 FHI-72: initialize mask, find correct libxran * !3019 SIB19 utilization on UE * !3162 Add Rocky 9.5 to list of distributions * !3163 NGAP-Initial Context Setup Failure * !2952 New LDPC coding library interface for decoding and encoding complete slots in one call to the library * !3125 Add support for O1 in O-DU via telnet * !3161 Cmd line option for sync in frames for iqrecorder
This commit is contained in:
+11
-116
@@ -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}
|
||||
)
|
||||
|
||||
|
||||
@@ -1474,6 +1386,7 @@ add_library(L2_UE
|
||||
${MAC_SRC_UE}
|
||||
)
|
||||
target_link_libraries(L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(L2_UE PRIVATE GTPV1U)
|
||||
|
||||
add_library(L2_UE_LTE_NR
|
||||
${L2_RRC_SRC_UE}
|
||||
@@ -1942,6 +1855,7 @@ target_link_libraries(lte-softmodem PRIVATE
|
||||
target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt sctp)
|
||||
target_link_libraries(lte-softmodem PRIVATE ${T_LIB})
|
||||
target_link_libraries(lte-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(lte-softmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES})
|
||||
|
||||
if(E2_AGENT)
|
||||
target_compile_definitions(lte-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
@@ -1997,6 +1911,7 @@ target_link_libraries(lte-uesoftmodem PRIVATE
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt sctp)
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB})
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES})
|
||||
|
||||
# force the generation of ASN.1 so that we don't need to wait during the build
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE
|
||||
@@ -2043,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)
|
||||
@@ -2079,6 +1988,7 @@ add_executable(nr-uesoftmodem
|
||||
${rrc_h}
|
||||
${s1ap_h}
|
||||
${OPENAIR_DIR}/executables/nr-uesoftmodem.c
|
||||
${OPENAIR_DIR}/executables/position_interface.c
|
||||
${OPENAIR_DIR}/executables/nr-ue.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR_DIR}/radio/COMMON/common_lib.c
|
||||
@@ -2100,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)
|
||||
@@ -2159,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}
|
||||
@@ -2260,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
|
||||
@@ -2322,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 ]
|
||||
|
||||
@@ -148,6 +148,13 @@ gNBs =
|
||||
#ext2
|
||||
#ntn_Config_r17
|
||||
cellSpecificKoffset_r17 = 478;
|
||||
ta-Common-r17 = 29314900;
|
||||
positionX-r17 = 0;
|
||||
positionY-r17 = 0;
|
||||
positionZ-r17 = 32433846;
|
||||
velocityVX-r17 = 0;
|
||||
velocityVY-r17 = 0;
|
||||
velocityVZ-r17 = 0;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
Active_gNBs = ( "oai-du");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "oai-du";
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 97; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pusch_AntennaPorts = 4;
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
maxMIMO_layers = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
force_UL256qam_off = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
physCellId = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3300.24 + 134*12*30e3 = 3348.48 MHz (5G NR GSCN: 7741)
|
||||
absoluteFrequencySSB = 649920; #JF maybe we should adjust a bit
|
||||
dl_frequencyBand = 78;
|
||||
# this is 3300.24 MHz
|
||||
dl_absoluteFrequencyPointA = 646724;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 273;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart))
|
||||
initialDLBWPlocationAndBandwidth = 1099;
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 78;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 273;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 1099;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 148; # JF check this and other PRACH related params
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 12;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 6;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 1;
|
||||
#ra_ReponseWindow
|
||||
#1,2,4,8,10,20,40,80
|
||||
ra_ResponseWindow = 5;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
msg3_DeltaPreamble = 1;
|
||||
p0_NominalWithGrant = -90;
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
# ssb_PositionsInBurs_BitmapPR
|
||||
# 1=short, 2=medium, 3=long
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5; #6;
|
||||
nrofDownlinkSlots = 3; #7;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1; #2;
|
||||
nrofUplinkSymbols = 4;
|
||||
ssPBCH_BlockPower = -10;
|
||||
}
|
||||
);
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.103"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.18.20";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.18.20";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 220;
|
||||
pucch_TargetSNRx10 = 220;
|
||||
ul_bler_target_upper=.35;
|
||||
ul_bler_target_lower=.15;
|
||||
pusch_FailureThres = 100;
|
||||
ul_max_mcs = 28;
|
||||
}
|
||||
);
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 130;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = 10;
|
||||
max_ldpc_iterations = 10;
|
||||
tx_amp_backoff_dB = 12; #9; needs to match O-RU configuration # JF important to check
|
||||
L1_rx_thread_core = 3;
|
||||
L1_tx_thread_core = 4; # relevant after merge of l1_tx_thread
|
||||
phase_compensation = 0; # needs to match O-RU configuration # JF to be tested
|
||||
}
|
||||
);
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 4;
|
||||
nb_rx = 4;
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 6;
|
||||
sl_ahead = 10; #5;
|
||||
##beamforming 1x2 matrix: 1 layer x 2 antennas
|
||||
bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000];
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="info";
|
||||
hw_log_level ="info";
|
||||
phy_log_level ="info";
|
||||
mac_log_level ="info";
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="info";
|
||||
f1ap_log_level ="info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1");
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
ru_addr = ("00:E0:0C:00:AE:06", "00:E0:0C:00:AE:06");
|
||||
mtu = 9000;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (125, 350);
|
||||
Ta4 = (110, 180);
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,6 +6,12 @@ uicc0 = {
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
position0 = {
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
z = 6377900.0;
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
@@ -34,4 +40,4 @@ channelmod = {
|
||||
ds_tdl = 0;
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,172 @@
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>test-5g-fhi72-metanoia-2x2</htmlTabRef>
|
||||
<htmlTabName>100 MHz TDD SA METANOIA</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<TestCaseRequestedList>
|
||||
200000
|
||||
110000
|
||||
800813
|
||||
120000
|
||||
102000
|
||||
102001
|
||||
100100
|
||||
100010
|
||||
100020
|
||||
100030
|
||||
100040
|
||||
103000
|
||||
100002
|
||||
130000
|
||||
777777
|
||||
888888
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="200000">
|
||||
<class>Custom_Script</class>
|
||||
<desc>Setup sriov and network interfaces Metanoia</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_sriov_metanoia.sh</script>
|
||||
<command_fail>yes</command_fail>
|
||||
</testCase>
|
||||
|
||||
<testCase id="110000">
|
||||
<class>Pull_Cluster_Image</class>
|
||||
<desc>Pull Images from Cluster</desc>
|
||||
<oc_project>oaicicd-ran</oc_project>
|
||||
<images>oai-gnb-fhi72</images>
|
||||
<node>cacofonix</node>
|
||||
</testCase>
|
||||
|
||||
<testCase id="800813">
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace for server 0</desc>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="120000">
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy gNB (TDD/Band78/100MHz/Metanoia) in a container</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb</yaml_path>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="102001">
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach UE</desc>
|
||||
<id>up2-fhi72</id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100100">
|
||||
<class>Ping</class>
|
||||
<desc>Ping: 100 pings in 10 sec</desc>
|
||||
<id>up2-fhi72</id>
|
||||
<ping_args>-c 100 -i 0.1 172.21.6.104</ping_args>
|
||||
<ping_packetloss_threshold>1</ping_packetloss_threshold>
|
||||
<ping_rttavg_threshold>15</ping_rttavg_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100010">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/570Mbps/UDP)(30 sec)(multi-ue profile)</desc>
|
||||
<iperf_args>-u -b 570M -t 30 -R</iperf_args>
|
||||
<id>up2-fhi72</id>
|
||||
<iperf_packetloss_threshold>20</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>80</iperf_bitrate_threshold>
|
||||
<iperf_profile>balanced</iperf_profile>
|
||||
<svr_id>oc-cn5g-20897</svr_id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100030">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/TCP)(30 sec)(multi-ue profile)</desc>
|
||||
<iperf_args>-t 30 -R</iperf_args>
|
||||
<id>up2-fhi72</id>
|
||||
<iperf_tcp_rate_target>80</iperf_tcp_rate_target>
|
||||
<svr_id>oc-cn5g-20897</svr_id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100020">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (UL/100Mbps/UDP)(30 sec)(multi-ue profile)</desc>
|
||||
<iperf_args>-u -b 100M -t 30</iperf_args>
|
||||
<id>up2-fhi72</id>
|
||||
<iperf_packetloss_threshold>20</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>80</iperf_bitrate_threshold>
|
||||
<iperf_profile>balanced</iperf_profile>
|
||||
<svr_id>oc-cn5g-20897</svr_id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100040">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (UL/TCP)(30 sec)(multi-ue profile)</desc>
|
||||
<iperf_args>-t 30</iperf_args>
|
||||
<id>up2-fhi72</id>
|
||||
<iperf_tcp_rate_target>80</iperf_tcp_rate_target>
|
||||
<svr_id>oc-cn5g-20897</svr_id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="103000">
|
||||
<class>Detach_UE</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Detach UE</desc>
|
||||
<id>up2-fhi72</id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100002">
|
||||
<class>IdleSleep</class>
|
||||
<desc>Sleep</desc>
|
||||
<idle_sleep_time_in_sec>5</idle_sleep_time_in_sec>
|
||||
</testCase>
|
||||
|
||||
<testCase id="130000">
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy gNB</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb</yaml_path>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="777777">
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-fhi72</images>
|
||||
</testCase>
|
||||
|
||||
<testCase id="888888">
|
||||
<class>Custom_Script</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Set CPU to idle state, set kernel parameters to default values</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_cleanup.sh</script>
|
||||
<command_fail>yes</command_fail>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -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>
|
||||
|
||||
@@ -110,7 +110,7 @@ services:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --rfsim --rfsimulator.prop_delay 238.74 --ntn-koffset 478 --ntn-ta-common 477.48 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
USE_ADDITIONAL_OPTIONS: --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --rfsim --rfsimulator.prop_delay 238.74 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr style="border-collapse: collapse; border: none;">
|
||||
<td style="border-collapse: collapse; border: none;">
|
||||
<a href="http://www.openairinterface.org/">
|
||||
<img src="../../../doc/images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
||||
</img>
|
||||
</a>
|
||||
</td>
|
||||
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
||||
<b><font size = "5">OAI O-RAN 7.2 Front-haul Docker Compose</font></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
|
||||
This docker-compose is designed to use `OAI-gNB` with a 7.2 compatible Radio Unit. Before using this docker compose you have to configure
|
||||
the host machine as per the [ORAN_FHI7.2_Tutorial](../../../doc/ORAN_FHI7.2_Tutorial.md). The container image used by the docker compose file is tested only on `Ubuntu 22.04` and `RHEL 9.4` docker host.
|
||||
|
||||
## Build Image (Optional)
|
||||
|
||||
Refer to [OAI Docker/Podman Build and Usage Procedures](../../../docker/README.md)
|
||||
|
||||
## Configure Networking
|
||||
|
||||
### SR-IOV Virtual Functions (VFs)
|
||||
|
||||
In docker-compose environment there is no automated method
|
||||
to configure the VFs on the fly. The user will have to manually configure
|
||||
C/U plane VFs before starting the container `OAI-gNB`.
|
||||
|
||||
You can follow the step
|
||||
[configure-network-interfaces-and-dpdk-vfs](../../../doc/ORAN_FHI7.2_Tutorial.md#configure-network-interfaces-and-dpdk-vfs).
|
||||
|
||||
### Interface towards AMF (N2)
|
||||
|
||||
For `N2` interface we are using `macvlan` driver of docker.
|
||||
|
||||
You can use the `bridge` driver, in situation
|
||||
|
||||
- When the core network is running on the same machine
|
||||
- or different machine but you have configured
|
||||
needed `ip route` and forwarding to access the core network from RAN host.
|
||||
|
||||
To configure docker `macvlan` network
|
||||
you need to choose `ipam.config` and `driver_opts.parent` are per your environment
|
||||
|
||||
```
|
||||
oai-net:
|
||||
driver: macvlan
|
||||
name: oai-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.21.16.0/22"
|
||||
ip_range: "172.21.18.20/32"
|
||||
gateway: "172.21.19.254"
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "oai-net"
|
||||
parent: ens7f0
|
||||
```
|
||||
|
||||
To configure `bridge` network you need to choose `ipam.config.subnet` as per your environment.
|
||||
|
||||
```
|
||||
oai-net:
|
||||
driver: bridge
|
||||
name: oai-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "oai-net"
|
||||
```
|
||||
|
||||
## Deploy OAI-gNB Container
|
||||
|
||||
The [configuration file](../../conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf) used by docker compose is configured for Metanoia RU.
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
To check the logs
|
||||
|
||||
```bash
|
||||
docker logs oai-gnb -f
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
services:
|
||||
oai-gnb:
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-fhi72:${TAG:-develop}
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
- IPC_LOCK
|
||||
- SYS_NICE
|
||||
cap_drop:
|
||||
- ALL
|
||||
container_name: oai-gnb
|
||||
environment:
|
||||
TZ: Europe/Paris
|
||||
USE_ADDITIONAL_OPTIONS: --sa --thread-pool 7,8,9,10,11,12
|
||||
devices:
|
||||
- /dev/vfio:/dev/vfio/
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
- /dev/hugepages:/dev/hugepages
|
||||
# Please change these values based on your system
|
||||
cpuset: "0,1,2,3,4,5,6,7,8,9,10,11,12"
|
||||
networks:
|
||||
oai-net:
|
||||
ipv4_address: 172.21.18.20
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-softmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
oai-net:
|
||||
driver: macvlan
|
||||
name: oai-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.21.16.0/22"
|
||||
ip_range: "172.21.18.20/32"
|
||||
gateway: "172.21.19.254"
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "oai-net"
|
||||
parent: ens7f0
|
||||
@@ -0,0 +1,5 @@
|
||||
set -e
|
||||
sudo cpupower idle-set -E > /dev/null
|
||||
sudo sysctl kernel.sched_rt_runtime_us=950000
|
||||
sudo sysctl kernel.timer_migration=1
|
||||
exit 0
|
||||
@@ -0,0 +1,20 @@
|
||||
set -e
|
||||
sudo cpupower idle-set -D 0 > /dev/null
|
||||
sudo sysctl kernel.sched_rt_runtime_us=-1
|
||||
sudo sysctl kernel.timer_migration=0
|
||||
sudo ethtool -G ens7f1 rx 8160 tx 8160
|
||||
sudo sh -c 'echo 0 > /sys/class/net/ens7f1/device/sriov_numvfs'
|
||||
sudo sh -c 'echo 3 > /sys/class/net/ens7f1/device/sriov_numvfs'
|
||||
sudo modprobe -r iavf
|
||||
sudo modprobe iavf
|
||||
# this next 2 lines is for C/U planes
|
||||
sudo ip link set ens7f1 vf 0 mac 00:11:22:33:44:55 vlan 3 spoofchk off mtu 9000
|
||||
sudo ip link set ens7f1 vf 1 mac 00:11:22:33:44:54 vlan 3 spoofchk off mtu 9000
|
||||
sleep 1
|
||||
# These are the DPDK bindings for C/U-planes on vlan 1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind c3:11.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind c3:11.1
|
||||
sudo modprobe vfio-pci
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci c3:11.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci c3:11.1
|
||||
exit 0
|
||||
@@ -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)"
|
||||
|
||||
|
||||
@@ -83,12 +83,15 @@ find_path(xran_INCLUDE_DIR
|
||||
xran_pkt.h
|
||||
xran_pkt_up.h
|
||||
xran_sync_api.h
|
||||
PATHS ${xran_LOCATION}
|
||||
PATH_SUFFIXES api
|
||||
HINTS ${xran_LOCATION}
|
||||
PATH_SUFFIXES api include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
find_library(xran_LIBRARY
|
||||
NAMES xran
|
||||
PATHS ${xran_LOCATION}/build
|
||||
HINTS ${xran_LOCATION}
|
||||
PATH_SUFFIXES build api
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
if (NOT xran_LIBRARY)
|
||||
message(FATAL_ERROR "could not detect xran build artifacts at ${xran_LOCATION}/build")
|
||||
|
||||
@@ -131,6 +131,7 @@ check_supported_distribution() {
|
||||
"rocky9.2") return 0 ;;
|
||||
"rocky9.3") return 0 ;;
|
||||
"rocky9.4") return 0 ;;
|
||||
"rocky9.5") return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree)
|
||||
// add the memory piece in the managed memory pieces list
|
||||
pthread_mutex_lock(&cfg->memBlocks_mutex);
|
||||
int newBlockIdx=cfg->numptrs++;
|
||||
AssertFatal(newBlockIdx < sizeofArray(cfg->oneBlock), "reached maximum number of dynamically allocatable blocks\n");
|
||||
oneBlock_t* tmp=&cfg->oneBlock[newBlockIdx];
|
||||
tmp->ptrs = (char *)ptr;
|
||||
tmp->ptrsAllocated = true;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "common/utils/T/T.h"
|
||||
#define CONFIG_MAX_OOPT_PARAMS 10 // maximum number of parameters in the -O option (-O <cfgmode>:P1:P2...
|
||||
#define CONFIG_MAX_ALLOCATEDPTRS 2048 // maximum number of parameters that can be dynamicaly allocated in the config module
|
||||
#define CONFIG_MAX_ALLOCATEDPTRS 32768 // maximum number of parameters that can be dynamicaly allocated in the config module
|
||||
|
||||
/* default values for configuration module parameters */
|
||||
#define CONFIG_LIBCONFIGFILE "libconfig" // use libconfig file
|
||||
|
||||
@@ -50,7 +50,8 @@ void *actor_thread(void *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
elt->processingFunc(NotifiedFifoData(elt));
|
||||
if (elt->processingFunc) // processing function can be NULL
|
||||
elt->processingFunc(NotifiedFifoData(elt));
|
||||
if (elt->reponseFifo) {
|
||||
pushNotifiedFIFO(elt->reponseFifo, elt);
|
||||
} else
|
||||
@@ -85,3 +86,14 @@ void shutdown_actor(Actor_t *actor)
|
||||
abortNotifiedFIFO(&response_fifo);
|
||||
pthread_join(actor->thread, NULL);
|
||||
}
|
||||
|
||||
void flush_actor(Actor_t *actor)
|
||||
{
|
||||
notifiedFIFO_t response_fifo;
|
||||
initNotifiedFIFO(&response_fifo);
|
||||
notifiedFIFO_elt_t *elt = newNotifiedFIFO_elt(0, 0, &response_fifo, NULL);
|
||||
pushNotifiedFIFO(&actor->fifo, elt);
|
||||
elt = pullNotifiedFIFO(&response_fifo);
|
||||
delNotifiedFIFO_elt(elt);
|
||||
abortNotifiedFIFO(&response_fifo);
|
||||
}
|
||||
|
||||
@@ -49,4 +49,9 @@ void destroy_actor(Actor_t *actor);
|
||||
/// @param actor
|
||||
void shutdown_actor(Actor_t *actor);
|
||||
|
||||
/// @brief This function will return when all current jobs in the queue are finished.
|
||||
/// The caller should make sure no new jobs are added to the queue between this function call and return.
|
||||
/// @param actor
|
||||
void flush_actor(Actor_t *actor);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,13 @@ add_library(telnetsrv_rrc MODULE telnetsrv_rrc.c)
|
||||
target_link_libraries(telnetsrv_rrc PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_dependencies(telnetsrv telnetsrv_rrc)
|
||||
|
||||
message(STATUS "Add CI specific telnet functions in libtelnetsrv_o1.so")
|
||||
add_library(telnetsrv_o1 MODULE telnetsrv_o1.c)
|
||||
target_link_libraries(telnetsrv_o1 PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_dependencies(telnetsrv telnetsrv_o1)
|
||||
|
||||
# all libraries should be written to root build dir
|
||||
set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE telnetsrv_bearer telnetsrv_rrc
|
||||
set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE
|
||||
telnetsrv_bearer telnetsrv_rrc telnetsrv_o1
|
||||
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../..
|
||||
)
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
[[_TOC_]]
|
||||
|
||||
The telnet O1 module (`telnetsrv_o1.c`) can be used to perform some O1-related
|
||||
actions (reading data, starting and stopping the nr-softmodem, reconfigurating
|
||||
frequency and bandwidth).
|
||||
|
||||
# General usage
|
||||
|
||||
The usage is similar to the general telnet usage, but in short:
|
||||
```
|
||||
./build_oai --ninja -c --gNB --nrUE --build-lib telnetsrv
|
||||
```
|
||||
to build everything including the telnet library. Then, run the nr-softmodem
|
||||
by activating telnet and loading the `o1` module:
|
||||
```
|
||||
./nr-softmodem -O <config> --telnetsrv --telnetsrv.shrmod o1
|
||||
```
|
||||
|
||||
Afterwards, it should be possible to connect via telnet on localhost, port
|
||||
9090. Use `help` to get help on the different command sections, and type e.g.
|
||||
`o1 stats` to get statistics (more information further below):
|
||||
|
||||
```
|
||||
$ telnet 127.0.0.1 9090
|
||||
Trying 127.0.0.1...
|
||||
Connected to 127.0.0.1.
|
||||
Escape character is '^]'.
|
||||
|
||||
softmodem_gnb> help
|
||||
[...]
|
||||
module 4 = o1:
|
||||
o1 stats
|
||||
o1 config ?
|
||||
o1 stop_modem
|
||||
o1 start_modem
|
||||
[...]
|
||||
softmodem_gnb> o1 stats
|
||||
[...]
|
||||
softmodem_gnb> exit
|
||||
Connection closed by foreign host.
|
||||
```
|
||||
|
||||
It also possible to send a command "directly from the command line", by piping
|
||||
the command into netcat:
|
||||
```
|
||||
echo o1 stats | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
Note that only one telnet client can be connected at a time.
|
||||
|
||||
# Get statistics
|
||||
|
||||
Use the `o1 stats` command. The output is in JSON format:
|
||||
```json
|
||||
{
|
||||
"o1-config": {
|
||||
"BWP": {
|
||||
"dl": [
|
||||
{
|
||||
"bwp3gpp:isInitialBwp": true,
|
||||
"bwp3gpp:numberOfRBs": 106,
|
||||
"bwp3gpp:startRB": 0,
|
||||
"bwp3gpp:subCarrierSpacing": 30
|
||||
}
|
||||
],
|
||||
"ul": [
|
||||
{
|
||||
"bwp3gpp:isInitialBwp": true,
|
||||
"bwp3gpp:numberOfRBs": 106,
|
||||
"bwp3gpp:startRB": 0,
|
||||
"bwp3gpp:subCarrierSpacing": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
"NRCELLDU": {
|
||||
"nrcelldu3gpp:ssbFrequency": 641280,
|
||||
"nrcelldu3gpp:arfcnDL": 640008,
|
||||
"nrcelldu3gpp:bSChannelBwDL": 40,
|
||||
"nrcelldu3gpp:arfcnUL": 640008,
|
||||
"nrcelldu3gpp:bSChannelBwUL": 40,
|
||||
"nrcelldu3gpp:nRPCI": 0,
|
||||
"nrcelldu3gpp:nRTAC": 1,
|
||||
"nrcelldu3gpp:mcc": "208",
|
||||
"nrcelldu3gpp:mnc": "95",
|
||||
"nrcelldu3gpp:sd": 16777215,
|
||||
"nrcelldu3gpp:sst": 1
|
||||
},
|
||||
"device": {
|
||||
"gnbId": 1,
|
||||
"gnbName": "gNB-Eurecom-5GNRBox",
|
||||
"vendor": "OpenAirInterface"
|
||||
}
|
||||
},
|
||||
"O1-Operational": {
|
||||
"frame-type": "tdd",
|
||||
"band-number": 78,
|
||||
"num-ues": 1,
|
||||
"ues": [
|
||||
6876
|
||||
],
|
||||
"load": 9,
|
||||
"ues-thp": [
|
||||
{
|
||||
"rnti": 6876,
|
||||
"dl": 3279,
|
||||
"ul": 2725
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that no actual JSON engine is used, so no actual verification is done; it
|
||||
is for convenience of the consumer. To verify, you can employ `jq`:
|
||||
```
|
||||
echo o1 stats | nc -N 127.0.0.1 9090 | awk '/^{$/, /^}$/' | jq .
|
||||
```
|
||||
(`awk`'s pattern matching makes that only everything between the first `{` and
|
||||
its corresponding `}` is printed).
|
||||
|
||||
There are two sections:
|
||||
1. `.o1-config` show some stats that map directly to the O1 Netconf model. Note
|
||||
that only one MCC/MNC/SD/SST (each) are supported right now. Also, note that
|
||||
as per 3GPP specifications, SD of value `0xffffff` (16777215 in decimal)
|
||||
means "no SD". `bSChannelBwDL/UL` is reported in MHz.
|
||||
2. `.O1-operational` output some statistics that do not map yet to any netconf
|
||||
parameters, but that might be useful nevertheless for a consumer.
|
||||
|
||||
# Write a new configuration
|
||||
|
||||
Use `o1 config` to write a configuration:
|
||||
```
|
||||
echo o1 config nrcelldu3gpp:ssbFrequency 620736 nrcelldu3gpp:arfcnDL 620020 nrcelldu3gpp:bSChannelBwDL 51 bwp3gpp:numberOfRBs 51 bwp3gpp:startRB 0 | nc -N 127.0.0.1 9090
|
||||
```
|
||||
You have to pass the above parameters in exactly this order. The softmodem
|
||||
needs to be stopped; it will pick up the new configuration when starting the
|
||||
softmodem again.
|
||||
|
||||
Note that you cannot switch three-quarter sampling for this as of now.
|
||||
|
||||
For values of the configuration, refer to the next section.
|
||||
|
||||
# Use hardcoded configuration
|
||||
|
||||
Use `o1 bwconfig` to write a hard-coded configuration for 20 or 40 MHz cells:
|
||||
```
|
||||
echo o1 bwconfig 20 | nc -N 127.0.0.1 9090
|
||||
echo o1 bwconfig 40 | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
The softmodem needs to be stopped; it will pick up the new configuration when
|
||||
starting the softmodem again.
|
||||
|
||||
Use `o1 stats` to see which configurations are set by these commands for the
|
||||
parameters `nrcelldu3gpp:ssbFrequency`, `nrcelldu3gpp:arfcnDL`,
|
||||
`nrcelldu3gpp:arfcnUL`, `nrcelldu3gpp:bSChannelBwDL`,
|
||||
`nrcelldu3gpp:bSChannelBwUL`, and `bwp3gpp:numberOfRBsbwp3gpp:startRB`.
|
||||
Furthermore, for 20MHz, it *disables* three-quarter sampling, whereas it
|
||||
*enables* three-quarter sampling for 40MHz.
|
||||
|
||||
# Restart the softmodem
|
||||
|
||||
Use `o1 stop_modem` to stop the `nr-softmodem`. To restart the softmodem, use
|
||||
`o1 start_modem`:
|
||||
```
|
||||
echo o1 stop_modem | nc -N 127.0.0.1 9090
|
||||
echo o1 start_modem | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
In fact, stopping terminates all L1 threads. It will be as if the softmodem
|
||||
"freezes", and no periodical output of statistics will occur (the O1 telnet
|
||||
interface will still work, though). Starting again will "defreeze" the
|
||||
softmodem.
|
||||
|
||||
Upon restart, the DU sends a gNB-DU configuration update to the CU to inform it
|
||||
about the updated configuration. Therefore, this also works in F1.
|
||||
@@ -3,5 +3,6 @@ The oai embedded telnet server is an optional monitoring and debugging tool. It
|
||||
* [Using the telnet server](telnetusage.md)
|
||||
* [Adding commands to the oai telnet server](telnetaddcmd.md)
|
||||
* [telnet server architecture ](telnetarch.md)
|
||||
* [on the telnet O1 module](telneto1.md)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define TELNETSERVERCODE
|
||||
#include "telnetsrv.h"
|
||||
|
||||
#include "openair2/RRC/NR/nr_rrc_defs.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
|
||||
#include "openair2/RRC/NR/nr_rrc_config.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
|
||||
#define ERROR_MSG_RET(mSG, aRGS...) do { prnt("FAILURE: " mSG, ##aRGS); return 1; } while (0)
|
||||
|
||||
#define ISINITBWP "bwp3gpp:isInitialBwp"
|
||||
//#define CYCLPREF "bwp3gpp:cyclicPrefix"
|
||||
#define NUMRBS "bwp3gpp:numberOfRBs"
|
||||
#define STARTRB "bwp3gpp:startRB"
|
||||
#define BWPSCS "bwp3gpp:subCarrierSpacing"
|
||||
|
||||
#define SSBFREQ "nrcelldu3gpp:ssbFrequency"
|
||||
#define ARFCNDL "nrcelldu3gpp:arfcnDL"
|
||||
#define BWDL "nrcelldu3gpp:bSChannelBwDL"
|
||||
#define ARFCNUL "nrcelldu3gpp:arfcnUL"
|
||||
#define BWUL "nrcelldu3gpp:bSChannelBwUL"
|
||||
#define PCI "nrcelldu3gpp:nRPCI"
|
||||
#define TAC "nrcelldu3gpp:nRTAC"
|
||||
#define MCC "nrcelldu3gpp:mcc"
|
||||
#define MNC "nrcelldu3gpp:mnc"
|
||||
#define SD "nrcelldu3gpp:sd"
|
||||
#define SST "nrcelldu3gpp:sst"
|
||||
|
||||
typedef struct b {
|
||||
long int dl;
|
||||
long int ul;
|
||||
} b_t;
|
||||
|
||||
typedef struct ue_stat {
|
||||
rnti_t rnti;
|
||||
b_t thr;
|
||||
} ue_stat_t;
|
||||
|
||||
#define PRINTLIST_i(len, fmt, ...) \
|
||||
{ \
|
||||
for (int i = 0; i < len; ++i) { \
|
||||
if (i != 0) prnt(", "); \
|
||||
prnt(fmt, __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
|
||||
static int get_stats(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (buf)
|
||||
ERROR_MSG_RET("no parameter allowed\n");
|
||||
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
AssertFatal(mac != NULL, "need MAC\n");
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
const f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
const f1ap_served_cell_info_t *cell_info = &sr->cell[0].info;
|
||||
|
||||
const NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
const NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
const NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
|
||||
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
||||
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
const NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters;
|
||||
|
||||
int scs = initialDL->subcarrierSpacing;
|
||||
AssertFatal(scs == initialUL->subcarrierSpacing, "different SCS for UL/DL not supported!\n");
|
||||
int band = *frequencyInfoDL->frequencyBandList.list.array[0];
|
||||
int nrb = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
AssertFatal(nrb == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth, "different BW for UL/DL not supported!\n");
|
||||
frequency_range_t fr = band > 256 ? FR2 : FR1;
|
||||
int bw_index = get_supported_band_index(scs, fr, nrb);
|
||||
int bw_mhz = get_supported_bw_mhz(fr, bw_index);
|
||||
|
||||
const mac_stats_t *stat = &mac->mac_stats;
|
||||
static mac_stats_t last = {0};
|
||||
int diff_used = stat->used_prb_aggregate - last.used_prb_aggregate;
|
||||
int diff_total = stat->total_prb_aggregate - last.total_prb_aggregate;
|
||||
int load = diff_total > 0 ? 100 * diff_used / diff_total : 0;
|
||||
last = *stat;
|
||||
|
||||
static struct timespec tp_last = {0};
|
||||
struct timespec tp_now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp_now);
|
||||
size_t diff_msec = (tp_now.tv_sec - tp_last.tv_sec) * 1000 + (tp_now.tv_nsec - tp_last.tv_nsec) / 1000000;
|
||||
tp_last = tp_now;
|
||||
|
||||
const int srb_flag = 0;
|
||||
const int rb_id = 1;
|
||||
static b_t last_total[MAX_MOBILES_PER_GNB] = {0}; // TODO: hash table?
|
||||
ue_stat_t ue_stat[MAX_MOBILES_PER_GNB] = {0};
|
||||
int num_ues = 0;
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
nr_rlc_get_statistics(it->rnti, srb_flag, rb_id, &rlc);
|
||||
b_t *lt = &last_total[num_ues];
|
||||
ue_stat_t *ue_s = &ue_stat[num_ues];
|
||||
ue_s->rnti = it->rnti;
|
||||
// static var last_total: we might have old data, larger than what
|
||||
// reports RLC, leading to a huge number -> cut off to zero
|
||||
if (lt->dl > rlc.txpdu_bytes)
|
||||
lt->dl = rlc.txpdu_bytes;
|
||||
if (lt->ul > rlc.rxpdu_bytes)
|
||||
lt->ul = rlc.rxpdu_bytes;
|
||||
ue_s->thr.dl = (rlc.txpdu_bytes - lt->dl) * 8 / diff_msec;
|
||||
ue_s->thr.ul = (rlc.rxpdu_bytes - lt->ul) * 8 / diff_msec;
|
||||
lt->dl = rlc.txpdu_bytes;
|
||||
lt->ul = rlc.rxpdu_bytes;
|
||||
num_ues++;
|
||||
}
|
||||
|
||||
prnt("{\n");
|
||||
prnt(" \"o1-config\": {\n");
|
||||
|
||||
prnt(" \"BWP\": {\n");
|
||||
prnt(" \"dl\": [{\n");
|
||||
prnt(" \"" ISINITBWP "\": true,\n");
|
||||
//prnt(" \"" CYCLPREF "\": %ld,\n", *initialDL->cyclicPrefix);
|
||||
prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialDL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs));
|
||||
prnt(" }],\n");
|
||||
prnt(" \"ul\": [{\n");
|
||||
prnt(" \"" ISINITBWP "\": true,\n");
|
||||
//prnt(" \"" CYCLPREF "\": %ld,\n", *initialUL->cyclicPrefix);
|
||||
prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialUL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialUL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs));
|
||||
prnt(" }]\n");
|
||||
prnt(" },\n");
|
||||
|
||||
prnt(" \"NRCELLDU\": {\n");
|
||||
prnt(" \"" SSBFREQ "\": %ld,\n", *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB);
|
||||
prnt(" \"" ARFCNDL "\": %ld,\n", frequencyInfoDL->absoluteFrequencyPointA);
|
||||
prnt(" \"" BWDL "\": %ld,\n", bw_mhz);
|
||||
prnt(" \"" ARFCNUL "\": %ld,\n", frequencyInfoUL->absoluteFrequencyPointA ? *frequencyInfoUL->absoluteFrequencyPointA : frequencyInfoDL->absoluteFrequencyPointA);
|
||||
prnt(" \"" BWUL "\": %ld,\n", bw_mhz);
|
||||
prnt(" \"" PCI "\": %ld,\n", *scc->physCellId);
|
||||
prnt(" \"" TAC "\": %ld,\n", *cell_info->tac);
|
||||
prnt(" \"" MCC "\": \"%03d\",\n", cell_info->plmn.mcc);
|
||||
prnt(" \"" MNC "\": \"%0*d\",\n", cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc);
|
||||
prnt(" \"" SD "\": %d,\n", cell_info->nssai[0].sd);
|
||||
prnt(" \"" SST "\": %d\n", cell_info->nssai[0].sst);
|
||||
prnt(" },\n");
|
||||
prnt(" \"device\": {\n");
|
||||
prnt(" \"gnbId\": %d,\n", sr->gNB_DU_id);
|
||||
prnt(" \"gnbName\": \"%s\",\n", sr->gNB_DU_name);
|
||||
prnt(" \"vendor\": \"OpenAirInterface\"\n");
|
||||
prnt(" }\n");
|
||||
prnt(" },\n");
|
||||
|
||||
prnt(" \"O1-Operational\": {\n");
|
||||
prnt(" \"frame-type\": \"%s\",\n", frame_type == TDD ? "tdd" : "fdd");
|
||||
prnt(" \"band-number\": %ld,\n", band);
|
||||
prnt(" \"num-ues\": %d,\n", num_ues);
|
||||
prnt(" \"ues\": ["); PRINTLIST_i(num_ues, "%d", ue_stat[i].rnti); prnt("],\n");
|
||||
prnt(" \"load\": %d,\n", load);
|
||||
prnt(" \"ues-thp\": [");
|
||||
PRINTLIST_i(num_ues, "\n {\"rnti\": %d, \"dl\": %ld, \"ul\": %ld}", ue_stat[i].rnti, ue_stat[i].thr.dl, ue_stat[i].thr.ul);
|
||||
prnt("\n ]\n");
|
||||
prnt(" }\n");
|
||||
prnt("}\n");
|
||||
prnt("OK\n");
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_long(const char *buf, const char *end, const char *id, long *val)
|
||||
{
|
||||
const char *curr = buf;
|
||||
while (isspace(*curr) && curr < end) // skip leading spaces
|
||||
curr++;
|
||||
int len = strlen(id);
|
||||
if (curr + len >= end)
|
||||
return -1;
|
||||
if (strncmp(curr, id, len) != 0) // check buf has id
|
||||
return -1;
|
||||
curr += len;
|
||||
while (isspace(*curr) && curr < end) // skip middle spaces
|
||||
curr++;
|
||||
if (curr >= end)
|
||||
return -1;
|
||||
int nread = sscanf(curr, "%ld", val);
|
||||
if (nread != 1)
|
||||
return -1;
|
||||
while (isdigit(*curr) && curr < end) // skip all digits read above
|
||||
curr++;
|
||||
if (curr > end)
|
||||
return -1;
|
||||
return curr - buf;
|
||||
}
|
||||
|
||||
bool running = true; // in the beginning, the softmodem is started automatically
|
||||
static int set_config(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!buf)
|
||||
ERROR_MSG_RET("need param: o1 config param1 val1 [param2 val2 ...]\n");
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot set parameters while L1 is running\n");
|
||||
const char *end = buf + strlen(buf);
|
||||
|
||||
/* we need to update the following fields to change frequency and/or
|
||||
* bandwidth:
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].absoluteFrequencySSB 620736 -> SSBFREQ
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].dl_absoluteFrequencyPointA 620020 -> ARFCNDL
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].dl_carrierBandwidth 51 -> BWDL
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].initialDLBWPlocationAndBandwidth 13750 -> NUMRBS + STARTRB
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].ul_carrierBandwidth 51 -> BWUL?
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].initialULBWPlocationAndBandwidth 13750 -> ?
|
||||
*/
|
||||
|
||||
int processed = 0;
|
||||
int pos = 0;
|
||||
|
||||
long ssbfreq;
|
||||
processed = read_long(buf + pos, end, SSBFREQ, &ssbfreq);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " SSBFREQ " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " SSBFREQ ": %ld [len %d]\n", ssbfreq, pos);
|
||||
|
||||
long arfcn;
|
||||
processed = read_long(buf + pos, end, ARFCNDL, &arfcn);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " ARFCNDL " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " ARFCNDL ": %ld [len %d]\n", arfcn, pos);
|
||||
|
||||
long bwdl;
|
||||
processed = read_long(buf + pos, end, BWDL, &bwdl);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " BWDL " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " BWDL ": %ld [len %d]\n", bwdl, pos);
|
||||
|
||||
long numrbs;
|
||||
processed = read_long(buf + pos, end, NUMRBS, &numrbs);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " NUMRBS " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " NUMRBS ": %ld [len %d]\n", numrbs, pos);
|
||||
|
||||
long startrb;
|
||||
processed = read_long(buf + pos, end, STARTRB, &startrb);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " STARTRB " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " STARTRB ": %ld [len %d]\n", startrb, pos);
|
||||
|
||||
int locationAndBandwidth = PRBalloc_to_locationandbandwidth0(numrbs, startrb, MAX_BWP_SIZE);
|
||||
prnt("inferred locationAndBandwidth: %d\n", locationAndBandwidth);
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bwconfig(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot set parameters while L1 is running\n");
|
||||
if (!buf)
|
||||
ERROR_MSG_RET("need param: o1 bwconfig <BW>\n");
|
||||
|
||||
char *end = NULL;
|
||||
if (NULL != (end = strchr(buf, '\n')))
|
||||
*end = 0;
|
||||
if (NULL != (end = strchr(buf, '\r')))
|
||||
*end = 0;
|
||||
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
|
||||
NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters;
|
||||
if (strcmp(buf, "40") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 640008;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106;
|
||||
initialDL->locationAndBandwidth = 28875;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106;
|
||||
initialUL->locationAndBandwidth = 28875;
|
||||
get_softmodem_params()->threequarter_fs = 1;
|
||||
} else if (strcmp(buf, "20") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 640596;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51;
|
||||
initialDL->locationAndBandwidth = 13750;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51;
|
||||
initialUL->locationAndBandwidth = 13750;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else if (strcmp(buf, "100") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 646668;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 643392;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273;
|
||||
initialDL->locationAndBandwidth = 1099;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273;
|
||||
initialUL->locationAndBandwidth = 1099;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else if (strcmp(buf, "60") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 621984;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 620040;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162;
|
||||
initialDL->locationAndBandwidth = 31624;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162;
|
||||
initialUL->locationAndBandwidth = 31624;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else {
|
||||
ERROR_MSG_RET("unhandled option %s\n", buf);
|
||||
}
|
||||
|
||||
free(RC.nrmac[0]->sched_ctrlCommon);
|
||||
RC.nrmac[0]->sched_ctrlCommon = NULL;
|
||||
|
||||
free_MIB_NR(mac->common_channels[0].mib);
|
||||
mac->common_channels[0].mib = get_new_MIB_NR(scc);
|
||||
|
||||
const f1ap_served_cell_info_t *info = &mac->f1_config.setup_req->cell[0].info;
|
||||
nr_mac_configure_sib1(mac, &info->plmn, info->nr_cellid, *info->tac);
|
||||
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int stop_L1(module_id_t gnb_id);
|
||||
static int stop_modem(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!running)
|
||||
ERROR_MSG_RET("cannot stop, nr-softmodem not running\n");
|
||||
|
||||
/* make UEs out of sync and wait 50ms to ensure no PUCCH is scheduled. After
|
||||
* a restart, the frame/slot numbers will be different, which "confuses" the
|
||||
* scheduler, which has many PUCCH structures filled with expected frame/slot
|
||||
* combinations that won't happen. */
|
||||
const gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
nr_mac_trigger_ul_failure(&it->UE_sched_ctrl, 1);
|
||||
}
|
||||
usleep(50000);
|
||||
|
||||
stop_L1(0);
|
||||
running = false;
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int start_L1L2(module_id_t gnb_id);
|
||||
static int start_modem(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot start, nr-softmodem already running\n");
|
||||
start_L1L2(0);
|
||||
running = true;
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void du_clear_all_ue_states();
|
||||
static int remove_mac_ues(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
du_clear_all_ue_states();
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static telnetshell_cmddef_t o1cmds[] = {
|
||||
{"stats", "", get_stats},
|
||||
{"config", "[]", set_config},
|
||||
{"bwconfig", "", set_bwconfig},
|
||||
{"stop_modem", "", stop_modem},
|
||||
{"start_modem", "", start_modem},
|
||||
{"remove_mac_ues", "", remove_mac_ues},
|
||||
{"", "", NULL},
|
||||
};
|
||||
|
||||
static telnetshell_vardef_t o1vars[] = {
|
||||
{"", 0, 0, NULL}
|
||||
};
|
||||
|
||||
void add_o1_cmds(void) {
|
||||
add_telnetcmd("o1", o1vars, o1cmds);
|
||||
}
|
||||
@@ -378,15 +378,15 @@ You might also want to consult TS 38.401 regarding the message exchange.
|
||||
### General
|
||||
|
||||
In the DU in UL, RLC checks in `deliver_sdu()` if we are operating in split
|
||||
mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends an
|
||||
`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task.
|
||||
mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends a GTP
|
||||
message through the GTP API.
|
||||
|
||||
In the CU in UL, assuming the tunnel is in place, GTP decapsulates the packet
|
||||
and calls the callback `cu_f1u_data_req()`, which calls `pdcp_data_ind()` in CU.
|
||||
|
||||
In the CU in DL, the PDCP function `deliver_pdu_drb_gnb()` either (direct) calls
|
||||
into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a
|
||||
`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task.
|
||||
into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a GTP message
|
||||
through the GTP API.
|
||||
|
||||
In the DU in DL, assuming the GTP-U tunnel exists, GTP decapsulates the packet
|
||||
and calls the reception call back `du_rlc_data_req()`, which calls
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# 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.
|
||||
+1
-1
@@ -338,7 +338,7 @@ On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` a
|
||||
|
||||
## PDCP Rx flow
|
||||
|
||||
At the Rx side, `pdcp_data_ind()` serves as the entry point for receiving data from RLC. Within `pdcp_data_ind()`, the PDCP manager mutex protects access to the PDU receiving function of PDCP (`recv_pdu()` callback corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs). Following this, the `deliver_sdu_drb()` function dispatches the received data to the GTP thread via an ITTI message (`GTPV1U_TUNNEL_DATA_REQ`).
|
||||
At the Rx side, `pdcp_data_ind()` serves as the entry point for receiving data from RLC. Within `pdcp_data_ind()`, the PDCP manager mutex protects access to the PDU receiving function of PDCP (`recv_pdu()` callback corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs). Following this, the `deliver_sdu_drb()` function dispatches the received data to the SDAP sublayer.
|
||||
|
||||
## PDCP security
|
||||
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ information on how the images are built.
|
||||
- NR performance tests: 2x2 configuration, 60 MHz and 100 MHz bandwidth
|
||||
- [RAN-SA-FHI72-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-FHI72-CN5G/)
|
||||
~5G-NR
|
||||
- cacofonix + FHI72 + VVDN (gNB), up2 (Quectel RM520N UE), OAI CN5G
|
||||
- cacofonix + FHI72 + Metanoia (gNB), up2 (Quectel RM520N UE), OAI CN5G
|
||||
- OpenShift cluster for CN deployment
|
||||
- FHI 7.2 testing with 100 MHz bandwidth, 2 layers in DL
|
||||
|
||||
|
||||
@@ -95,6 +95,10 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_bearer.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \
|
||||
/usr/local/lib/
|
||||
|
||||
# Now we are copying from builder-image the UHD files.
|
||||
|
||||
@@ -145,6 +145,9 @@ f1ap_cudu_inst_t *getCxt(instance_t instanceP)
|
||||
return &fake;
|
||||
}
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id) { };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/// static configuration for NR at the moment
|
||||
|
||||
@@ -383,12 +383,16 @@ void init_gNB_Tpool(int inst) {
|
||||
|
||||
void term_gNB_Tpool(int inst) {
|
||||
PHY_VARS_gNB *gNB = RC.gNB[inst];
|
||||
abortTpool(&gNB->threadPool);
|
||||
abortNotifiedFIFO(&gNB->respDecode);
|
||||
abortNotifiedFIFO(&gNB->resp_L1);
|
||||
pthread_join(gNB->L1_rx_thread, NULL);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_out);
|
||||
pthread_join(gNB->L1_tx_thread, NULL);
|
||||
|
||||
abortTpool(&gNB->threadPool);
|
||||
abortNotifiedFIFO(&gNB->respPuschSymb);
|
||||
abortNotifiedFIFO(&gNB->respDecode);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_free);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_filled);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_out);
|
||||
abortNotifiedFIFO(&gNB->L1_rx_out);
|
||||
|
||||
gNB_L1_proc_t *proc = &gNB->proc;
|
||||
@@ -403,7 +407,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);
|
||||
|
||||
|
||||
@@ -1443,6 +1443,12 @@ void kill_NR_RU_proc(int inst) {
|
||||
RU_t *ru = RC.ru[inst];
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
|
||||
if (ru->if_south != REMOTE_IF4p5) {
|
||||
abortTpool(ru->threadPool);
|
||||
abortNotifiedFIFO(ru->respfeprx);
|
||||
abortNotifiedFIFO(ru->respfeptx);
|
||||
}
|
||||
|
||||
/* Note: it seems pthread_FH and and FEP thread below both use
|
||||
* mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do
|
||||
* the same for FEP thread below again (using broadcast() to ensure both
|
||||
|
||||
+101
-24
@@ -401,6 +401,105 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) {
|
||||
//extern void free_transport(PHY_VARS_gNB *);
|
||||
extern void nr_phy_free_RU(RU_t *);
|
||||
|
||||
int stop_L1(module_id_t gnb_id)
|
||||
{
|
||||
RU_t *ru = RC.ru[gnb_id];
|
||||
if (!ru) {
|
||||
LOG_W(GNB_APP, "no RU configured\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!RC.gNB[gnb_id]->configured) {
|
||||
LOG_W(GNB_APP, "L1 already stopped\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_I(GNB_APP, "stopping nr-softmodem\n");
|
||||
oai_exit = 1;
|
||||
|
||||
/* these tasks/layers need to pick up new configuration */
|
||||
if (RC.nb_nr_L1_inst > 0)
|
||||
stop_gNB(RC.nb_nr_L1_inst);
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* stop trx devices, multiple carrier currently not supported by RU */
|
||||
if (ru->rfdevice.trx_stop_func) {
|
||||
ru->rfdevice.trx_stop_func(&ru->rfdevice);
|
||||
LOG_I(GNB_APP, "turned off RU rfdevice\n");
|
||||
}
|
||||
|
||||
if (ru->ifdevice.trx_stop_func) {
|
||||
ru->ifdevice.trx_stop_func(&ru->ifdevice);
|
||||
LOG_I(GNB_APP, "turned off RU ifdevice\n");
|
||||
}
|
||||
|
||||
/* release memory used by the RU/gNB threads (incomplete), after all
|
||||
* threads have been stopped (they partially use the same memory) */
|
||||
for (int inst = 0; inst < RC.nb_RU; inst++) {
|
||||
nr_phy_free_RU(RC.ru[inst]);
|
||||
}
|
||||
|
||||
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
||||
phy_free_nr_gNB(RC.gNB[inst]);
|
||||
}
|
||||
|
||||
RC.gNB[gnb_id]->configured = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart the nr-softmodem after it has been soft-stopped with stop_L1L2()
|
||||
*/
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
int start_L1L2(module_id_t gnb_id)
|
||||
{
|
||||
LOG_I(GNB_APP, "starting nr-softmodem\n");
|
||||
/* block threads */
|
||||
oai_exit = 0;
|
||||
sync_var = -1;
|
||||
extern void init_sched_response(void);
|
||||
init_sched_response();
|
||||
|
||||
/* update config */
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
nr_mac_config_scc(mac, scc, &mac->radio_config);
|
||||
|
||||
NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib;
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1;
|
||||
|
||||
/* update existing config in F1 Setup request structures */
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
f1ap_served_cell_info_t *info = &sr->cell[0].info;
|
||||
DevAssert(info->mode == F1AP_MODE_TDD);
|
||||
DevAssert(scc->tdd_UL_DL_ConfigurationCommon != NULL);
|
||||
info->tdd = read_tdd_config(scc); /* updates radio config */
|
||||
/* send gNB-DU configuration update to RRC */
|
||||
f1ap_gnb_du_configuration_update_t update = {
|
||||
.transaction_id = 1,
|
||||
.num_cells_to_modify = 1,
|
||||
};
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1);
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
|
||||
init_NR_RU(config_get_if(), NULL);
|
||||
|
||||
start_NR_RU();
|
||||
wait_RUs();
|
||||
init_eNB_afterRU();
|
||||
LOG_I(GNB_APP, "Sending sync to all threads\n");
|
||||
pthread_mutex_lock(&sync_mutex);
|
||||
sync_var=0;
|
||||
pthread_cond_broadcast(&sync_cond);
|
||||
pthread_mutex_unlock(&sync_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_nfapi_init(char *thread_name)
|
||||
{
|
||||
pthread_mutex_lock( &nfapi_sync_mutex );
|
||||
@@ -629,37 +728,15 @@ int main( int argc, char **argv ) {
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
itti_wait_tasks_end(NULL);
|
||||
printf("Returned from ITTI signal handler\n");
|
||||
oai_exit=1;
|
||||
|
||||
// cleanup
|
||||
if (RC.nb_nr_L1_inst > 0)
|
||||
stop_gNB(RC.nb_nr_L1_inst);
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* release memory used by the RU/gNB threads (incomplete), after all
|
||||
* threads have been stopped (they partially use the same memory) */
|
||||
for (int inst = 0; inst < RC.nb_RU; inst++) {
|
||||
nr_phy_free_RU(RC.ru[inst]);
|
||||
}
|
||||
|
||||
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
||||
phy_free_nr_gNB(RC.gNB[inst]);
|
||||
}
|
||||
if (RC.nb_nr_L1_inst > 0 || RC.nb_RU > 0)
|
||||
stop_L1(0);
|
||||
|
||||
pthread_cond_destroy(&sync_cond);
|
||||
pthread_mutex_destroy(&sync_mutex);
|
||||
pthread_cond_destroy(&nfapi_sync_cond);
|
||||
pthread_mutex_destroy(&nfapi_sync_mutex);
|
||||
|
||||
// *** Handle per CC_id openair0
|
||||
|
||||
for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
|
||||
if (RC.ru[ru_id]->ifdevice.trx_end_func)
|
||||
RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
|
||||
}
|
||||
|
||||
free(pckg);
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
@@ -52,7 +52,7 @@ extern void stop_RU(int nb_ru);
|
||||
extern void kill_NR_RU_proc(int inst);
|
||||
extern void set_function_spec_param(RU_t *ru);
|
||||
|
||||
void init_gNB_afterRU(void);
|
||||
void init_eNB_afterRU(void);
|
||||
|
||||
void init_pdcp(void);
|
||||
|
||||
|
||||
+122
-50
@@ -41,6 +41,7 @@
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "instrumentation.h"
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
#include "position_interface.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -155,7 +156,9 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id)
|
||||
ue->if_inst = nr_ue_if_module_init(UE_id);
|
||||
ue->dci_thres = 0;
|
||||
ue->target_Nid_cell = -1;
|
||||
ue->timing_advance = ue->frame_parms.samples_per_subframe * get_nrUE_params()->ntn_ta_common;
|
||||
|
||||
ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message));
|
||||
ue->ntn_config_message->update = false;
|
||||
|
||||
// initialize all signal buffers
|
||||
init_nr_ue_signal(ue, nb_connected_gNB);
|
||||
@@ -443,6 +446,7 @@ static void UE_synch(void *arg) {
|
||||
static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
{
|
||||
PHY_VARS_NR_UE *UE = rxtxD->UE;
|
||||
const fapi_nr_config_request_t *cfg = &UE->nrUE_config;
|
||||
const UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
@@ -466,10 +470,10 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
flags = TX_BURST_START_AND_END;
|
||||
} else {
|
||||
int slots_frame = fp->slots_per_frame;
|
||||
int curr_slot = nr_ue_slot_select(&UE->nrUE_config, slot);
|
||||
int curr_slot = nr_ue_slot_select(cfg, slot);
|
||||
if (curr_slot != NR_DOWNLINK_SLOT) {
|
||||
int next_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + 1) % slots_frame);
|
||||
int prev_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + slots_frame - 1) % slots_frame);
|
||||
int next_slot = nr_ue_slot_select(cfg, (slot + 1) % slots_frame);
|
||||
int prev_slot = nr_ue_slot_select(cfg, (slot + slots_frame - 1) % slots_frame);
|
||||
if (prev_slot == NR_DOWNLINK_SLOT)
|
||||
flags = TX_BURST_START;
|
||||
else if (next_slot == NR_DOWNLINK_SLOT)
|
||||
@@ -480,11 +484,23 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
}
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, proc->timestamp_tx, txp, rxtxD->writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == rxtxD->writeBlockSize, "");
|
||||
openair0_timestamp writeTimestamp = proc->timestamp_tx;
|
||||
int writeBlockSize = rxtxD->writeBlockSize;
|
||||
if ( writeBlockSize > fp->get_samples_per_slot(proc->nr_slot_tx, fp)) {
|
||||
// if writeBlockSize gets longer that slot size, fill with dummy
|
||||
const int dummyBlockSize = writeBlockSize - fp->get_samples_per_slot(proc->nr_slot_tx, fp);
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, dummyBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == dummyBlockSize, "");
|
||||
|
||||
writeTimestamp += dummyBlockSize;
|
||||
writeBlockSize -= dummyBlockSize;
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == writeBlockSize, "");
|
||||
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
memset(txp[i], 0, rxtxD->writeBlockSize);
|
||||
memset(txp[i], 0, writeBlockSize);
|
||||
}
|
||||
|
||||
void processSlotTX(void *arg)
|
||||
@@ -550,13 +566,59 @@ void processSlotTX(void *arg)
|
||||
|
||||
int slots_per_frame = (UE->sl_mode == 2) ? UE->SL_UE_PHY_PARAMS.sl_frame_params.slots_per_frame
|
||||
: UE->frame_parms.slots_per_frame;
|
||||
int next_slot = (proc->nr_slot_tx + 1) % slots_per_frame;
|
||||
dynamic_barrier_join(&UE->process_slot_tx_barriers[next_slot]);
|
||||
int next_slot_and_frame = proc->nr_slot_tx + 1 + proc->nr_slot_tx_offset + proc->frame_tx * slots_per_frame;
|
||||
dynamic_barrier_join(&UE->process_slot_tx_barriers[next_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
||||
RU_write(rxtxD, sl_tx_action);
|
||||
free(rxtxD);
|
||||
TracyCZoneEnd(ctx);
|
||||
}
|
||||
|
||||
static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32_t pointA_freq_khz)
|
||||
{
|
||||
const uint64_t bw = (NR_NB_SC_PER_RB * N_RB) * MU_SCS(mu);
|
||||
const uint64_t carrier_freq = (pointA_freq_khz + bw / 2) * 1000;
|
||||
return carrier_freq;
|
||||
}
|
||||
|
||||
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
// Start synchronization with a target gNB
|
||||
if (UE->synch_request.received_synch_request == 1) {
|
||||
// if upper layers signal BW scan we do as instructed by command line parameter
|
||||
// if upper layers disable BW scan we set it to false
|
||||
if (UE->synch_request.synch_req.ssb_bw_scan)
|
||||
UE->UE_scan_carrier = get_nrUE_params()->UE_scan_carrier;
|
||||
else
|
||||
UE->UE_scan_carrier = false;
|
||||
UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell;
|
||||
|
||||
const fapi_nr_ue_carrier_config_t *cfg = &UE->nrUE_config.carrier_config;
|
||||
uint64_t dl_CarrierFreq = get_carrier_frequency(fp->N_RB_DL, fp->numerology_index, cfg->dl_frequency);
|
||||
uint64_t ul_CarrierFreq = get_carrier_frequency(fp->N_RB_UL, fp->numerology_index, cfg->uplink_frequency);
|
||||
if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) {
|
||||
fp->dl_CarrierFreq = dl_CarrierFreq;
|
||||
fp->ul_CarrierFreq = ul_CarrierFreq;
|
||||
nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0);
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]);
|
||||
init_symbol_rotation(fp);
|
||||
}
|
||||
|
||||
/* Clearing UE harq while DL actors are active causes race condition.
|
||||
So we let the current execution to complete here.*/
|
||||
for (int i = 0; i < NUM_DL_ACTORS; i++) {
|
||||
flush_actor(UE->dl_actors + i);
|
||||
}
|
||||
/*TODO: Flush UL jobs */
|
||||
|
||||
clean_UE_harq(UE);
|
||||
UE->is_synchronized = 0;
|
||||
UE->synch_request.received_synch_request = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
int *tx_wait_for_dlsch,
|
||||
@@ -570,35 +632,6 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
if (IS_SOFTMODEM_NOS1 || IS_SA_MODE(get_softmodem_params())) {
|
||||
// Start synchronization with a target gNB
|
||||
if (UE->synch_request.received_synch_request == 1) {
|
||||
fapi_nr_synch_request_t *synch_req = &UE->synch_request.synch_req;
|
||||
UE->is_synchronized = 0;
|
||||
// if upper layers signal BW scan we do as instructed by command line parameter
|
||||
// if upper layers disable BW scan we set it to false
|
||||
if (UE->synch_request.synch_req.ssb_bw_scan)
|
||||
UE->UE_scan_carrier = get_nrUE_params()->UE_scan_carrier;
|
||||
else
|
||||
UE->UE_scan_carrier = false;
|
||||
UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell;
|
||||
UE->target_Nid_cell = synch_req->target_Nid_cell;
|
||||
|
||||
uint64_t dl_bw = (12 * fp->N_RB_DL) * (15000 << fp->numerology_index);
|
||||
uint64_t dl_CarrierFreq = (dl_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.dl_frequency * 1000;
|
||||
uint64_t ul_bw = (12 * fp->N_RB_UL) * (15000 << fp->numerology_index);
|
||||
uint64_t ul_CarrierFreq = (ul_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.uplink_frequency * 1000;
|
||||
if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) {
|
||||
fp->dl_CarrierFreq = dl_CarrierFreq;
|
||||
fp->ul_CarrierFreq = ul_CarrierFreq;
|
||||
nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0);
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]);
|
||||
init_symbol_rotation(fp);
|
||||
}
|
||||
|
||||
clean_UE_harq(UE);
|
||||
UE->synch_request.received_synch_request = 0;
|
||||
}
|
||||
|
||||
/* send tick to RLC and PDCP every ms */
|
||||
if (proc->nr_slot_rx % fp->slots_per_subframe == 0) {
|
||||
void nr_rlc_tick(int frame, int subframe);
|
||||
@@ -792,6 +825,8 @@ void *UE_thread(void *arg)
|
||||
UE->is_synchronized = 0;
|
||||
int tmp2 = UE->rfdevice.trx_start_func(&UE->rfdevice);
|
||||
AssertFatal(tmp2 == 0, "Could not start the device\n");
|
||||
if (usrp_tx_thread == 1)
|
||||
UE->rfdevice.trx_write_init(&UE->rfdevice);
|
||||
|
||||
notifiedFIFO_t nf;
|
||||
initNotifiedFIFO(&nf);
|
||||
@@ -807,8 +842,7 @@ void *UE_thread(void *arg)
|
||||
int absolute_slot = 0, decoded_frame_rx = MAX_FRAME_NUMBER - 1, trashed_frames = 0;
|
||||
int tx_wait_for_dlsch[NR_MAX_SLOTS_PER_FRAME];
|
||||
|
||||
int num_ind_fifo = nb_slot_frame;
|
||||
for(int i = 0; i < num_ind_fifo; i++) {
|
||||
for(int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) {
|
||||
dynamic_barrier_init(&UE->process_slot_tx_barriers[i]);
|
||||
}
|
||||
int shiftForNextFrame = 0;
|
||||
@@ -819,13 +853,21 @@ void *UE_thread(void *arg)
|
||||
if (get_softmodem_params()->sync_ref && UE->sl_mode == 2) {
|
||||
UE->is_synchronized = 1;
|
||||
} else {
|
||||
//warm up the RF board
|
||||
//warm up the RF board
|
||||
int64_t tmp;
|
||||
for (int i = 0; i < 50; i++)
|
||||
readFrame(UE, &tmp, true);
|
||||
}
|
||||
|
||||
double ntn_ta_common = 0;
|
||||
int ntn_koffset = 0;
|
||||
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int nr_slot_tx_offset = 0;
|
||||
bool update_ntn_system_information = false;
|
||||
|
||||
while (!oai_exit) {
|
||||
nr_slot_tx_offset = 0;
|
||||
if (syncRunning) {
|
||||
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf);
|
||||
|
||||
@@ -851,8 +893,11 @@ void *UE_thread(void *arg)
|
||||
stream_status = STREAM_STATUS_UNSYNC;
|
||||
} else {
|
||||
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
|
||||
// For IQ recorder-player we force synchronization to happen in 280 ms
|
||||
while (trashed_frames != 28) {
|
||||
/* For IQ recorder-player we force synchronization to happen in a fixed duration so that
|
||||
the replay runs in sync with recorded samples.
|
||||
*/
|
||||
const unsigned int sync_in_frames = UE->rfdevice.openair0_cfg->recplay_conf->u_f_sync;
|
||||
while (trashed_frames != sync_in_frames) {
|
||||
readFrame(UE, &sync_timestamp, true);
|
||||
trashed_frames += 2;
|
||||
}
|
||||
@@ -896,7 +941,7 @@ void *UE_thread(void *arg)
|
||||
openair0_write_reorder_clear_context(&UE->rfdevice);
|
||||
if (get_nrUE_params()->time_sync_I)
|
||||
// ntn_ta_commondrift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
|
||||
UE->max_pos_acc = get_nrUE_params()->ntn_ta_commondrift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I;
|
||||
UE->max_pos_acc = mac->ntn_ta.ntn_ta_commondrift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I;
|
||||
else
|
||||
UE->max_pos_acc = 0;
|
||||
shiftForNextFrame = -(UE->init_sync_frame + trashed_frames + 2) * UE->max_pos_acc * get_nrUE_params()->time_sync_I; // compensate for the time drift that happened during initial sync
|
||||
@@ -923,24 +968,44 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
// We have resynchronized, maybe after RF loss so we need to purge any existing context
|
||||
memset(tx_wait_for_dlsch, 0, sizeof(tx_wait_for_dlsch));
|
||||
for (int i = 0; i < num_ind_fifo; i++) {
|
||||
for (int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) {
|
||||
dynamic_barrier_reset(&UE->process_slot_tx_barriers[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if MAC has sent sync request */
|
||||
if (handle_sync_req_from_mac(UE) == 0)
|
||||
continue;
|
||||
|
||||
// start of normal case, the UE is in sync
|
||||
absolute_slot++;
|
||||
TracyCFrameMark;
|
||||
|
||||
if (update_ntn_system_information) {
|
||||
update_ntn_system_information = false;
|
||||
int ta_offset = UE->frame_parms.samples_per_subframe * (UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms - ntn_ta_common);
|
||||
|
||||
UE->timing_advance += ta_offset;
|
||||
ntn_ta_common = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
ntn_koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
timing_advance = ntn_koffset * (UE->frame_parms.samples_per_subframe >> mac->current_UL_BWP->scs);
|
||||
}
|
||||
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
update_ntn_system_information = true;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
}
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
nr_rxtx_thread_data_t curMsg = {0};
|
||||
curMsg.UE=UE;
|
||||
// update thread index for received subframe
|
||||
curMsg.proc.nr_slot_rx = slot_nr;
|
||||
curMsg.proc.nr_slot_tx = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame;
|
||||
curMsg.proc.nr_slot_tx = (absolute_slot + duration_rx_to_tx) % nb_slot_frame;
|
||||
curMsg.proc.frame_rx = (absolute_slot / nb_slot_frame) % MAX_FRAME_NUMBER;
|
||||
curMsg.proc.frame_tx = ((absolute_slot + DURATION_RX_TO_TX) / nb_slot_frame) % MAX_FRAME_NUMBER;
|
||||
curMsg.proc.frame_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) % MAX_FRAME_NUMBER;
|
||||
if (UE->received_config_request) {
|
||||
if (UE->sl_mode) {
|
||||
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD);
|
||||
@@ -993,11 +1058,11 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
|
||||
// use previous timing_advance value to compute writeTimestamp
|
||||
const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, DURATION_RX_TO_TX)
|
||||
const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx)
|
||||
- firstSymSamp - UE->N_TA_offset - timing_advance;
|
||||
|
||||
// but use current UE->timing_advance value to compute writeBlockSize
|
||||
int writeBlockSize = fp->get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, fp) - iq_shift_to_apply;
|
||||
int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
|
||||
if (UE->timing_advance != timing_advance) {
|
||||
writeBlockSize -= UE->timing_advance - timing_advance;
|
||||
timing_advance = UE->timing_advance;
|
||||
@@ -1023,15 +1088,22 @@ void *UE_thread(void *arg)
|
||||
curMsgTx->proc.timestamp_tx = writeTimestamp;
|
||||
curMsgTx->UE = UE;
|
||||
curMsgTx->stream_status = stream_status;
|
||||
curMsgTx->proc.nr_slot_tx_offset = nr_slot_tx_offset;
|
||||
|
||||
int sync_to_previous_thread = stream_status == STREAM_STATUS_SYNCED ? 1 : 0;
|
||||
int slot = curMsgTx->proc.nr_slot_tx;
|
||||
dynamic_barrier_update(&UE->process_slot_tx_barriers[slot],
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame;
|
||||
|
||||
dynamic_barrier_update(&UE->process_slot_tx_barriers[slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS],
|
||||
tx_wait_for_dlsch[slot] + sync_to_previous_thread,
|
||||
start_process_slot_tx,
|
||||
curMsgTx);
|
||||
stream_status = STREAM_STATUS_SYNCED;
|
||||
tx_wait_for_dlsch[slot] = 0;
|
||||
// apply new duration next run to avoid thread dead lock
|
||||
if (update_ntn_system_information) {
|
||||
duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -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"
|
||||
@@ -129,9 +130,6 @@ int otg_enabled;
|
||||
double cpuf;
|
||||
uint32_t N_RB_DL = 106;
|
||||
|
||||
// NTN cellSpecificKoffset-r17, but in slots for DL SCS
|
||||
unsigned int NTN_UE_Koffset = 0;
|
||||
|
||||
int create_tasks_nrue(uint32_t ue_nb) {
|
||||
LOG_D(NR_RRC, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb);
|
||||
itti_wait_ready(1);
|
||||
@@ -219,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;
|
||||
@@ -388,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)
|
||||
{
|
||||
@@ -427,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");
|
||||
@@ -445,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,9 +516,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// NTN cellSpecificKoffset-r17, but in slots for DL SCS
|
||||
NTN_UE_Koffset = nrUE_params.ntn_koffset << PHY_vars_UE_g[0][0]->frame_parms.numerology_index;
|
||||
|
||||
init_openair0();
|
||||
lock_memory_to_ram();
|
||||
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
#define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n"
|
||||
#define CONFIG_HLP_TIME_SYNC_P "coefficient for Proportional part of time sync PI controller\n"
|
||||
#define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n"
|
||||
#define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n"
|
||||
#define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n"
|
||||
#define CONFIG_HLP_NTN_TA_COMMONDRIFT "NTN ta-CommonDrift, but given in µs/s\n"
|
||||
#define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n"
|
||||
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
|
||||
|
||||
@@ -42,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}, \
|
||||
@@ -67,9 +63,6 @@
|
||||
{"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \
|
||||
{"time-sync-P", CONFIG_HLP_TIME_SYNC_P, 0, .dblptr=&(nrUE_params.time_sync_P), .defdblval=0.5, TYPE_DOUBLE, 0}, \
|
||||
{"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \
|
||||
{"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"ntn-ta-commondrift", CONFIG_HLP_NTN_TA_COMMONDRIFT, 0, .dblptr=&(nrUE_params.ntn_ta_commondrift), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \
|
||||
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
|
||||
}
|
||||
@@ -91,12 +84,8 @@ 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;
|
||||
unsigned int ntn_koffset;
|
||||
double ntn_ta_common;
|
||||
double ntn_ta_commondrift;
|
||||
int autonomous_ta;
|
||||
int agc;
|
||||
char *usrp_args;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "position_interface.h"
|
||||
|
||||
extern uint16_t NB_UE_INST;
|
||||
|
||||
static void read_position_coordinates(char *sectionName, position_t *position)
|
||||
{
|
||||
paramdef_t position_params[] = POSITION_CONFIG_PARAMS_DEF;
|
||||
int ret = config_get(config_get_if(), position_params, sizeofArray(position_params), sectionName);
|
||||
AssertFatal(ret >= 0, "configuration couldn't be performed for position name: %s", sectionName);
|
||||
}
|
||||
|
||||
void get_position_coordinates(int Mod_id, position_t *position)
|
||||
{
|
||||
AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST);
|
||||
char positionName[64];
|
||||
snprintf(positionName, sizeof(positionName), "position%d", Mod_id);
|
||||
read_position_coordinates(positionName, position);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __POSITION_INTERFACE__H__
|
||||
#define __POSITION_INTERFACE__H__
|
||||
|
||||
#include <executables/nr-softmodem-common.h>
|
||||
#include <executables/softmodem-common.h>
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "executables/nr-uesoftmodem.h"
|
||||
|
||||
/* position configuration parameters name */
|
||||
#define CONFIG_STRING_POSITION_X "x"
|
||||
#define CONFIG_STRING_POSITION_Y "y"
|
||||
#define CONFIG_STRING_POSITION_Z "z"
|
||||
|
||||
#define HELP_STRING_POSITION "Postion coordinates (x, y, z) config params"
|
||||
|
||||
// Position parameters config
|
||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* position configuration parameters */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
// clang-format off
|
||||
#define POSITION_CONFIG_PARAMS_DEF { \
|
||||
{CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->positionX), .defuintval=0, TYPE_DOUBLE, 0}, \
|
||||
{CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->positionY), .defuintval=0, TYPE_DOUBLE, 0}, \
|
||||
{CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->positionZ), .defuintval=0, TYPE_DOUBLE, 0} \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
typedef struct position {
|
||||
double positionX;
|
||||
double positionY;
|
||||
double positionZ;
|
||||
} position_t;
|
||||
|
||||
void get_position_coordinates(int Mod_id, position_t *position);
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
#define FAPI_NR_DL_CONFIG_TYPE_CSI_RS 0x06
|
||||
#define FAPI_NR_DL_CONFIG_TYPE_CSI_IM 0x07
|
||||
#define FAPI_NR_CONFIG_TA_COMMAND 0x08
|
||||
#define FAPI_NR_DL_CONFIG_TYPES 0x08
|
||||
#define FAPI_NR_DL_NTN_CONFIG_PARAMS 0x09
|
||||
#define FAPI_NR_DL_CONFIG_TYPES 0x09
|
||||
|
||||
|
||||
#define FAPI_NR_CCE_REG_MAPPING_TYPE_INTERLEAVED 0x01
|
||||
#define FAPI_NR_CCE_REG_MAPPING_TYPE_NON_INTERLEAVED 0x02
|
||||
|
||||
@@ -555,6 +555,19 @@ typedef struct {
|
||||
bool is_rar;
|
||||
} fapi_nr_ta_command_pdu;
|
||||
|
||||
typedef struct {
|
||||
// N_common_ta_adj represents common propagation delay received in SIB19 (ms)
|
||||
double N_common_ta_adj;
|
||||
// N_UE_TA_adj calculated propagation delay from UE and SAT (ms)
|
||||
double N_UE_TA_adj;
|
||||
// drift rate of common ta in µs/s
|
||||
double ntn_ta_commondrift;
|
||||
// cell scheduling offset expressed in terms of 15kHz SCS
|
||||
long cell_specific_k_offset;
|
||||
|
||||
double ntn_total_time_advance_ms;
|
||||
} fapi_nr_dl_ntn_config_command_pdu;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pdu_type;
|
||||
union {
|
||||
@@ -563,6 +576,7 @@ typedef struct {
|
||||
fapi_nr_dl_config_csirs_pdu csirs_config_pdu;
|
||||
fapi_nr_dl_config_csiim_pdu csiim_config_pdu;
|
||||
fapi_nr_ta_command_pdu ta_command_pdu;
|
||||
fapi_nr_dl_ntn_config_command_pdu ntn_config_command_pdu;
|
||||
};
|
||||
} fapi_nr_dl_config_request_pdu_t;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(nr_phy_common)
|
||||
add_subdirectory(TOOLS)
|
||||
add_subdirectory(NR_TRANSPORT)
|
||||
add_subdirectory(CODING)
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
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)
|
||||
@@ -1,21 +1,134 @@
|
||||
# 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.
|
||||
|
||||
### 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 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
|
||||
```
|
||||
|
||||
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 _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.so`:
|
||||
loading `libldpc_optim8seg.so` instead of `libldpc_optim8segmulti.so`:
|
||||
|
||||
```
|
||||
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg
|
||||
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _optim8seg
|
||||
.......................
|
||||
[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] loader.ldpc 1 options set from command line
|
||||
[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;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
add_subdirectory(nrLDPC_coding_segment)
|
||||
add_subdirectory(nrLDPC_coding_xdma)
|
||||
add_subdirectory(nrLDPC_coding_t2)
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
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()
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
##########################################################
|
||||
|
||||
# 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()
|
||||
+356
-292
@@ -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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
##########################################################
|
||||
|
||||
# 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()
|
||||
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -0,0 +1,783 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
@@ -180,4 +180,8 @@ void nr_phy_free_RU(RU_t *ru)
|
||||
free_and_zero(ru->common.beam_id[i]);
|
||||
free_and_zero(ru->common.beam_id);
|
||||
}
|
||||
|
||||
PHY_VARS_gNB *gNB0 = ru->gNB_list[0];
|
||||
gNB0->num_RU--;
|
||||
DevAssert(gNB0->num_RU >= 0);
|
||||
}
|
||||
|
||||
@@ -338,6 +338,8 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
free_and_zero(ue->prs_vars[idx]);
|
||||
}
|
||||
|
||||
free_and_zero(ue->ntn_config_message);
|
||||
|
||||
sl_ue_free(ue);
|
||||
}
|
||||
|
||||
@@ -356,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);
|
||||
}
|
||||
@@ -406,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);
|
||||
|
||||
@@ -177,10 +177,9 @@ c16_t *gNB_dmrs_lowpaprtype1_sequence[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MA
|
||||
void generate_lowpapr_typ1_refsig_sequences(unsigned int scaling)
|
||||
{
|
||||
/* prevent multiple calls, relevant when both UE & gNB initialize this */
|
||||
static bool already_called = false;
|
||||
bool already_called = gNB_dmrs_lowpaprtype1_sequence[0][0][0] != NULL;
|
||||
if (already_called)
|
||||
return;
|
||||
already_called = true;
|
||||
unsigned int v = 0; // sequence hopping and group hopping are not supported yet
|
||||
|
||||
for (unsigned int Msc_RS = 0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) {
|
||||
@@ -200,9 +199,8 @@ c16_t *dmrs_lowpaprtype1_ul_ref_sig[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MAX_
|
||||
void generate_ul_reference_signal_sequences(unsigned int scaling)
|
||||
{
|
||||
/* prevent multiple calls, relevant when both UE & gNB initialize this */
|
||||
static bool already_called = false;
|
||||
bool already_called = rv_ul_ref_sig[0][0][0] != NULL;
|
||||
if (already_called) return;
|
||||
already_called = true;
|
||||
|
||||
unsigned int u,v,Msc_RS;
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
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];
|
||||
}
|
||||
int num_segments = 0;
|
||||
|
||||
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
|
||||
}
|
||||
for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
|
||||
|
||||
impp.BG = rel15->maintenance_parms_v3.ldpcBaseGraph;
|
||||
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
|
||||
|
||||
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);
|
||||
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
NR_gNB_PHY_STATS_t *phy_stats = NULL;
|
||||
if (rel15->rnti != 0xFFFF)
|
||||
phy_stats = get_phy_stats(gNB, rel15->rnti);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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];
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
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));
|
||||
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);
|
||||
|
||||
encoder_implemparams_t arr[n_seg];
|
||||
task_ans_t ans[n_seg];
|
||||
memset(ans, 0, n_seg * sizeof(task_ans_t));
|
||||
TB_parameters->tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
|
||||
|
||||
for (int j = 0; j < n_seg; j++) {
|
||||
encoder_implemparams_t *perJobImpp = &arr[j];
|
||||
*perJobImpp = impp;
|
||||
perJobImpp->macro_num = j;
|
||||
perJobImpp->ans = &ans[j];
|
||||
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);
|
||||
|
||||
task_t t = {.func = ldpc8blocks, .args = perJobImpp};
|
||||
pushTpool(&gNB->threadPool, t);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (rdata->decodeIterations <= p_decoderParms->numMaxIter)
|
||||
memcpy(ulsch_harq->c[r],llrProcBuf, Kr>>3);
|
||||
|
||||
// Task completed
|
||||
completed_task_ans(rdata->ans);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (decodeIterations < 0) {
|
||||
LOG_E(PHY, "ulsch_decoding.c: Problem in LDPC decoder offload\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
uint32_t *G,
|
||||
uint8_t *ULSCH_ids,
|
||||
int nb_pusch)
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
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
|
||||
};
|
||||
|
||||
if (!harq_process) {
|
||||
LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n");
|
||||
return -1;
|
||||
}
|
||||
int max_num_segments = 0;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
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;
|
||||
// ------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
harq_process->TBS = pusch_pdu->pusch_data.tb_size;
|
||||
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id];
|
||||
|
||||
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]);
|
||||
TB_parameters->G = G[pusch_id];
|
||||
|
||||
if (!harq_process) {
|
||||
LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n");
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
uint8_t harq_pid = ulsch->harq_pid;
|
||||
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,
|
||||
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", 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);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
nrLDPC_segment_decoding_parameters_t segments[nb_pusch][max_num_segments];
|
||||
memset(segments, 0, sizeof(segments));
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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;
|
||||
if (!ulsch_llr) {
|
||||
LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
task_t t = {.func = &nr_processULSegment, .args = rdata};
|
||||
pushTpool(&phy_vars_gNB->threadPool, t);
|
||||
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) {
|
||||
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, "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;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return ret_decoder;
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ static void nr_ulsch_det_HhH (int32_t *after_mf_00,//a
|
||||
int32_t *after_mf_01,//b
|
||||
int32_t *after_mf_10,//c
|
||||
int32_t *after_mf_11,//d
|
||||
int32_t *det_fin,//1/ad-bc
|
||||
uint32_t *det_fin,//1/ad-bc
|
||||
unsigned short nb_rb,
|
||||
unsigned char symbol,
|
||||
int32_t shift)
|
||||
@@ -493,11 +493,12 @@ static simde__m128i nr_ulsch_comp_muli_sum(simde__m128i input_x,
|
||||
//print_ints("rx_re:",(int32_t*)&xy_re_128[0]);
|
||||
//print_ints("rx_Img:",(int32_t*)&xy_im_128[0]);
|
||||
//divide by matrix det and convert back to Q15 before packing
|
||||
int sum_det =0;
|
||||
for (int k=0; k<4;k++) {
|
||||
sum_det += ((((int *)&det)[k])>>2);
|
||||
//printf("det_%d = %d log2 =%d \n",k,(((int *)&det[0])[k]),log2_approx(((int *)&det[0])[k]));
|
||||
}
|
||||
uint64_t sum_det = 0;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
sum_det += (((uint32_t *)&det)[k]);
|
||||
}
|
||||
// Add bias to reduce rounding error
|
||||
sum_det = (sum_det + 2) >> 2;
|
||||
|
||||
int b = log2_approx(sum_det) - 8;
|
||||
if (b > 0) {
|
||||
@@ -680,7 +681,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t af_mf_01[12*nb_rb] __attribute__((aligned(32)));
|
||||
int32_t af_mf_10[12*nb_rb] __attribute__((aligned(32)));
|
||||
int32_t af_mf_11[12*nb_rb] __attribute__((aligned(32)));
|
||||
int32_t determ_fin[12*nb_rb] __attribute__((aligned(32)));
|
||||
uint32_t determ_fin[12*nb_rb] __attribute__((aligned(32)));
|
||||
|
||||
switch (n_rx) {
|
||||
case 2://
|
||||
@@ -945,12 +946,12 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms,
|
||||
|
||||
// Magnitude computation
|
||||
if (mod_order > 2) {
|
||||
|
||||
int sum_det = 0;
|
||||
uint64_t sum_det = 0;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
AssertFatal(((int *)&determ_fin_128[0])[k] > 0 ,"Right shifting negative values is UB" );
|
||||
sum_det += ((((uint32_t *)&determ_fin_128[0])[k]) >> 2);
|
||||
sum_det += (((uint32_t *)&determ_fin_128[0])[k]);
|
||||
}
|
||||
// Add bias to reduce rounding error
|
||||
sum_det = (sum_det + 2) >> 2;
|
||||
|
||||
int b = log2_approx(sum_det) - 8;
|
||||
if (b > 0) {
|
||||
|
||||
@@ -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;
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
int max_num_segments = 0;
|
||||
|
||||
bool decodeSuccess = (rdata->decodeIterations < (1+dlsch->max_ldpc_iterations));
|
||||
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];
|
||||
|
||||
if (decodeSuccess) {
|
||||
memcpy(b+rdata->offset,
|
||||
harq_process->c[r],
|
||||
rdata->Kr_bytes - (harq_process->F>>3) -((harq_process->C>1)?3:0));
|
||||
AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type);
|
||||
uint8_t nb_re_dmrs;
|
||||
|
||||
(*num_seg_ok)++;
|
||||
} else {
|
||||
LOG_D(PHY, "DLSCH %d in error\n", rdata->dlsch_id);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT);
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD))
|
||||
LOG_I(PHY, "Segmentation: C %d, K %d\n", harq_process->C, harq_process->K);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!last)
|
||||
return false; // continue decoding
|
||||
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));
|
||||
|
||||
// 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;
|
||||
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];
|
||||
|
||||
harq_process->decodeResult = *num_seg_ok == harq_process->C;
|
||||
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id];
|
||||
TB_parameters->segments = segments[pdsch_id];
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
int ret_decoder = phy_vars_ue->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
|
||||
|
||||
if (ret_decoder != 0) {
|
||||
return dlsch->max_ldpc_iterations + 1;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
kpiStructure.nb_total++;
|
||||
kpiStructure.blockSize = dlsch_config->TBS;
|
||||
kpiStructure.dl_mcs = dlsch_config->mcs;
|
||||
kpiStructure.nofRBs = dlsch_config->number_rbs;
|
||||
|
||||
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,
|
||||
"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");
|
||||
" 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 (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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
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_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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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 (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));
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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 (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+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);
|
||||
|
||||
/////////////////////////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};
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
///////////////////////// 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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT);
|
||||
max_num_segments = max(max_num_segments, TB_parameters->C);
|
||||
|
||||
#ifdef DEBUG_ULSCH_CODING
|
||||
uint16_t Kr_bytes;
|
||||
Kr_bytes = impp.Kr >> 3;
|
||||
#endif
|
||||
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
|
||||
|
||||
///////////////////////// 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
|
||||
}
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
|
||||
}
|
||||
nrLDPC_segment_encoding_parameters_t segments[nb_ulsch][max_num_segments];
|
||||
memset(segments, 0, sizeof(segments));
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
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];
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
///////////////////////// 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);
|
||||
reset_meas(&segment_parameters->ts_interleave);
|
||||
reset_meas(&segment_parameters->ts_rate_match);
|
||||
reset_meas(&segment_parameters->ts_ldpc_encode);
|
||||
|
||||
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;
|
||||
} // TB_parameters->C
|
||||
} // pusch_id
|
||||
|
||||
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);
|
||||
///////////////////////// | LDCP coding | ////////////////////////////////////
|
||||
|
||||
#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
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
|
||||
|
||||
///////////////////////// 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;
|
||||
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_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
|
||||
|
||||
@@ -85,10 +85,20 @@
|
||||
#define UNUSED(x) (void)x;
|
||||
#define NUM_DL_ACTORS 4
|
||||
|
||||
// Set the number of barriers for processSlotTX to 512. This value has to be at least 483 for NTN where
|
||||
// DL-to-UL offset is up to 483. The selected value is also half of the frame range so that
|
||||
// (slot + frame * slots_per_frame) % NUM_PROCESS_SLOT_TX_BARRIERS is contiguous between the last slot of
|
||||
// frame 1023 and first slot of frame 0
|
||||
// e.g. in numerology 1:
|
||||
// (19 + 1023 * 20) % 512 = 511
|
||||
// (0 + 0 * 20) % 512 = 0
|
||||
#define NUM_PROCESS_SLOT_TX_BARRIERS 512
|
||||
|
||||
#include "impl_defs_top.h"
|
||||
#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"
|
||||
@@ -322,6 +332,11 @@ typedef struct UE_NR_SCAN_INFO_s {
|
||||
int32_t freq_offset_Hz[3][10];
|
||||
} UE_NR_SCAN_INFO_t;
|
||||
|
||||
typedef struct {
|
||||
bool update;
|
||||
fapi_nr_dl_ntn_config_command_pdu ntn_config_params;
|
||||
} ntn_config_message_t;
|
||||
|
||||
/// Top-level PHY Data Structure for UE
|
||||
typedef struct PHY_VARS_NR_UE_s {
|
||||
/// \brief Module ID indicator for this instance
|
||||
@@ -394,7 +409,6 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
uint8_t prs_active_gNBs;
|
||||
NR_DL_UE_HARQ_t dl_harq_processes[2][NR_MAX_DLSCH_HARQ_PROCESSES];
|
||||
NR_UL_UE_HARQ_t ul_harq_processes[NR_MAX_ULSCH_HARQ_PROCESSES];
|
||||
|
||||
//Paging parameters
|
||||
uint32_t IMSImod1024;
|
||||
uint32_t PF;
|
||||
@@ -481,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;
|
||||
|
||||
@@ -523,7 +538,7 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
void *phy_sim_pdsch_dl_ch_estimates_ext;
|
||||
uint8_t *phy_sim_dlsch_b;
|
||||
|
||||
dynamic_barrier_t process_slot_tx_barriers[NR_MAX_SLOTS_PER_FRAME];
|
||||
dynamic_barrier_t process_slot_tx_barriers[NUM_PROCESS_SLOT_TX_BARRIERS];
|
||||
|
||||
// Gain change required for automation RX gain change
|
||||
int adjust_rxgain;
|
||||
@@ -533,6 +548,9 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS;
|
||||
Actor_t sync_actor;
|
||||
Actor_t dl_actors[NUM_DL_ACTORS];
|
||||
|
||||
ntn_config_message_t* ntn_config_message;
|
||||
|
||||
} PHY_VARS_NR_UE;
|
||||
|
||||
typedef struct {
|
||||
@@ -540,6 +558,10 @@ typedef struct {
|
||||
int gNB_id;
|
||||
/// NR slot index within frame_tx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_tx;
|
||||
/// NR slot index tx offset to resume
|
||||
/// in case of NTN, tx_offset can be changed dynamically via SIB19
|
||||
/// we need to notify the right tx thread slot based on TX offset change
|
||||
int nr_slot_tx_offset;
|
||||
int rx_slot_type;
|
||||
/// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_rx;
|
||||
|
||||
@@ -276,20 +276,6 @@
|
||||
/* - between reception of un uplink grant and its related transmission (k2) */
|
||||
#define NR_UE_CAPABILITY_SLOT_RX_TO_TX (3)
|
||||
|
||||
/* When the OAI UE receives RX slot N, it starts sending TX slot N+DURATION_RX_TO_TX.
|
||||
* Therefore DURATION_RX_TO_TX must not be larger than the minimum k1 and k2 values (NR_UE_CAPABILITY_SLOT_RX_TO_TX).
|
||||
* In case of NTN, the propagation delay is so large, that the TX slot needs to be transmitted far in advance.
|
||||
* Therefore, the NTN_UE_Koffset is added to DURATION_RX_TO_TX.
|
||||
*
|
||||
* Note: currently, the UE requires this to be a constant.
|
||||
* But in case of NTN, Koffset is only known after receiving SIB19.
|
||||
* Therefore, support should be added to allow changing DURATION_RX_TO_TX on reception of SIB19 (via FAPI-like interface).
|
||||
* E.g. no transmission before successful reception of SIB19, and re-sync with disabled transmission if Koffset changes.
|
||||
* When this has been implemented, the global variable NTN_UE_Koffset should be removed, too.
|
||||
*/
|
||||
extern unsigned int NTN_UE_Koffset;
|
||||
#define DURATION_RX_TO_TX (NR_UE_CAPABILITY_SLOT_RX_TO_TX + NTN_UE_Koffset)
|
||||
|
||||
#define NR_MAX_ULSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 6.1 UE procedure for receiving the physical uplink shared channel */
|
||||
#define NR_MAX_DLSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 5.1 UE procedure for receiving the physical downlink shared channel */
|
||||
#endif
|
||||
@@ -317,6 +303,6 @@ typedef struct {
|
||||
#include "common/openairinterface5g_limits.h"
|
||||
#include "assertions.h"
|
||||
|
||||
#endif //__PHY_IMPLEMENTATION_DEFS_H__
|
||||
/**@}
|
||||
#endif //__PHY_IMPLEMENTATION_DEFS_H__
|
||||
/**@}
|
||||
*/
|
||||
|
||||
@@ -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));
|
||||
|
||||
} else {
|
||||
LOG_D(PHY, "ULSCH %d in error\n", rdata->ulsch_id);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
//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));
|
||||
if (nb_pusch == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 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) && !gNB->pusch_vars[rdata->ulsch_id].DTX) {
|
||||
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);
|
||||
}
|
||||
|
||||
return ret_nr_ulsch_decoding;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -326,6 +326,19 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0,
|
||||
}
|
||||
}
|
||||
|
||||
static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_command_pdu* ntn_params_message)
|
||||
{
|
||||
if (!ue->ntn_config_message) {
|
||||
ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message));
|
||||
}
|
||||
|
||||
ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset;
|
||||
ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj;
|
||||
ue->ntn_config_message->ntn_config_params.ntn_ta_commondrift = ntn_params_message->ntn_ta_commondrift;
|
||||
ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms;
|
||||
ue->ntn_config_message->update = true;
|
||||
}
|
||||
|
||||
static void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_command_pdu)
|
||||
{
|
||||
/* Time Alignment procedure
|
||||
@@ -451,6 +464,9 @@ static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac,
|
||||
case FAPI_NR_CONFIG_TA_COMMAND:
|
||||
configure_ta_command(phy, &pdu->ta_command_pdu);
|
||||
break;
|
||||
case FAPI_NR_DL_NTN_CONFIG_PARAMS:
|
||||
configure_ntn_params(phy, &pdu->ntn_config_command_pdu);
|
||||
break;
|
||||
default:
|
||||
LOG_W(PHY, "unhandled dl pdu type %d \n", pdu->pdu_type);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ int slot_select_nr(NR_DL_FRAME_PARMS *frame_parms, int nr_frame, int nr_slot);
|
||||
* @param nr_slot : slot number
|
||||
@returns int : downlink, uplink or mixed slot type */
|
||||
|
||||
int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot);
|
||||
int nr_ue_slot_select(const fapi_nr_config_request_t *cfg, int nr_slot);
|
||||
|
||||
/** \brief This function frees tdd configuration for nr
|
||||
* @param frame_parms NR DL Frame parameters
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot)
|
||||
int nr_ue_slot_select(const fapi_nr_config_request_t *cfg, int nr_slot)
|
||||
{
|
||||
if (cfg->cell_config.frame_duplex_type == FDD)
|
||||
return NR_UPLINK_SLOT | NR_DOWNLINK_SLOT;
|
||||
@@ -47,7 +47,7 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot)
|
||||
int period = cfg->tdd_table_1.tdd_period_in_slots +
|
||||
(cfg->tdd_table_2 ? cfg->tdd_table_2->tdd_period_in_slots : 0);
|
||||
int rel_slot = nr_slot % period;
|
||||
fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table_1;
|
||||
const fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table_1;
|
||||
if (cfg->tdd_table_2 && rel_slot >= tdd_table->tdd_period_in_slots) {
|
||||
rel_slot -= tdd_table->tdd_period_in_slots;
|
||||
tdd_table = cfg->tdd_table_2;
|
||||
@@ -56,7 +56,7 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot)
|
||||
if (tdd_table->max_tdd_periodicity_list == NULL) // this happens before receiving TDD configuration
|
||||
return NR_DOWNLINK_SLOT;
|
||||
|
||||
fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot];
|
||||
const fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot];
|
||||
|
||||
// if the 1st symbol is UL the whole slot is UL
|
||||
if (current_slot->max_num_of_symbol_per_slot_list[0].slot_config == 1)
|
||||
@@ -109,7 +109,7 @@ uint8_t sl_determine_if_sidelink_slot(uint8_t sl_startsym, uint8_t sl_lensym, ui
|
||||
* Mixed Slot is a sidelink slot if the uplink symbols in Mixed slot
|
||||
* overlaps with Sidelink start symbol and number of symbols.
|
||||
*/
|
||||
int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int slot, uint8_t frame_duplex_type)
|
||||
int sl_nr_ue_slot_select(const sl_nr_phy_config_request_t *cfg, int slot, uint8_t frame_duplex_type)
|
||||
{
|
||||
int ul_sym = 0, slot_type = 0;
|
||||
|
||||
@@ -122,9 +122,9 @@ int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int slot, uint8_t fram
|
||||
|
||||
int period = cfg->tdd_table.tdd_period_in_slots;
|
||||
int rel_slot = slot % period;
|
||||
fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table;
|
||||
const fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table;
|
||||
|
||||
fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot];
|
||||
const fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot];
|
||||
|
||||
for (int symbol_count = 0; symbol_count < NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) {
|
||||
if (current_slot->max_num_of_symbol_per_slot_list[symbol_count].slot_config == 1) {
|
||||
|
||||
@@ -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,67 +704,69 @@ 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) {
|
||||
// don't wait anymore
|
||||
LOG_E(NR_PHY, "Internal error nr_ue_dlsch_procedure() called but no active cw on slot %d, harq %d\n", nr_slot_rx, harq_pid);
|
||||
const int ack_nack_slot = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) % ue->frame_parms.slots_per_frame;
|
||||
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]);
|
||||
const int ack_nack_slot_and_frame =
|
||||
(proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
||||
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
|
||||
|
||||
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;
|
||||
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;
|
||||
@@ -790,87 +785,44 @@ 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);
|
||||
}
|
||||
|
||||
// DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH
|
||||
if (dlsch[0].rnti_type == TYPE_C_RNTI_) {
|
||||
const int ack_nack_slot = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) % ue->frame_parms.slots_per_frame;
|
||||
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]);
|
||||
const int ack_nack_slot_and_frame =
|
||||
(proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
||||
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;
|
||||
}
|
||||
@@ -1144,12 +1096,14 @@ 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");
|
||||
int ack_nack_slot = (proc->nr_slot_rx + dlsch_config->k1_feedback) % ue->frame_parms.slots_per_frame;
|
||||
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]);
|
||||
const int ack_nack_slot_and_frame =
|
||||
proc->nr_slot_rx + dlsch_config->k1_feedback + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
||||
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
||||
LOG_W(NR_PHY, "nr_ue_pdsch_procedures failed in slot %d\n", proc->nr_slot_rx);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -467,6 +467,7 @@ int main(int argc, char **argv){
|
||||
ru->nb_rx = n_rx;
|
||||
ru->num_gNB = 1;
|
||||
ru->gNB_list[0] = gNB;
|
||||
gNB->num_RU = 1;
|
||||
gNB->gNB_config.carrier_config.num_tx_ant.value = 1;
|
||||
gNB->gNB_config.carrier_config.num_rx_ant.value = 1;
|
||||
if (mu == 0)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
|
||||
MESSAGE_DEF(GTPV1U_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_tunnel_data_req_t, Gtpv1uTunnelDataReq)
|
||||
MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_req_t,Gtpv1uDataForwardingReq)
|
||||
MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_ind_t,Gtpv1uDataForwardingInd)
|
||||
MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq)
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#define NR_GTPV1U_MAX_BEARERS_PER_UE max_val_NR_DRB_Identity
|
||||
|
||||
#define GTPV1U_ENB_TUNNEL_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataInd
|
||||
#define GTPV1U_TUNNEL_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataReq
|
||||
#define GTPV1U_ENB_DATA_FORWARDING_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingReq
|
||||
#define GTPV1U_ENB_DATA_FORWARDING_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingInd
|
||||
#define GTPV1U_ENB_END_MARKER_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerReq
|
||||
@@ -107,15 +106,6 @@ typedef struct gtpv1u_enb_delete_tunnel_resp_s {
|
||||
teid_t enb_S1u_teid; ///< local S1U Tunnel Endpoint Identifier to be deleted
|
||||
} gtpv1u_enb_delete_tunnel_resp_t;
|
||||
|
||||
|
||||
typedef struct gtpv1u_tunnel_data_req_s {
|
||||
uint8_t *buffer;
|
||||
uint32_t length;
|
||||
uint32_t offset; ///< start of message offset in buffer
|
||||
ue_id_t ue_id;
|
||||
rb_id_t bearer_id;
|
||||
} gtpv1u_tunnel_data_req_t;
|
||||
|
||||
typedef struct gtpv1u_enb_data_forwarding_req_s {
|
||||
uint8_t *buffer;
|
||||
uint32_t length;
|
||||
|
||||
@@ -553,9 +553,12 @@ typedef struct ngap_initial_context_setup_resp_s {
|
||||
} ngap_initial_context_setup_resp_t;
|
||||
|
||||
typedef struct ngap_initial_context_setup_fail_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* TODO add cause */
|
||||
uint64_t amf_ue_ngap_id;
|
||||
|
||||
ngap_Cause_t cause;
|
||||
long cause_value;
|
||||
} ngap_initial_context_setup_fail_t, ngap_ue_ctxt_modification_fail_t, ngap_pdusession_setup_req_fail_t;
|
||||
|
||||
typedef struct ngap_nas_non_delivery_ind_s {
|
||||
|
||||
@@ -143,7 +143,6 @@ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t asso
|
||||
message_p->ittiMsgHeader.originInstance = assoc_id;
|
||||
f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it
|
||||
*req = msg; // copy F1 message to ITTI
|
||||
free_f1ap_du_configuration_update(&msg);
|
||||
LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n");
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p);
|
||||
return 0;
|
||||
|
||||
@@ -262,12 +262,9 @@ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance,
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return -1;
|
||||
}
|
||||
// Allocate and send an ITTI message
|
||||
MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
|
||||
f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p);
|
||||
// Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
*msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p);
|
||||
|
||||
gnb_du_configuration_update_acknowledge(&in);
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
#ifndef F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
#define F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
|
||||
#include "f1ap_common.h"
|
||||
#include <openair2/RRC/NR/MESSAGES/asn1_msg.h>
|
||||
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
|
||||
struct F1AP_F1AP_PDU;
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, struct F1AP_F1AP_PDU *pdu);
|
||||
|
||||
int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg);
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1
|
||||
OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac);
|
||||
}
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
// NR Cell Identity (M)
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid);
|
||||
// NR PCI (M)
|
||||
@@ -310,7 +310,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP
|
||||
"in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n");
|
||||
const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid);
|
||||
// NR PCI (O)
|
||||
if (cell->nRPCI != NULL)
|
||||
@@ -534,20 +534,56 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out
|
||||
return true;
|
||||
}
|
||||
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src)
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src)
|
||||
{
|
||||
// shallow copy
|
||||
*dest = *src;
|
||||
// tac
|
||||
f1ap_served_cell_info_t dst = {
|
||||
.plmn = src->plmn,
|
||||
.nr_cellid = src->nr_cellid,
|
||||
.nr_pci = src->nr_pci,
|
||||
.num_ssi = src->num_ssi,
|
||||
.mode = src->mode,
|
||||
};
|
||||
|
||||
for (int i = 0; i < src->num_ssi; ++i)
|
||||
dst.nssai[i] = src->nssai[i];
|
||||
|
||||
if (src->mode == F1AP_MODE_TDD)
|
||||
dst.tdd = src->tdd;
|
||||
else
|
||||
dst.fdd = src->fdd;
|
||||
|
||||
if (src->tac) {
|
||||
dest->tac = malloc_or_fail(sizeof(*dest->tac));
|
||||
*dest->tac = *src->tac;
|
||||
dst.tac = malloc_or_fail(sizeof(*dst.tac));
|
||||
*dst.tac = *src->tac;
|
||||
}
|
||||
// measurement timing config
|
||||
if (src->measurement_timing_config_len) {
|
||||
dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config));
|
||||
memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
|
||||
if (src->measurement_timing_config_len > 0) {
|
||||
dst.measurement_timing_config_len = src->measurement_timing_config_len;
|
||||
dst.measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dst.measurement_timing_config));
|
||||
memcpy(dst.measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static f1ap_gnb_du_system_info_t *copy_f1ap_gnb_du_system_info(const f1ap_gnb_du_system_info_t *src)
|
||||
{
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
f1ap_gnb_du_system_info_t *dst = calloc_or_fail(1, sizeof(*dst));
|
||||
if (src->mib_length > 0) {
|
||||
dst->mib_length = src->mib_length;
|
||||
dst->mib = calloc_or_fail(src->mib_length, sizeof(*src->mib));
|
||||
memcpy(dst->mib, src->mib, dst->mib_length);
|
||||
}
|
||||
|
||||
if (src->sib1_length > 0) {
|
||||
dst->sib1_length = src->sib1_length;
|
||||
dst->sib1 = calloc_or_fail(src->sib1_length, sizeof(*dst->sib1));
|
||||
memcpy(dst->sib1, src->sib1, dst->sib1_length);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,25 +603,9 @@ f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg)
|
||||
cp.num_cells_available = msg->num_cells_available;
|
||||
for (int n = 0; n < msg->num_cells_available; n++) {
|
||||
/* cell.info */
|
||||
f1ap_served_cell_info_t *sci = &cp.cell[n].info;
|
||||
const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info;
|
||||
copy_f1ap_served_cell_info(sci, msg_sci);
|
||||
cp.cell[n].info = copy_f1ap_served_cell_info(&msg->cell[n].info);
|
||||
/* cell.sys_info */
|
||||
if (msg->cell[n].sys_info) {
|
||||
f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info;
|
||||
f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info));
|
||||
cp.cell[n].sys_info = copy_sys_info;
|
||||
if (orig_sys_info->mib_length > 0) {
|
||||
copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib));
|
||||
copy_sys_info->mib_length = orig_sys_info->mib_length;
|
||||
memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length);
|
||||
}
|
||||
if (orig_sys_info->sib1_length > 0) {
|
||||
copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1));
|
||||
copy_sys_info->sib1_length = orig_sys_info->sib1_length;
|
||||
memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length);
|
||||
}
|
||||
}
|
||||
cp.cell[n].sys_info = copy_f1ap_gnb_du_system_info(msg->cell[n].sys_info);
|
||||
}
|
||||
for (int i = 0; i < sizeofArray(msg->rrc_ver); i++)
|
||||
cp.rrc_ver[i] = msg->rrc_ver[i];
|
||||
@@ -1002,7 +1022,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
/* mandatory */
|
||||
/* c2. Served_Cells_To_Add */
|
||||
if (msg->num_cells_to_add > 0) {
|
||||
AssertFatal(false, "code for adding cells not tested\n");
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2);
|
||||
ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List;
|
||||
ie2->criticality = F1AP_Criticality_reject;
|
||||
@@ -1060,7 +1079,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List;
|
||||
ie4->criticality = F1AP_Criticality_reject;
|
||||
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List;
|
||||
AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n");
|
||||
for (int i = 0; i < msg->num_cells_to_delete; i++) {
|
||||
asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list,
|
||||
F1AP_Served_Cells_To_Delete_ItemIEs_t,
|
||||
@@ -1114,8 +1132,8 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
} break;
|
||||
case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: {
|
||||
/* Served Cells To Add List */
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count;
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
for (int i = 0; i < out->num_cells_to_add; i++) {
|
||||
F1AP_Served_Cells_To_Add_Item_t *served_cells_item =
|
||||
&((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i])
|
||||
@@ -1142,7 +1160,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
/* Old NR CGI (M) */
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn;
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
/* Old NR CGI Cell ID */
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid);
|
||||
/* Served Cell Information (M) */
|
||||
@@ -1166,7 +1184,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn;
|
||||
/* Old NR CGI (M) */
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
// NR cellID
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid);
|
||||
}
|
||||
@@ -1216,10 +1234,8 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
for (int i = 0; i < a->num_cells_to_add; i++) {
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info))
|
||||
return false;
|
||||
if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
/* to delete */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete);
|
||||
@@ -1231,12 +1247,13 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
/* to modify */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify);
|
||||
for (int i = 0; i < a->num_cells_to_modify; i++) {
|
||||
if (!eq_f1ap_plmn(&a->cell_to_modify[i].old_plmn, &b->cell_to_modify[i].old_plmn))
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(a->cell_to_modify[i].old_nr_cellid, b->cell_to_modify[i].old_nr_cellid);
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info))
|
||||
return false;
|
||||
if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1256,6 +1273,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
cp.transaction_id = msg->transaction_id;
|
||||
/* to add */
|
||||
cp.num_cells_to_add = msg->num_cells_to_add;
|
||||
for (int i = 0; i < cp.num_cells_to_add; ++i) {
|
||||
cp.cell_to_add[i].info = copy_f1ap_served_cell_info(&msg->cell_to_add[i].info);
|
||||
cp.cell_to_add[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_add[i].sys_info);
|
||||
}
|
||||
/* to delete */
|
||||
cp.num_cells_to_delete = msg->num_cells_to_delete;
|
||||
for (int i = 0; i < cp.num_cells_to_delete; i++) {
|
||||
@@ -1265,31 +1286,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
/* to modify */
|
||||
cp.num_cells_to_modify = msg->num_cells_to_modify;
|
||||
for (int i = 0; i < cp.num_cells_to_modify; i++) {
|
||||
cp.cell_to_modify[i].info = msg->cell_to_modify[i].info;
|
||||
f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info;
|
||||
if (info->measurement_timing_config_len > 0) {
|
||||
info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config));
|
||||
for (int j = 0; j < info->measurement_timing_config_len; j++)
|
||||
info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j];
|
||||
}
|
||||
/* TAC */
|
||||
info->tac = calloc_or_fail(1, sizeof(*info->tac));
|
||||
*info->tac = *msg->cell_to_modify[i].info.tac;
|
||||
/* System information */
|
||||
cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info));
|
||||
f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info;
|
||||
if (msg->cell_to_modify[i].sys_info->mib_length > 0) {
|
||||
sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length;
|
||||
sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib));
|
||||
for (int j = 0; j < sys_info->mib_length; j++)
|
||||
sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j];
|
||||
}
|
||||
if (msg->cell_to_modify[i].sys_info->sib1_length > 0) {
|
||||
sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length;
|
||||
sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1));
|
||||
for (int j = 0; j < sys_info->sib1_length; j++)
|
||||
sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j];
|
||||
}
|
||||
cp.cell_to_modify[i].old_plmn = msg->cell_to_modify[i].old_plmn;
|
||||
cp.cell_to_modify[i].old_nr_cellid = msg->cell_to_modify[i].old_nr_cellid;
|
||||
cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info);
|
||||
cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
@@ -1521,7 +1521,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu,
|
||||
const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
|
||||
TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid);
|
||||
// Cause (M)
|
||||
switch (item->cause.present) {
|
||||
|
||||
@@ -32,7 +32,7 @@ bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t
|
||||
f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b);
|
||||
void free_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b);
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src);
|
||||
void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info);
|
||||
|
||||
/* F1 Setup Response */
|
||||
|
||||
@@ -53,7 +53,10 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
{
|
||||
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci);
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
if ((!a->tac) ^ (!b->tac))
|
||||
return false;
|
||||
if (a->tac)
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
_F1_EQ_CHECK_INT(a->mode, b->mode);
|
||||
if (a->mode == F1AP_MODE_TDD) {
|
||||
/* TDD */
|
||||
@@ -81,6 +84,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
|
||||
bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return true;
|
||||
|
||||
/* will fail if not both a/b NULL or set */
|
||||
if ((!a) ^ (!b))
|
||||
return false;
|
||||
|
||||
/* MIB */
|
||||
_F1_EQ_CHECK_INT(a->mib_length, b->mib_length);
|
||||
for (int i = 0; i < a->mib_length; i++)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user