From 49bdcfd95cfdd069cd8ef8397d84856bbaf56d3d Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:31:56 +0200 Subject: [PATCH] feat(nrLDPC_coding_interface): Add ldpc_slot_segment coding library --- CMakeLists.txt | 15 +- .../nrLDPC_coding_segment_decoder.c | 344 ++++++++++++++++++ .../nrLDPC_coding_segment_encoder.c | 245 +++++++++++++ 3 files changed, 601 insertions(+), 3 deletions(-) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d9a226aed4..b446d7fb41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -849,6 +849,12 @@ set(PHY_NR_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c ) +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 + ${PHY_NR_CODINGIF} +) + set(PHY_NRLDPC_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c ) @@ -873,6 +879,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 @@ -2049,7 +2056,7 @@ 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) @@ -2106,7 +2113,7 @@ 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) @@ -2269,6 +2276,7 @@ add_executable(nr_ulsim if (ENABLE_LDPC_T2) add_dependencies(nr_ulsim ldpc_t2) 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 @@ -2335,7 +2343,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 + dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c new file mode 100644 index 0000000000..9264c7a5b6 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -0,0 +1,344 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +* \brief Top-level routines for decoding LDPC transport channels +*/ + + +// [from gNB coding] +#include "PHY/defs_gNB.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_TRANSPORT/nr_ulsch.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "SCHED_NR/sched_nr.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "defs.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "common/utils/LOG/log.h" + +#include +#include +#include +#include +//#define gNB_DEBUG_TRACE + +#define OAI_LDPC_DECODER_MAX_NUM_LLR 27000 //26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 +//#define DEBUG_CRC +#ifdef DEBUG_CRC +#define PRINT_CRC_CHECK(a) a +#else +#define PRINT_CRC_CHECK(a) +#endif + +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" + +/** + * \typedef nrLDPC_decoding_parameters_t + * \struct nrLDPC_decoding_parameters_s + * \brief decoding parameter of transport blocks + * \var decoderParms decoder parameters + * \var Qm modulation order + * \var Kc size of base graph input + * \var rv_index + * \var max_number_iterations maximum number of LDPC iterations + * \var abort_decode pointer to decode abort flag + * \var tbslbrm transport block size LBRM in bytes + * \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1) + * \var K Code block size at decoder output + * \var Z lifting size + * \var F filler bits size + * \var r segment index in TB + * \var E input llr segment size + * \var C number of segments + * \var llr input llr segment array + * \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2) + * \var d_to_be_cleared + * pointer to the flag used to clear d properly + * when true, clear d after rate dematching + * \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2) + * \var decodeSuccess pointer to the flag indicating that the decoding of the segment was successful + * \var ans pointer to task answer used by the thread pool to detect task completion + * \var p_ts_deinterleave pointer to deinterleaving time stats + * \var p_ts_rate_unmatch pointer to rate unmatching time stats + * \var p_ts_ldpc_decode pointer to decoding time stats + */ +typedef struct nrLDPC_decoding_parameters_s{ + + t_nrLDPC_dec_params decoderParms; + + uint8_t Qm; + + uint8_t Kc; + uint8_t rv_index; + decode_abort_t *abort_decode; + + uint32_t tbslbrm; + uint32_t A; + uint32_t K; + uint32_t Z; + uint32_t F; + + uint32_t C; + + int E; + short *llr; + int16_t *d; + bool *d_to_be_cleared; + uint8_t *c; + bool *decodeSuccess; + + task_ans_t *ans; + + time_stats_t *p_ts_deinterleave; + time_stats_t *p_ts_rate_unmatch; + time_stats_t *p_ts_ldpc_decode; +} nrLDPC_decoding_parameters_t; + +// Global var to limit the rework of the dirty legacy code +ldpc_interface_t ldpc_interface_segment; + +static void nr_process_decode_segment(void *arg) +{ + nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg; + t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms; + const int Kr = rdata->K; + const int Kr_bytes = Kr >> 3; + const int K_bits_F = Kr - rdata->F; + const int A = rdata->A; + const int E = rdata->E; + const int Qm = rdata->Qm; + const int rv_index = rdata->rv_index; + const uint8_t kc = rdata->Kc; + short *ulsch_llr = rdata->llr; + int8_t llrProcBuf[OAI_LDPC_DECODER_MAX_NUM_LLR] __attribute__((aligned(32))); + + t_nrLDPC_time_stats procTime = {0}; + t_nrLDPC_time_stats *p_procTime = &procTime; + + //////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// nr_deinterleaving_ldpc /////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////// ulsch_llr =====> ulsch_harq->e ////////////////////////////// + + start_meas(rdata->p_ts_deinterleave); + + /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t harq_e[E]; + + nr_deinterleaving_ldpc(E, Qm, harq_e, ulsch_llr); + + ////////////////////////////////////////////////////////////////////////////////////////// + + stop_meas(rdata->p_ts_deinterleave); + + start_meas(rdata->p_ts_rate_unmatch); + + ////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////// nr_rate_matching_ldpc_rx //////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////// ulsch_harq->e =====> ulsch_harq->d ///////////////////////// + + + if (nr_rate_matching_ldpc_rx(rdata->tbslbrm, + p_decoderParms->BG, + p_decoderParms->Z, + rdata->d, + harq_e, + rdata->C, + rv_index, + *rdata->d_to_be_cleared, + E, + rdata->F, + Kr - rdata->F - 2 * (p_decoderParms->Z)) + == -1) { + + stop_meas(rdata->p_ts_rate_unmatch); + LOG_E(PHY, "nrLDPC_coding_segment_decoder.c: Problem in rate_matching\n"); + + // Task completed + completed_task_ans(rdata->ans); + return; + } + stop_meas(rdata->p_ts_rate_unmatch); + + *rdata->d_to_be_cleared = false; + + memset(rdata->c, 0, Kr_bytes); + p_decoderParms->crc_type = crcType(rdata->C, A); + p_decoderParms->E = lenWithCrc(rdata->C, A); + + // set first 2*Z_c bits to zeros + + int16_t z[68 * 384 + 16] __attribute__((aligned(16))); + + start_meas(rdata->p_ts_ldpc_decode); + + memset(z, 0, 2 * rdata->Z * sizeof(*z)); + // set Filler bits + memset(z + K_bits_F, 127, rdata->F * sizeof(*z)); + // Move coded bits before filler bits + memcpy(z + 2 * rdata->Z, rdata->d, (K_bits_F - 2 * rdata->Z) * sizeof(*z)); + // skip filler bits + memcpy(z + Kr, rdata->d + (Kr - 2 * rdata->Z), (kc * rdata->Z - Kr) * sizeof(*z)); + // Saturate coded bits before decoding into 8 bits values + simde__m128i *pv = (simde__m128i *)&z; + int8_t l[68 * 384 + 16] __attribute__((aligned(16))); + simde__m128i *pl = (simde__m128i *)&l; + for (int i = 0, j = 0; j < ((kc * rdata->Z) >> 4) + 1; i += 2, j++) { + pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]); + } + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////// nrLDPC_decoder ///////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// + int decodeIterations = + ldpc_interface_segment.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); + + if (decodeIterations <= p_decoderParms->numMaxIter) { + memcpy(rdata->c,llrProcBuf, Kr>>3); + *rdata->decodeSuccess = true; + } else { + *rdata->decodeSuccess = false; + } + stop_meas(rdata->p_ts_ldpc_decode); + + // Task completed + completed_task_ans(rdata->ans); +} + +int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int pusch_id, thread_info_tm_t *t_info) +{ + + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + + *nrLDPC_TB_decoding_parameters->processedSegments = 0; + t_nrLDPC_dec_params decParams = {.check_crc = check_crc}; + decParams.BG = nrLDPC_TB_decoding_parameters->BG; + decParams.Z = nrLDPC_TB_decoding_parameters->Z; + decParams.numMaxIter = nrLDPC_TB_decoding_parameters->max_ldpc_iterations; + decParams.outMode = 0; + + for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) { + + nrLDPC_decoding_parameters_t *rdata = &((nrLDPC_decoding_parameters_t *)t_info->buf)[t_info->len]; + DevAssert(t_info->len < t_info->cap); + rdata->ans = &t_info->ans[t_info->len]; + t_info->len += 1; + + decParams.R = nrLDPC_TB_decoding_parameters->segments[r].R; + decParams.setCombIn = !nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared; + rdata->decoderParms = decParams; + rdata->llr = nrLDPC_TB_decoding_parameters->segments[r].llr; + rdata->Kc = decParams.BG == 2 ? 52 : 68; + rdata->C = nrLDPC_TB_decoding_parameters->C; + rdata->E = nrLDPC_TB_decoding_parameters->segments[r].E; + rdata->A = nrLDPC_TB_decoding_parameters->A; + rdata->Qm = nrLDPC_TB_decoding_parameters->Qm; + rdata->K = nrLDPC_TB_decoding_parameters->K; + rdata->Z = nrLDPC_TB_decoding_parameters->Z; + rdata->F = nrLDPC_TB_decoding_parameters->F; + rdata->rv_index = nrLDPC_TB_decoding_parameters->rv_index; + rdata->tbslbrm = nrLDPC_TB_decoding_parameters->tbslbrm; + rdata->abort_decode = nrLDPC_TB_decoding_parameters->abort_decode; + rdata->d = nrLDPC_TB_decoding_parameters->segments[r].d; + rdata->d_to_be_cleared = nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared; + rdata->c = nrLDPC_TB_decoding_parameters->segments[r].c; + rdata->decodeSuccess = &nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess; + rdata->p_ts_deinterleave = &nrLDPC_TB_decoding_parameters->segments[r].ts_deinterleave; + rdata->p_ts_rate_unmatch = &nrLDPC_TB_decoding_parameters->segments[r].ts_rate_unmatch; + rdata->p_ts_ldpc_decode = &nrLDPC_TB_decoding_parameters->segments[r].ts_ldpc_decode; + + task_t t = {.func = &nr_process_decode_segment, .args = rdata}; + pushTpool(nrLDPC_slot_decoding_parameters->threadPool, t); + + LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r); + } + return nrLDPC_TB_decoding_parameters->C; +} + +int32_t nrLDPC_coding_init(void){ + + char *segment_shlibversion = NULL; + paramdef_t LoaderParams[] = { + {"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_segment"); + load_LDPClib(segment_shlibversion, &ldpc_interface_segment); + + return 0; + +} + +int32_t nrLDPC_coding_shutdown(void){ + + free_LDPClib(&ldpc_interface_segment); + + return 0; + +} + +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){ + + int nbSegments = 0; + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + nbSegments += nrLDPC_TB_decoding_parameters->C; + } + nrLDPC_decoding_parameters_t arr[nbSegments]; + task_ans_t ans[nbSegments]; + memset(ans, 0, nbSegments * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbSegments, .ans = ans}; + + int nbDecode = 0; + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nbDecode += nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters, pusch_id, &t_info); + } + + DevAssert(nbDecode == t_info.len); + + // Execute thread poool tasks + join_task_ans(t_info.ans, t_info.len); + + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) { + if (nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess) { + *nrLDPC_TB_decoding_parameters->processedSegments = *nrLDPC_TB_decoding_parameters->processedSegments + 1; + } + } + } + return 0; + +} + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c new file mode 100644 index 0000000000..2a9682d585 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c @@ -0,0 +1,245 @@ +/* + * 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 + +#include + +//#define DEBUG_LDPC_ENCODING +//#define DEBUG_LDPC_ENCODING_FREE 1 + +extern ldpc_interface_t ldpc_interface_segment; + +typedef struct ldpc8blocks_args_s { + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters; + encoder_implemparams_t impp; +} ldpc8blocks_args_t; + +static void ldpc8blocks_coding_segment(void *p) +{ + ldpc8blocks_args_t *args = (ldpc8blocks_args_t *)p; + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = args->nrLDPC_TB_encoding_parameters; + encoder_implemparams_t *impp = &args->impp; + + uint8_t mod_order = nrLDPC_TB_encoding_parameters->Qm; + uint16_t nb_rb = nrLDPC_TB_encoding_parameters->nb_rb; + uint32_t A = nrLDPC_TB_encoding_parameters->A; + + unsigned int G = nrLDPC_TB_encoding_parameters->G; + LOG_D(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + A,impp->K,G, nb_rb,(int)mod_order); + + // nrLDPC_encoder output is in "d" + // let's make this interface happy! + uint8_t tmp[8][68 * 384]__attribute__((aligned(32))); + uint8_t *d[impp->n_segments]; + for (int rr=impp->macro_num*8, i=0; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++,i++ ) + d[rr] = tmp[i]; + + uint8_t *c[nrLDPC_TB_encoding_parameters->C]; + for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) + c[r]=nrLDPC_TB_encoding_parameters->segments[r].c; + start_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num*8].ts_ldpc_encode); + ldpc_interface_segment.LDPCencoder(c, d, impp); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num*8].ts_ldpc_encode); + // Compute where to place in output buffer that is concatenation of all segments + + uint32_t r_offset=0; + for (int i=0; i < impp->macro_num*8; i++ ) + r_offset+=nrLDPC_TB_encoding_parameters->segments[i].E; + for (int rr=impp->macro_num*8; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++ ) { + if (impp->F>0) { + // writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212 + memset(&d[rr][impp->K - impp->F - 2 * impp->Zc], NR_NULL, impp->F); + } + +#ifdef DEBUG_LDPC_ENCODING + LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]); +#endif + uint32_t E = nrLDPC_TB_encoding_parameters->segments[rr].E; + LOG_D(NR_PHY, + "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb " + "%d,nrOfLayer %d)...\n", + rr, + impp->n_segments, + G, + E, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + mod_order, + nb_rb, + nrLDPC_TB_encoding_parameters->nb_layers); + + uint32_t Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm; + + uint8_t e[E]; + bzero (e, E); + start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match); + nr_rate_matching_ldpc(Tbslbrm, + impp->BG, + impp->Zc, + d[rr], + e, + impp->n_segments, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + nrLDPC_TB_encoding_parameters->rv_index, + E); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match); + if (impp->K - impp->F - 2 * impp->Zc > E) { + LOG_E(PHY, + "dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + A, + impp->K, + G, + nb_rb, + (int)mod_order); + + LOG_E(NR_PHY, + "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, " + "nb_rb %d)...\n", + rr, + impp->n_segments, + G, + E, + impp->K, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + mod_order, + nb_rb); + } +#ifdef DEBUG_LDPC_ENCODING + + for (int i =0; i<16; i++) + printf("output ratematching e[%d]= %d r_offset %u\n", i,e[i], r_offset); + +#endif + start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave); + nr_interleaving_ldpc(E, + mod_order, + e, + impp->output+r_offset); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave); +#ifdef DEBUG_LDPC_ENCODING + + for (int i =0; i<16; i++) + printf("output interleaving f[%d]= %d r_offset %u\n", i,impp->output[i+r_offset], r_offset); + + if (r==impp->n_segments-1) + write_output("enc_output.m","enc",impp->output,G,1,4); + +#endif + r_offset += E; + } + + // Task running in // completed + completed_task_ans(impp->ans); +} + +static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int dlsch_id, thread_info_tm_t *t_info) +{ + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; + + encoder_implemparams_t impp = {0}; + + impp.n_segments = nrLDPC_TB_encoding_parameters->C; + impp.tinput = nrLDPC_slot_encoding_parameters->tinput; + impp.tprep = nrLDPC_slot_encoding_parameters->tprep; + impp.tparity = nrLDPC_slot_encoding_parameters->tparity; + impp.toutput = nrLDPC_slot_encoding_parameters->toutput; + impp.Kb = nrLDPC_TB_encoding_parameters->Kb; + impp.Zc = nrLDPC_TB_encoding_parameters->Z; + NR_DL_gNB_HARQ_t harq; + impp.harq = &harq; + impp.BG = nrLDPC_TB_encoding_parameters->BG; + impp.output = nrLDPC_TB_encoding_parameters->segments->output; + impp.K = nrLDPC_TB_encoding_parameters->K; + impp.F = nrLDPC_TB_encoding_parameters->F; + 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; + + size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); + + for (int j = 0; j < n_seg; j++) { + ldpc8blocks_args_t *perJobImpp = &((ldpc8blocks_args_t *)t_info->buf)[t_info->len]; + DevAssert(t_info->len < t_info->cap); + impp.ans = &t_info->ans[t_info->len]; + t_info->len += 1; + + impp.macro_num = j; + perJobImpp->impp = impp; + perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters; + + task_t t = {.func = ldpc8blocks_coding_segment, .args = perJobImpp}; + pushTpool(nrLDPC_slot_encoding_parameters->threadPool, t); + } + return n_seg; +} + +int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + + int nbTasks = 0; + for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; + size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1)); + nbTasks += n_seg; + } + ldpc8blocks_args_t arr[nbTasks]; + task_ans_t ans[nbTasks]; + memset(ans, 0, nbTasks * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbTasks, .ans = ans}; + + int nbEncode = 0; + for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { + nbEncode += nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info); + } + + DevAssert(nbEncode == t_info.len); + + // Execute thread poool tasks + join_task_ans(ans, nbEncode); + + return 0; + +}