From 8756afdb5ad640595b40fcaff58687305a000448 Mon Sep 17 00:00:00 2001 From: Yi-Hung Chang Date: Wed, 9 Oct 2024 14:45:31 +0200 Subject: [PATCH] feat(nrLDPC_coding_interface): Add ldpc_xdma coding library --- CMakeLists.txt | 26 +- cmake_targets/build_oai | 2 +- .../nrLDPC_coding_xdma/nrLDPC_coding_xdma.c | 455 ++++++++++ .../nrLDPC_coding_xdma_offload.c | 783 ++++++++++++++++++ .../nrLDPC_coding_xdma_offload.h | 67 ++ .../nrLDPC_coding_xdma/xdma_diag.h | 119 +++ 6 files changed, 1450 insertions(+), 2 deletions(-) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 44a2d0d487..e1528d1a62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,6 +508,19 @@ 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 + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c + ) + add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC}) +endif() + include_directories ("${OPENAIR_DIR}/radio/COMMON") ############################################################## @@ -2065,6 +2078,10 @@ if (ENABLE_LDPC_T2) add_dependencies(nr-softmodem ldpc_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 target_link_libraries(nr-softmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2126,6 +2143,10 @@ if (ENABLE_LDPC_T2) add_dependencies(nr-uesoftmodem ldpc_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) @@ -2283,6 +2304,9 @@ add_executable(nr_ulsim if (ENABLE_LDPC_T2) add_dependencies(nr_ulsim ldpc_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 @@ -2350,7 +2374,7 @@ 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_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 ldpc_xdma dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 5e1ad1467e..d6d3720bca 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -46,7 +46,7 @@ BUILD_DOXYGEN=0 DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="RelWithDebInfo" CMAKE_CMD="$CMAKE" -OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 websrv oai_iqplayer imscope" +OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 ldpc_xdma websrv oai_iqplayer imscope" TARGET_LIST="" BUILD_TOOL_OPT="-j$(nproc)" diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c new file mode 100644 index 0000000000..613c999042 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -0,0 +1,455 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the + * License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c + * \brief Top-level routines for decoding LDPC (ULSCH) transport channels + * decoding implemented using a FEC IP core on FPGA through XDMA driver + */ + +// [from gNB coding] +#include + +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_TRANSPORT/nr_ulsch.h" +#include "PHY/defs_gNB.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "SCHED_NR/sched_nr.h" +#include "common/utils/LOG/log.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "defs.h" +// #define DEBUG_ULSCH_DECODING +// #define gNB_DEBUG_TRACE + +#define OAI_UL_LDPC_MAX_NUM_LLR 27000 // 26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 +// #define DEBUG_CRC +#ifdef DEBUG_CRC +#define PRINT_CRC_CHECK(a) a +#else +#define PRINT_CRC_CHECK(a) +#endif + +// extern double cpuf; + +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" + +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" + +// Global var to limit the rework of the dirty legacy code +ldpc_interface_t ldpc_interface_segment; +int num_threads_prepare_max = 0; +char *user_device = NULL; +char *enc_read_device = NULL; +char *enc_write_device = NULL; +char *dec_read_device = NULL; +char *dec_write_device = NULL; + +/*! + * \typedef args_fpga_decode_prepare_t + * \struct args_fpga_decode_prepare_s + * \brief arguments structure for passing arguments to the nr_ulsch_FPGA_decoding_prepare_blocks function + */ +typedef struct args_fpga_decode_prepare_s { + nrLDPC_TB_decoding_parameters_t *TB_params; /*!< transport blocks parameters */ + + uint8_t *multi_indata; /*!< pointer to the head of the block destination array that is then passed to the FPGA decoding */ + int no_iteration_ldpc; /*!< pointer to the number of iteration set by this function */ + uint32_t r_first; /*!< index of the first block to be prepared within this function */ + uint32_t r_span; /*!< number of blocks to be prepared within this function */ + int r_offset; /*!< r index expressed in bits */ + int input_CBoffset; /*!< */ + int kc; /*!< */ + int K_bits_F; /*!< */ + task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */ +} args_fpga_decode_prepare_t; + +int32_t nrLDPC_coding_init(void); +int32_t nrLDPC_coding_shutdown(void); +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx); +// int32_t nrLDPC_coding_encoder(void); +int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, + int frame_rx, + int slot_rx, + tpool_t *ldpc_threadPool); +void nr_ulsch_FPGA_decoding_prepare_blocks(void *args); + +int32_t nrLDPC_coding_init(void) +{ + char *encoder_shlibversion = NULL; + paramdef_t LoaderParams[] = { + {"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL}, + {"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL}, + {"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL}, + {"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL}, + {"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL}, + {"dec_read_device", NULL, 0, .strptr = &dec_read_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_READ, TYPE_STRING, 0, NULL}, + {"dec_write_device", NULL, 0, .strptr = &dec_write_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_WRITE, TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_xdma"); + AssertFatal(num_threads_prepare_max != 0, "nrLDPC_coding_xdma.num_threads_prepare was not provided"); + + load_LDPClib(encoder_shlibversion, &ldpc_interface_segment); + return 0; +} + +int32_t nrLDPC_coding_shutdown(void) +{ + free_LDPClib(&ldpc_interface_segment); + return 0; +} + +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx) +{ + int nbDecode = 0; + for (int ULSCH_id = 0; ULSCH_id < slot_params->nb_TBs; ULSCH_id++) + nbDecode += decoder_xdma(&slot_params->TBs[ULSCH_id], frame_rx, slot_rx, slot_params->threadPool); + return nbDecode; +} + +/* +int32_t nrLDPC_coding_encoder(void) +{ + return 0; +} +*/ + +int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, + int frame_rx, + int slot_rx, + tpool_t *ldpc_threadPool) +{ + const uint32_t Kr = TB_params->K; + const uint32_t Kr_bytes = Kr >> 3; + const int kc = TB_params->BG == 2 ? 52 : 68; + int r_offset = 0, offset = 0; + int K_bits_F = Kr - TB_params->F; + + // FPGA parameter preprocessing + static uint8_t multi_indata[27000 * 25]; // FPGA input data + static uint8_t multi_outdata[1100 * 25]; // FPGA output data + + int bg_len = TB_params->BG == 1 ? 22 : 10; + + // Calc input CB offset + int input_CBoffset = TB_params->Z * kc * 8; + if ((input_CBoffset & 0x7F) == 0) + input_CBoffset = input_CBoffset / 8; + else + input_CBoffset = 16 * ((input_CBoffset / 128) + 1); + + DecIFConf dec_conf = {0}; + dec_conf.Zc = TB_params->Z; + dec_conf.BG = TB_params->BG; + dec_conf.max_iter = TB_params->max_ldpc_iterations; + dec_conf.numCB = TB_params->C; + // input soft bits length, Zc x 66 - length of filler bits + dec_conf.numChannelLls = (K_bits_F - 2 * TB_params->Z) + (kc * TB_params->Z - Kr); + // filler bits length + dec_conf.numFillerBits = TB_params->F; + dec_conf.max_schedule = 0; + dec_conf.SetIdx = 12; + dec_conf.nRows = (dec_conf.BG == 1) ? 46 : 42; + + dec_conf.user_device = user_device; + dec_conf.enc_read_device = enc_read_device; + dec_conf.enc_write_device = enc_write_device; + dec_conf.dec_read_device = dec_read_device; + dec_conf.dec_write_device = dec_write_device; + + int out_CBoffset = dec_conf.Zc * bg_len; + if ((out_CBoffset & 0x7F) == 0) + out_CBoffset = out_CBoffset / 8; + else + out_CBoffset = 16 * ((out_CBoffset / 128) + 1); + +#ifdef LDPC_DATA + printf("\n------------------------\n"); + printf("BG:\t\t%d\n", dec_conf.BG); + printf("TB_params->C: %d\n", TB_params->C); + printf("TB_params->K: %d\n", TB_params->K); + printf("TB_params->Z: %d\n", TB_params->Z); + printf("TB_params->F: %d\n", TB_params->F); + printf("numChannelLls:\t %d = (%d - 2 * %d) + (%d * %d - %d)\n", + dec_conf.numChannelLls, + K_bits_F, + TB_params->Z, + kc, + TB_params->Z, + Kr); + printf("numFillerBits:\t %d\n", TB_params->F); + printf("------------------------\n"); + // =================================== + // debug mode + // =================================== + FILE *fptr_llr, *fptr_ldpc; + fptr_llr = fopen("../../../cmake_targets/log/ulsim_ldpc_llr.txt", "w"); + fptr_ldpc = fopen("../../../cmake_targets/log/ulsim_ldpc_output.txt", "w"); + // =================================== +#endif + + int length_dec = lenWithCrc(TB_params->C, TB_params->A); + uint8_t crc_type = crcType(TB_params->C, TB_params->A); + int no_iteration_ldpc = 2; + + uint32_t num_threads_prepare = 0; + + // calculate required number of jobs + uint32_t r_while = 0; + while (r_while < TB_params->C) { + + // calculate number of segments processed in the new job + uint32_t modulus = (TB_params->C - r_while) % (num_threads_prepare_max - num_threads_prepare); + uint32_t quotient = (TB_params->C - r_while) / (num_threads_prepare_max - num_threads_prepare); + uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1; + + // saturate to be sure to not go above C + uint32_t r_span = TB_params->C - r_while < r_span_max ? TB_params->C - r_while : r_span_max; + + // increment + num_threads_prepare++; + r_while += r_span; + } + + args_fpga_decode_prepare_t arr[num_threads_prepare]; + task_ans_t ans[num_threads_prepare]; + memset(ans, 0, num_threads_prepare * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = num_threads_prepare, .ans = ans}; + + // start the prepare jobs + uint32_t r_remaining = 0; + for (uint32_t r = 0; r < TB_params->C; r++) { + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + if (r_remaining == 0) { + // TODO: int nr_tti_rx = 0; + + args_fpga_decode_prepare_t *args = &((args_fpga_decode_prepare_t *)t_info.buf)[t_info.len]; + DevAssert(t_info.len < t_info.cap); + args->ans = &t_info.ans[t_info.len]; + t_info.len += 1; + + args->TB_params = TB_params; + args->multi_indata = multi_indata; + args->no_iteration_ldpc = no_iteration_ldpc; + args->r_first = r; + + uint32_t modulus = (TB_params->C - r) % (num_threads_prepare_max - num_threads_prepare); + uint32_t quotient = (TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare); + uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1; + + uint32_t r_span = TB_params->C - r < r_span_max ? TB_params->C - r : r_span_max; + args->r_span = r_span; + args->r_offset = r_offset; + args->input_CBoffset = input_CBoffset; + args->kc = kc; + args->K_bits_F = K_bits_F; + + r_remaining = r_span; + + task_t t = {.func = &nr_ulsch_FPGA_decoding_prepare_blocks, .args = args}; + pushTpool(ldpc_threadPool, t); + + LOG_D(PHY, "Added %d block(s) to prepare for decoding, in pipe: %d to %d\n", r_span, r, r + r_span - 1); + } + r_offset += segment_params->E; + offset += (Kr_bytes - (TB_params->F >> 3) - ((TB_params->C > 1) ? 3 : 0)); + r_remaining -= 1; + } + + // reset offset in order to properly fill the output array later + offset = 0; + + DevAssert(num_threads_prepare == t_info.len); + + // wait for the prepare jobs to complete + join_task_ans(t_info.ans, t_info.len); + + for (uint32_t job = 0; job < num_threads_prepare; job++) { + args_fpga_decode_prepare_t *args = &arr[job]; + if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations) + no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + } + + // launch decode with FPGA + LOG_I(PHY, "Run the LDPC ------[FPGA version]------\n"); + //================================================================== + // Xilinx FPGA LDPC decoding function -> nrLDPC_decoder_FPGA_PYM() + //================================================================== + start_meas(&TB_params->segments[0].ts_ldpc_decode); + nrLDPC_decoder_FPGA_PYM(&multi_indata[0], &multi_outdata[0], dec_conf); + // printf("Xilinx FPGA -> CB = %d\n", harq_process->C); + stop_meas(&TB_params->segments[0].ts_ldpc_decode); + + *TB_params->processedSegments = 0; + for (uint32_t r = 0; r < TB_params->C; r++) { + // ------------------------------------------------------------ + // --------------------- copy FPGA output --------------------- + // ------------------------------------------------------------ + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + if (check_crc(multi_outdata, length_dec, crc_type)) { +#ifdef DEBUG_CRC + LOG_I(PHY, "Segment %d CRC OK\n", r); +#endif + no_iteration_ldpc = 2; + } else { +#ifdef DEBUG_CRC + LOG_I(PHY, "segment %d CRC NOK\n", r); +#endif + no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + } + for (int i = 0; i < out_CBoffset; i++) { + segment_params->c[i] = multi_outdata[i + r * out_CBoffset]; + } + segment_params->decodeSuccess = (no_iteration_ldpc <= TB_params->max_ldpc_iterations); + if (segment_params->decodeSuccess) { + *TB_params->processedSegments = *TB_params->processedSegments + 1; + } + } + + return 0; +} + +/*! + * \fn nr_ulsch_FPGA_decoding_prepare_blocks(void *args) + * \brief prepare blocks for LDPC decoding on FPGA + * + * \param args pointer to the arguments of the function in a structure of type args_fpga_decode_prepare_t + */ +void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) +{ + // extract the arguments + args_fpga_decode_prepare_t *arguments = (args_fpga_decode_prepare_t *)args; + + nrLDPC_TB_decoding_parameters_t *TB_params = arguments->TB_params; + + uint8_t Qm = TB_params->Qm; + + uint8_t BG = TB_params->BG; + uint8_t rv_index = TB_params->rv_index; + uint8_t max_ldpc_iterations = TB_params->max_ldpc_iterations; + + uint32_t tbslbrm = TB_params->tbslbrm; + uint32_t Kr = TB_params->K; + uint32_t Z = TB_params->Z; + uint32_t F = TB_params->F; + + uint32_t C = TB_params->C; + + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[0]; + + short *ulsch_llr = segment_params->llr; + + uint8_t *multi_indata = arguments->multi_indata; + int no_iteration_ldpc = arguments->no_iteration_ldpc; + uint32_t r_first = arguments->r_first; + uint32_t r_span = arguments->r_span; + int r_offset = arguments->r_offset; + int input_CBoffset = arguments->input_CBoffset; + int kc = arguments->kc; + int K_bits_F = arguments->K_bits_F; + + int16_t z[68 * 384 + 16] __attribute__((aligned(16))); + simde__m128i *pv = (simde__m128i *)&z; + + // the function processes r_span blocks starting from block at index r_first in ulsch_llr + for (uint32_t r = r_first; r < (r_first + r_span); r++) { + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + // ----------------------- FPGA pre process ------------------------ + simde__m128i ones = simde_mm_set1_epi8(255); // Generate a vector with all elements set to 255 + simde__m128i *temp_multi_indata = (simde__m128i *)&multi_indata[r * input_CBoffset]; + // ----------------------------------------------------------------- + + // code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t harq_e[segment_params->E]; + // ------------------------------------------------------------------------------------------- + // deinterleaving + // ------------------------------------------------------------------------------------------- + start_meas(&segment_params->ts_deinterleave); + nr_deinterleaving_ldpc(segment_params->E, Qm, harq_e, ulsch_llr + r_offset); + stop_meas(&segment_params->ts_deinterleave); + // ------------------------------------------------------------------------------------------- + // dematching + // ------------------------------------------------------------------------------------------- + start_meas(&segment_params->ts_rate_unmatch); + if (nr_rate_matching_ldpc_rx(tbslbrm, + BG, + Z, + segment_params->d, + harq_e, + C, + rv_index, + *segment_params->d_to_be_cleared, + segment_params->E, + F, + Kr - F - 2 * Z) + == -1) { + stop_meas(&segment_params->ts_rate_unmatch); + LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n"); + no_iteration_ldpc = max_ldpc_iterations + 1; + arguments->no_iteration_ldpc = no_iteration_ldpc; + return; + } else { + stop_meas(&segment_params->ts_rate_unmatch); + } + + *segment_params->d_to_be_cleared = false; + + memset(segment_params->c, 0, Kr >> 3); + + // set first 2*Z_c bits to zeros + memset(&z[0], 0, 2 * Z * sizeof(int16_t)); + // set Filler bits + memset((&z[0] + K_bits_F), 127, F * sizeof(int16_t)); + // Move coded bits before filler bits + memcpy((&z[0] + 2 * Z), segment_params->d, (K_bits_F - 2 * Z) * sizeof(int16_t)); + // skip filler bits + memcpy((&z[0] + Kr), segment_params->d + (Kr - 2 * Z), (kc * Z - Kr) * sizeof(int16_t)); + + // Saturate coded bits before decoding into 8 bits values + for (int i = 0, j = 0; j < ((kc * Z) >> 4); i += 2, j++) { + temp_multi_indata[j] = + simde_mm_xor_si128(simde_mm_packs_epi16(pv[i], pv[i + 1]), + simde_mm_cmpeq_epi32(ones, + ones)); // Perform NOT operation and write the result to temp_multi_indata[j] + } + + // the last bytes before reaching "kc * harq_process->Z" should not be written 128 bits at a time to avoid overwritting the + // following block in multi_indata + simde__m128i tmp = + simde_mm_xor_si128(simde_mm_packs_epi16(pv[2 * ((kc * Z) >> 4)], pv[2 * ((kc * Z) >> 4) + 1]), + simde_mm_cmpeq_epi32(ones, + ones)); // Perform NOT operation and write the result to temp_multi_indata[j] + uint8_t *tmp_p = (uint8_t *)&tmp; + for (int i = 0, j = ((kc * Z) & 0xfffffff0); j < kc * Z; i++, j++) { + multi_indata[r * input_CBoffset + j] = tmp_p[i]; + } + + r_offset += segment_params->E; + } + + arguments->no_iteration_ldpc = no_iteration_ldpc; +} diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c new file mode 100644 index 0000000000..0673ad2c73 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2016-present, Xilinx, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license + * the terms of the BSD Licence are reported below: + * + * BSD License + * + * For Xilinx DMA IP software + * + * Copyright (c) 2016-present, Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name Xilinx nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _DEFAULT_SOURCE +#define _XOPEN_SOURCE 500 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "xdma_diag.h" +#include "nrLDPC_coding_xdma_offload.h" + +#include "common/utils/assertions.h" + +typedef unsigned long long U64; +void* map_base; +int fd; +int fd_enc_write, fd_enc_read; +char *dev_enc_write, *dev_enc_read; +int fd_dec_write, fd_dec_read; +char *dev_dec_write, *dev_dec_read; +char allocated_write[24 * 1024] __attribute__((aligned(4096))); +char allocated_read[24 * 1024 * 3] __attribute__((aligned(4096))); + +// dma_from_device.c + +// [Start] #include "dma_utils.c" =================================== + +/* + * man 2 write: + * On Linux, write() (and similar system calls) will transfer at most + * 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes + * actually transferred. (This is true on both 32-bit and 64-bit + * systems.) + */ + +#define RW_MAX_SIZE 0x7ffff000 + +int verbose = 0; + +uint64_t getopt_integer(char* optarg) +{ + int rc; + uint64_t value; + + rc = sscanf(optarg, "0x%lx", &value); + if (rc <= 0) + rc = sscanf(optarg, "%lu", &value); + + return value; +} + +ssize_t read_to_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base) +{ + ssize_t rc; + uint64_t count = 0; + char* buf = buffer; + off_t offset = base; + + while (count < size) { + uint64_t bytes = size - count; + + if (bytes > RW_MAX_SIZE) + bytes = RW_MAX_SIZE; + + if (offset) { + rc = lseek(fd, offset, SEEK_SET); + if (rc != offset) { + fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset); + perror("seek file"); + return -EIO; + } + } + /* read data from file into memory buffer */ + rc = read(fd, buf, bytes); + + if (rc != bytes) { + fprintf(stderr, "%s, R off 0x%lx, 0x%lx != 0x%lx.\n", fname, count, rc, bytes); + perror("read file"); + return -EIO; + } + + count += bytes; + buf += bytes; + offset += bytes; + } + + if (count != size) { + fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size); + return -EIO; + } + return count; +} + +ssize_t write_from_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base) +{ + ssize_t rc; + uint64_t count = 0; + char* buf = buffer; + off_t offset = base; + + while (count < size) { + uint64_t bytes = size - count; + + if (bytes > RW_MAX_SIZE) + bytes = RW_MAX_SIZE; + + if (offset) { + rc = lseek(fd, offset, SEEK_SET); + if (rc != offset) { + fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset); + perror("seek file"); + return -EIO; + } + } + + /* write data to file from memory buffer */ + rc = write(fd, buf, bytes); + if (rc != bytes) { + fprintf(stderr, "%s, W off 0x%lx, 0x%lx != 0x%lx.\n", fname, offset, rc, bytes); + perror("write file"); + return -EIO; + } + + count += bytes; + buf += bytes; + offset += bytes; + } + + if (count != size) { + fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size); + return -EIO; + } + return count; +} + +// [End] #include "dma_utils.c" =================================== + +int test_dma_enc_read(char* EncOut, EncIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = CB_PROCESS_NUMBER; + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + mb = Confparam.kb_1 + kb; + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j; + uint32_t OutDataNUM = Z_val * mb; + uint32_t Out_dwNumItems_p128; + uint32_t Out_dwNumItems; + + if ((OutDataNUM & 0x7F) == 0) + Out_dwNumItems_p128 = OutDataNUM >> 5; + else + Out_dwNumItems_p128 = ((OutDataNUM >> 7) + 1) << 2; + Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num); + size = Out_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_ENC_OUT; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + if (fd_enc_read < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_read, fd_enc_read); + perror("open device"); + return -EINVAL; + } + + /* lseek & read data from AXI MM into buffer using SGDMA */ + rc = read_to_buffer(dev_enc_read, fd_enc_read, EncOut, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +int test_dma_enc_write(char* data, EncIPConf Confparam) +{ + ssize_t rc; + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = CB_PROCESS_NUMBER; + + // this values should be given by Shane + max_schedule = 0; + + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + mb = Confparam.kb_1 + kb; + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j; + uint32_t InDataNUM = Z_val * kb; + uint32_t In_dwNumItems_p128; + uint32_t In_dwNumItems; + + if ((InDataNUM & 0x7F) == 0) + In_dwNumItems_p128 = InDataNUM >> 5; + else + In_dwNumItems_p128 = ((InDataNUM >> 7) + 1) << 2; + + In_dwNumItems = ((In_dwNumItems_p128 << 2) * CB_num); + size = In_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_ENC_IN; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + if (fd_enc_write < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_write, fd_enc_write); + perror("open device"); + return -EINVAL; + } + + rc = write_from_buffer(dev_enc_write, fd_enc_write, data, size, 0); + if (rc < 0) + goto out; + rc = 0; + +out: + + return rc; +} + +// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam) +int test_dma_dec_read(char* DecOut, DecIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = Confparam.CB_num; + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + max_iter = 8; + sc_idx = 12; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = + (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j; + + uint32_t OutDataNUM = Z_val * kb; + uint32_t Out_dwNumItems_p128; + uint32_t Out_dwNumItems; + + if (CB_num & 0x01) // odd cb number + { + if ((OutDataNUM & 0xFF) == 0) + Out_dwNumItems_p128 = OutDataNUM; + else + Out_dwNumItems_p128 = 256 * ((OutDataNUM / 256) + 1); + + Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3; + } else { + if ((OutDataNUM & 0x7F) == 0) + Out_dwNumItems_p128 = OutDataNUM; + else + Out_dwNumItems_p128 = 128 * ((OutDataNUM / 128) + 1); + + Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3; + if ((Out_dwNumItems & 0x1f) != 0) + Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5; + + } + size = Out_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_DEC_OUT; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + + if (fd_dec_read < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_read, fd_dec_read); + perror("open device"); + return -EINVAL; + } + + /* lseek & read data from AXI MM into buffer using SGDMA */ + rc = read_to_buffer(dev_dec_read, fd_dec_read, DecOut, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam) +int test_dma_dec_write(char* data, DecIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = Confparam.CB_num; // CB_PROCESS_NUMBER_Dec;// + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + max_iter = 8; + sc_idx = 12; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = + (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j; + + uint32_t InDataNUM = Z_val * mb; + uint32_t In_dwNumItems_p128; + uint32_t In_dwNumItems; + + InDataNUM = Z_val * mb * 8; + if ((InDataNUM & 0x7F) == 0) + In_dwNumItems_p128 = InDataNUM; + else + In_dwNumItems_p128 = 128 * ((InDataNUM / 128) + 1); + + In_dwNumItems = (In_dwNumItems_p128 * CB_num) >> 3; + if ((In_dwNumItems & 0x1f) != 0) + In_dwNumItems = ((In_dwNumItems + 31) >> 5) << 5; + + size = In_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_DEC_IN; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + + if (fd_dec_write < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_write, fd_dec_write); + perror("open device"); + return -EINVAL; + } + + rc = write_from_buffer(dev_dec_write, fd_dec_write, data, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +void test_dma_init(devices_t devices) +{ + /* access width */ + char* device2 = devices.user_device; + + AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2); + fflush(stdout); + + /* map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base); + + void* virt_addr; + virt_addr = map_base + OFFSET_RESET; + *((uint32_t*)virt_addr) = 1; + + dev_enc_write = devices.enc_write_device; + dev_enc_read = devices.enc_read_device; + dev_dec_write = devices.dec_write_device; + dev_dec_read = devices.dec_read_device; + + fd_enc_write = open(dev_enc_write, O_RDWR); + fd_enc_read = open(dev_enc_read, O_RDWR); + fd_dec_write = open(dev_dec_write, O_RDWR); + fd_dec_read = open(dev_dec_read, O_RDWR); + + fflush(stdout); + +} + +void dma_reset(devices_t devices) +{ + char* device2 = devices.user_device; + + void* virt_addr; + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure"); + close(fd_enc_write); + close(fd_enc_read); + close(fd_dec_write); + close(fd_dec_read); + close(fd); + + AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2); + fflush(stdout); + + /* map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base); + + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + virt_addr = map_base + OFFSET_RESET; + *((uint32_t*)virt_addr) = 1; + + dev_enc_write = devices.enc_write_device; + dev_enc_read = devices.enc_read_device; + dev_dec_write = devices.dec_write_device; + dev_dec_read = devices.dec_read_device; + + fd_enc_write = open(dev_enc_write, O_RDWR); + fd_enc_read = open(dev_enc_read, O_RDWR); + fd_dec_write = open(dev_dec_write, O_RDWR); + fd_dec_read = open(dev_dec_read, O_RDWR); + + fflush(stdout); +} + +void test_dma_shutdown() +{ + + void* virt_addr; + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure"); + close(fd_enc_write); + close(fd_enc_read); + close(fd_dec_write); + close(fd_dec_read); + close(fd); + +} + +// reg_rx.c +int nrLDPC_decoder_FPGA_PYM(uint8_t* buf_in, uint8_t* buf_out, DecIFConf dec_conf) +{ + struct timespec ts_start0; // evaluate time from input setting to output setting including xdma + + int Zc; + int nRows; + int baseGraph; + int CB_num; + + DecIPConf Confparam; + int z_a, z_tmp; + int z_j = 0; + + + int input_CBoffset, output_CBoffset; + + uint8_t i_LS; + + devices_t devices = { + .user_device = dec_conf.user_device, + .enc_write_device = dec_conf.enc_write_device, + .enc_read_device = dec_conf.enc_read_device, + .dec_write_device = dec_conf.dec_write_device, + .dec_read_device = dec_conf.dec_read_device + }; + + static int init_flag = 0; + if (init_flag == 0) { + /*Init*/ + test_dma_init(devices); + init_flag = 1; + } else { + dma_reset(devices); + } + + clock_gettime(CLOCK_MONOTONIC, &ts_start0); // time start0 + // LDPC input parameter + Zc = dec_conf.Zc; // shifting size + nRows = dec_conf.nRows; // number of Rows + baseGraph = dec_conf.BG; // base graph + CB_num = dec_conf.numCB; // 31 number of code block + + // calc xdma LDPC parameter + // calc i_LS + if ((Zc % 15) == 0) + i_LS = 7; + else if ((Zc % 13) == 0) + i_LS = 6; + else if ((Zc % 11) == 0) + i_LS = 5; + else if ((Zc % 9) == 0) + i_LS = 4; + else if ((Zc % 7) == 0) + i_LS = 3; + else if ((Zc % 5) == 0) + i_LS = 2; + else if ((Zc % 3) == 0) + i_LS = 1; + else + i_LS = 0; + + // calc z_a + if (i_LS == 0) + z_a = 2; + else + z_a = i_LS * 2 + 1; + + // calc z_j + z_tmp = Zc / z_a; + while (z_tmp % 2 == 0) { + z_j = z_j + 1; + z_tmp = z_tmp / 2; + } + + // calc CB_num and mb + Confparam.CB_num = CB_num; + if (baseGraph == 1) + Confparam.mb = 22 + nRows; + else + Confparam.mb = 10 + nRows; + + // set BGSel, z_set, z_j + Confparam.BGSel = baseGraph; + Confparam.z_set = i_LS + 1; + Confparam.z_j = z_j; + + // Calc input CB offset + input_CBoffset = Zc * Confparam.mb * 8; + if ((input_CBoffset & 0x7F) == 0) + input_CBoffset = input_CBoffset / 8; + else + input_CBoffset = 16 * ((input_CBoffset / 128) + 1); + + // Calc output CB offset + output_CBoffset = Zc * (Confparam.mb - nRows); + if ((output_CBoffset & 0x7F) == 0) + output_CBoffset = output_CBoffset / 8; + else + output_CBoffset = 16 * ((output_CBoffset / 128) + 1); + + // LDPC accelerator start + // write into accelerator + if (test_dma_dec_write((char *)buf_in, Confparam) != 0) { + exit(1); + printf("write exit!!\n"); + } + + // read output of accelerator + if (test_dma_dec_read((char *)buf_out, Confparam) != 0) { + exit(1); + printf("read exit!!\n"); + } + + return 0; +} + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h new file mode 100644 index 0000000000..e908051156 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h @@ -0,0 +1,67 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the + * License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h + * \briefFPGA accelerator integrated into OAI (for one and multi code block) + * \author Sendren Xu, SY Yeh(fdragon), Hongming, Terng-Yin Hsu + * \date 2022-05-31 + * \version 5.0 + * \email: summery19961210@gmail.com + */ + +#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_ + +#define __NRLDPC_CODING_XDMA_OFFLOAD__H_ + +#include + +#define DEVICE_NAME_DEFAULT_USER "/dev/xdma0_user" +#define DEVICE_NAME_DEFAULT_ENC_READ "/dev/xdma0_c2h_1" +#define DEVICE_NAME_DEFAULT_ENC_WRITE "/dev/xdma0_h2c_1" +#define DEVICE_NAME_DEFAULT_DEC_READ "/dev/xdma0_c2h_0" +#define DEVICE_NAME_DEFAULT_DEC_WRITE "/dev/xdma0_h2c_0" + +/** + \brief LDPC input parameter + \param Zc shifting size + \param Rows + \param baseGraph base graph + \param CB_num number of code block + \param numChannelLlrs input soft bits length, Zc x 66 - length of filler bits + \param numFillerBits filler bits length +*/ +typedef struct { + char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device; + unsigned char max_schedule; + unsigned char SetIdx; + int Zc; + unsigned char numCB; + unsigned char BG; + unsigned char max_iter; + int nRows; + int numChannelLls; + int numFillerBits; +} DecIFConf; + +int nrLDPC_decoder_FPGA_PYM(uint8_t *buf_in, uint8_t *buf_out, DecIFConf dec_conf); + +#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_ + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h new file mode 100644 index 0000000000..8ef498c770 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016-present, Xilinx, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license + * the terms of the BSD Licence are reported below: + * + * BSD License + * + * For Xilinx DMA IP software + * + * Copyright (c) 2016-present, Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name Xilinx nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MODULES_TXCTRL_INC_XDMA_DIAG_H_ +#define MODULES_TXCTRL_INC_XDMA_DIAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unsigned char max_schedule; // max_schedule = 0; + unsigned char mb; // mb = 32; + unsigned char CB_num; // id = CB_num; + unsigned char BGSel; // bg = 1; + unsigned char z_set; // z_set = 0; + unsigned char z_j; // z_j = 6; + unsigned char max_iter; // max_iter = 8; + unsigned char SetIdx; // sc_idx = 12; +} DecIPConf; + +typedef struct { + int SetIdx; + int NumCBSegm; + int PayloadLen; + int Z; + int z_set; + int z_j; + int Kbmax; + int BGSel; + unsigned mb; + unsigned char CB_num; + unsigned char kb_1; +} EncIPConf; + +typedef struct { + char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device; +} devices_t; + +/* ltoh: little to host */ +/* htol: little to host */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ltohl(x) (x) +#define ltohs(x) (x) +#define htoll(x) (x) +#define htols(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define ltohl(x) __bswap_32(x) +#define ltohs(x) __bswap_16(x) +#define htoll(x) __bswap_32(x) +#define htols(x) __bswap_16(x) +#endif + +#define MAP_SIZE (32 * 1024UL) +#define MAP_MASK (MAP_SIZE - 1) + +#define SIZE_DEFAULT (32) +#define COUNT_DEFAULT (1) + +#define OFFSET_DEC_IN 0x0000 +#define OFFSET_DEC_OUT 0x0004 +#define OFFSET_ENC_IN 0x0008 +#define OFFSET_ENC_OUT 0x000c +#define OFFSET_RESET 0x0020 +#define PCIE_OFF 0x0030 + +#define CB_PROCESS_NUMBER 24 // add by JW +#define CB_PROCESS_NUMBER_Dec 24 + +// dma_from_device.c + +int test_dma_enc_read(char *EncOut, EncIPConf Confparam); +int test_dma_enc_write(char *data, EncIPConf Confparam); +int test_dma_dec_read(char *DecOut, DecIPConf Confparam); +int test_dma_dec_write(char *data, DecIPConf Confparam); +void test_dma_init(devices_t devices); +void test_dma_shutdown(); +void dma_reset(devices_t devices); + +#ifdef __cplusplus +} +#endif +#endif