Compare commits

...

24 Commits

Author SHA1 Message Date
Romain Beurdouche
982dc17fb3 fix(unit test): add T2 ofload case to nr-uesoftmodem unit test 2024-11-04 09:41:13 +01:00
Romain Beurdouche
e407c22bbe fix(unit tests): feat(nrLDPC_coding_interface): adopt definitive naming convention 2024-11-04 09:41:13 +01:00
Romain Beurdouche
628dc69f53 fix(unit tests): fix(nrLDPC_coding_interface_xdma): naming convention, replace remaining slot_xdma by xdma 2024-11-04 09:41:13 +01:00
Romain Beurdouche
8f13920a84 fix(unit tests): fix(nrLDPC_coding_interface_t2): naming convention, remaining nrLDPC_slot_t2 2024-11-04 09:41:13 +01:00
Romain Beurdouche
c24d11fa83 fix(unit tests): fix(nrLDPC_coding_interface): Adapt T2 decoding after generalizing the decoding interface for nrUE 2024-11-04 09:41:13 +01:00
Romain Beurdouche
0be56976a9 fix(unit tests): feat(ldpc-decoding-module-interface-rework): slot decoding with T2 2024-11-04 09:41:13 +01:00
Romain Beurdouche
e4e1f1e8ff fix(unit tests): feat(nrLDPC_coding_xdma): Add XDMA documentation and modify build options 2024-11-04 09:41:13 +01:00
Romain Beurdouche
90b9d5cedb feat(nrLDPC_coding_xdma): Add UE coding unit test for xdma 2024-11-04 09:41:13 +01:00
Romain Beurdouche
fb6e8049c2 fix(unit tests): fix(nrLDPC_coding_xdma): Review after tests 2024-11-04 09:41:13 +01:00
Yi-Hung Chang
253fd8ccd6 feat: Add unit tests for xdma 2024-11-04 09:41:13 +01:00
Romain Beurdouche
6d61850b9f fix(unit tests): feat(nrLDPC_coding_interface): Enable nrLDPC_coding_interface in nr_ulschsim and nr_dlschsim and add unit tests for both 2024-11-04 09:41:13 +01:00
Romain Beurdouche
56135b29b0 feat(nrLDPC_coding_interface): Add UE coding unit test 2024-11-04 09:41:13 +01:00
Romain Beurdouche
ff20305098 feat(nrLDPC_coding_interface): add unit tests for nr_ulsim, nr_dlsim and nr-softmodem with 2 rfsim UEs 2024-11-04 09:41:13 +01:00
Robert Schmidt
2dfa10c372 Allow to run nr_ulsim/nr_dlsim in CI unit tests
First, build nr_ulsim/nr_dlsim including required dfts and ldpc to run
these tests in the unit tests.

Second, pass the environment variable LD_LIBRARY_PATH so that
nr_ulsim/nr_dlsim find dfts/ldpc, because we use asan inside.
2024-11-04 09:41:13 +01:00
Robert Schmidt
b2d29a36ca Install libbenchmark-dev in unit test dockerfile
Avoid to download it from git all the time, and use (ideally) the cache
of docker.
2024-11-04 09:41:13 +01:00
Raphael Defosseux
5004fb9fd3 chore(ci): explicitly support BSD-3-Clause as legit license in OAI
Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
2024-11-04 09:34:26 +01:00
Romain Beurdouche
6636c0a910 feat(nrLDPC_coding_interface): Documentation 2024-11-04 09:34:26 +01:00
Yi-Hung Chang
7487536ee1 feat(nrLDPC_coding_interface): Add ldpc_xdma coding library 2024-11-04 09:34:26 +01:00
Romain Beurdouche
9cf8610213 feat(nrLDPC_coding_interface): Add ldpc_slot_t2 coding library 2024-11-04 09:34:26 +01:00
Romain Beurdouche
a0ad75d19f feat(nrLDPC_coding_interface): Add ldpc_slot_segment coding library 2024-11-04 09:34:26 +01:00
Romain Beurdouche
e8bbfdb227 feat(nrLDPC_coding_interface): Use reworked interface in PHY simulators 2024-11-04 09:34:26 +01:00
Yi-Hung Chang
22f5bb4857 feat(nrLDPC_coding_interface): Use reworked interface in UE 2024-11-04 09:34:26 +01:00
Romain Beurdouche
eb44d5f200 feat(nrLDPC_coding_interface): Use reworked interface in gNB 2024-11-04 09:34:16 +01:00
Romain Beurdouche
f6a05b0574 feat(nrLDPC_coding_interface): Add reworked interface definition and loader 2024-10-29 14:49:05 +01:00
61 changed files with 8960 additions and 104 deletions

View File

@@ -496,10 +496,28 @@ if (ENABLE_LDPC_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})
set(PHY_NRLDPC_CODING_T2_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c
)
add_library(ldpc_slot_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC})
set_target_properties(ldpc_slot_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API")
target_link_libraries(ldpc_slot_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2})
endif()
##########################################################
# LDPC offload library - XDMA
##########################################################
add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF)
if (ENABLE_LDPC_XDMA)
set(PHY_NRLDPC_CODING_XDMA_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
)
add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC})
endif()
include_directories ("${OPENAIR_DIR}/radio/COMMON")
##############################################################
@@ -838,10 +856,19 @@ 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_NRLDPC_CODING_SEGMENT_SRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
)
set(PHY_NR_CODINGIF
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c
)
set(PHY_NRLDPC_CODINGIF
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c
)
##############################################
# Base CUDA setting
##############################################
@@ -862,6 +889,7 @@ add_library(coding MODULE ${PHY_TURBOSRC} )
add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c)
add_library(ldpc_slot_segment MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC})
set(PHY_SRC_COMMON
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
@@ -1021,7 +1049,9 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_tools.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding_slot.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding_slot.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c
@@ -1051,6 +1081,7 @@ set(PHY_SRC_UE
${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
@@ -1070,7 +1101,9 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding_slot.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding_slot.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach_common.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c
@@ -1106,6 +1139,7 @@ set(PHY_SRC_UE
${PHY_POLARSRC}
${PHY_SMALLBLOCKSRC}
${PHY_NR_CODINGIF}
${PHY_NRLDPC_CODINGIF}
)
@@ -2037,10 +2071,14 @@ if(E2_AGENT)
endif()
add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc)
add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment)
if (ENABLE_LDPC_T2)
add_dependencies(nr-softmodem ldpc_t2)
add_dependencies(nr-softmodem ldpc_t2 ldpc_slot_t2)
endif()
if (ENABLE_LDPC_XDMA)
add_dependencies(nr-softmodem ldpc_xdma)
endif()
# force the generation of ASN.1 so that we don't need to wait during the build
@@ -2094,12 +2132,20 @@ 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 )
add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment)
if (ENABLE_LDPC_CUDA)
add_dependencies(nr-uesoftmodem ldpc_cuda)
add_dependencies(nr-softmodem ldpc_cuda)
endif()
if (ENABLE_LDPC_T2)
add_dependencies(nr-uesoftmodem ldpc_t2 ldpc_slot_t2)
endif()
if (ENABLE_LDPC_XDMA)
add_dependencies(nr-uesoftmodem ldpc_xdma)
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)
@@ -2255,8 +2301,12 @@ add_executable(nr_ulsim
)
if (ENABLE_LDPC_T2)
add_dependencies(nr_ulsim ldpc_t2)
add_dependencies(nr_ulsim ldpc_t2 ldpc_slot_t2)
endif()
if (ENABLE_LDPC_XDMA)
add_dependencies(nr_ulsim ldpc_xdma)
endif()
add_dependencies(nr_ulsim ldpc_slot_segment)
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
@@ -2323,7 +2373,8 @@ if (${T_TRACER})
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)
ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_slot_t2 ldpc_xdma
dfts config_internals nr_common)
if (TARGET ${i})
add_dependencies(${i} generate_T)
endif()

View File

@@ -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 ]

View File

@@ -783,7 +783,7 @@ class Containerize():
HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile])
# it worked, build and execute tests, and close connection
ret = cmd.run(f'docker run -a STDOUT --rm ran-unittests:{baseTag} ctest --output-on-failure --no-label-summary -j$(nproc)')
ret = cmd.run(f'docker run -a STDOUT -e LD_LIBRARY_PATH=. --rm ran-unittests:{baseTag} ctest --output-on-failure --no-label-summary -j$(nproc)')
cmd.run(f'docker rmi ran-unittests:{baseTag}')
build_log_name = f'build_log_{self.testCase_id}'
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)

View File

@@ -31,6 +31,7 @@ RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \
DEBIAN_FRONTEND=noninteractive apt-get install --yes \
libgtest-dev \
libbenchmark-dev \
libyaml-cpp-dev
RUN rm -Rf /oai-ran
@@ -38,4 +39,4 @@ WORKDIR /oai-ran
COPY . .
WORKDIR /oai-ran/build
RUN cmake -GNinja -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=True .. && ninja tests
RUN cmake -GNinja -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=True .. && ninja tests nr_ulsim nr_dlsim dfts ldpc

View File

@@ -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=""
function print_help() {

View File

@@ -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:
@@ -102,11 +97,71 @@ cd cmake_targets
./build_oai -w USRP --ninja --gNB -P --build-lib "ldpc_t2" -C
```
Shared object file *libldpc_t2.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using *--build-lib ldpc_t2*.
Shared object file *libldpc_slot_t2.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using *--build-lib ldpc_t2*.
*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 : "_slot_t2";
};
};
```
# 5G PHY simulators
## nr_ulsim test
Offload of the channel decoding to the T2 card is in nr_ulsim specified by *--loader.ldpc.shlibversion _slot_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 --loader.ldpc.shlibversion _slot_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:
```
cd ~/openairinterface5g
source oaienv
cd cmake_targets/ran_build/build
sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 --loader.ldpc.shlibversion _slot_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 *--loader.ldpc.shlibversion _slot_t2* option.
## Run OAI gNB with USRP B210
```
cd ~/openairinterface5g
source oaienv
cd cmake_targets/ran_build/build
sudo ./nr-softmodem --sa -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --loader.ldpc.shlibversion _slot_t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1
```
# Alternative legacy implementation
The current implementation of LDPC coding with T2 described above is new and may still comprise some regression in comparison to the legacy implementation besides all the test and improvements performed.
Therefore, the legacy implementation remains available.
It is compiled at the same time as the current implementation and it can be selected with the arguments described below.
## 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*
## 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:
```
@@ -124,10 +179,8 @@ cd cmake_targets/ran_build/build
sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 -c --ldpc_offload.dpdk_dev 01:00.0
```
# OTA test
Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--ldpc-offload-enable* option.
## Run OAI gNB with USRP B210
Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--ldpc-offload-enable* option.
```
cd ~/openairinterface5g
source oaienv

View File

@@ -0,0 +1,155 @@
[TOC]
This documentation aims to provide a tutorial for Xilinx FPGA PCIe-XDMA integration into OAI and its usage. It can offload LDPC decoding to FPGA.
# Requirements
- XDMA driver
# XDMA Driver Build & Install
The *xdma_driver* directory contains the following:
```bash
xdma_driver
├── cmake
├── FPGA_TEST_datasheet.txt
├── include
├── libfpga_0720_vt.so
├── libfpga_8038_vt.so
├── libfpga_ldpc.a
├── libTHIRD_PARTY.a
├── nr_ldpc_decoding_pym.h
├── README.md
├── tests
├── xdma
└── xdma_diag.h
```
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
```
cd xdma_driver/xdma
sudo make clean
sudo make install
cd xdma_driver/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 --sa --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 --sa --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 --sa --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 --sa --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.

View File

@@ -43,6 +43,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"
@@ -387,6 +388,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)
{
@@ -423,10 +425,15 @@ 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 nrLDPC_coding_interface_flag = 0;
int ret_loader = load_nrLDPC_coding_interface(NULL, &nrLDPC_coding_interface);
if (ret_loader >= 0) {
nrLDPC_coding_interface_flag = 1;
} else {
load_LDPClib(NULL, &ldpc_interface);
if (nrUE_params.ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
}
if (ouput_vcd) {
vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd");
@@ -441,6 +448,7 @@ 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]));
PHY_vars_UE_g[inst][CC_id]->nrLDPC_coding_interface_flag = nrLDPC_coding_interface_flag;
}
}

View File

@@ -1,3 +1,4 @@
add_subdirectory(nr_phy_common)
add_subdirectory(TOOLS)
add_subdirectory(NR_TRANSPORT)
add_subdirectory(CODING)

View File

@@ -0,0 +1,3 @@
if(ENABLE_TESTS)
add_subdirectory(tests)
endif()

View File

@@ -1,7 +1,12 @@
# 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 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:
@@ -118,7 +123,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:
@@ -196,4 +201,115 @@ Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`,
`libldpc_cl.so`is under development.
## 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`.\
If `libldpc.so` does not implement the LDPC slot decoder interface then the loader just fails which allows to fallback to the code segment decoding interface.\
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_slot_segment.so` instead of `libldpc.so`:
```
./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _slot_segment
.......................
[CONFIG] loader.ldpc.shlibversion set to default value ""
[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
[CONFIG] shlibversion set to _slot_segment from command line
[CONFIG] loader.ldpc 1 options set from command line
shlib_path libldpc_slot_segment.so
[LOADER] library libldpc_slot_segment.so successfully loaded
........................
```
`libldpc_slot_segment.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: `libldpc_slot_segment.so` is just to test the slot coding interface and uses a segment coding library behind.*
*The segment coding library is `libldpc.so` by default but it can be chosen with option `--nrLDPC_coding_segment.segment_shlibversion` followed by the library version - like with `--loder.ldpc.shlibversion` in the segment coding case above -*
loading `libldpc_slot_t2.so` instead of `libldpc.so`:
`make ldpc_slot_t2`
This command creates the `libldpc_slot_t2.so` shared library.
```
Building C object CMakeFiles/ldpc_slot_t2.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c.o
Linking C shared module libldpc_slot_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 --sa --log_config.gtpu_log_level info --loader.ldpc.shlibversion _slot_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 _slot_t2 from command line
[CONFIG] loader.ldpc 1 options set from command line
shlib_path libldpc_slot_t2.so
[LOADER] library libldpc_slot_t2.so successfully loaded
........................
```
`libldpc_slot_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 --sa --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_slot_segment.so` is completed.
`libldpc_slot_t2.so` is completed.
`libldpc_xdma.so` is completed.
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)

View File

@@ -0,0 +1,263 @@
/*
* 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
* \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
* 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 xlsch_id ulsch or dlsch index
* \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 rnti RNTI
* \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 max_ldpc_iterations maximum number of LDPC iterations
* \var abort_decode pointer to decode abort flag
* \var G
* \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
* \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{
uint8_t xlsch_id;
uint32_t *processedSegments;
uint16_t rnti;
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 respDecode pointer to the queue for decoding tasks
* \var threadPool pointer to the thread pool
* \var TBs array of TBs decoding parameters
*/
typedef struct nrLDPC_slot_decoding_parameters_s{
int frame;
int slot;
int nb_TBs;
notifiedFIFO_t *respDecode;
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 xlsch_id ulsch or dlsch index
* \var rnti RNTI
* \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
* \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
* \var K
* \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{
uint8_t xlsch_id;
uint16_t rnti;
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 respEncode pointer to the queue for encoding tasks
* \var threadPool pointer to the thread pool
* \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;
notifiedFIFO_t *respEncode;
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);
//TODO replace the global structure below
// Global var to limit the rework of the dirty legacy code
extern nrLDPC_coding_interface_t nrLDPC_coding_interface;
#endif

View File

@@ -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();
}

View File

@@ -0,0 +1,319 @@
/*
* 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 <syscall.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 decoderParams 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
* \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 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;
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");
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);
}
int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int pusch_id)
{
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++) {
union ldpcReqUnion id = {.s = {nrLDPC_TB_decoding_parameters->rnti, nrLDPC_slot_decoding_parameters->frame, nrLDPC_slot_decoding_parameters->slot, 0, 0}};
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(nrLDPC_decoding_parameters_t), id.p, nrLDPC_slot_decoding_parameters->respDecode, &nr_process_decode_segment);
nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)NotifiedFifoData(req);
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;
pushTpool(nrLDPC_slot_decoding_parameters->threadPool, req);
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 = "", 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 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);
}
// Execute thread pool tasks if any
while (nbDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(nrLDPC_slot_decoding_parameters->respDecode, nrLDPC_slot_decoding_parameters->threadPool);
if (req == NULL)
return -1; // Tpool has been stopped
delNotifiedFIFO_elt(req);
nbDecode--;
}
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;
}

View File

@@ -0,0 +1,220 @@
/*
* 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 <syscall.h>
#include <openair2/UTIL/OPT/opt.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;
}
}
static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int dlsch_id)
{
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
encoder_implemparams_t impp;
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;
impp.Qm = nrLDPC_TB_encoding_parameters->Qm;
impp.Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm;
impp.G = nrLDPC_TB_encoding_parameters->G;
for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) {
impp.perCB[r].E_cb = nrLDPC_TB_encoding_parameters->segments[r].E;
}
impp.rv = nrLDPC_TB_encoding_parameters->rv_index;
int nbJobs = 0;
for (int j = 0; j < (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); j++) {
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(ldpc8blocks_args_t), j, nrLDPC_slot_encoding_parameters->respEncode, ldpc8blocks_coding_segment);
ldpc8blocks_args_t *perJobImpp = (ldpc8blocks_args_t *)NotifiedFifoData(req);
impp.macro_num = j;
perJobImpp->impp = impp;
perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters;
pushTpool(nrLDPC_slot_encoding_parameters->threadPool, req);
nbJobs++;
}
return nbJobs;
}
int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
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);
}
return nbEncode;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,414 @@
/*
* 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;
/*!
* \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 */
int8_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; /*!< */
} 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,
notifiedFIFO_t *ldpc_respDecode);
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 = "", 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, slot_params->respDecode);
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,
notifiedFIFO_t *ldpc_respDecode)
{
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 int8_t multi_indata[27000 * 25]; // FPGA input data
static int8_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;
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;
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;
uint32_t r_remaining = 0;
// start the prepare jobs
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) {
void (*nr_ulsch_FPGA_decoding_prepare_blocks_ptr)(void *) = &nr_ulsch_FPGA_decoding_prepare_blocks;
// TODO: int nr_tti_rx = 0;
union ldpcReqUnion id = {.s = {TB_params->rnti, frame_rx, slot_rx, 0, 0}};
notifiedFIFO_elt_t *req =
newNotifiedFIFO_elt(sizeof(args_fpga_decode_prepare_t), id.p, ldpc_respDecode, nr_ulsch_FPGA_decoding_prepare_blocks_ptr);
args_fpga_decode_prepare_t *args = (args_fpga_decode_prepare_t *)NotifiedFifoData(req);
args->TB_params = TB_params;
args->multi_indata = multi_indata;
args->no_iteration_ldpc = no_iteration_ldpc;
args->r_first = r;
uint32_t r_span_max = ((TB_params->C - r) % (num_threads_prepare_max - num_threads_prepare)) == 0
? (TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare)
: ((TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare)) + 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;
pushTpool(ldpc_threadPool, req);
LOG_D(PHY, "Added %d block(s) to prepare for decoding, in pipe: %d to %d\n", r_span, r, r + r_span - 1);
num_threads_prepare++;
}
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;
// wait for the prepare jobs to complete
while (num_threads_prepare > 0) {
notifiedFIFO_elt_t *req = (notifiedFIFO_elt_t *)pullTpool(ldpc_respDecode, ldpc_threadPool);
if (req == NULL)
LOG_E(PHY, "FPGA decoding preparation: pullTpool returned NULL\n");
args_fpga_decode_prepare_t *args = (args_fpga_decode_prepare_t *)NotifiedFifoData(req);
if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations)
no_iteration_ldpc = TB_params->max_ldpc_iterations + 1;
num_threads_prepare -= 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((int8_t *)&multi_indata[0], (int8_t *)&multi_outdata[0], dec_conf);
// printf("Xilinx FPGA -> CB = %d\n", harq_process->C);
// nrLDPC_decoder_FPGA_PYM((int8_t *)&temp_multi_indata[0], (int8_t *)&multi_outdata[0], dec_conf);
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((uint8_t *)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] = (uint8_t)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;
int8_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]
int8_t *tmp_p = (int8_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;
}

View File

@@ -0,0 +1,984 @@
/*
* 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 _BSD_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;
static struct option const long_opts[] = {{"device", required_argument, NULL, 'd'},
{"address", required_argument, NULL, 'a'},
{"size", required_argument, NULL, 's'},
{"offset", required_argument, NULL, 'o'},
{"count", required_argument, NULL, 'c'},
{"data infile", required_argument, NULL, 'f'},
{"data outfile", required_argument, NULL, 'w'},
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{0, 0, 0, 0}};
#if 0
/* 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 DEVICE_NAME_DEFAULT_READ "/dev/xdma0_c2h_1"
#define DEVICE_NAME_DEFAULT_WRITE "/dev/xdma0_h2c_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 CB_PROCESS_NUMBER 12 // add by JW
#endif
void* map_base;
int fd;
int fd_enc_write, fd_enc_read;
int fd_dec_write, fd_dec_read;
char *allocated_write, *allocated_read;
// dma_from_device.c
#if 0
int test_dma_end_read();
int test_dma_enc_write();
#endif
static int no_write = 0;
// [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);
// printf("sscanf() = %d, value = 0x%lx\n", rc, 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;
}
/* Subtract timespec t2 from t1
*
* Both t1 and t2 must already be normalized
* i.e. 0 <= nsec < 1000000000
*/
static int timespec_check(struct timespec* t)
{
if ((t->tv_nsec < 0) || (t->tv_nsec >= 1000000000))
return -1;
return 0;
}
/*
void timespec_sub(struct timespec* t1, struct timespec* t2)
{
if (timespec_check(t1) < 0) {
fprintf(stderr, "invalid time #1: %lld.%.9ld.\n", (long long)t1->tv_sec, t1->tv_nsec);
return;
}
if (timespec_check(t2) < 0) {
fprintf(stderr, "invalid time #2: %lld.%.9ld.\n", (long long)t2->tv_sec, t2->tv_nsec);
return;
}
t1->tv_sec -= t2->tv_sec;
t1->tv_nsec -= t2->tv_nsec;
if (t1->tv_nsec >= 1000000000) {
t1->tv_sec++;
t1->tv_nsec -= 1000000000;
} else if (t1->tv_nsec < 0) {
t1->tv_sec--;
t1->tv_nsec += 1000000000;
}
}
*/
// [End] #include "dma_utils.c" ===================================
int test_dma_enc_read(char* EncOut, EncIPConf Confparam)
{
// U64 tTotal = MLogPhyTick();
ssize_t rc;
uint64_t i;
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;
// printf("max_schedule:%d (mb - kb):%d id:%d bg:%d z_set:%d z_j:%d\n",max_schedule,(mb - kb),id,bg,z_set,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;
// printf("0x%04x \n",Out_dwNumItems_p128);
Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num);
// printf("0x%04x \n",Out_dwNumItems);
// MLogPhyTask(PID_DL_FEC_GEN3_R1, tTotal, MLogPhyTick());
size = Out_dwNumItems;
writeval = ctrl_data;
// printf("read : %d byte, ctrl : 0x%08x\n",size,writeval);
/* 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;
// MLogPhyTask(PID_DL_FEC_GEN3_R2, tTotal, MLogPhyTick());
if (fd_enc_read < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", DEVICE_NAME_DEFAULT_ENC_READ, fd_enc_read);
perror("open device");
return -EINVAL;
}
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(DEVICE_NAME_DEFAULT_ENC_READ, fd_enc_read, EncOut, size, 0);
// rc = read_to_buffer(DEVICE_NAME_DEFAULT_ENC_READ, fd_enc_read, allocated_read, size, 0);
// MLogPhyTask(PID_DL_FEC_GEN3_R3, tTotal, MLogPhyTick());
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
int test_dma_enc_write(char* data, EncIPConf Confparam)
{
uint64_t i;
ssize_t rc;
// U64 tTotal = MLogPhyTick();
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;
// printf("max_schedule:%d (mb - kb):%d id:%d bg:%d z_set:%d z_j:%d\n",max_schedule,(mb - kb),id,bg,z_set,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);
// MLogPhyTask(PID_DL_FEC_GEN3_W1, tTotal, MLogPhyTick());
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;
// MLogPhyTask(PID_DL_FEC_GEN3_W2, tTotal, MLogPhyTick());
if (fd_enc_write < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", DEVICE_NAME_DEFAULT_ENC_WRITE, fd_enc_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(DEVICE_NAME_DEFAULT_ENC_WRITE, fd_enc_write, data, size, 0);
// rc = write_from_buffer(DEVICE_NAME_DEFAULT_ENC_WRITE, fd_enc_write, allocated_write, size, 0);
if (rc < 0)
goto out;
// MLogPhyTask(PID_DL_FEC_GEN3_W3, tTotal, MLogPhyTick());
rc = 0;
out:
return rc;
}
// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam)
int test_dma_dec_read(char* DecOut, DecIPConf Confparam)
{
struct timespec read_start_2, read_end_2;
ssize_t rc;
uint64_t i;
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 = 4;
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;
// printf("Z_val%d CB_num%d OutDataNUM%d Out_dwNumItems_p128%d Out_dwNumItems%d\n" , Z_val, CB_num, OutDataNUM,
// Out_dwNumItems_p128, Out_dwNumItems);
} 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;
// printf("Z_val%d CB_num%d OutDataNUM%d Out_dwNumItems_p128%d Out_dwNumItems%d\n" , Z_val, CB_num, OutDataNUM,
// Out_dwNumItems_p128, Out_dwNumItems);
if ((Out_dwNumItems & 0x1f) != 0)
Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5;
// printf("Z_val%d kb%d OutDataNUM%d Out_dwNumItems_p128%d Out_dwNumItems%d CB_num=%d\n" , Z_val, kb, OutDataNUM,
// Out_dwNumItems_p128, Out_dwNumItems, CB_num);
}
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", DEVICE_NAME_DEFAULT_DEC_READ, fd_dec_read);
perror("open device");
return -EINVAL;
}
// clock_gettime(CLOCK_MONOTONIC, &read_start_2);
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(DEVICE_NAME_DEFAULT_DEC_READ, fd_dec_read, DecOut, size, 0);
if (rc < 0)
goto out;
rc = 0;
// clock_gettime(CLOCK_MONOTONIC, &read_end_2);
// timespec_sub(&read_end_2, &read_start_2);
// printf("[2]read_to_buffer() time %.2f µsec\n", (float)(read_end_2.tv_nsec) / 1000);
out:
return rc;
}
// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam)
int test_dma_dec_write(char* data, DecIPConf Confparam)
{
uint64_t i;
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 = 4;
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;
// printf("Z_val[%d] CB_num[%d] mb[%d] InDataNUM[%d] In_dwNumItems_p128[%d] In_dwNumItems[%d]\n" , Z_val, CB_num, mb, InDataNUM,
// In_dwNumItems_p128, In_dwNumItems);
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", DEVICE_NAME_DEFAULT_DEC_WRITE, fd_dec_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(DEVICE_NAME_DEFAULT_DEC_WRITE, fd_dec_write, data, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
void test_dma_init()
{
/* access width */
int access_width = 'w';
char* device2 = "/dev/xdma0_user"; //
uint32_t size1 = 24 * 1024;
uint32_t size2 = 24 * 1024 * 3;
// printf("\n###################################################\n");
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
// printf("# CHARACTER DEVICE %s OPENED. #\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);
// printf("# MEMORY MAPPED AT ADDRESS %p. #\n", map_base);
// printf("###################################################\n\n");
void* virt_addr;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
fd_enc_write = open(DEVICE_NAME_DEFAULT_ENC_WRITE, O_RDWR);
fd_enc_read = open(DEVICE_NAME_DEFAULT_ENC_READ, O_RDWR);
fd_dec_write = open(DEVICE_NAME_DEFAULT_DEC_WRITE, O_RDWR);
fd_dec_read = open(DEVICE_NAME_DEFAULT_DEC_READ, O_RDWR);
fflush(stdout);
allocated_write = NULL;
posix_memalign((void**)&allocated_write, 4096 /*alignment */, size1 + 4096);
allocated_read = NULL;
posix_memalign((void**)&allocated_read, 4096 /*alignment */, size2 + 4096);
}
void dma_reset()
{
char* device2 = "/dev/xdma0_user"; //
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);
// printf("\n###################################################\n");
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
// printf("# CHARACTER DEVICE %s OPENED. #\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);
// printf("# MEMORY MAPPED AT ADDRESS %p. #\n", map_base);
// printf("###################################################\n\n");
// void *virt_addr;
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
// void *virt_addr;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
fd_enc_write = open(DEVICE_NAME_DEFAULT_ENC_WRITE, O_RDWR);
fd_enc_read = open(DEVICE_NAME_DEFAULT_ENC_READ, O_RDWR);
fd_dec_write = open(DEVICE_NAME_DEFAULT_DEC_WRITE, O_RDWR);
fd_dec_read = open(DEVICE_NAME_DEFAULT_DEC_READ, O_RDWR);
fflush(stdout);
}
void test_dma_shutdown()
{
free(allocated_write);
free(allocated_read);
}
#if 1
// reg_rx.c
int nrLDPC_decoder_FPGA_PYM(int8_t* buf_in, int8_t* buf_out, DecIFConf dec_conf)
{
struct timespec ts_start, ts_end; // evaluate core xdma run time
struct timespec ts_start0, ts_end0; // ealuate time from input setting to output setting include xdma
struct timespec read_start, read_end;
struct timespec write_start, write_end;
int Zc;
int nRows;
int baseGraph;
int CB_num;
DecIPConf Confparam;
int z_a, z_tmp, ii, jj, i;
int z_j = 0;
int numChannelLlrs; // input soft bits length, Zc x 66 - length of filler bits
int numFillerBits; // filler bits length
char in_softbits[26112 * 52 + 1]; // Random by default value, 52 is max CBs in UL 272RBs and 2 layers with 64QAM
char out_MessageBytes[1056 * 52 + 1]; // 52 = max number of code block
int iterationAtTermination; // output results
int parityPassedAtTermination; // output results
// char buffer_in[26112 * 52 + 1];
char buffer_out[1056 * 52 + 1];
int numMsgBits, numMsgBytes, input_CBoffset, output_CBoffset;
uint8_t i_LS;
static int init_flag = 0;
if (init_flag == 0) {
/*Init*/
test_dma_init();
init_flag = 1;
} else {
dma_reset();
}
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
numChannelLlrs = dec_conf.numChannelLls; // input soft bits length, Zc x 66 - length of filler bits
numFillerBits = dec_conf.numFillerBits; // filler bits length
// 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 output numMsgBits
if (baseGraph == 1)
numMsgBits = Zc * 22 - numFillerBits;
else
numMsgBits = Zc * 10 - numFillerBits;
// 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);
// memset(buf_in, 0, 26112 * 52 + 1);
// memset(buf_out, 0, 27500); // memset(buffer_out, 0, 1056 * 52 + 1);
#if 1 // Input Setting FPGA
// set input buffer_in from the llr output (in_softbits)
// Arrange data format
// for (jj = 0; jj < CB_num; jj++) {
// for (ii = 0; ii < (numChannelLlrs + numFillerBits + Zc * 2); ii++) {
// if (buf_in[ii + input_CBoffset * jj] == -128) {
// buf_in[ii + input_CBoffset * jj] = -127;
// }
// if (ii < Zc * 2)
// buf_in[ii + input_CBoffset * jj] = 0x00;
// else if (ii < numMsgBits)
// buf_in[ii + input_CBoffset * jj] = ((buf_in[ii - Zc * 2 + numChannelLlrs * jj]) ^ (0xFF)) + 1;
// else if (ii < (numMsgBits + numFillerBits))
// buf_in[ii + input_CBoffset * jj] = 0x80;
// else
// buf_in[ii + input_CBoffset * jj] = ((buf_in[ii - Zc * 2 - numFillerBits + numChannelLlrs * jj]) ^ (0xFF)) + 1;
// }
// printf("\nInput_LLR[%d] = ", jj);
// for (i = 0; i < 20; i++) {
// printf("%d,", buf_in[i + input_CBoffset * jj + 2 * Zc]);
// }
// }
// printf("input setting done\n");
#endif // Input Setting FPGA
// LDPC accelerator start
// printf("[%s] Start DMA write\n", __func__);
// clock_gettime(CLOCK_MONOTONIC, &ts_start); // time start
// ===================================================
// printf("[%s] DMA write 0\n", __func__);
// write into accelerator
// clock_gettime(CLOCK_MONOTONIC, &write_start);
if (test_dma_dec_write(buf_in, Confparam) != 0) {
exit(1);
printf("write exit!!\n");
}
// clock_gettime(CLOCK_MONOTONIC, &write_end);
// timespec_sub(&write_end, &write_start);
// printf("Write time %.2f µsec\n", (float)(write_end.tv_nsec) / 1000);
// ===================================================
// printf("[%s] DMA read 0\n", __func__);
// read output of accelerator
// clock_gettime(CLOCK_MONOTONIC, &read_start);
if (test_dma_dec_read(buf_out, Confparam) != 0) {
exit(1);
printf("read exit!!\n");
}
// clock_gettime(CLOCK_MONOTONIC, &read_end);
// timespec_sub(&read_end, &read_start);
// printf("[1]Read time %.2f µsec\n", (float)(read_end.tv_nsec) / 1000);
// // ===================================================
// clock_gettime(CLOCK_MONOTONIC, &ts_end); // time end
// printf("[%s] End DMA read\n", __func__);
// LDPC accelerator end
// timespec_sub(&ts_end, &ts_start);
// printf("[%s] finish DMA, CB_num[%d], total time %ld nsec\n", __func__, CB_num, ts_end.tv_nsec);
#if 1 // Output Setting FPGA
// set output out_MessageBytes from the xdma output (buffer_out) , iterationAtTermination , parityPassedAtTermination
for (jj = 0; jj < CB_num; jj++) {
if ((numMsgBits & 0x7) == 0)
numMsgBytes = numMsgBits / 8;
else {
numMsgBytes = (numMsgBits / 8) + 1;
}
iterationAtTermination = 1; // output
parityPassedAtTermination = 1; // output
// memcpy((int8_t*)&buf_out[output_CBoffset * jj], (int8_t*)&buffer_out[output_CBoffset * jj], numMsgBytes);
// -----------------------------------
// Compare output information:
// -----------------------------------
// printf("buffer_out[%d] = ", jj);
// for (i = 0; i < 10; i++) {
// printf("%d, ", buffer_out[i + output_CBoffset * jj]);
// }
// printf("\n");
// printf("buf_out[%d] = ", jj);
// for (i = 0; i < 10; i++) {
// printf("%d, ", buf_out[i + output_CBoffset * jj]);
// }
// printf("\n");
}
// printf("[%s] Output setting done\n", __func__);
#endif // Output Setting FPGA
// clock_gettime(CLOCK_MONOTONIC, &ts_end0); // time end0
// timespec_sub(&ts_end0, &ts_start0);
// printf("[%s] finish LDPC, CB_num[%d], total time %ld nsec\n", __func__, CB_num, ts_end0.tv_nsec);
// printf("Accelerator card is completed!\n");
return 0;
}
#endif

View File

@@ -0,0 +1,62 @@
/*
* 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
*/
#include <stdint.h>
#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_
#define __NRLDPC_CODING_XDMA_OFFLOAD__H_
/**
\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 {
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_8038(int8_t *buf_in, int8_t *buf_out, DecIFConf dec_conf);
int nrLDPC_decoder_FPGA_PYM(int8_t *buf_in, int8_t *buf_out, DecIFConf dec_conf);
// int nrLDPC_decoder_FPGA_PYM();
#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_

View File

@@ -0,0 +1,138 @@
/*
* 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
// #define _BSD_SOURCE
// #define _XOPEN_SOURCE 500
// #include "../../LDPC/LDPC_api.h"
// #include "dma_utils.c"
/*static struct option const long_opts[] = {
{"device", required_argument, NULL, 'd'},
{"address", required_argument, NULL, 'a'},
{"size", required_argument, NULL, 's'},
{"offset", required_argument, NULL, 'o'},
{"count", required_argument, NULL, 'c'},
{"data infile", required_argument, NULL, 'f'},
{"data outfile", required_argument, NULL, 'w'},
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{0, 0, 0, 0}
};*/
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;
/* 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 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"
#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();
void test_dma_shutdown();
void dma_reset();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,394 @@
####################################################################################
###### nr_ulsim unit test ######
####################################################################################
set(default_ldpc "")
set(slot_segment "-O" "${CMAKE_CURRENT_SOURCE_DIR}/slot_segment.conf")
set(t2_offload_nr_ulsim "-o" "-O" "${CMAKE_CURRENT_SOURCE_DIR}/t2_offload.conf")
set(slot_t2 "-O" "${CMAKE_CURRENT_SOURCE_DIR}/slot_t2.conf")
set(xdma "-O" "${CMAKE_CURRENT_SOURCE_DIR}/xdma.conf")
set(NR_ULSIM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_ULSIM_OPTION_TO_TEST_LIST
t2_offload_nr_ulsim
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_ULSIM_OPTION_TO_TEST_LIST
xdma
)
endif()
set(test_nr_ulsim_misc_test1 "-n100" "-m9" "-r106" "-s5")
set(test_nr_ulsim_misc_test2 "-n100" "-m16" "-s10")
set(test_nr_ulsim_misc_test3 "-n100" "-m28" "-s20")
set(test_nr_ulsim_misc_test4 "-n100" "-m27" "-s25" "-q1")
set(test_nr_ulsim_misc_test5 "-n100" "-m9" "-R217" "-r217" "-s5")
set(test_nr_ulsim_misc_test6 "-n100" "-m9" "-R273" "-r273" "-s5")
set(test_nr_ulsim_misc_test7 "-n100" "-s5" "-U0,1,1,1")
set(test_nr_ulsim_misc_test8 "-n100" "-s5" "-T1,2" "-U0,2,1,1")
set(test_nr_ulsim_misc_test9 "-n100" "-s5" "-T2,2" "-U1,2,1,1")
set(test_nr_ulsim_misc_test10 "-n100" "-s5" "-a4" "-b8" "-T1,2" "-U1,3,1,1")
set(test_nr_ulsim_misc_test11 "-n100" "-u0" "-m0" "-R25" "-r25" "-i1,0")
set(test_nr_ulsim_misc_test12 "-n100" "-m0" "-S" "-0.6" "-i1,0")
set(test_nr_ulsim_misc_test13 "-n100" "-m28" "-R106" "-r106" "-t90" "-s24" "-S24" "-d8")
set(test_nr_ulsim_sc_test1 "-n100" "-s5" "-Z")
set(test_nr_ulsim_sc_test2 "-n100" "-s5" "-Z" "-r75")
set(test_nr_ulsim_sc_test3 "-n50" "-s5" "-Z" "-r216" "-R217")
set(test_nr_ulsim_sc_test4 "-n50" "-s5" "-Z" "-r270" "-R273")
set(test_nr_ulsim_sc_test5 "-n100" "-s5" "-Z" "-U0,2,1,2")
set(test_nr_ulsim_mimo_test1 "-n100" "-m19" "-s10" "-S15" "-z2")
set(test_nr_ulsim_mimo_test2 "-n100" "-m9" "-r106" "-s8" "-W2" "-y2" "-z2")
set(test_nr_ulsim_mimo_test3 "-n100" "-m10" "-r106" "-s12" "-W2" "-y2" "-z2")
set(test_nr_ulsim_mimo_test4 "-n100" "-m19" "-r106" "-s22" "-W2" "-y2" "-z2")
set(test_nr_ulsim_mimo_test5 "-n100" "-m9" "-r106" "-s10" "-W4" "-y4" "-z4")
set(test_nr_ulsim_3gpp_test1 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U0,1,1,2" "-z2" "-s12.4" "-S12.4")
set(test_nr_ulsim_3gpp_test2 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U0,1,1,2" "-z4" "-s8.5" "-S8.5")
set(test_nr_ulsim_3gpp_test3 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U0,1,1,2" "-z8" "-s5.4" "-S5.4")
set(test_nr_ulsim_3gpp_test4 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R25" "-r25" "-U1,1,1,2" "-z2" "-s12.5" "-S12.5")
set(test_nr_ulsim_3gpp_test5 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R25" "-r25" "-U1,1,1,2" "-z4" "-s8.9" "-S8.9")
set(test_nr_ulsim_3gpp_test6 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R25" "-r25" "-U1,1,1,2" "-z8" "-s5.7" "-S5.7")
set(test_nr_ulsim_3gpp_test7 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R52" "-r52" "-U1,1,1,2" "-z2" "-s12.6" "-S12.6")
set(test_nr_ulsim_3gpp_test8 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R52" "-r52" "-U1,1,1,2" "-z4" "-s8.9" "-S8.9")
set(test_nr_ulsim_3gpp_test9 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R52" "-r52" "-U1,1,1,2" "-z8" "-s5.8" "-S5.8")
set(test_nr_ulsim_3gpp_test10 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z2" "-s12.3" "-S12.3")
set(test_nr_ulsim_3gpp_test11 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z4" "-s8.8" "-S8.8")
set(test_nr_ulsim_3gpp_test12 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u0" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z8" "-s5.7" "-S5.7")
set(test_nr_ulsim_3gpp_test13 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R24" "-r24" "-U1,1,1,2" "-z2" "-s12.5" "-S12.5")
set(test_nr_ulsim_3gpp_test14 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R24" "-r24" "-U1,1,1,2" "-z4" "-s8.6" "-S8.6")
set(test_nr_ulsim_3gpp_test15 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R24" "-r24" "-U1,1,1,2" "-z8" "-s5.6" "-S5.6")
set(test_nr_ulsim_3gpp_test16 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R51" "-r51" "-U1,1,1,2" "-z2" "-s12.5" "-S12.5")
set(test_nr_ulsim_3gpp_test17 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R51" "-r51" "-U1,1,1,2" "-z4" "-s8.6" "-S8.6")
set(test_nr_ulsim_3gpp_test18 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R51" "-r51" "-U1,1,1,2" "-z8" "-s5.6" "-S5.6")
set(test_nr_ulsim_3gpp_test19 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z2" "-s12.5" "-S12.5")
set(test_nr_ulsim_3gpp_test20 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z4" "-s8.7" "-S8.7")
set(test_nr_ulsim_3gpp_test21 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R106" "-r106" "-U1,1,1,2" "-z8" "-s5.5" "-S5.5")
set(test_nr_ulsim_3gpp_test22 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R273" "-r273" "-U1,1,1,2" "-z2" "-s13.1" "-S13.1")
set(test_nr_ulsim_3gpp_test23 "-n100" "-b14" "-I7" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R273" "-r273" "-U1,1,1,2" "-z4" "-s9.2" "-S9.2")
set(test_nr_ulsim_3gpp_test24 "-n100" "-b14" "-I8" "-i0,1" "-gA,l,10" "-t70" "-u1" "-m20" "-R273" "-r273" "-U1,1,1,2" "-z8" "-s5.9" "-S5.9")
set(test_nr_ulsim_3gpp_test25 "-n100" "-b14" "-I15" "-i0,1" "-gB,l" "-t70" "-u1" "-m2" "-R106" "-r106" "-U1,1,1,2" "-W2" "-y2" "-z2" "-s1.7" "-S1.7")
set(test_nr_ulsim_3gpp_test26 "-n100" "-b14" "-I15" "-i0,1" "-gB,l" "-t70" "-u1" "-m2" "-R106" "-r106" "-U1,1,1,2" "-W2" "-y2" "-z4" "-s-2.1" "-S-2.1")
set(test_nr_ulsim_3gpp_test27 "-n100" "-b14" "-I15" "-i0,1" "-gC,l" "-t70" "-u1" "-m16" "-R106" "-r106" "-U1,1,1,2" "-W2" "-y2" "-z2" "-s18.7" "-S18.7")
set(test_nr_ulsim_3gpp_test28 "-n100" "-b14" "-I15" "-i0,1" "-gC,l" "-t70" "-u1" "-m16" "-R106" "-r106" "-U1,1,1,2" "-W2" "-y2" "-z4" "-s11.2" "-S11.2")
set(NR_ULSIM_TEST_CASE_OPTION_LIST
test_nr_ulsim_misc_test1
test_nr_ulsim_misc_test2
test_nr_ulsim_misc_test3
test_nr_ulsim_misc_test4
test_nr_ulsim_misc_test5
test_nr_ulsim_misc_test6
test_nr_ulsim_misc_test7
test_nr_ulsim_misc_test8
test_nr_ulsim_misc_test9
test_nr_ulsim_misc_test10
test_nr_ulsim_misc_test11
test_nr_ulsim_misc_test12
test_nr_ulsim_misc_test13
test_nr_ulsim_sc_test1
test_nr_ulsim_sc_test2
test_nr_ulsim_sc_test3
test_nr_ulsim_sc_test4
test_nr_ulsim_sc_test5
test_nr_ulsim_mimo_test1
test_nr_ulsim_mimo_test2
test_nr_ulsim_mimo_test3
test_nr_ulsim_mimo_test4
test_nr_ulsim_mimo_test5
test_nr_ulsim_3gpp_test1
test_nr_ulsim_3gpp_test2
test_nr_ulsim_3gpp_test3
test_nr_ulsim_3gpp_test4
test_nr_ulsim_3gpp_test5
test_nr_ulsim_3gpp_test6
test_nr_ulsim_3gpp_test7
test_nr_ulsim_3gpp_test8
test_nr_ulsim_3gpp_test9
test_nr_ulsim_3gpp_test10
test_nr_ulsim_3gpp_test11
test_nr_ulsim_3gpp_test12
test_nr_ulsim_3gpp_test13
test_nr_ulsim_3gpp_test14
test_nr_ulsim_3gpp_test15
test_nr_ulsim_3gpp_test16
test_nr_ulsim_3gpp_test17
test_nr_ulsim_3gpp_test18
test_nr_ulsim_3gpp_test19
test_nr_ulsim_3gpp_test20
test_nr_ulsim_3gpp_test21
test_nr_ulsim_3gpp_test22
test_nr_ulsim_3gpp_test23
test_nr_ulsim_3gpp_test24
test_nr_ulsim_3gpp_test25
test_nr_ulsim_3gpp_test26
test_nr_ulsim_3gpp_test27
test_nr_ulsim_3gpp_test28
)
foreach(NR_ULSIM_OPTION_TO_TEST IN LISTS NR_ULSIM_OPTION_TO_TEST_LIST)
foreach(NR_ULSIM_TEST_CASE IN LISTS NR_ULSIM_TEST_CASE_OPTION_LIST)
add_test(
NAME ${NR_ULSIM_TEST_CASE}_${NR_ULSIM_OPTION_TO_TEST}
COMMAND nr_ulsim -P -C1 ${${NR_ULSIM_TEST_CASE}} ${${NR_ULSIM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
endforeach()
####################################################################################
###### nr_ulschsim unit test ######
####################################################################################
set(NR_ULSCHSIM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_ULSCHSIM_OPTION_TO_TEST_LIST
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_ULSCHSIM_OPTION_TO_TEST_LIST
xdma
)
endif()
set(test_nr_ulschsim_test1 "-R" "106" "-m9" "-s13" "-n100")
set(test_nr_ulschsim_test2 "-R" "217" "-m15" "-s15" "-n100")
set(test_nr_ulschsim_test3 "-R" "273" "-m19" "-s20" "-n100")
set(test_nr_ulschsim_test4 "-R" "106" "-m9" "-s13" "-n100" "-y4" "-z4" "-W4")
set(NR_ULSCHSIM_TEST_CASE_OPTION_LIST
test_nr_ulschsim_test1
test_nr_ulschsim_test2
test_nr_ulschsim_test3
test_nr_ulschsim_test4
)
foreach(NR_ULSCHSIM_OPTION_TO_TEST IN LISTS NR_ULSCHSIM_OPTION_TO_TEST_LIST)
foreach(NR_ULSCHSIM_TEST_CASE IN LISTS NR_ULSCHSIM_TEST_CASE_OPTION_LIST)
add_test(
NAME ${NR_ULSCHSIM_TEST_CASE}_${NR_ULSCHSIM_OPTION_TO_TEST}
COMMAND nr_ulschsim ${${NR_ULSCHSIM_TEST_CASE}} ${${NR_ULSCHSIM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
endforeach()
####################################################################################
###### nr_dlsim unit test ######
####################################################################################
set(t2_offload_nr_dlsim "-c" "-O" "${CMAKE_CURRENT_SOURCE_DIR}/t2_offload.conf")
set(NR_DLSIM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_DLSIM_OPTION_TO_TEST_LIST
t2_offload_nr_dlsim
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_DLSIM_OPTION_TO_TEST_LIST
xdma
)
endif()
set(test_nr_dlsim_basic_test1 "-n100" "-R106" "-b106" "-s5")
set(test_nr_dlsim_basic_test2 "-n100" "-R217" "-b217" "-s5")
set(test_nr_dlsim_basic_test3 "-n100" "-R273" "-b273" "-s5")
set(test_nr_dlsim_basic_test4 "-n100" "-s1" "-S2" "-t25")
set(test_nr_dlsim_basic_test5 "-n100" "-s1" "-S2" "-t33")
set(test_nr_dlsim_basic_test6 "-n100" "-s5" "-S7" "-t50")
set(test_nr_dlsim_basic_test7 "-n100" "-m0" "-e0" "-R25" "-b25" "-i" "2" "1" "0")
set(test_nr_dlsim_offset_test1 "-n100" "-R106" "-a25" "-s5")
set(test_nr_dlsim_offset_test2 "-n100" "-R106" "-a51" "-s5")
set(test_nr_dlsim_offset_test3 "-n100" "-R217" "-b100" "-s5")
set(test_nr_dlsim_offset_test4 "-n100" "-R217" "-a80" "-s5")
set(test_nr_dlsim_offset_test5 "-n100" "-R217" "-a110" "-s5" "-b100")
set(test_nr_dlsim_mcs_mimo_test1 "-n100" "-e27" "-s30")
set(test_nr_dlsim_mcs_mimo_test2 "-n100" "-e16" "-s11" "-S13")
set(test_nr_dlsim_mcs_mimo_test3 "-n100" "-q1" "-e26" "-s30")
set(test_nr_dlsim_mcs_mimo_test4 "-n100" "-e0 -t95" "-S-1.0" "-i" "2" "1" "0")
set(test_nr_dlsim_mcs_mimo_test5 "-n10" "-s20" "-U" "3" "0" "0" "2" "-gA" "-x1" "-y4" "-z4")
set(test_nr_dlsim_mcs_mimo_test6 "-n10" "-s20" "-U" "3" "0" "0" "2" "-gA" "-x2" "-y4" "-z4")
set(test_nr_dlsim_mcs_mimo_test7 "-n10" "-s20" "-U" "3" "0" "0" "2" "-x4" "-y4" "-z4")
set(test_nr_dlsim_dmrs_ptrs_test1 "-n100" "-s5" "-T" "2" "2" "2")
set(test_nr_dlsim_dmrs_ptrs_test2 "-n100" "-s5" "-T" "2" "1" "2")
set(test_nr_dlsim_dmrs_ptrs_test3 "-n100" "-s5" "-T" "2" "0" "4")
set(test_nr_dlsim_dmrs_ptrs_test4 "-n100" "-s5" "-S7" "-U" "2" "0" "1")
set(test_nr_dlsim_dmrs_ptrs_test5 "-n100" "-s5" "-S7" "-U" "2" "0" "2")
set(test_nr_dlsim_dmrs_ptrs_test6 "-n100" "-s5" "-S7" "-U" "2" "1" "3")
set(NR_DLSIM_TEST_CASE_OPTION_LIST
test_nr_dlsim_basic_test1
test_nr_dlsim_basic_test2
test_nr_dlsim_basic_test3
test_nr_dlsim_basic_test4
test_nr_dlsim_basic_test5
test_nr_dlsim_basic_test6
test_nr_dlsim_basic_test7
test_nr_dlsim_offset_test1
test_nr_dlsim_offset_test2
test_nr_dlsim_offset_test3
test_nr_dlsim_offset_test4
test_nr_dlsim_offset_test5
test_nr_dlsim_mcs_mimo_test1
test_nr_dlsim_mcs_mimo_test2
test_nr_dlsim_mcs_mimo_test3
test_nr_dlsim_mcs_mimo_test4
test_nr_dlsim_mcs_mimo_test5
test_nr_dlsim_mcs_mimo_test6
test_nr_dlsim_mcs_mimo_test7
test_nr_dlsim_dmrs_ptrs_test1
test_nr_dlsim_dmrs_ptrs_test2
test_nr_dlsim_dmrs_ptrs_test3
test_nr_dlsim_dmrs_ptrs_test4
test_nr_dlsim_dmrs_ptrs_test5
test_nr_dlsim_dmrs_ptrs_test6
)
foreach(NR_DLSIM_OPTION_TO_TEST IN LISTS NR_DLSIM_OPTION_TO_TEST_LIST)
foreach(NR_DLSIM_TEST_CASE IN LISTS NR_DLSIM_TEST_CASE_OPTION_LIST)
add_test(
NAME ${NR_DLSIM_TEST_CASE}_${NR_DLSIM_OPTION_TO_TEST}
COMMAND nr_dlsim -P ${${NR_DLSIM_TEST_CASE}} ${${NR_DLSIM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
set_property(
TEST ${NR_DLSIM_TEST_CASE}_${NR_DLSIM_OPTION_TO_TEST}
PROPERTY PASS_REGULAR_EXPRESSION "PDSCH test OK"
)
endforeach()
endforeach()
####################################################################################
###### nr_dlschsim unit test ######
####################################################################################
set(NR_DLSCHSIM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_DLSCHSIM_OPTION_TO_TEST_LIST
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_DLSCHSIM_OPTION_TO_TEST_LIST
xdma
)
endif()
set(test_nr_dlschsim_test1 "-R" "106" "-m9" "-s13" "-n100")
set(test_nr_dlschsim_test2 "-R" "217" "-m15" "-s15" "-n100")
set(test_nr_dlschsim_test3 "-R" "273" "-m19" "-s20" "-n100")
set(NR_DLSCHSIM_TEST_CASE_OPTION_LIST
test_nr_dlschsim_test1
test_nr_dlschsim_test2
test_nr_dlschsim_test3
)
foreach(NR_DLSCHSIM_OPTION_TO_TEST IN LISTS NR_DLSCHSIM_OPTION_TO_TEST_LIST)
foreach(NR_DLSCHSIM_TEST_CASE IN LISTS NR_DLSCHSIM_TEST_CASE_OPTION_LIST)
add_test(
NAME ${NR_DLSCHSIM_TEST_CASE}_${NR_DLSCHSIM_OPTION_TO_TEST}
COMMAND nr_dlschsim ${${NR_DLSCHSIM_TEST_CASE}} ${${NR_DLSCHSIM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
endforeach()
####################################################################################
###### nr-softmodem unit test ######
####################################################################################
set(default_ldpc "-O" "${CMAKE_CURRENT_SOURCE_DIR}/gnb.sa.band78.106prb.rfsim.2x2.conf")
set(slot_segment "-O" "${CMAKE_CURRENT_SOURCE_DIR}/gnb.sa.band78.106prb.rfsim.2x2.slot_segment.conf")
set(t2_offload "-O" "${CMAKE_CURRENT_SOURCE_DIR}/gnb.sa.band78.106prb.rfsim.2x2.t2_offload.conf" "--ldpc-offload-enable")
set(slot_t2 "-O" "${CMAKE_CURRENT_SOURCE_DIR}/gnb.sa.band78.106prb.rfsim.2x2.slot_t2.conf")
set(xdma "-O" "${CMAKE_CURRENT_SOURCE_DIR}/gnb.sa.band78.106prb.rfsim.2x2.xdma.conf")
set(NR_SOFTMODEM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_SOFTMODEM_OPTION_TO_TEST_LIST
t2_offload
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_SOFTMODEM_OPTION_TO_TEST_LIST
xdma
)
endif()
foreach(NR_SOFTMODEM_OPTION_TO_TEST IN LISTS NR_SOFTMODEM_OPTION_TO_TEST_LIST)
add_test(
NAME two_ues_rfsim_${NR_SOFTMODEM_OPTION_TO_TEST}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/two_ues_rfsim.sh ${${NR_SOFTMODEM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
####################################################################################
###### nr-uesoftmodem unit test ######
####################################################################################
set(default_ldpc "-O" "${CMAKE_CURRENT_SOURCE_DIR}/nrue.uicc.1.conf")
set(slot_segment "-O" "${CMAKE_CURRENT_SOURCE_DIR}/nrue.uicc.1.slot_segment.conf")
set(t2_offload "-O" "${CMAKE_CURRENT_SOURCE_DIR}/nrue.uicc.1.t2_offload.conf" "--ldpc-offload-enable")
set(slot_t2 "-O" "${CMAKE_CURRENT_SOURCE_DIR}/nrue.uicc.1.slot_t2.conf")
set(xdma "-O" "${CMAKE_CURRENT_SOURCE_DIR}/nrue.uicc.1.xdma.conf")
set(NR_UESOFTMODEM_OPTION_TO_TEST_LIST
default_ldpc
slot_segment
)
if (ENABLE_LDPC_T2)
list(APPEND NR_UESOFTMODEM_OPTION_TO_TEST_LIST
t2_offload
slot_t2
)
endif()
if (ENABLE_LDPC_XDMA)
list(APPEND NR_UESOFTMODEM_OPTION_TO_TEST_LIST
xdma
)
endif()
foreach(NR_UESOFTMODEM_OPTION_TO_TEST IN LISTS NR_UESOFTMODEM_OPTION_TO_TEST_LIST)
add_test(
NAME ue_coding_rfsim_${NR_UESOFTMODEM_OPTION_TO_TEST}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ue_coding_rfsim.sh ${${NR_UESOFTMODEM_OPTION_TO_TEST}}
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()

View File

@@ -0,0 +1,268 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};

View File

@@ -0,0 +1,274 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};
loader : {
ldpc : {
shlibversion : "_slot_segment";
};
};

View File

@@ -0,0 +1,279 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};
nrLDPC_coding_t2 : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};
loader : {
ldpc : {
shlibversion : "_slot_t2";
};
};

View File

@@ -0,0 +1,278 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -0,0 +1,273 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};
ldpc_offload : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};

View File

@@ -0,0 +1,278 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1 }) });
nr_cellid = 12345678L;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 1;
min_rxtxtime = 5;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68
absoluteFrequencySSB = 621312;
dl_frequencyBand = 78;
# this is 3300.60 MHz
dl_absoluteFrequencyPointA = 620040;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# 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 = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#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 = 4;
#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 = 3;
#oneHalf (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 = -70;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
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 = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# ------- 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.5";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
GNB_INTERFACE_NAME_FOR_NG_AMF = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51/22";
GNB_INTERFACE_NAME_FOR_NGU = "enp193s0f0";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51/22";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
#pusch_TargetSNRx10 = 150;
#pucch_TargetSNRx10 = 200;
dl_max_mcs = 16; # there are retransmissions if more
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 2
nb_rx = 2
att_tx = 0
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
eNB_instances = [0];
##beamforming 1x2 matrix: 1 layer x 2 antennas
bf_weights = [0x00007fff, 0x0000];
#clock_src = "internal";
sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator :
{
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
};
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 ="debug";
f1ap_log_level ="info";
};
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -0,0 +1,7 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}

View File

@@ -0,0 +1,13 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
loader : {
ldpc : {
shlibversion : "_slot_demo";
};
};

View File

@@ -0,0 +1,13 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
loader : {
ldpc : {
shlibversion : "_slot_segment";
};
};

View File

@@ -0,0 +1,18 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
nrLDPC_coding_t2 : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};
loader : {
ldpc : {
shlibversion : "_slot_t2";
};
};

View File

@@ -0,0 +1,17 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -0,0 +1,12 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
ldpc_offload : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};

View File

@@ -0,0 +1,17 @@
uicc0 = {
imsi = "208990100001132";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -0,0 +1,7 @@
uicc0 = {
imsi = "208990100001133";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai";
nssai_sst=1;
}

View File

@@ -0,0 +1,5 @@
loader : {
ldpc : {
shlibversion : "_slot_segment";
};
};

View File

@@ -0,0 +1,10 @@
nrLDPC_coding_t2 : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};
loader : {
ldpc : {
shlibversion : "_slot_t2";
};
};

View File

@@ -0,0 +1,9 @@
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -0,0 +1,4 @@
ldpc_offload : {
dpdk_dev : "41:00.0";
dpdk_core_list : "14-15";
};

View File

@@ -0,0 +1,92 @@
#!/bin/bash
create_namespace() {
local ue_id=$1
local name="ue$ue_id"
echo "creating namespace for UE ID ${ue_id} name ${name}"
ip netns add $name
ip link add v-eth$ue_id type veth peer name v-ue$ue_id
ip link set v-ue$ue_id netns $name
BASE_IP=$((200+ue_id))
ip addr add 10.$BASE_IP.1.100/24 dev v-eth$ue_id
ip link set v-eth$ue_id up
iptables -t nat -A POSTROUTING -s 10.$BASE_IP.1.0/255.255.255.0 -o lo -j MASQUERADE
iptables -A FORWARD -i lo -o v-eth$ue_id -j ACCEPT
iptables -A FORWARD -o lo -i v-eth$ue_id -j ACCEPT
ip netns exec $name ip link set dev lo up
ip netns exec $name ip addr add 10.$BASE_IP.1.$ue_id/24 dev v-ue$ue_id
ip netns exec $name ip link set v-ue$ue_id up
}
delete_namespace() {
local ue_id=$1
local name="ue$ue_id"
echo "deleting namespace for UE ID ${ue_id} name ${name}"
ip link delete v-eth$ue_id
ip netns delete $name
}
usage () {
echo "$1 <gnb_args>"
}
prog_name=$(basename $0)
if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root"; exit 1; fi
if [[ $# -eq 0 ]]; then echo "error: no parameters given"; usage $prog_name; exit 1; fi
# Write gNB arguments
GNB_ARGS=""
for arg in $@
do
GNB_ARGS="${GNB_ARGS} ${arg}"
done
# Launch gNB
./nr-softmodem --sa --rfsim --log_config.global_log_options level,nocolor,time$GNB_ARGS &
GNB_PID=$!
sleep 3
# Create 2 network namespaces
create_namespace 1
create_namespace 2
# Launch UE 1
ip netns exec ue1 ./nr-uesoftmodem --sa --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 2 --ue-nb-ant-rx 2 -O ../../../openair1/PHY/CODING/tests/nrue.uicc.1.conf --rfsimulator.serveraddr 10.201.1.100 &
UE1_PID=$!
sleep 3
# Launch UE 2
ip netns exec ue2 ./nr-uesoftmodem --sa --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 2 --ue-nb-ant-rx 2 -O ../../../openair1/PHY/CODING/tests/nrue.uicc.2.conf --rfsimulator.serveraddr 10.202.1.100 &
UE2_PID=$!
# Wait
sleep 9
# Test phase using ping
SUCCESS=0
ip netns exec ue1 ping -c 5 -i 0.1 -w 1 12.1.1.1
SUCCESS=$((${SUCCESS}+$?))
ip netns exec ue2 ping -c 5 -i 0.1 -w 1 12.1.1.1
SUCCESS=$((${SUCCESS}+$?))
# Stop UEs and gNB
# SIGINT
kill -2 ${UE1_PID}
kill -2 ${UE2_PID}
sleep 3
kill -2 ${GNB_PID}
sleep 3
# SIGKILL
kill -9 ${UE1_PID}
kill -9 ${UE2_PID}
kill -9 ${GNB_PID}
# Delete network namespaces
delete_namespace 1
delete_namespace 2
exit ${SUCCESS}

View File

@@ -0,0 +1,80 @@
#!/bin/bash
create_namespace() {
local ue_id=$1
local name="ue$ue_id"
echo "creating namespace for UE ID ${ue_id} name ${name}"
ip netns add $name
ip link add v-eth$ue_id type veth peer name v-ue$ue_id
ip link set v-ue$ue_id netns $name
BASE_IP=$((200+ue_id))
ip addr add 10.$BASE_IP.1.100/24 dev v-eth$ue_id
ip link set v-eth$ue_id up
iptables -t nat -A POSTROUTING -s 10.$BASE_IP.1.0/255.255.255.0 -o lo -j MASQUERADE
iptables -A FORWARD -i lo -o v-eth$ue_id -j ACCEPT
iptables -A FORWARD -o lo -i v-eth$ue_id -j ACCEPT
ip netns exec $name ip link set dev lo up
ip netns exec $name ip addr add 10.$BASE_IP.1.$ue_id/24 dev v-ue$ue_id
ip netns exec $name ip link set v-ue$ue_id up
}
delete_namespace() {
local ue_id=$1
local name="ue$ue_id"
echo "deleting namespace for UE ID ${ue_id} name ${name}"
ip link delete v-eth$ue_id
ip netns delete $name
}
usage () {
echo "$1 <ue_args>"
}
prog_name=$(basename $0)
if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root"; exit 1; fi
if [[ $# -eq 0 ]]; then echo "error: no parameters given"; usage $prog_name; exit 1; fi
# Launch gNB
./nr-softmodem --sa --rfsim --log_config.global_log_options level,nocolor,time -O ../../../openair1/PHY/CODING/tests/gnb.sa.band78.106prb.rfsim.2x2.conf &
GNB_PID=$!
sleep 3
# Create 1 network namespaces
create_namespace 1
# Write UE arguments
UE_ARGS=""
for arg in $@
do
UE_ARGS="${UE_ARGS} ${arg}"
done
# Launch UE 1
ip netns exec ue1 ./nr-uesoftmodem --sa --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 2 --ue-nb-ant-rx 2 --rfsimulator.serveraddr 10.201.1.100 $UE_ARGS &
UE1_PID=$!
# Wait
sleep 9
# Test phase using ping
SUCCESS=0
ip netns exec ue1 ping -c 5 -i 0.1 -w 1 12.1.1.1
SUCCESS=$((${SUCCESS}+$?))
# Stop UEs and gNB
# SIGINT
kill -2 ${UE1_PID}
sleep 3
kill -2 ${GNB_PID}
sleep 3
# SIGKILL
kill -9 ${UE1_PID}
kill -9 ${GNB_PID}
# Delete network namespaces
delete_namespace 1
exit ${SUCCESS}

View File

@@ -0,0 +1,9 @@
nrLDPC_coding_xdma : {
num_threads_prepare : 2;
};
loader : {
ldpc : {
shlibversion : "_xdma";
};
};

View File

@@ -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() {
@@ -102,6 +104,7 @@ 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};
nrLDPC_coding_interface_t nrLDPC_coding_interface = {0};
void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
{
@@ -138,15 +141,18 @@ 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);
gNB->nrLDPC_coding_interface_flag = 0;
int ret_loader = load_nrLDPC_coding_interface(NULL, &nrLDPC_coding_interface);
if (ret_loader >= 0) {
gNB->nrLDPC_coding_interface_flag = 1;
} else {
load_LDPClib(NULL, &ldpc_interface);
if (gNB->ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
}
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);

View File

@@ -49,7 +49,7 @@ static void nr_pdsch_codeword_scrambling(uint8_t *in, uint32_t size, uint8_t q,
nr_codeword_scrambling(in, size, q, Nid, n_RNTI, out);
}
void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
void nr_generate_pdsch_TB(processingData_L1tx_t *msgTx, int frame, int slot)
{
PHY_VARS_gNB *gNB = msgTx->gNB;
const int16_t amp = gNB->TX_AMP;
@@ -587,6 +587,603 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
}// dlsch loop
}
void nr_generate_pdsch_slot(processingData_L1tx_t *msgTx, int frame, int slot)
{
PHY_VARS_gNB *gNB = msgTx->gNB;
const int16_t amp = gNB->TX_AMP;
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
time_stats_t *dlsch_encoding_stats=&gNB->dlsch_encoding_stats;
time_stats_t *dlsch_scrambling_stats=&gNB->dlsch_scrambling_stats;
time_stats_t *dlsch_modulation_stats=&gNB->dlsch_modulation_stats;
time_stats_t *tinput=&gNB->tinput;
time_stats_t *tprep=&gNB->tprep;
time_stats_t *tparity=&gNB->tparity;
time_stats_t *toutput=&gNB->toutput;
time_stats_t *dlsch_rate_matching_stats=&gNB->dlsch_rate_matching_stats;
time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats;
time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats;
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_slot(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];
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB;
const int dmrs_Type = rel15->dmrsConfigType;
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
const int amp_dmrs = (int)((double)amp * sqrt(rel15->numDmrsCdmGrpsNoData)); // 3GPP TS 38.214 Section 4.1: Table 4.1-1
LOG_D(PHY,"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
rel15->BWPStart,rel15->BWPSize,rel15->rbStart,rel15->rbSize);
const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs;
const int dmrs_symbol_map = rel15->dlDmrsSymbPos; // single DMRS: 010000100 Double DMRS 110001100
const int xOverhead = 0;
const int nb_re =
(12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * rel15->rbSize * rel15->nrOfLayers;
const int Qm = rel15->qamModOrder[0];
const int encoded_length = nb_re * Qm;
/* 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;
#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]);
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[offset_output + (i<<3) + j]);
printf("\t");
}
printf("\n");
#endif
if (IS_SOFTMODEM_DLSIM)
memcpy(harq->f, &output[offset_output], encoded_length);
c16_t mod_symbs[rel15->NrOfCodewords][encoded_length];
for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
/// scrambling
start_meas(dlsch_scrambling_stats);
uint32_t scrambled_output[(encoded_length>>5)+4]; // modulator acces by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
if ( encoded_length > rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers) abort();
nr_pdsch_codeword_scrambling(&output[offset_output], encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
#ifdef DEBUG_DLSCH
printf("PDSCH scrambling:\n");
for (int i=0; i<encoded_length>>8; i++) {
for (int j=0; j<8; j++)
printf("0x%08x\t", scrambled_output[(i<<3)+j]);
printf("\n");
}
#endif
stop_meas(dlsch_scrambling_stats);
/// Modulation
start_meas(dlsch_modulation_stats);
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
stop_meas(dlsch_modulation_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
for (int i = 0; i < nb_re; i += 8) {
for (int j=0; j<8; j++) {
printf("%d %d\t", mod_symbs[codeWord][i + j].r, mod_symbs[codeWord][i + j].i);
}
printf("\n");
}
#endif
}
/// 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
*/
size_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
offset_output += (size_output_tb + 63 - ((size_output_tb + 63) % 64));
// 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)
start_sc -= frame_parms->ofdm_symbol_size;
const uint32_t txdataF_offset = slot * frame_parms->samples_per_slot_wCP;
c16_t txdataF_precoding[rel15->nrOfLayers][NR_NUMBER_OF_SYMBOLS_PER_SLOT][frame_parms->ofdm_symbol_size] __attribute__((aligned(64)));;
#ifdef DEBUG_DLSCH_MAPPING
printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n",
start_sc,
rel15->StartSymbolIndex,
rel15->rbSize,
nb_re,
rel15->nrOfLayers);
#endif
start_meas(&gNB->dlsch_resource_mapping_stats);
for (int layer = 0; layer < rel15->nrOfLayers; layer++) {
c16_t tx_layer[layerSz] __attribute__((aligned(64)));
nr_layer_mapping(rel15->NrOfCodewords, encoded_length, mod_symbs, rel15->nrOfLayers, layerSz, nb_re, tx_layer, layer);
int dmrs_port = get_dmrs_port(layer, rel15->dmrsPorts);
// DMRS params for this dmrs port
int Wt[2], Wf[2];
get_Wt(Wt, dmrs_port, dmrs_Type);
get_Wf(Wf, dmrs_port, dmrs_Type);
const int8_t delta = get_delta(dmrs_port, dmrs_Type);
int8_t l_prime = 0; // single symbol layer 0
int8_t l_overline = get_l0(rel15->dlDmrsSymbPos);
#ifdef DEBUG_DLSCH_MAPPING
uint8_t dmrs_symbol = l_overline + l_prime;
printf("DMRS Type %d params for layer %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
1 + dmrs_Type,
layer,
Wt[0],
Wt[1],
Wf[0],
Wf[1],
delta,
l_prime,
l_overline,
dmrs_symbol);
#endif
uint32_t cur_re = 0, dmrs_idx = 0;
AssertFatal(n_dmrs, "n_dmrs can't be 0\n");
c16_t mod_dmrs[n_dmrs] __attribute__((aligned(64)));
// Loop Over OFDM symbols:
for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) {
/// DMRS QPSK modulation
uint8_t k_prime = 0;
uint16_t n = 0;
if ((dmrs_symbol_map & (1 << l_symbol))) { // DMRS time occasion
// The reference point for is subcarrier 0 of the lowest-numbered resource block in CORESET 0 if the corresponding
// PDCCH is associated with CORESET 0 and Type0-PDCCH common search space and is addressed to SI-RNTI
// 3GPP TS 38.211 V15.8.0 Section 7.4.1.1.2 Mapping to physical resources
dmrs_idx = rel15->rbStart;
if (rel15->rnti != SI_RNTI)
dmrs_idx += rel15->BWPStart;
dmrs_idx *= dmrs_Type == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
if (l_symbol == (l_overline + 1)) // take into account the double DMRS symbols
l_prime = 1;
else if (l_symbol > (l_overline + 1)) { // new DMRS pair
l_overline = l_symbol;
l_prime = 0;
}
/// DMRS QPSK modulation
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
const uint32_t *gold =
nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER,
(int16_t *)mod_dmrs); // Qm = 2 as DMRS is QPSK modulated
#ifdef DEBUG_DLSCH
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
for (int i = 0; i < n_dmrs / 2; i += 8) {
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_dmrs[i + j].r, mod_dmrs[i + j].i);
}
printf("\n");
}
#endif
}
/* calculate if current symbol is PTRS symbols */
int ptrs_idx = 0;
int ptrs_symbol = 0;
c16_t mod_ptrs[max(n_ptrs, 1)] __attribute__((aligned(64))); //max only to please sanitizer, that kills if 0 even if it is not a error
if(rel15->pduBitmap & 0x1) {
ptrs_symbol = is_ptrs_symbol(l_symbol, dlPtrsSymPos);
if(ptrs_symbol) {
/* PTRS QPSK Modulation for each OFDM symbol in a slot */
LOG_D(PHY, "Doing ptrs modulation for symbol %d, n_ptrs %d\n", l_symbol, n_ptrs);
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
const uint32_t *gold =
nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
}
}
uint16_t k = start_sc;
if (ptrs_symbol || dmrs_symbol_map & (1 << l_symbol)) {
// Loop Over SCs:
for (int i=0; i<rel15->rbSize*NR_NB_SC_PER_RB; i++) {
/* check if cuurent RE is PTRS RE*/
uint8_t is_ptrs_re = 0;
/* check for PTRS symbol and set flag for PTRS RE */
if(ptrs_symbol){
is_ptrs_re = is_ptrs_subcarrier(k,
rel15->rnti,
rel15->PTRSFreqDensity,
rel15->rbSize,
rel15->PTRSReOffset,
start_sc,
frame_parms->ofdm_symbol_size);
}
/* Map DMRS Symbol */
if ((dmrs_symbol_map & (1 << l_symbol))
&& (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (frame_parms->ofdm_symbol_size)))) {
txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15);
#ifdef DEBUG_DLSCH_MAPPING
printf("dmrs_idx %u\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
dmrs_idx,
l_symbol,
k,
k_prime,
n,
txdataF_precoding[layer][l_symbol][k].r,
txdataF_precoding[layer][l_symbol][k].i);
#endif
dmrs_idx++;
k_prime++;
k_prime&=1;
n+=(k_prime)?0:1;
}
/* Map PTRS Symbol */
else if (is_ptrs_re) {
uint16_t beta_ptrs = 1;
txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15);
#ifdef DEBUG_DLSCH_MAPPING
printf("ptrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d, mod_ptrs: %d %d\n",
ptrs_idx,
l_symbol,
k,
k_prime,
n,
txdataF_precoding[layer][l_symbol][k].r,
txdataF_precoding[layer][l_symbol][k].i,
mod_ptrs[ptrs_idx].r,
mod_ptrs[ptrs_idx].i);
#endif
ptrs_idx++;
}
/* Map DATA Symbol */
else if (ptrs_symbol
|| allowed_xlsch_re_in_dmrs_symbol(k,
start_sc,
frame_parms->ofdm_symbol_size,
rel15->numDmrsCdmGrpsNoData,
dmrs_Type)) {
txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(tx_layer[cur_re], amp, 15);
#ifdef DEBUG_DLSCH_MAPPING
printf("re %u\t l %d \t k %d \t txdataF: %d %d\n",
cur_re,
l_symbol,
k,
txdataF_precoding[layer][l_symbol][k].r,
txdataF_precoding[layer][l_symbol][k].i);
#endif
cur_re++;
}
/* mute RE */
else {
txdataF_precoding[layer][l_symbol][k] = (c16_t){0};
}
if (++k >= frame_parms->ofdm_symbol_size)
k -= frame_parms->ofdm_symbol_size;
} //RE loop
} else { // no PTRS or DMRS in this symbol
// Loop Over SCs:
int upper_limit=rel15->rbSize*NR_NB_SC_PER_RB;
int remaining_re = 0;
if (start_sc + upper_limit > frame_parms->ofdm_symbol_size) {
remaining_re = upper_limit + start_sc - frame_parms->ofdm_symbol_size;
upper_limit = frame_parms->ofdm_symbol_size - start_sc;
}
// fix the alignment issues later, use 64-bit SIMD below instead of 128.
// can be made with loadu/storeu
if (0/*(frame_parms->N_RB_DL&1)==0*/) {
simde__m128i *txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol][start_sc];
simde__m128i *txl = (simde__m128i *)&tx_layer[cur_re];
simde__m128i amp128=simde_mm_set1_epi16(amp);
for (int i=0; i<(upper_limit>>2); i++) {
txF[i] = simde_mm_mulhrs_epi16(amp128,txl[i]);
} //RE loop, first part
cur_re += upper_limit;
if (remaining_re > 0) {
txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol];
txl = (simde__m128i *)&tx_layer[cur_re];
for (int i = 0; i < (remaining_re >> 2); i++) {
txF[i] = simde_mm_mulhrs_epi16(amp128, txl[i]);
}
}
}
else {
simde__m128i *txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol][start_sc];
simde__m128i *txl = (simde__m128i *)&tx_layer[cur_re];
simde__m128i amp64 = simde_mm_set1_epi16(amp);
int i;
for (i = 0; i < (upper_limit >> 2); i++) {
const simde__m128i txL = simde_mm_loadu_si128(txl + i);
simde_mm_storeu_si128(txF + i, simde_mm_mulhrs_epi16(amp64, txL));
#ifdef DEBUG_DLSCH_MAPPING
for (int j = 0; j < 4; j++)
printf("re %u\t l %d \t k %d \t txdataF: %d %d\n",
cur_re + 4 * i + j,
l_symbol,
start_sc + 4 * i + j,
txdataF_precoding[layer][l_symbol][start_sc + 4 * i + j].r,
txdataF_precoding[layer][l_symbol][start_sc + 4 * i + j].i);
#endif
/* handle this, mute RE */
/*else {
txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) ] = 0;
txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
}*/
}
if (i * 4 != upper_limit) {
c16_t *txFc = &txdataF_precoding[layer][l_symbol][start_sc];
c16_t *txlc = &tx_layer[cur_re];
for (i = (upper_limit >> 2) << 2; i < upper_limit; i++) {
txFc[i].r = (((txlc[i].r * amp) >> 14) + 1) >> 1;
txFc[i].i = (((txlc[i].i * amp) >> 14) + 1) >> 1;
#ifdef DEBUG_DLSCH_MAPPING
printf("re %u\t l %d \t k %d \t txdataF: %d %d\n", cur_re + i, l_symbol, start_sc + i, txFc[i].r, txFc[i].i);
#endif
}
}
cur_re += upper_limit;
if (remaining_re > 0) {
txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol];
txl = (simde__m128i *)&tx_layer[cur_re];
int i;
for (i = 0; i < (remaining_re >> 2); i++) {
const simde__m128i txL = simde_mm_loadu_si128(txl + i);
simde_mm_storeu_si128(txF + i, simde_mm_mulhrs_epi16(amp64, txL));
#ifdef DEBUG_DLSCH_MAPPING
for (int j = 0; j < 4; j++)
printf("re %u\t l %d \t k %d \t txdataF: %d %d\n",
cure-re + 4 * i + j,
l_symbol,
4 * i + j,
txdataF_precoding[layer][l_symbol][4 * i + j].r,
txdataF_precoding[layer][l_symbol][4 * i + j].i);
#endif
/* handle this, mute RE */
/*else {
txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) ] = 0;
txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
}*/
} // RE loop, second part
if (i * 4 != remaining_re) {
c16_t *txFc = txdataF_precoding[layer][l_symbol];
c16_t *txlc = &tx_layer[cur_re];
for (i = (remaining_re >> 2) << 2; i < remaining_re; i++) {
txFc[i].r = (((txlc[i].r * amp) >> 14) + 1) >> 1;
txFc[i].i = (((txlc[i].i * amp) >> 14) + 1) >> 1;
#ifdef DEBUG_DLSCH_MAPPING
printf("re %u\t l %d \t k %d \t txdataF: %d %d\n", cur_re + i, l_symbol, i, txFc[i].r, txFc[i].i);
#endif
}
}
} // remaining_re > 0
cur_re += remaining_re;
} // N_RB_DL even
} // no DMRS/PTRS in symbol
} // symbol loop
} // layer loop
stop_meas(&gNB->dlsch_resource_mapping_stats);
///Layer Precoding and Antenna port mapping
// tx_layers 1-8 are mapped on antenna ports 1000-1007
// 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:
// The Codebook Type I
start_meas(&gNB->dlsch_precoding_stats);
nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming;
// beam number in multi-beam scenario (concurrent beams)
int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
&gNB->common_vars,
slot,
frame_parms->symbols_per_slot,
rel15->StartSymbolIndex,
rel15->NrOfSymbols);
c16_t **txdataF = gNB->common_vars.txdataF[beam_nb];
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) {
uint16_t subCarrier = start_sc;
const size_t txdataF_offset_per_symbol = l_symbol * frame_parms->ofdm_symbol_size + txdataF_offset;
int rb = 0;
while(rb < rel15->rbSize) {
//get pmi info
const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0;
const int pmi2 = (rb < (rel15->rbSize - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb+1)/pb->prg_size].pm_idx) : -1;
// If pmi of next RB and pmi of current RB are the same, we do 2 RB in a row
// if pmi differs, or current rb is the end (rel15->rbSize - 1), than we do 1 RB in a row
const int rb_step = pmi == pmi2 ? 2 : 1;
const int re_cnt = NR_NB_SC_PER_RB * rb_step;
if (pmi == 0) {//unitary Precoding
if (subCarrier + re_cnt <= frame_parms->ofdm_symbol_size) { // RB does not cross DC
if (ant < rel15->nrOfLayers)
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][l_symbol][subCarrier],
re_cnt * sizeof(**txdataF));
else
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
0,
re_cnt * sizeof(**txdataF));
} else { // RB does cross DC
const int neg_length = frame_parms->ofdm_symbol_size - subCarrier;
const int pos_length = re_cnt - neg_length;
if (ant < rel15->nrOfLayers) {
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][l_symbol][subCarrier],
neg_length * sizeof(**txdataF));
memcpy(&txdataF[ant][txdataF_offset_per_symbol],
&txdataF_precoding[ant][l_symbol],
pos_length * sizeof(**txdataF));
} else {
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
0,
neg_length * sizeof(**txdataF));
memset(&txdataF[ant][txdataF_offset_per_symbol],
0,
pos_length * sizeof(**txdataF));
}
}
subCarrier += re_cnt;
if (subCarrier >= frame_parms->ofdm_symbol_size) {
subCarrier -= frame_parms->ofdm_symbol_size;
}
}
else { // non-unitary Precoding
AssertFatal(frame_parms->nb_antennas_tx > 1, "No precoding can be done with a single antenna port\n");
//get the precoding matrix weights:
nfapi_nr_pm_pdu_t *pmi_pdu = &gNB->gNB_config.pmi_list.pmi_pdu[pmi - 1]; // pmi 0 is identity matrix
AssertFatal(pmi == pmi_pdu->pm_idx, "PMI %d doesn't match to the one in precoding matrix %d\n",
pmi, pmi_pdu->pm_idx);
AssertFatal(ant < pmi_pdu->num_ant_ports, "Antenna port index %d exceeds precoding matrix AP size %d\n",
ant, pmi_pdu->num_ant_ports);
AssertFatal(rel15->nrOfLayers == pmi_pdu->numLayers, "Number of layers %d doesn't match to the one in precoding matrix %d\n",
rel15->nrOfLayers, pmi_pdu->numLayers);
if ((subCarrier + re_cnt) < frame_parms->ofdm_symbol_size){ // within ofdm_symbol_size, use SIMDe
nr_layer_precoder_simd(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
ant,
pmi_pdu,
l_symbol,
subCarrier,
re_cnt,
&txdataF[ant][txdataF_offset_per_symbol]);
subCarrier += re_cnt;
} else { // crossing ofdm_symbol_size, use simple arithmetic operations
for (int i = 0; i < re_cnt; i++) {
txdataF[ant][txdataF_offset_per_symbol + subCarrier] =
nr_layer_precoder_cm(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
ant,
pmi_pdu,
l_symbol,
subCarrier);
#ifdef DEBUG_DLSCH_MAPPING
printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n",
ant,
l_symbol,
subCarrier,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].r,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].i);
#endif
if (++subCarrier >= frame_parms->ofdm_symbol_size) {
subCarrier -= frame_parms->ofdm_symbol_size;
}
}
} // else{ // crossing ofdm_symbol_size, use simple arithmetic operations
} // else { // non-unitary Precoding
rb += rb_step;
} // RB loop: while(rb < rel15->rbSize)
} // symbol loop
} // port loop
stop_meas(&gNB->dlsch_precoding_stats);
}// dlsch loop
}
void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
{
PHY_VARS_gNB *gNB = msgTx->gNB;
if(gNB->nrLDPC_coding_interface_flag)
return nr_generate_pdsch_slot(msgTx, frame, slot);
else
return nr_generate_pdsch_TB(msgTx, frame, slot);
}
void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB) {
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
NR_gNB_PHY_STATS_t *stats = &gNB->phy_stats[i];
@@ -601,3 +1198,4 @@ void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB) {
}
}
}

View File

@@ -57,6 +57,20 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats);
int nr_dlsch_encoding_slot(PHY_VARS_gNB *gNB,
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);
void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB);

View File

@@ -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.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/NR_TRANSPORT/nr_dlsch_coding_slot.c
* \brief Top-level routines for implementing LDPC-coded (DLSCH) transport channels from 38-212, 15.2
*/
#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 <syscall.h>
#include <openair2/UTIL/OPT/opt.h>
//#define DEBUG_DLSCH_CODING
//#define DEBUG_DLSCH_FREE 1
int nr_dlsch_encoding_slot(PHY_VARS_gNB *gNB,
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)
{
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN);
nrLDPC_slot_encoding_parameters_t nrLDPC_slot_encoding_parameters;
nrLDPC_slot_encoding_parameters.frame = frame;
nrLDPC_slot_encoding_parameters.slot = slot;
nrLDPC_slot_encoding_parameters.nb_TBs = msgTx->num_pdsch_slot;
//nrLDPC_slot_encoding_parameters.respEncode = &gNB->respEncode;
nrLDPC_slot_encoding_parameters.threadPool = &gNB->threadPool;
nrLDPC_slot_encoding_parameters.tinput = tinput;
nrLDPC_slot_encoding_parameters.tprep = tprep;
nrLDPC_slot_encoding_parameters.tparity = tparity;
nrLDPC_slot_encoding_parameters.toutput = toutput;
nrLDPC_TB_encoding_parameters_t TBs[msgTx->num_pdsch_slot];
nrLDPC_slot_encoding_parameters.TBs = TBs;
int num_segments = 0;
for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
unsigned int crc=1;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
uint32_t A = rel15->TBSize[0]<<3;
unsigned char *a=harq->pdu;
if (rel15->rnti != SI_RNTI) {
ws_trace_t tmp = {.nr = true,
.direction = DIRECTION_DOWNLINK,
.pdu_buffer = a,
.pdu_buffer_size = rel15->TBSize[0],
.ueid = 0,
.rntiType = WS_C_RNTI,
.rnti = rel15->rnti,
.sysFrame = frame,
.subframe = slot,
.harq_pid = 0, // difficult to find the harq pid here
.oob_event = 0,
.oob_event_value = 0};
trace_pdu(&tmp);
}
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 nrLDPC_TB_encoding_parameters;
nrLDPC_TB_encoding_parameters.xlsch_id = dlsch_id;
nrLDPC_TB_encoding_parameters.BG = rel15->maintenance_parms_v3.ldpcBaseGraph;
nrLDPC_TB_encoding_parameters.Z = harq->Z;
nrLDPC_TB_encoding_parameters.A = A;
start_meas(dlsch_segmentation_stats);
nrLDPC_TB_encoding_parameters.Kb = nr_segmentation(harq->b,
harq->c,
B,
&nrLDPC_TB_encoding_parameters.C,
&nrLDPC_TB_encoding_parameters.K,
&nrLDPC_TB_encoding_parameters.Z,
&nrLDPC_TB_encoding_parameters.F,
nrLDPC_TB_encoding_parameters.BG);
stop_meas(dlsch_segmentation_stats);
if (nrLDPC_TB_encoding_parameters.C>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", nrLDPC_TB_encoding_parameters.C, B);
return(-1);
}
num_segments += nrLDPC_TB_encoding_parameters.C;
TBs[dlsch_id] = nrLDPC_TB_encoding_parameters;
}
nrLDPC_segment_encoding_parameters_t segments[num_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 nrLDPC_TB_encoding_parameters = TBs[dlsch_id];
nrLDPC_TB_encoding_parameters.segments = &segments[segments_offset];
for (int r = 0; r < nrLDPC_TB_encoding_parameters.C; r++) {
nrLDPC_TB_encoding_parameters.segments[r].c = harq->c[r];
#ifdef DEBUG_DLSCH_CODING
LOG_D(PHY, "Encoder: B %d F %d \n", harq->B, nrLDPC_TB_encoding_parameters.F);
LOG_D(PHY, "start ldpc encoder segment %d/%d\n", r, nrLDPC_TB_encoding_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 * (nrLDPC_TB_encoding_parameters.Z) / 8; cnt++) {
LOG_D(PHY, "%d ", harq->c[r][cnt]);
}
LOG_D(PHY, "\n");
#endif
}
nrLDPC_TB_encoding_parameters.rnti = rel15->rnti;
nrLDPC_TB_encoding_parameters.nb_rb = rel15->rbSize;
nrLDPC_TB_encoding_parameters.Qm = rel15->qamModOrder[0];
nrLDPC_TB_encoding_parameters.mcs = rel15->mcsIndex[0];
nrLDPC_TB_encoding_parameters.nb_layers = rel15->nrOfLayers;
nrLDPC_TB_encoding_parameters.rv_index = rel15->rvIndex[0];
int nb_re_dmrs =
(rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData);
nrLDPC_TB_encoding_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);
nrLDPC_TB_encoding_parameters.tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
size_t r_offset = 0;
for (int r = 0; r < nrLDPC_TB_encoding_parameters.C; r++) {
nrLDPC_TB_encoding_parameters.segments[r].E = nr_get_E(nrLDPC_TB_encoding_parameters.G,
nrLDPC_TB_encoding_parameters.C,
nrLDPC_TB_encoding_parameters.Qm,
rel15->nrOfLayers,
r);
nrLDPC_TB_encoding_parameters.segments[r].output = &output[dlsch_offset + r_offset];
r_offset += nrLDPC_TB_encoding_parameters.segments[r].E;
reset_meas(&nrLDPC_TB_encoding_parameters.segments[r].ts_interleave);
reset_meas(&nrLDPC_TB_encoding_parameters.segments[r].ts_rate_match);
reset_meas(&nrLDPC_TB_encoding_parameters.segments[r].ts_ldpc_encode);
}
TBs[dlsch_id] = nrLDPC_TB_encoding_parameters;
segments_offset += nrLDPC_TB_encoding_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));
}
notifiedFIFO_t nf;
initNotifiedFIFO(&nf);
nrLDPC_slot_encoding_parameters.respEncode = &nf;
int nbJobs = nrLDPC_coding_interface.nrLDPC_coding_encoder(&nrLDPC_slot_encoding_parameters);
if (nbJobs < 0)
return -1;
while (nbJobs) {
notifiedFIFO_elt_t *req = pullTpool(&nf, &gNB->threadPool);
if (req == NULL)
break; // Tpool has been stopped
delNotifiedFIFO_elt(req);
nbJobs--;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_OUT);
return 0;
}

View File

@@ -64,6 +64,24 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
uint8_t harq_pid,
uint32_t G);
/*! \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 frame_parms, Pointer to frame descriptor structure
@param frame, current received frame
@param nr_tti_rx, current received TTI
@param G
@param ULSCH_ids, array of ULSCH ids
@param nb_pusch, number of uplink shared channels
*/
int nr_ulsch_decoding_slot(PHY_VARS_gNB *phy_vars_gNB,
NR_DL_FRAME_PARMS *frame_parms,
uint32_t frame,
uint8_t nr_tti_rx,
uint32_t *G,
uint8_t *ULSCH_ids,
int nb_pusch);
/*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1
@param llr, Pointer to llr bits
@param size, length of llr bits

View File

@@ -0,0 +1,264 @@
/*
* 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/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
*/
// [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 <syscall.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;
int nr_ulsch_decoding_slot(PHY_VARS_gNB *phy_vars_gNB,
NR_DL_FRAME_PARMS *frame_parms,
uint32_t frame,
uint8_t nr_tti_rx,
uint32_t *G,
uint8_t *ULSCH_ids,
int nb_pusch)
{
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING, 1);
nrLDPC_slot_decoding_parameters_t nrLDPC_slot_decoding_parameters;
nrLDPC_slot_decoding_parameters.frame = frame;
nrLDPC_slot_decoding_parameters.slot = nr_tti_rx;
nrLDPC_slot_decoding_parameters.nb_TBs = nb_pusch;
nrLDPC_slot_decoding_parameters.threadPool = &phy_vars_gNB->threadPool;
nrLDPC_slot_decoding_parameters.respDecode = &phy_vars_gNB->respDecode;
nrLDPC_TB_decoding_parameters_t TBs[nb_pusch];
nrLDPC_slot_decoding_parameters.TBs = TBs;
int max_num_segments = 0;
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 = &phy_vars_gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu;
nrLDPC_TB_decoding_parameters_t nrLDPC_TB_decoding_parameters;
nrLDPC_TB_decoding_parameters.G = G[pusch_id];
if (!harq_process) {
LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n");
return -1;
}
nrLDPC_TB_decoding_parameters.xlsch_id = ULSCH_id;
// ------------------------------------------------------------------
nrLDPC_TB_decoding_parameters.nb_rb = pusch_pdu->rb_size;
nrLDPC_TB_decoding_parameters.Qm = pusch_pdu->qam_mod_order;
nrLDPC_TB_decoding_parameters.mcs = pusch_pdu->mcs_index;
nrLDPC_TB_decoding_parameters.nb_layers = pusch_pdu->nrOfLayers;
// ------------------------------------------------------------------
nrLDPC_TB_decoding_parameters.processedSegments = &harq_process->processedSegments;
harq_process->TBS = pusch_pdu->pusch_data.tb_size;
nrLDPC_TB_decoding_parameters.BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph;
nrLDPC_TB_decoding_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 = nrLDPC_TB_decoding_parameters.Qm;
stats->ulsch_stats.current_RI = nrLDPC_TB_decoding_parameters.nb_layers;
stats->ulsch_stats.total_bytes_tx += harq_process->TBS;
}
}
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,
nrLDPC_TB_decoding_parameters.A,
nrLDPC_TB_decoding_parameters.G,
nrLDPC_TB_decoding_parameters.mcs,
nrLDPC_TB_decoding_parameters.nb_layers,
nrLDPC_TB_decoding_parameters.nb_rb,
nrLDPC_TB_decoding_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, nrLDPC_TB_decoding_parameters.A), // size in case of 1 segment
&nrLDPC_TB_decoding_parameters.C,
&nrLDPC_TB_decoding_parameters.K,
&nrLDPC_TB_decoding_parameters.Z, // [hna] Z is Zc
&nrLDPC_TB_decoding_parameters.F,
nrLDPC_TB_decoding_parameters.BG);
harq_process->C = nrLDPC_TB_decoding_parameters.C;
harq_process->K = nrLDPC_TB_decoding_parameters.K;
harq_process->Z = nrLDPC_TB_decoding_parameters.Z;
harq_process->F = nrLDPC_TB_decoding_parameters.F;
uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * nrLDPC_TB_decoding_parameters.nb_layers; // number of segments to be allocated
if (nrLDPC_TB_decoding_parameters.C > a_segments) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, nrLDPC_TB_decoding_parameters.A);
return(-1);
}
if (nrLDPC_TB_decoding_parameters.nb_rb != 273) {
a_segments = a_segments*nrLDPC_TB_decoding_parameters.nb_rb;
a_segments = a_segments/273 +1;
}
if (nrLDPC_TB_decoding_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, nrLDPC_TB_decoding_parameters.C);
#ifdef DEBUG_ULSCH_DECODING
printf("ulsch decoding nr segmentation Z %d\n", nrLDPC_TB_decoding_parameters.Z);
if (!frame % 100)
printf("K %d C %d Z %d \n",
nrLDPC_TB_decoding_parameters.K,
nrLDPC_TB_decoding_parameters.C,
nrLDPC_TB_decoding_parameters.Z);
printf("Segmentation: C %d, K %d\n",
nrLDPC_TB_decoding_parameters.C,
nrLDPC_TB_decoding_parameters.K);
#endif
nrLDPC_TB_decoding_parameters.rnti = ulsch->rnti;
nrLDPC_TB_decoding_parameters.max_ldpc_iterations = ulsch->max_ldpc_iterations;
nrLDPC_TB_decoding_parameters.rv_index = pusch_pdu->pusch_data.rv_index;
nrLDPC_TB_decoding_parameters.tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes;
nrLDPC_TB_decoding_parameters.abort_decode = &harq_process->abort_decode;
set_abort(&harq_process->abort_decode, false);
TBs[pusch_id] = nrLDPC_TB_decoding_parameters;
}
nrLDPC_segment_decoding_parameters_t segments[nb_pusch][max_num_segments];
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;
nrLDPC_TB_decoding_parameters_t nrLDPC_TB_decoding_parameters = TBs[pusch_id];
nrLDPC_TB_decoding_parameters.segments = segments[pusch_id];
uint32_t r_offset = 0;
for (int r = 0; r < nrLDPC_TB_decoding_parameters.C; r++) {
nrLDPC_segment_decoding_parameters_t nrLDPC_segment_decoding_parameters;
nrLDPC_segment_decoding_parameters.E = nr_get_E(nrLDPC_TB_decoding_parameters.G,
nrLDPC_TB_decoding_parameters.C,
nrLDPC_TB_decoding_parameters.Qm,
nrLDPC_TB_decoding_parameters.nb_layers,
r);
nrLDPC_segment_decoding_parameters.R = nr_get_R_ldpc_decoder(nrLDPC_TB_decoding_parameters.rv_index,
nrLDPC_segment_decoding_parameters.E,
nrLDPC_TB_decoding_parameters.BG,
nrLDPC_TB_decoding_parameters.Z,
&harq_process->llrLen,
harq_process->round);
nrLDPC_segment_decoding_parameters.llr = ulsch_llr + r_offset;
nrLDPC_segment_decoding_parameters.d = harq_process->d[r];
nrLDPC_segment_decoding_parameters.d_to_be_cleared = &harq_process->d_to_be_cleared[r];
nrLDPC_segment_decoding_parameters.c = harq_process->c[r];
nrLDPC_segment_decoding_parameters.decodeSuccess = false;
reset_meas(&nrLDPC_segment_decoding_parameters.ts_deinterleave);
reset_meas(&nrLDPC_segment_decoding_parameters.ts_rate_unmatch);
reset_meas(&nrLDPC_segment_decoding_parameters.ts_ldpc_decode);
nrLDPC_TB_decoding_parameters.segments[r] = nrLDPC_segment_decoding_parameters;
r_offset += nrLDPC_segment_decoding_parameters.E;
}
if (harq_process->harq_to_be_cleared) {
for (int r = 0; r < nrLDPC_TB_decoding_parameters.C; r++) {
harq_process->d_to_be_cleared[r] = true;
}
harq_process->harq_to_be_cleared = false;
}
TBs[pusch_id] = nrLDPC_TB_decoding_parameters;
}
int ret_decoder = nrLDPC_coding_interface.nrLDPC_coding_decoder(&nrLDPC_slot_decoding_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 nrLDPC_TB_decoding_parameters = TBs[pusch_id];
uint32_t offset = 0;
for (int r = 0; r < nrLDPC_TB_decoding_parameters.C; r++) {
nrLDPC_segment_decoding_parameters_t nrLDPC_segment_decoding_parameters = nrLDPC_TB_decoding_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;
}

View File

@@ -0,0 +1,336 @@
/*
* 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/NR_UE_TRANSPORT/nr_dlsch_decoding_slot.c
*/
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "PHY/defs_nr_UE.h"
#include "SCHED_NR_UE/harq_nr.h"
#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"
#include "executables/nr-uesoftmodem.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "common/utils/nr/nr_common.h"
#include "openair1/PHY/TOOLS/phy_scope_interface.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
static extended_kpi_ue kpiStructure = {0};
/*! \brief Prepare necessary parameters for nrLDPC_coding_interface
*/
uint32_t nr_dlsch_decoding_slot(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)
{
notifiedFIFO_t nf;
initNotifiedFIFO(&nf);
nrLDPC_slot_decoding_parameters_t slot_decoding_params;
slot_decoding_params.frame = proc->frame_rx;
slot_decoding_params.slot = proc->nr_slot_rx;
slot_decoding_params.nb_TBs = nb_dlsch;
slot_decoding_params.threadPool = &get_nrUE_params()->Tpool;
slot_decoding_params.respDecode = &nf;
nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch];
slot_decoding_params.TBs = TBs;
int max_num_segments = 0;
for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) {
uint8_t DLSCH_id = DLSCH_ids[pdsch_id];
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
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];
uint8_t dmrs_Type = dlsch_config->dmrsConfigType;
AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type);
uint8_t nb_re_dmrs;
phy_vars_ue->dl_stats[harq_process->DLround]++;
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_decoding_params = &TBs[pdsch_id];
TB_decoding_params->xlsch_id = DLSCH_id;
// ------------------------------------------------------------------
TB_decoding_params->G = G[DLSCH_id];
TB_decoding_params->nb_rb = dlsch_config->number_rbs;
TB_decoding_params->Qm = dlsch_config->qamModOrder;
TB_decoding_params->mcs = dlsch_config->mcs;
TB_decoding_params->nb_layers = dlsch[DLSCH_id].Nl;
TB_decoding_params->BG = dlsch_config->ldpcBaseGraph;
TB_decoding_params->A = dlsch_config->TBS;
// ------------------------------------------------------------------
TB_decoding_params->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_decoding_params.frame,
slot_decoding_params.slot,
DLSCH_id,
harq_pid,
dlsch_config->TBS,
TB_decoding_params->G,
nb_re_dmrs,
dmrs_length,
TB_decoding_params->mcs,
TB_decoding_params->nb_layers,
dlsch_config->number_symbols,
TB_decoding_params->nb_rb,
TB_decoding_params->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_decoding_params->A), // We give a max size in case of 1 segment
&TB_decoding_params->C,
&TB_decoding_params->K,
&TB_decoding_params->Z, // [hna] Z is Zc
&TB_decoding_params->F,
TB_decoding_params->BG);
harq_process->C = TB_decoding_params->C;
harq_process->K = TB_decoding_params->K;
harq_process->Z = TB_decoding_params->Z;
harq_process->F = TB_decoding_params->F;
if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * TB_decoding_params->nb_layers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_decoding_params->A);
return dlsch[DLSCH_id].max_ldpc_iterations + 1;
}
if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!slot_decoding_params.frame % 100))
LOG_I(PHY, "K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, TB_decoding_params->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_decoding_params->C = harq_process->C;
TB_decoding_params->K = harq_process->K;
TB_decoding_params->Z = harq_process->Z;
TB_decoding_params->F = harq_process->F;
}
max_num_segments = max(max_num_segments, TB_decoding_params->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_decoding_params->rnti = dlsch[DLSCH_id].rnti;
TB_decoding_params->max_ldpc_iterations = dlsch[DLSCH_id].max_ldpc_iterations;
TB_decoding_params->rv_index = dlsch_config->rv;
TB_decoding_params->tbslbrm = dlsch_config->tbslbrm;
TB_decoding_params->abort_decode = &harq_process->abort_decode;
set_abort(&harq_process->abort_decode, false);
}
nrLDPC_segment_decoding_parameters_t segments[nb_dlsch][max_num_segments];
bool d_to_be_cleared[nb_dlsch][max_num_segments];
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_decoding_params = &TBs[pdsch_id];
TB_decoding_params->segments = segments[pdsch_id];
uint32_t r_offset = 0;
for (int r = 0; r < TB_decoding_params->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_decoding_params = &TB_decoding_params->segments[r];
segment_decoding_params->E =
nr_get_E(TB_decoding_params->G, TB_decoding_params->C, TB_decoding_params->Qm, TB_decoding_params->nb_layers, r);
segment_decoding_params->R = nr_get_R_ldpc_decoder(TB_decoding_params->rv_index,
segment_decoding_params->E,
TB_decoding_params->BG,
TB_decoding_params->Z,
&harq_process->llrLen,
harq_process->DLround);
segment_decoding_params->llr = dlsch_llr[DLSCH_id] + r_offset;
segment_decoding_params->d = harq_process->d[r];
segment_decoding_params->d_to_be_cleared = &d_to_be_cleared[pdsch_id][r];
segment_decoding_params->c = harq_process->c[r];
segment_decoding_params->decodeSuccess = false;
reset_meas(&segment_decoding_params->ts_deinterleave);
reset_meas(&segment_decoding_params->ts_rate_unmatch);
reset_meas(&segment_decoding_params->ts_ldpc_decode);
r_offset += segment_decoding_params->E;
}
}
int number_tasks_decode = nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_decoding_params);
// Execute thread pool tasks if any
while (number_tasks_decode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&nf, &get_nrUE_params()->Tpool);
if (req == NULL)
return dlsch[0].last_iteration_cnt; // Tpool has been stopped
delNotifiedFIFO_elt(req);
number_tasks_decode--;
}
// 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_decoding_params = &TBs[pdsch_id];
uint32_t offset = 0;
for (int r = 0; r < TB_decoding_params->C; r++) {
nrLDPC_segment_decoding_parameters_t *segment_decoding_params = &TB_decoding_params->segments[r];
if (segment_decoding_params->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 {
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_decoding_params->ts_deinterleave);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &segment_decoding_params->ts_rate_unmatch);
merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &segment_decoding_params->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,
" 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) {
// 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;
}
}
}
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;
}
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);
}
return dlsch[0].last_iteration_cnt;
}

View File

@@ -65,29 +65,29 @@ 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
/** \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
computes the segmentation information, followed by rate dematching and sub-block deinterleaving 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
LDPC decoding algorithm for each segment and 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] eNB_id
@param[in] dlsch_llr Pointer to LLR values computed by dlsch_demodulation
@param[in] frame_parms Pointer to frame descriptor
@param[in] dlsch Pointer to DLSCH descriptor
@param[in] harq_process
@param[in] frame Frame number
@param[in] nb_symb_sch
@param[in] nr_slot_rx Slot number
@param[in] harq_pid
@param[in] b_size
@param[in] b
@param[in] G
@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,
@@ -103,6 +103,44 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
uint8_t b[b_size],
int G);
/** \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_slot(PHY_VARS_NR_UE *phy_vars_ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t *dlsch,
short **dlsch_llr,
uint8_t **b,
int *G,
int nb_dlsch,
uint8_t *DLSCH_ids);
/** \brief This is the top-level entry point for ULSCH encoding 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 LDPC encoding algorithm of the
Transport Block for each transport block segment. It then calls the
rate dematching and sub-block deinterleaving for each segment.
@param[in] phy_vars_ue Pointer to ue variables
@param[in] ulsch Pointer to ULSCH descriptor
@param[in] frame_parms Pointer to frame descriptor
@param[in] harq_pid HARQ process id
@param[in] tb_size Transport Block size
@param[in] G
@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,
@@ -110,6 +148,27 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
uint32_t tb_size,
unsigned int G);
/** \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_slot(PHY_VARS_NR_UE *ue,
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
@param[in] size of input bits
@@ -130,8 +189,14 @@ void nr_pusch_codeword_scrambling(uint8_t *in,
- scrambling
- modulation
- transform precoding
@param[in] UE pointer to ue variables
@param[in] harq_pid
@param[in] frame frame index
@param[in] slot slot index
@param[in] gNB_id gNB 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,
@@ -140,6 +205,25 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF);
/** \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_slot(PHY_VARS_NR_UE *UE,
const uint32_t frame,
const uint8_t slot,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF);
/** \brief This function does IFFT for PUSCH
*/

View File

@@ -126,6 +126,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;

View File

@@ -0,0 +1,202 @@
/*
* 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 PHY/NR_UE_TRANSPORT/nr_ulsch_coding_slot.c
*/
#include "PHY/defs_UE.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/CODING/coding_defs.h"
#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"
int nr_ulsch_encoding_slot(PHY_VARS_NR_UE *ue,
NR_UE_ULSCH_t *ulsch,
const uint32_t frame,
const uint8_t slot,
unsigned int *G,
int nb_ulsch,
uint8_t *ULSCH_ids)
{
start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN);
notifiedFIFO_t nf;
initNotifiedFIFO(&nf);
nrLDPC_slot_encoding_parameters_t slot_encoding_params;
slot_encoding_params.frame = frame;
slot_encoding_params.slot = slot;
slot_encoding_params.nb_TBs = nb_ulsch;
slot_encoding_params.respEncode = &nf;
slot_encoding_params.threadPool = &get_nrUE_params()->Tpool;
slot_encoding_params.tinput = NULL;
slot_encoding_params.tprep = NULL;
slot_encoding_params.tparity = NULL;
slot_encoding_params.toutput = NULL;
nrLDPC_TB_encoding_parameters_t TBs[nb_ulsch];
slot_encoding_params.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_encoding_params = &TBs[pusch_id];
TB_encoding_params->xlsch_id = 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 * pusch_pdu->nrOfLayers * 1056;
int B;
if (A > NR_MAX_PDSCH_TBS) {
// Add 24-bit crc (polynomial A) to payload
crc = crc24a(harq_process->payload_AB, A) >> 8;
harq_process->payload_AB[A >> 3] = ((uint8_t *)&crc)[2];
harq_process->payload_AB[1 + (A >> 3)] = ((uint8_t *)&crc)[1];
harq_process->payload_AB[2 + (A >> 3)] = ((uint8_t *)&crc)[0];
B = A + 24;
AssertFatal((A / 8) + 4 <= max_payload_bytes, "A %d is too big (A/8+4 = %d > %d)\n", A, (A / 8) + 4, max_payload_bytes);
} else {
// Add 16-bit crc (polynomial A) to payload
crc = crc16(harq_process->payload_AB, A) >> 16;
harq_process->payload_AB[A >> 3] = ((uint8_t *)&crc)[1];
harq_process->payload_AB[1 + (A >> 3)] = ((uint8_t *)&crc)[0];
B = A + 16;
AssertFatal((A / 8) + 3 <= max_payload_bytes, "A %d is too big (A/8+3 = %d > %d)\n", A, (A / 8) + 3, max_payload_bytes);
}
///////////////////////// b---->| block segmentation |---->c /////////////////////////
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);
TB_encoding_params->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_encoding_params->C = harq_process->C;
TB_encoding_params->K = harq_process->K;
TB_encoding_params->Z = harq_process->Z;
TB_encoding_params->F = harq_process->F;
TB_encoding_params->BG = harq_process->BG;
if (TB_encoding_params->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_encoding_params->C, B);
return (-1);
}
stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT);
max_num_segments = max(max_num_segments, TB_encoding_params->C);
TB_encoding_params->rnti = pusch_pdu->rnti;
TB_encoding_params->nb_rb = nb_rb;
TB_encoding_params->Qm = Qm;
TB_encoding_params->mcs = pusch_pdu->mcs_index;
TB_encoding_params->nb_layers = pusch_pdu->nrOfLayers;
TB_encoding_params->rv_index = pusch_pdu->pusch_data.rv_index;
TB_encoding_params->G = G[pusch_id];
TB_encoding_params->tbslbrm = pusch_pdu->tbslbrm;
TB_encoding_params->A = A;
} // pusch_id
nrLDPC_segment_encoding_parameters_t segments[nb_ulsch][max_num_segments];
for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) {
uint8_t ULSCH_id = ULSCH_ids[pusch_id];
uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id;
nrLDPC_TB_encoding_parameters_t *TB_encoding_params = &TBs[pusch_id];
NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid];
TB_encoding_params->segments = segments[pusch_id];
int r_offset = 0;
for (int r = 0; r < TB_encoding_params->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_encoding_params = &TB_encoding_params->segments[r];
segment_encoding_params->c = harq_process->c[r];
segment_encoding_params->E =
nr_get_E(TB_encoding_params->G, TB_encoding_params->C, TB_encoding_params->Qm, TB_encoding_params->nb_layers, r);
segment_encoding_params->output = harq_process->f + r_offset;
r_offset += segment_encoding_params->E;
reset_meas(&segment_encoding_params->ts_interleave);
reset_meas(&segment_encoding_params->ts_rate_match);
reset_meas(&segment_encoding_params->ts_ldpc_encode);
} // TB_encoding_params->C
} // pusch_id
///////////////////////// | LDCP coding | ////////////////////////////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
int nbJobs = 0;
nbJobs = nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_encoding_params);
if (nbJobs < 0)
return -1;
while (nbJobs) {
notifiedFIFO_elt_t *req = pullTpool(&nf, &get_nrUE_params()->Tpool);
if (req == NULL)
break; // Tpool has been stopped
delNotifiedFIFO_elt(req);
nbJobs--;
}
for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) {
nrLDPC_TB_encoding_parameters_t *TB_encoding_params = &TBs[pusch_id];
for (int r = 0; r < TB_encoding_params->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_encoding_params = &TB_encoding_params->segments[r];
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_INTERLEAVING_STATS], &segment_encoding_params->ts_interleave);
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS], &segment_encoding_params->ts_rate_match);
merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_LDPC_ENCODING_STATS], &segment_encoding_params->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;
}

View File

@@ -461,6 +461,371 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
}
}
void nr_ue_ulsch_procedures_slot(PHY_VARS_NR_UE *UE,
const uint32_t frame,
const uint8_t slot,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF)
{
int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id;
if (UE->ul_harq_processes[harq_pid].ULstatus != ACTIVE)
return;
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;
uint16_t number_dmrs_symbols = 0;
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;
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)
number_dmrs_symbols += 1;
}
///////////////////////PTRS parameters' initialization///////////////////
unsigned int K_ptrs = 0, k_RE_ref = 0;
uint32_t unav_res = 0;
if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
K_ptrs = pusch_pdu->pusch_ptrs.ptrs_freq_density;
k_RE_ref = pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset;
uint8_t L_ptrs = 1 << pusch_pdu->pusch_ptrs.ptrs_time_density;
ulsch_ue->ptrs_symbols = 0;
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);
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);
ws_trace_t tmp = {.nr = true,
.direction = DIRECTION_UPLINK,
.pdu_buffer = harq_process_ul_ue->payload_AB,
.pdu_buffer_size = tb_size,
.ueid = 0,
.rntiType = WS_C_RNTI,
.rnti = rnti,
.sysFrame = frame,
.subframe = slot,
.harq_pid = harq_pid,
.oob_event = 0,
.oob_event_value = 0};
trace_pdu(&tmp);
/////////////////////////ULSCH coding/////////////////////////
if (nr_ulsch_encoding_slot(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[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));
nr_pusch_codeword_scrambling(harq_process_ul_ue->f,
available_bits,
pusch_pdu->data_scrambling_id,
rnti,
false,
scrambled_output);
/////////////////////////ULSCH modulation/////////////////////////
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
available_bits,
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
uint8_t u = 0, v = 0;
c16_t *dmrs_seq = NULL;
/// Transform-coded "y"-sequences (for definition see 38-211 V15.3.0 2018-09, subsection 6.3.1.4)
c16_t ulsch_mod_tp[max_num_re] __attribute__((aligned(16)));
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 y_offset = 0;
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);
u = pusch_pdu->dfts_ofdm.low_papr_group_number;
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(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);
for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) {
if ((ul_dmrs_symb_pos >> l) & 0x01)
/* In the symbol with DMRS no data would be transmitted CDM groups is 2*/
continue;
nr_dft(&ulsch_mod_tp[y_offset], &ulsch_mod[0][y_offset], nb_re_pusch);
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);
#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);
#endif
}
#ifdef DEBUG_DFT_IDFT
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);
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++) {
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);
#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];
memset(tx_precoding, 0, sizeof(tx_precoding));
for (int nl = 0; nl < Nl; nl++) {
#ifdef DEBUG_PUSCH_MAPPING
printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u);
#endif
const uint8_t dmrs_port = get_dmrs_port(nl, pusch_pdu->dmrs_ports);
const uint8_t delta = get_delta(dmrs_port, dmrs_type);
int Wt[2];
int Wf[2];
get_Wt(Wt, dmrs_port, dmrs_type);
get_Wf(Wf, dmrs_port, dmrs_type);
c16_t *data = (pusch_pdu->transform_precoding == transformPrecoder_enabled) ? ulsch_mod_tp : ulsch_mod[nl];
nr_phy_pxsch_params_t params = {.rnti = rnti,
.K_ptrs = K_ptrs,
.k_RE_ref = k_RE_ref,
.first_sc_offset = frame_parms->first_carrier_offset,
.fft_size = frame_parms->ofdm_symbol_size,
.num_rb_max = frame_parms->N_RB_UL,
.symbols_per_slot = frame_parms->symbols_per_slot,
.dmrs_scrambling_id = pusch_pdu->ul_dmrs_scrambling_id,
.scid = pusch_pdu->scid,
.dmrs_port = dmrs_port,
.Wt = Wt[l_prime[0]],
.Wf = Wf,
.dmrs_symb_pos = ul_dmrs_symb_pos,
.ptrs_symb_pos = ulsch_ue->ptrs_symbols,
.pdu_bit_map = pusch_pdu->pdu_bit_map,
.transform_precoding = pusch_pdu->transform_precoding,
.bwp_start = pusch_pdu->bwp_start,
.start_rb = start_rb,
.nb_rb = nb_rb,
.start_symbol = start_symbol,
.num_symbols = number_of_symbols,
.dmrs_type = dmrs_type,
.delta = delta,
.num_cdm_no_data = cdm_grps_no_data};
map_symbols(params, slot, dmrs_seq, data, tx_precoding[nl]);
} // 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++) {
uint16_t k = start_sc;
for (int rb = 0; rb < nb_rb; rb++) {
// get pmi info
uint8_t pmi = pusch_pdu->Tpmi;
if (pmi == 0) { // unitary Precoding
if (k + NR_NB_SC_PER_RB <= frame_parms->ofdm_symbol_size) { // RB does not cross DC
if (ap < pusch_pdu->nrOfLayers)
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k],
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size + k],
NR_NB_SC_PER_RB * sizeof(c16_t));
else
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k], 0, NR_NB_SC_PER_RB * sizeof(int32_t));
} else { // RB does cross DC
int neg_length = frame_parms->ofdm_symbol_size - k;
int pos_length = NR_NB_SC_PER_RB - neg_length;
if (ap < pusch_pdu->nrOfLayers) {
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k],
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size + k],
neg_length * sizeof(c16_t));
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size],
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size],
pos_length * sizeof(int32_t));
} else {
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k], 0, neg_length * sizeof(int32_t));
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size], 0, pos_length * sizeof(int32_t));
}
}
k += NR_NB_SC_PER_RB;
if (k >= frame_parms->ofdm_symbol_size) {
k -= frame_parms->ofdm_symbol_size;
}
} else {
// get the precoding matrix weights:
const char *W_prec;
switch (frame_parms->nb_antennas_tx) {
case 1: // 1 antenna port
W_prec = nr_W_1l_2p[pmi][ap];
break;
case 2: // 2 antenna ports
if (pusch_pdu->nrOfLayers == 1) // 1 layer
W_prec = nr_W_1l_2p[pmi][ap];
else // 2 layers
W_prec = nr_W_2l_2p[pmi][ap];
break;
case 4: // 4 antenna ports
if (pusch_pdu->nrOfLayers == 1) // 1 layer
W_prec = nr_W_1l_4p[pmi][ap];
else if (pusch_pdu->nrOfLayers == 2) // 2 layers
W_prec = nr_W_2l_4p[pmi][ap];
else if (pusch_pdu->nrOfLayers == 3) // 3 layers
W_prec = nr_W_3l_4p[pmi][ap];
else // 4 layers
W_prec = nr_W_4l_4p[pmi][ap];
break;
default:
LOG_D(PHY, "Precoding 1,2, or 4 antenna ports are currently supported\n");
W_prec = nr_W_1l_2p[pmi][ap];
break;
}
for (int i = 0; i < NR_NB_SC_PER_RB; i++) {
int32_t re_offset = l * frame_parms->ofdm_symbol_size + k;
txdataF[ap][re_offset] = nr_layer_precoder(slot_sz, tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset);
if (++k >= frame_parms->ofdm_symbol_size) {
k -= frame_parms->ofdm_symbol_size;
}
}
}
} // RB loop
} // symbol loop
} // port loop
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);
}
void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
const unsigned char harq_pid,
const uint32_t frame,

View File

@@ -493,7 +493,9 @@ typedef struct PHY_VARS_gNB_s {
/// OFDM symbol offset divisor for UL
uint32_t ofdm_offset_divisor;
/// NR LDPC coding related
int ldpc_offload_flag;
int nrLDPC_coding_interface_flag; // Flag enabling NR LDPC coding module
int max_ldpc_iterations;
/// indicate the channel estimation technique in time domain

View File

@@ -490,6 +490,9 @@ typedef struct PHY_VARS_NR_UE_s {
/// N0 (used for abstraction)
double N0;
/// NR LDPC coding related
int nrLDPC_coding_interface_flag; // Flag enabling NR LDPC coding module
uint8_t max_ldpc_iterations;
int ldpc_offload_enable;

View File

@@ -406,6 +406,144 @@ static void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req)
}
}
static int nr_ulsch_procedures_slot(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint8_t *ulsch_to_decode)
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
int nb_pusch = 0;
for (uint8_t ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
if (ulsch_to_decode[ULSCH_id] == 1) {
nb_pusch++;
}
}
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] == 1) {
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_slot =
nr_ulsch_decoding_slot(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) && !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,
ULSCH_id,
ulsch->frame,
ulsch->slot,
ulsch->rnti,
ulsch->harq_pid,
pusch_pdu->pusch_data.new_data_indicator,
ulsch->active,
ulsch_harq->round,
ulsch_harq->TBS,
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;
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)\n",
gNB->Mod_id,
ulsch->frame,
ulsch->slot,
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);
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",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
}
}
return ret_nr_ulsch_decoding_slot;
}
static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH_id, uint8_t harq_pid)
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
@@ -451,12 +589,6 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int
//----------------------------------------------------------
//--------------------- 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 nbDecode =
nr_ulsch_decoding(gNB, ULSCH_id, gNB->pusch_vars[ULSCH_id].llr, frame_parms, pusch_pdu, frame_rx, slot_rx, harq_pid, G);
@@ -819,7 +951,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
}
}
int totalDecode = 0;
uint8_t ulsch_to_decode[gNB->max_nb_pusch];
bzero((void *)ulsch_to_decode, gNB->max_nb_pusch);
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;
@@ -911,18 +1044,43 @@ 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] = 1;
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);
if (tasks_added > 0)
totalDecode += tasks_added;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 0);
}
}
/* 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);
if(gNB->nrLDPC_coding_interface_flag){
int const ret_nr_ulsch_procedures_slot = nr_ulsch_procedures_slot(gNB, frame_rx, slot_rx, ulsch_to_decode);
if (ret_nr_ulsch_procedures_slot != 0) {
LOG_E(PHY,"Error in nr_ulsch_procedures_slot, returned %d\n",ret_nr_ulsch_procedures_slot);
}
}
else
{
int totalDecode = 0;
for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
if (ulsch_to_decode[ULSCH_id] == 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);
if (tasks_added > 0)
totalDecode += tasks_added;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 0);
}
}
while (totalDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&gNB->respDecode, &gNB->threadPool);
if (req == NULL)
@@ -931,6 +1089,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
delNotifiedFIFO_elt(req);
totalDecode--;
}
}
/* 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

View File

@@ -287,11 +287,15 @@ 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);
if (ue->nrLDPC_coding_interface_flag) {
nr_ue_ulsch_procedures_slot(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF);
} else {
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);
}
}
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF);
@@ -684,6 +688,153 @@ 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_slot(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t dlsch[2],
int16_t *llr[2]) {
if (dlsch[0].active == false) {
LOG_E(PHY, "DLSCH should be active when calling this function\n");
return true;
}
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;
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);
nr_downlink_indication_t dl_indication;
fapi_nr_rx_indication_t rx_ind = {0};
uint16_t number_pdus = 1;
uint8_t is_cw0_active = dl_harq0->status;
uint8_t is_cw1_active = dl_harq1->status;
int nb_dlsch = 0;
if (is_cw0_active == ACTIVE) nb_dlsch++;
if (is_cw1_active == ACTIVE) nb_dlsch++;
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;
}
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;
send_dl_done_to_tx_thread(ue->tx_resume_ind_fifo + ack_nack_slot, proc->nr_slot_rx);
return false;
}
int G[2];
uint8_t DLSCH_ids[nb_dlsch];
int pdsch_id = 0;
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);
}
// 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_0[dlsch_bytes];
__attribute__((aligned(32))) uint8_t p_b_1[dlsch_bytes];
uint8_t *p_b[2] = {p_b_0, p_b_1};
start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
ret = nr_dlsch_decoding_slot(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
if (ret < ue->max_ldpc_iterations + 1) dec = true;
int ind_type = -1;
switch (dlsch[0].rnti_type) {
case TYPE_RA_RNTI_:
ind_type = FAPI_NR_RX_PDU_TYPE_RAR;
break;
case TYPE_SI_RNTI_:
ind_type = FAPI_NR_RX_PDU_TYPE_SIB;
break;
case TYPE_C_RNTI_:
ind_type = FAPI_NR_RX_PDU_TYPE_DLSCH;
break;
default:
AssertFatal(true, "Invalid DLSCH type %d\n", dlsch[0].rnti_type);
break;
}
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[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);
if (cpumeas(CPUMEAS_GETSTATE)) {
LOG_D(PHY,
" --> 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 %5.3f\n",
frame_rx % 1024,
nr_slot_rx,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
}
// 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;
send_dl_done_to_tx_thread(ue->tx_resume_ind_fifo + ack_nack_slot, proc->nr_slot_rx);
}
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;
}
static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t dlsch[2],
@@ -1146,8 +1297,12 @@ 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) {
if (ue->nrLDPC_coding_interface_flag)
nr_ue_dlsch_procedures_slot(ue, proc, dlsch, llr);
else
nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G);
}
else {
LOG_E(NR_PHY, "Demodulation impossible, internal error\n");
send_dl_done_to_tx_thread(

View File

@@ -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,9 @@ int main(int argc, char **argv)
//nr_init_frame_parms_ue(&UE->frame_parms);
//init_nr_ue_transport(UE, 0);
UE->nrLDPC_coding_interface_flag = gNB->nrLDPC_coding_interface_flag;
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 +517,12 @@ 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);
if (gNB->nrLDPC_coding_interface_flag) {
msgDataTx.num_pdsch_slot = 1;
nr_dlsch_encoding_slot(gNB, &msgDataTx, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else {
nr_dlsch_encoding(gNB, frame, slot, &dlsch->harq_process, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
}
for (SNR = snr0; SNR < snr1; SNR += snr_step) {
@@ -569,20 +578,35 @@ 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];
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);
if (gNB->nrLDPC_coding_interface_flag) {
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_slot(UE,
&proc,
dlsch0_ue,
&p_channel_output_fixed,
&p_b,
available_bits_array,
1,
DLSCH_ids);
} else {
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);
}
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0, VCD_FUNCTION_OUT);

View File

@@ -38,6 +38,7 @@
#include "PHY/defs_nr_UE.h"
#include "PHY/phy_vars_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/nr_modulation.h"
@@ -843,6 +844,8 @@ int main(int argc, char **argv)
init_nr_ue_transport(UE);
UE->nrLDPC_coding_interface_flag = gNB->nrLDPC_coding_interface_flag;
nr_l2_init_ue(1);
UE_mac = get_mac_inst(0);
ue_init_config_request(UE_mac, mu);
@@ -1302,6 +1305,9 @@ int main(int argc, char **argv)
if (gNB->ldpc_offload_flag)
free_LDPClib(&ldpc_interface_offload);
if (gNB->nrLDPC_coding_interface_flag)
free_nrLDPC_coding_interface(&nrLDPC_coding_interface);
if (output_fd)
fclose(output_fd);

View File

@@ -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"
@@ -448,6 +449,12 @@ 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);
UE->nrLDPC_coding_interface_flag = gNB->nrLDPC_coding_interface_flag;
if (UE->nrLDPC_coding_interface_flag) {
initFloatingCoresTpool(1, &nrUE_params.Tpool, false, "UE-tpool");
}
unsigned char harq_pid = 0;
unsigned int TBS = 8424;
unsigned int available_bits;
@@ -530,7 +537,12 @@ 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);
if (UE->nrLDPC_coding_interface_flag) {
uint8_t ULSCH_ids[] = {0};
nr_ulsch_encoding_slot(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids);
} else {
nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, TBS>>3, G);
}
}
printf("\n");
@@ -594,18 +606,26 @@ int main(int argc, char **argv)
exit(-1);
#endif
int nbDecode = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G);
int nb_ok = 0;
if (nbDecode > 0)
while (nbDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&gNB->respDecode, &gNB->threadPool);
ret = nr_postDecode_sim(gNB, req, &nb_ok);
delNotifiedFIFO_elt(req);
nbDecode--;
}
if (gNB->nrLDPC_coding_interface_flag) {
nr_ulsch_decoding_slot(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++;
}
} else {
int nbDecode = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G);
int nb_ok = 0;
if (nbDecode > 0)
while (nbDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&gNB->respDecode, &gNB->threadPool);
ret = nr_postDecode_sim(gNB, req, &nb_ok);
delNotifiedFIFO_elt(req);
nbDecode--;
}
if (ret)
n_errors++;
if (ret)
n_errors++;
}
}
printf("*****************************************\n");

View File

@@ -35,6 +35,7 @@
#include "PHY/defs_nr_UE.h"
#include "PHY/phy_vars_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_UE.h"
#include "PHY/MODULATION/nr_modulation.h"
@@ -704,6 +705,8 @@ int main(int argc, char *argv[])
init_nr_ue_transport(UE);
UE->nrLDPC_coding_interface_flag = gNB->nrLDPC_coding_interface_flag;
//Configure UE
nr_l2_init_ue(1);
NR_UE_MAC_INST_t* UE_mac = get_mac_inst(0);
@@ -718,6 +721,10 @@ int main(int argc, char *argv[])
UE_mac->if_module = nr_ue_if_module_init(0);
if (UE->nrLDPC_coding_interface_flag) {
initFloatingCoresTpool(threadCnt, &nrUE_params.Tpool, false, "UE-tpool");
}
nr_ue_phy_config_request(&UE_mac->phy_config);
unsigned char harq_pid = 0;
@@ -1564,6 +1571,9 @@ int main(int argc, char *argv[])
if (gNB->ldpc_offload_flag)
free_LDPClib(&ldpc_interface_offload);
if (gNB->nrLDPC_coding_interface_flag)
free_nrLDPC_coding_interface(&nrLDPC_coding_interface);
if (output_fd)
fclose(output_fd);