mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Compare commits
6 Commits
multi-test
...
armral_ldp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3378eac2b | ||
|
|
449bf03893 | ||
|
|
ed587269f9 | ||
|
|
b5c66955b3 | ||
|
|
dc0b220276 | ||
|
|
8c3f7bb79c |
@@ -41,7 +41,8 @@ BUILD_DIR=ran_build
|
||||
DISABLE_HARDWARE_DEPENDENCY="False"
|
||||
CMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
CMAKE_CMD="$CMAKE"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_aal ldpc_xdma websrv oai_iqplayer imscope imscope_record"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_aal ldpc_xdma websrv oai_iqplayer imscope imscope_record ldpc_armral"
|
||||
|
||||
TARGET_LIST=""
|
||||
BUILD_TOOL_OPT="-j$(nproc)"
|
||||
|
||||
|
||||
@@ -143,6 +143,20 @@ void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out)
|
||||
_mm512_storeu_epi8(&out[i], reversed);
|
||||
}
|
||||
|
||||
for (; i < sz; ++i) {
|
||||
out[i] = bit_reverse_table_256[in[i]];
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
int simde_sz = 16;
|
||||
int i = 0;
|
||||
int simde_bound = sz - simde_sz;
|
||||
if((((uintptr_t)in & 63) == 0) && (((uintptr_t)out & 63)== 0)) {
|
||||
for (; i <= simde_bound; i += simde_sz) {
|
||||
uint8x16_t input = vld1q_u8(&in[i]);
|
||||
*((uint8x16_t *)&in[i]) = vrbitq_u8(input);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < sz; ++i) {
|
||||
out[i] = bit_reverse_table_256[in[i]];
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ RUN git clone https://gerrit.o-ran-sc.org/r/o-du/phy.git /opt/phy && \
|
||||
## Build Arm RAN Acceleration Library
|
||||
RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \
|
||||
cd /opt/ral && \
|
||||
git checkout armral-25.01 &&\
|
||||
git checkout armral-25.04 &&\
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake -GNinja -DBUILD_SHARED_LIBS=On /opt/ral/ && \
|
||||
@@ -79,7 +79,7 @@ RUN /bin/sh oaienv && \
|
||||
mkdir -p log && \
|
||||
./build_oai \
|
||||
--ninja --gNB \
|
||||
--build-lib "telnetsrv enbscope uescope nrscope" \
|
||||
--build-lib "telnetsrv enbscope uescope nrscope ldpc_armral" \
|
||||
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
||||
--build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
||||
$BUILD_OPTION && \
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(nrLDPC_coding_segment)
|
||||
add_subdirectory(nrLDPC_coding_xdma)
|
||||
add_subdirectory(nrLDPC_coding_aal)
|
||||
add_subdirectory(nrLDPC_coding_armral)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
##########################################################
|
||||
|
||||
# LDPC coding library - ArmRAN Acceleration Library
|
||||
##########################################################
|
||||
|
||||
add_boolean_option(ENABLE_LDPC_ARMRAL OFF "Build support for LDPC coding with the Arm RAN Acceleration Library" OFF)
|
||||
|
||||
if (ENABLE_LDPC_ARMRAL)
|
||||
|
||||
find_package(armral REQUIRED)
|
||||
add_library(ldpc_armral MODULE
|
||||
nrLDPC_coding_armral_encoder.c
|
||||
nrLDPC_coding_armral_decoder.c
|
||||
)
|
||||
set_target_properties(ldpc_armral PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(ldpc_armral PRIVATE ldpc_gen_HEADERS)
|
||||
target_link_libraries(ldpc_armral PRIVATE armral)
|
||||
|
||||
add_dependencies(ldpctest ldpc_armral)
|
||||
add_dependencies(nr-softmodem ldpc_armral)
|
||||
add_dependencies(nr-uesoftmodem ldpc_armral)
|
||||
add_dependencies(nr_ulsim ldpc_armral)
|
||||
add_dependencies(nr_ulschsim ldpc_armral)
|
||||
add_dependencies(nr_dlsim ldpc_armral)
|
||||
add_dependencies(nr_dlschsim ldpc_armral)
|
||||
|
||||
add_library(ldpc_armral_dec MODULE
|
||||
../nrLDPC_coding_segment/nr_rate_matching.c
|
||||
nrLDPC_coding_armral_decoder.c
|
||||
../nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
|
||||
../../nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
|
||||
)
|
||||
set_target_properties(ldpc_armral_dec PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(ldpc_armral_dec PRIVATE ldpc_gen_HEADERS)
|
||||
target_link_libraries(ldpc_armral_dec PRIVATE armral)
|
||||
|
||||
add_dependencies(ldpctest ldpc_armral_dec)
|
||||
add_dependencies(nr-softmodem ldpc_armral_dec)
|
||||
add_dependencies(nr-uesoftmodem ldpc_armral_dec)
|
||||
add_dependencies(nr_ulsim ldpc_armral_dec)
|
||||
add_dependencies(nr_ulschsim ldpc_armral_dec)
|
||||
add_dependencies(nr_dlsim ldpc_armral_dec)
|
||||
add_dependencies(nr_dlschsim ldpc_armral_dec)
|
||||
|
||||
#ensure that the T header files are generated before targets depending on them
|
||||
if (${T_TRACER})
|
||||
add_dependencies(ldpc_armral generate_T)
|
||||
add_dependencies(ldpc_armral_dec generate_T)
|
||||
endif (${T_TRACER})
|
||||
|
||||
endif()
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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_armral/nrLDPC_coding_armral_decoder.c
|
||||
* \brief Top-level routines for decoding LDPC transport channels using the Arm RAN Acceleration Library
|
||||
* \author Romain Beurdouche
|
||||
* \date 2025
|
||||
* \company EURECOM
|
||||
* \email romain.beurdouche@eurecom.fr
|
||||
* \note ArmRAL available at https://git.gitlab.arm.com/networking/ral.git
|
||||
* \warning
|
||||
*/
|
||||
|
||||
// [from gNB coding]
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "PHY/CODING/coding_extern.h"
|
||||
#include "PHY/CODING/coding_defs.h"
|
||||
#include "PHY/CODING/lte_interleaver_inline.h"
|
||||
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
|
||||
#include "PHY/CODING/nrLDPC_extern.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_ulsch.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "SCHED_NR/fapi_nr_l1.h"
|
||||
#include "defs.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
#include <stdalign.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <time.h>
|
||||
#include <armral.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 A Transport block size (This is A from 38.212 V15.4.0 section 5.1)
|
||||
* \var K Code block size at decoder output
|
||||
* \var Z lifting size
|
||||
* \var F filler bits size
|
||||
* \var C number of segments
|
||||
* \var E input llr segment size
|
||||
* \var BG Base graph index (BG1: 1, BG2: 2)
|
||||
* \var max_number_iterations maximum number of LDPC iterations
|
||||
* \var tbslbrm transport block size LBRM in bytes
|
||||
* \var Qm modulation order
|
||||
* \var rv_index
|
||||
* \var llr input llr segment array
|
||||
* \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2)
|
||||
* \var d_to_be_cleared
|
||||
* pointer to the flag used to clear d properly
|
||||
* when true, clear d after rate dematching
|
||||
* \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2)
|
||||
* \var decodeSuccess pointer to the flag indicating that the decoding of the segment was successful
|
||||
* \var ans pointer to task answer used by the thread pool to detect task completion
|
||||
* \var abort_decode pointer to decode abort flag
|
||||
* \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 {
|
||||
uint32_t A;
|
||||
uint32_t K;
|
||||
uint32_t Z;
|
||||
uint32_t F;
|
||||
|
||||
uint32_t C;
|
||||
uint32_t E;
|
||||
|
||||
uint8_t BG;
|
||||
uint32_t max_number_iterations;
|
||||
|
||||
uint32_t tbslbrm;
|
||||
uint32_t Qm;
|
||||
uint8_t rv_index;
|
||||
|
||||
short *llr;
|
||||
int16_t *d;
|
||||
bool *d_to_be_cleared;
|
||||
uint8_t *c;
|
||||
bool *decodeSuccess;
|
||||
|
||||
task_ans_t *ans;
|
||||
// decode_abort_t *abort_decode;
|
||||
|
||||
time_stats_t *p_ts_rate_unmatch;
|
||||
time_stats_t *p_ts_ldpc_decode;
|
||||
} nrLDPC_decoding_parameters_t;
|
||||
|
||||
static void nr_process_decode_segment(void *arg)
|
||||
{
|
||||
nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg;
|
||||
const uint32_t A = rdata->A;
|
||||
const uint32_t K = rdata->K;
|
||||
const uint32_t Z = rdata->Z;
|
||||
const uint32_t F = rdata->F;
|
||||
const uint32_t C = rdata->C;
|
||||
const uint32_t Kprime = K - rdata->F;
|
||||
const uint32_t E = rdata->E;
|
||||
const uint32_t max_number_iterations = rdata->max_number_iterations;
|
||||
const uint32_t Qm = rdata->Qm;
|
||||
const uint32_t rv_index = rdata->rv_index;
|
||||
short *ulsch_llr = rdata->llr;
|
||||
uint8_t llrProcBuf[OAI_LDPC_DECODER_MAX_NUM_LLR] __attribute__((aligned(32)));
|
||||
|
||||
start_meas(rdata->p_ts_rate_unmatch);
|
||||
|
||||
armral_ldpc_graph_t armral_bg = rdata->BG == 2 ? LDPC_BASE_GRAPH_2 : LDPC_BASE_GRAPH_1;
|
||||
|
||||
uint32_t Nref = 3 * rdata->tbslbrm / (2 * C); // R_LBRM = 2/3
|
||||
|
||||
armral_modulation_type armral_mod = ARMRAL_MOD_QPSK;
|
||||
switch (Qm) {
|
||||
case 2:
|
||||
armral_mod = ARMRAL_MOD_QPSK;
|
||||
break;
|
||||
case 4:
|
||||
armral_mod = ARMRAL_MOD_16QAM;
|
||||
break;
|
||||
case 6:
|
||||
armral_mod = ARMRAL_MOD_64QAM;
|
||||
break;
|
||||
case 8:
|
||||
armral_mod = ARMRAL_MOD_256QAM;
|
||||
break;
|
||||
default:
|
||||
LOG_E(PHY, "Modulation order not supported: Qm = %d\n", Qm);
|
||||
break;
|
||||
}
|
||||
|
||||
int size_f = ceil_mod(E, 16);
|
||||
int8_t f[size_f] __attribute__((aligned(64)));
|
||||
memset(f, 0, size_f * sizeof(int8_t));
|
||||
for (int i = 0; i < (size_f >> 4); i++) {
|
||||
((simde__m128i *)f)[i] = simde_mm_packs_epi16(((simde__m128i *)ulsch_llr)[2 * i], ((simde__m128i *)ulsch_llr)[2 * i + 1]);
|
||||
}
|
||||
|
||||
if (*rdata->d_to_be_cleared) {
|
||||
memset(rdata->d, 0, 68 * 384 * sizeof(*rdata->d));
|
||||
*rdata->d_to_be_cleared = false;
|
||||
}
|
||||
|
||||
armral_status status_rate_recovery =
|
||||
armral_ldpc_rate_recovery(armral_bg, Z, E, Nref, F, K, rv_index, armral_mod, f, (int8_t *)rdata->d);
|
||||
if (status_rate_recovery == ARMRAL_ARGUMENT_ERROR) {
|
||||
LOG_E(PHY, "argument error in armral rate recovery\n");
|
||||
} else if (status_rate_recovery == ARMRAL_FAIL) {
|
||||
LOG_E(PHY, "failure in armral rate recovery\n");
|
||||
}
|
||||
|
||||
stop_meas(rdata->p_ts_rate_unmatch);
|
||||
start_meas(rdata->p_ts_ldpc_decode);
|
||||
|
||||
const uint32_t N = rdata->BG == 2 ? 50 * Z : 66 * Z;
|
||||
|
||||
int crc_type = crcType(C, A);
|
||||
uint32_t armral_ldpc_decode_options = ARMRAL_LDPC_DEFAULT_OPTIONS;
|
||||
armral_ldpc_decode_options |= ARMRAL_LDPC_CRC_EVERY_ITER;
|
||||
switch (crc_type) {
|
||||
case CRC24_A:
|
||||
armral_ldpc_decode_options |= ARMRAL_LDPC_CRC_24A;
|
||||
break;
|
||||
|
||||
case CRC24_B:
|
||||
armral_ldpc_decode_options |= ARMRAL_LDPC_CRC_24B;
|
||||
break;
|
||||
|
||||
case CRC16:
|
||||
armral_ldpc_decode_options |= ARMRAL_LDPC_CRC_16;
|
||||
break;
|
||||
|
||||
case CRC8:
|
||||
armral_ldpc_decode_options |= ARMRAL_LDPC_CRC_NO;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1, "Invalid crc_type \n");
|
||||
}
|
||||
|
||||
armral_status status_decoding = armral_ldpc_decode_block(N,
|
||||
(int8_t *)rdata->d,
|
||||
armral_bg,
|
||||
Z,
|
||||
F,
|
||||
llrProcBuf,
|
||||
max_number_iterations,
|
||||
armral_ldpc_decode_options);
|
||||
if (status_decoding == ARMRAL_ARGUMENT_ERROR) {
|
||||
LOG_E(PHY, "argument error in armral decoding\n");
|
||||
}
|
||||
|
||||
if (check_crc(llrProcBuf, Kprime, crc_type)) {
|
||||
memcpy(rdata->c, llrProcBuf, K >> 3);
|
||||
*rdata->decodeSuccess = true;
|
||||
} else {
|
||||
memset(rdata->c, 0, K >> 3);
|
||||
*rdata->decodeSuccess = false;
|
||||
}
|
||||
stop_meas(rdata->p_ts_ldpc_decode);
|
||||
|
||||
// Task completed
|
||||
completed_task_ans(rdata->ans);
|
||||
}
|
||||
|
||||
int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters,
|
||||
int pusch_id,
|
||||
thread_info_tm_t *t_info)
|
||||
{
|
||||
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id];
|
||||
|
||||
*nrLDPC_TB_decoding_parameters->processedSegments = 0;
|
||||
|
||||
for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) {
|
||||
nrLDPC_decoding_parameters_t *rdata = &((nrLDPC_decoding_parameters_t *)t_info->buf)[t_info->len];
|
||||
DevAssert(t_info->len < t_info->cap);
|
||||
rdata->ans = t_info->ans;
|
||||
t_info->len += 1;
|
||||
|
||||
rdata->A = nrLDPC_TB_decoding_parameters->A;
|
||||
rdata->K = nrLDPC_TB_decoding_parameters->K;
|
||||
rdata->Z = nrLDPC_TB_decoding_parameters->Z;
|
||||
rdata->F = nrLDPC_TB_decoding_parameters->F;
|
||||
rdata->C = nrLDPC_TB_decoding_parameters->C;
|
||||
rdata->E = nrLDPC_TB_decoding_parameters->segments[r].E;
|
||||
rdata->BG = nrLDPC_TB_decoding_parameters->BG;
|
||||
rdata->max_number_iterations = nrLDPC_TB_decoding_parameters->max_ldpc_iterations;
|
||||
rdata->tbslbrm = nrLDPC_TB_decoding_parameters->tbslbrm;
|
||||
rdata->Qm = nrLDPC_TB_decoding_parameters->Qm;
|
||||
rdata->rv_index = nrLDPC_TB_decoding_parameters->rv_index;
|
||||
rdata->llr = nrLDPC_TB_decoding_parameters->segments[r].llr;
|
||||
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->abort_decode = nrLDPC_TB_decoding_parameters->abort_decode;
|
||||
rdata->p_ts_rate_unmatch = &nrLDPC_TB_decoding_parameters->segments[r].ts_rate_unmatch;
|
||||
rdata->p_ts_ldpc_decode = &nrLDPC_TB_decoding_parameters->segments[r].ts_ldpc_decode;
|
||||
|
||||
task_t t = {.func = &nr_process_decode_segment, .args = rdata};
|
||||
pushTpool(nrLDPC_slot_decoding_parameters->threadPool, t);
|
||||
|
||||
LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r);
|
||||
}
|
||||
return nrLDPC_TB_decoding_parameters->C;
|
||||
}
|
||||
|
||||
int32_t nrLDPC_coding_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t nrLDPC_coding_shutdown(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters)
|
||||
{
|
||||
int nbSegments = 0;
|
||||
for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) {
|
||||
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id];
|
||||
nbSegments += nrLDPC_TB_decoding_parameters->C;
|
||||
}
|
||||
nrLDPC_decoding_parameters_t arr[nbSegments];
|
||||
task_ans_t ans;
|
||||
init_task_ans(&ans, nbSegments);
|
||||
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbSegments, .ans = &ans};
|
||||
|
||||
for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) {
|
||||
(void)nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters, pusch_id, &t_info);
|
||||
}
|
||||
|
||||
// Execute thread pool tasks
|
||||
join_task_ans(t_info.ans);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c
|
||||
* \brief Top-level routines for implementing LDPC encoding of transport channels
|
||||
*/
|
||||
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "PHY/CODING/coding_extern.h"
|
||||
#include "PHY/CODING/coding_defs.h"
|
||||
#include "PHY/CODING/lte_interleaver_inline.h"
|
||||
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
|
||||
#include "PHY/CODING/nrLDPC_extern.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include <openair2/UTIL/OPT/opt.h>
|
||||
|
||||
#include <syscall.h>
|
||||
#include "armral.h"
|
||||
|
||||
#define DEBUG_LDPC_ENCODING
|
||||
//#define DEBUG_LDPC_ENCODING_FREE 1
|
||||
|
||||
typedef struct ldpc8blocks_args_s {
|
||||
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters;
|
||||
uint32_t macro_num;
|
||||
time_stats_t *toutput;
|
||||
task_ans_t *ans;
|
||||
} ldpc8blocks_args_t;
|
||||
|
||||
static void ldpc8blocks(void *p)
|
||||
{
|
||||
ldpc8blocks_args_t *args = (ldpc8blocks_args_t *)p;
|
||||
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = args->nrLDPC_TB_encoding_parameters;
|
||||
|
||||
uint32_t A = nrLDPC_TB_encoding_parameters->A;
|
||||
uint32_t K = nrLDPC_TB_encoding_parameters->K;
|
||||
uint32_t Z = nrLDPC_TB_encoding_parameters->Z;
|
||||
uint32_t F = nrLDPC_TB_encoding_parameters->F;
|
||||
uint32_t C = nrLDPC_TB_encoding_parameters->C;
|
||||
uint8_t Qm = nrLDPC_TB_encoding_parameters->Qm;
|
||||
uint16_t nb_rb = nrLDPC_TB_encoding_parameters->nb_rb;
|
||||
|
||||
unsigned int G = nrLDPC_TB_encoding_parameters->G;
|
||||
LOG_D(PHY, "dlsch coding A %d K %d G %d (nb_rb %d, Qm %d)\n", A, K, G, nb_rb, (int)Qm);
|
||||
|
||||
armral_ldpc_graph_t armral_bg = nrLDPC_TB_encoding_parameters->BG == 2 ? LDPC_BASE_GRAPH_2 : LDPC_BASE_GRAPH_1;
|
||||
|
||||
uint32_t Nref = 3 * nrLDPC_TB_encoding_parameters->tbslbrm / (2 * C); // R_LBRM = 2/3
|
||||
|
||||
armral_modulation_type armral_mod = ARMRAL_MOD_QPSK;
|
||||
switch (Qm) {
|
||||
case 2:
|
||||
armral_mod = ARMRAL_MOD_QPSK;
|
||||
break;
|
||||
case 4:
|
||||
armral_mod = ARMRAL_MOD_16QAM;
|
||||
break;
|
||||
case 6:
|
||||
armral_mod = ARMRAL_MOD_64QAM;
|
||||
break;
|
||||
case 8:
|
||||
armral_mod = ARMRAL_MOD_256QAM;
|
||||
break;
|
||||
default:
|
||||
LOG_E(PHY, "Modulation order not supported: Qm = %d\n", Qm);
|
||||
break;
|
||||
}
|
||||
|
||||
// 384 (lifting size in bits) / 8 = 48 (lifting size in bytes)
|
||||
uint8_t d[68 * 48] __attribute__((aligned(64)));
|
||||
uint8_t f[68 * 48] __attribute__((aligned(64)));
|
||||
|
||||
unsigned int macro_segment = 8 * args->macro_num;
|
||||
unsigned int macro_segment_end = (C > 8 * (args->macro_num + 1)) ? 8 * (args->macro_num + 1) : C;
|
||||
unsigned int offset_output_bit = 0;
|
||||
|
||||
// Calculate initial offset in output buffer
|
||||
for (int r = 0; r < macro_segment; r++) {
|
||||
offset_output_bit += nrLDPC_TB_encoding_parameters->segments[r].E;
|
||||
}
|
||||
|
||||
for (int r = macro_segment; r < macro_segment_end; r++) {
|
||||
start_meas(&nrLDPC_TB_encoding_parameters->segments[r].ts_ldpc_encode);
|
||||
|
||||
memset(d, 0, 68 * 48 * sizeof(*d));
|
||||
armral_status status_encoding = armral_ldpc_encode_block(nrLDPC_TB_encoding_parameters->segments[r].c, armral_bg, Z, F, d);
|
||||
if (status_encoding == ARMRAL_ARGUMENT_ERROR) {
|
||||
LOG_E(PHY, "argument error in armral encoding\n");
|
||||
} else if (status_encoding == ARMRAL_FAIL) {
|
||||
LOG_E(PHY, "failure in armral encoding\n");
|
||||
}
|
||||
|
||||
stop_meas(&nrLDPC_TB_encoding_parameters->segments[r].ts_ldpc_encode);
|
||||
|
||||
start_meas(&nrLDPC_TB_encoding_parameters->segments[r].ts_rate_match);
|
||||
|
||||
unsigned int E = nrLDPC_TB_encoding_parameters->segments[r].E;
|
||||
LOG_D(NR_PHY,
|
||||
"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d Qm %d, nb_rb "
|
||||
"%d,nrOfLayer %d)...\n",
|
||||
r,
|
||||
C,
|
||||
G,
|
||||
E,
|
||||
F,
|
||||
K - F - 2 * Z,
|
||||
Qm,
|
||||
nb_rb,
|
||||
nrLDPC_TB_encoding_parameters->nb_layers);
|
||||
|
||||
if (K - F - 2 * Z > E) {
|
||||
LOG_E(PHY, "dlsch coding A %d Kr %d G %d (nb_rb %d, Qm %d)\n", A, K, G, nb_rb, Qm);
|
||||
|
||||
LOG_E(NR_PHY,
|
||||
"Rate Matching, Code segments %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d Qm %d, "
|
||||
"nb_rb %d)...\n",
|
||||
macro_segment,
|
||||
C,
|
||||
G,
|
||||
E,
|
||||
K,
|
||||
F,
|
||||
K - F - 2 * Z,
|
||||
Qm,
|
||||
nb_rb);
|
||||
}
|
||||
|
||||
memset(f, 0, 68 * 48 * sizeof(*f));
|
||||
armral_status status_rate_matching =
|
||||
armral_ldpc_rate_matching(armral_bg, Z, E, Nref, F, K, nrLDPC_TB_encoding_parameters->rv_index, armral_mod, d, f);
|
||||
if (status_rate_matching == ARMRAL_ARGUMENT_ERROR) {
|
||||
LOG_E(PHY, "argument error in armral rate matching\n");
|
||||
} else if (status_rate_matching == ARMRAL_FAIL) {
|
||||
LOG_E(PHY, "failure in armral rate matching\n");
|
||||
}
|
||||
|
||||
stop_meas(&nrLDPC_TB_encoding_parameters->segments[r].ts_rate_match);
|
||||
|
||||
if (args->toutput != NULL)
|
||||
start_meas(args->toutput);
|
||||
|
||||
unsigned int f_reverse_size = (E & 7) == 0 ? E >> 3 : (E >> 3) + 1;
|
||||
reverse_bits_u8(f, f_reverse_size, f);
|
||||
|
||||
if ((offset_output_bit & 7) == 0) {
|
||||
LOG_D(PHY, "encoder output aligned on byte, using memcpy\n");
|
||||
unsigned int output_copy_size = (E & 7) == 0 ? E >> 3 : (E >> 3) + 1;
|
||||
memcpy(&nrLDPC_TB_encoding_parameters->output[offset_output_bit >> 3], f, output_copy_size);
|
||||
} else {
|
||||
LOG_D(PHY, "encoder output NOT aligned on byte, using Neon\n");
|
||||
uint64_t *f_64 = (uint64_t *)f;
|
||||
unsigned int output_offset_64 = (offset_output_bit >> 3) - ((offset_output_bit >> 3) & 7);
|
||||
uint64_t *output_64 = (uint64_t *)&nrLDPC_TB_encoding_parameters->output[output_offset_64];
|
||||
unsigned int nb_vec = (E & 63) == 0 ? E >> 6 : (E >> 6) + 1;
|
||||
int64_t shift_bit_low = offset_output_bit & 63;
|
||||
int64x1_t shift_bit_low_64x1 = vld1_s64(&shift_bit_low);
|
||||
int64_t shift_bit_high = shift_bit_low - 64;
|
||||
int64x1_t shift_bit_high_64x1 = vld1_s64(&shift_bit_high);
|
||||
for (int i = 0; i < nb_vec; i++) {
|
||||
uint64x1_t f_64x1 = vld1_u64(&f_64[i]);
|
||||
|
||||
uint64x1_t f_64x1_low = vshl_u64(f_64x1, shift_bit_low_64x1);
|
||||
uint64x1_t output_64x1_low = vld1_u64(&output_64[i]);
|
||||
output_64[i] = (uint64_t)vorr_u64(output_64x1_low, f_64x1_low);
|
||||
|
||||
uint64x1_t f_64x1_high = vshl_u64(f_64x1, shift_bit_high_64x1);
|
||||
uint64x1_t output_64x1_high = vld1_u64(&output_64[i + 1]);
|
||||
output_64[i + 1] = (uint64_t)vorr_u64(output_64x1_high, f_64x1_high);
|
||||
}
|
||||
}
|
||||
|
||||
if (args->toutput != NULL)
|
||||
stop_meas(args->toutput);
|
||||
|
||||
// Increment offset in output buffer
|
||||
offset_output_bit += E;
|
||||
// TODO Manage race condition every 8 segment end
|
||||
}
|
||||
|
||||
// Task running in // completed
|
||||
completed_task_ans(args->ans);
|
||||
}
|
||||
|
||||
static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters,
|
||||
int dlsch_id,
|
||||
thread_info_tm_t *t_info)
|
||||
{
|
||||
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
|
||||
uint32_t C = nrLDPC_TB_encoding_parameters->C;
|
||||
|
||||
size_t const n_seg = (C / 8 + ((C & 7) == 0 ? 0 : 1));
|
||||
|
||||
for (int j = 0; j < n_seg; j++) {
|
||||
ldpc8blocks_args_t *perJobImpp = &((ldpc8blocks_args_t *)t_info->buf)[t_info->len];
|
||||
DevAssert(t_info->len < t_info->cap);
|
||||
perJobImpp->ans = t_info->ans;
|
||||
t_info->len += 1;
|
||||
|
||||
perJobImpp->macro_num = j;
|
||||
perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters;
|
||||
perJobImpp->toutput = nrLDPC_slot_encoding_parameters->toutput;
|
||||
|
||||
task_t t = {.func = ldpc8blocks, .args = perJobImpp};
|
||||
pushTpool(nrLDPC_slot_encoding_parameters->threadPool, t);
|
||||
}
|
||||
return n_seg;
|
||||
}
|
||||
|
||||
int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
|
||||
{
|
||||
int nbTasks = 0;
|
||||
|
||||
for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) {
|
||||
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id];
|
||||
uint32_t C = nrLDPC_TB_encoding_parameters->C;
|
||||
size_t n_seg = (C / 8 + ((C & 7) == 0 ? 0 : 1));
|
||||
nbTasks += n_seg;
|
||||
}
|
||||
ldpc8blocks_args_t arr[nbTasks];
|
||||
task_ans_t ans;
|
||||
init_task_ans(&ans, nbTasks);
|
||||
thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbTasks, .ans = &ans};
|
||||
|
||||
int nbEncode = 0;
|
||||
for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) {
|
||||
nbEncode += nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info);
|
||||
}
|
||||
if (nbEncode < nbTasks) {
|
||||
completed_many_task_ans(&ans, nbTasks - nbEncode);
|
||||
}
|
||||
// Execute thread pool tasks
|
||||
join_task_ans(&ans);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user