Commit 8756afdb authored by Yi-Hung Chang's avatar Yi-Hung Chang Committed by Romain Beurdouche

feat(nrLDPC_coding_interface): Add ldpc_xdma coding library

parent 73770da5
......@@ -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)
......
......@@ -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)"
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
* \brief Top-level routines for decoding LDPC (ULSCH) transport channels
* decoding implemented using a FEC IP core on FPGA through XDMA driver
*/
// [from gNB coding]
#include <syscall.h>
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/coding_extern.h"
#include "PHY/CODING/lte_interleaver_inline.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_ulsch.h"
#include "PHY/defs_gNB.h"
#include "SCHED_NR/fapi_nr_l1.h"
#include "SCHED_NR/sched_nr.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "defs.h"
// #define DEBUG_ULSCH_DECODING
// #define gNB_DEBUG_TRACE
#define OAI_UL_LDPC_MAX_NUM_LLR 27000 // 26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
// #define DEBUG_CRC
#ifdef DEBUG_CRC
#define PRINT_CRC_CHECK(a) a
#else
#define PRINT_CRC_CHECK(a)
#endif
// extern double cpuf;
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
// Global var to limit the rework of the dirty legacy code
ldpc_interface_t ldpc_interface_segment;
int num_threads_prepare_max = 0;
char *user_device = NULL;
char *enc_read_device = NULL;
char *enc_write_device = NULL;
char *dec_read_device = NULL;
char *dec_write_device = NULL;
/*!
* \typedef args_fpga_decode_prepare_t
* \struct args_fpga_decode_prepare_s
* \brief arguments structure for passing arguments to the nr_ulsch_FPGA_decoding_prepare_blocks function
*/
typedef struct args_fpga_decode_prepare_s {
nrLDPC_TB_decoding_parameters_t *TB_params; /*!< transport blocks parameters */
uint8_t *multi_indata; /*!< pointer to the head of the block destination array that is then passed to the FPGA decoding */
int no_iteration_ldpc; /*!< pointer to the number of iteration set by this function */
uint32_t r_first; /*!< index of the first block to be prepared within this function */
uint32_t r_span; /*!< number of blocks to be prepared within this function */
int r_offset; /*!< r index expressed in bits */
int input_CBoffset; /*!< */
int kc; /*!< */
int K_bits_F; /*!< */
task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */
} args_fpga_decode_prepare_t;
int32_t nrLDPC_coding_init(void);
int32_t nrLDPC_coding_shutdown(void);
int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx);
// int32_t nrLDPC_coding_encoder(void);
int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params,
int frame_rx,
int slot_rx,
tpool_t *ldpc_threadPool);
void nr_ulsch_FPGA_decoding_prepare_blocks(void *args);
int32_t nrLDPC_coding_init(void)
{
char *encoder_shlibversion = NULL;
paramdef_t LoaderParams[] = {
{"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL},
{"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "", 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;
}
/*
* Copyright (c) 2016-present, Xilinx, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license
* the terms of the BSD Licence are reported below:
*
* BSD License
*
* For Xilinx DMA IP software
*
* Copyright (c) 2016-present, Xilinx, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name Xilinx nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <byteswap.h>
#include <signal.h>
#include <ctype.h>
#include <termios.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include "xdma_diag.h"
#include "nrLDPC_coding_xdma_offload.h"
#include "common/utils/assertions.h"
typedef unsigned long long U64;
void* map_base;
int fd;
int fd_enc_write, fd_enc_read;
char *dev_enc_write, *dev_enc_read;
int fd_dec_write, fd_dec_read;
char *dev_dec_write, *dev_dec_read;
char allocated_write[24 * 1024] __attribute__((aligned(4096)));
char allocated_read[24 * 1024 * 3] __attribute__((aligned(4096)));
// dma_from_device.c
// [Start] #include "dma_utils.c" ===================================
/*
* man 2 write:
* On Linux, write() (and similar system calls) will transfer at most
* 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
* actually transferred. (This is true on both 32-bit and 64-bit
* systems.)
*/
#define RW_MAX_SIZE 0x7ffff000
int verbose = 0;
uint64_t getopt_integer(char* optarg)
{
int rc;
uint64_t value;
rc = sscanf(optarg, "0x%lx", &value);
if (rc <= 0)
rc = sscanf(optarg, "%lu", &value);
return value;
}
ssize_t read_to_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
{
ssize_t rc;
uint64_t count = 0;
char* buf = buffer;
off_t offset = base;
while (count < size) {
uint64_t bytes = size - count;
if (bytes > RW_MAX_SIZE)
bytes = RW_MAX_SIZE;
if (offset) {
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
perror("seek file");
return -EIO;
}
}
/* read data from file into memory buffer */
rc = read(fd, buf, bytes);
if (rc != bytes) {
fprintf(stderr, "%s, R off 0x%lx, 0x%lx != 0x%lx.\n", fname, count, rc, bytes);
perror("read file");
return -EIO;
}
count += bytes;
buf += bytes;
offset += bytes;
}
if (count != size) {
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
return -EIO;
}
return count;
}
ssize_t write_from_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base)
{
ssize_t rc;
uint64_t count = 0;
char* buf = buffer;
off_t offset = base;
while (count < size) {
uint64_t bytes = size - count;
if (bytes > RW_MAX_SIZE)
bytes = RW_MAX_SIZE;
if (offset) {
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset);
perror("seek file");
return -EIO;
}
}
/* write data to file from memory buffer */
rc = write(fd, buf, bytes);
if (rc != bytes) {
fprintf(stderr, "%s, W off 0x%lx, 0x%lx != 0x%lx.\n", fname, offset, rc, bytes);
perror("write file");
return -EIO;
}
count += bytes;
buf += bytes;
offset += bytes;
}
if (count != size) {
fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size);
return -EIO;
}
return count;
}
// [End] #include "dma_utils.c" ===================================
int test_dma_enc_read(char* EncOut, EncIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = CB_PROCESS_NUMBER;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
mb = Confparam.kb_1 + kb;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
uint32_t OutDataNUM = Z_val * mb;
uint32_t Out_dwNumItems_p128;
uint32_t Out_dwNumItems;
if ((OutDataNUM & 0x7F) == 0)
Out_dwNumItems_p128 = OutDataNUM >> 5;
else
Out_dwNumItems_p128 = ((OutDataNUM >> 7) + 1) << 2;
Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num);
size = Out_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_ENC_OUT;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_enc_read < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_read, fd_enc_read);
perror("open device");
return -EINVAL;
}
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(dev_enc_read, fd_enc_read, EncOut, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
int test_dma_enc_write(char* data, EncIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = CB_PROCESS_NUMBER;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
mb = Confparam.kb_1 + kb;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j;
uint32_t InDataNUM = Z_val * kb;
uint32_t In_dwNumItems_p128;
uint32_t In_dwNumItems;
if ((InDataNUM & 0x7F) == 0)
In_dwNumItems_p128 = InDataNUM >> 5;
else
In_dwNumItems_p128 = ((InDataNUM >> 7) + 1) << 2;
In_dwNumItems = ((In_dwNumItems_p128 << 2) * CB_num);
size = In_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_ENC_IN;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_enc_write < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_write, fd_enc_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(dev_enc_write, fd_enc_write, data, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam)
int test_dma_dec_read(char* DecOut, DecIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = Confparam.CB_num;
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
max_iter = 8;
sc_idx = 12;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data =
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
uint32_t OutDataNUM = Z_val * kb;
uint32_t Out_dwNumItems_p128;
uint32_t Out_dwNumItems;
if (CB_num & 0x01) // odd cb number
{
if ((OutDataNUM & 0xFF) == 0)
Out_dwNumItems_p128 = OutDataNUM;
else
Out_dwNumItems_p128 = 256 * ((OutDataNUM / 256) + 1);
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
} else {
if ((OutDataNUM & 0x7F) == 0)
Out_dwNumItems_p128 = OutDataNUM;
else
Out_dwNumItems_p128 = 128 * ((OutDataNUM / 128) + 1);
Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3;
if ((Out_dwNumItems & 0x1f) != 0)
Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5;
}
size = Out_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_DEC_OUT;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_dec_read < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_read, fd_dec_read);
perror("open device");
return -EINVAL;
}
/* lseek & read data from AXI MM into buffer using SGDMA */
rc = read_to_buffer(dev_dec_read, fd_dec_read, DecOut, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam)
int test_dma_dec_write(char* data, DecIPConf Confparam)
{
ssize_t rc;
void* virt_addr;
uint64_t size;
uint32_t writeval;
uint32_t Z_val;
uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx;
uint16_t z_set;
uint32_t ctrl_data;
uint32_t CB_num = Confparam.CB_num; // CB_PROCESS_NUMBER_Dec;//
// this values should be given by Shane
max_schedule = 0;
mb = Confparam.mb;
id = CB_num;
bg = Confparam.BGSel - 1;
z_set = Confparam.z_set - 1;
z_j = Confparam.z_j;
max_iter = 8;
sc_idx = 12;
if (z_set == 0)
z_a = 2;
else if (z_set == 1)
z_a = 3;
else if (z_set == 2)
z_a = 5;
else if (z_set == 3)
z_a = 7;
else if (z_set == 4)
z_a = 9;
else if (z_set == 5)
z_a = 11;
else if (z_set == 6)
z_a = 13;
else
z_a = 15;
if (bg == 0)
kb = 22;
else if (bg == 1)
kb = 10;
else if (bg == 2)
kb = 9;
else if (bg == 3)
kb = 8;
else
kb = 6;
Z_val = (unsigned int)(z_a << z_j);
ctrl_data =
(max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j;
uint32_t InDataNUM = Z_val * mb;
uint32_t In_dwNumItems_p128;
uint32_t In_dwNumItems;
InDataNUM = Z_val * mb * 8;
if ((InDataNUM & 0x7F) == 0)
In_dwNumItems_p128 = InDataNUM;
else
In_dwNumItems_p128 = 128 * ((InDataNUM / 128) + 1);
In_dwNumItems = (In_dwNumItems_p128 * CB_num) >> 3;
if ((In_dwNumItems & 0x1f) != 0)
In_dwNumItems = ((In_dwNumItems + 31) >> 5) << 5;
size = In_dwNumItems;
writeval = ctrl_data;
/* calculate the virtual address to be accessed */
virt_addr = map_base + OFFSET_DEC_IN;
/* swap 32-bit endianess if host is not little-endian */
writeval = htoll(writeval);
*((uint32_t*)virt_addr) = writeval;
if (fd_dec_write < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_write, fd_dec_write);
perror("open device");
return -EINVAL;
}
rc = write_from_buffer(dev_dec_write, fd_dec_write, data, size, 0);
if (rc < 0)
goto out;
rc = 0;
out:
return rc;
}
void test_dma_init(devices_t devices)
{
/* access width */
char* device2 = devices.user_device;
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
fflush(stdout);
/* map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
void* virt_addr;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
dev_enc_write = devices.enc_write_device;
dev_enc_read = devices.enc_read_device;
dev_dec_write = devices.dec_write_device;
dev_dec_read = devices.dec_read_device;
fd_enc_write = open(dev_enc_write, O_RDWR);
fd_enc_read = open(dev_enc_read, O_RDWR);
fd_dec_write = open(dev_dec_write, O_RDWR);
fd_dec_read = open(dev_dec_read, O_RDWR);
fflush(stdout);
}
void dma_reset(devices_t devices)
{
char* device2 = devices.user_device;
void* virt_addr;
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
close(fd_enc_write);
close(fd_enc_read);
close(fd_dec_write);
close(fd_dec_read);
close(fd);
AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2);
fflush(stdout);
/* map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base);
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
virt_addr = map_base + OFFSET_RESET;
*((uint32_t*)virt_addr) = 1;
dev_enc_write = devices.enc_write_device;
dev_enc_read = devices.enc_read_device;
dev_dec_write = devices.dec_write_device;
dev_dec_read = devices.dec_read_device;
fd_enc_write = open(dev_enc_write, O_RDWR);
fd_enc_read = open(dev_enc_read, O_RDWR);
fd_dec_write = open(dev_dec_write, O_RDWR);
fd_dec_read = open(dev_dec_read, O_RDWR);
fflush(stdout);
}
void test_dma_shutdown()
{
void* virt_addr;
virt_addr = map_base + PCIE_OFF;
*((uint32_t*)virt_addr) = 1;
AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure");
close(fd_enc_write);
close(fd_enc_read);
close(fd_dec_write);
close(fd_dec_read);
close(fd);
}
// reg_rx.c
int nrLDPC_decoder_FPGA_PYM(uint8_t* buf_in, uint8_t* buf_out, DecIFConf dec_conf)
{
struct timespec ts_start0; // evaluate time from input setting to output setting including xdma
int Zc;
int nRows;
int baseGraph;
int CB_num;
DecIPConf Confparam;
int z_a, z_tmp;
int z_j = 0;
int input_CBoffset, output_CBoffset;
uint8_t i_LS;
devices_t devices = {
.user_device = dec_conf.user_device,
.enc_write_device = dec_conf.enc_write_device,
.enc_read_device = dec_conf.enc_read_device,
.dec_write_device = dec_conf.dec_write_device,
.dec_read_device = dec_conf.dec_read_device
};
static int init_flag = 0;
if (init_flag == 0) {
/*Init*/
test_dma_init(devices);
init_flag = 1;
} else {
dma_reset(devices);
}
clock_gettime(CLOCK_MONOTONIC, &ts_start0); // time start0
// LDPC input parameter
Zc = dec_conf.Zc; // shifting size
nRows = dec_conf.nRows; // number of Rows
baseGraph = dec_conf.BG; // base graph
CB_num = dec_conf.numCB; // 31 number of code block
// calc xdma LDPC parameter
// calc i_LS
if ((Zc % 15) == 0)
i_LS = 7;
else if ((Zc % 13) == 0)
i_LS = 6;
else if ((Zc % 11) == 0)
i_LS = 5;
else if ((Zc % 9) == 0)
i_LS = 4;
else if ((Zc % 7) == 0)
i_LS = 3;
else if ((Zc % 5) == 0)
i_LS = 2;
else if ((Zc % 3) == 0)
i_LS = 1;
else
i_LS = 0;
// calc z_a
if (i_LS == 0)
z_a = 2;
else
z_a = i_LS * 2 + 1;
// calc z_j
z_tmp = Zc / z_a;
while (z_tmp % 2 == 0) {
z_j = z_j + 1;
z_tmp = z_tmp / 2;
}
// calc CB_num and mb
Confparam.CB_num = CB_num;
if (baseGraph == 1)
Confparam.mb = 22 + nRows;
else
Confparam.mb = 10 + nRows;
// set BGSel, z_set, z_j
Confparam.BGSel = baseGraph;
Confparam.z_set = i_LS + 1;
Confparam.z_j = z_j;
// Calc input CB offset
input_CBoffset = Zc * Confparam.mb * 8;
if ((input_CBoffset & 0x7F) == 0)
input_CBoffset = input_CBoffset / 8;
else
input_CBoffset = 16 * ((input_CBoffset / 128) + 1);
// Calc output CB offset
output_CBoffset = Zc * (Confparam.mb - nRows);
if ((output_CBoffset & 0x7F) == 0)
output_CBoffset = output_CBoffset / 8;
else
output_CBoffset = 16 * ((output_CBoffset / 128) + 1);
// LDPC accelerator start
// write into accelerator
if (test_dma_dec_write((char *)buf_in, Confparam) != 0) {
exit(1);
printf("write exit!!\n");
}
// read output of accelerator
if (test_dma_dec_read((char *)buf_out, Confparam) != 0) {
exit(1);
printf("read exit!!\n");
}
return 0;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h
* \briefFPGA accelerator integrated into OAI (for one and multi code block)
* \author Sendren Xu, SY Yeh(fdragon), Hongming, Terng-Yin Hsu
* \date 2022-05-31
* \version 5.0
* \email: summery19961210@gmail.com
*/
#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_
#define __NRLDPC_CODING_XDMA_OFFLOAD__H_
#include <stdint.h>
#define DEVICE_NAME_DEFAULT_USER "/dev/xdma0_user"
#define DEVICE_NAME_DEFAULT_ENC_READ "/dev/xdma0_c2h_1"
#define DEVICE_NAME_DEFAULT_ENC_WRITE "/dev/xdma0_h2c_1"
#define DEVICE_NAME_DEFAULT_DEC_READ "/dev/xdma0_c2h_0"
#define DEVICE_NAME_DEFAULT_DEC_WRITE "/dev/xdma0_h2c_0"
/**
\brief LDPC input parameter
\param Zc shifting size
\param Rows
\param baseGraph base graph
\param CB_num number of code block
\param numChannelLlrs input soft bits length, Zc x 66 - length of filler bits
\param numFillerBits filler bits length
*/
typedef struct {
char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device;
unsigned char max_schedule;
unsigned char SetIdx;
int Zc;
unsigned char numCB;
unsigned char BG;
unsigned char max_iter;
int nRows;
int numChannelLls;
int numFillerBits;
} DecIFConf;
int nrLDPC_decoder_FPGA_PYM(uint8_t *buf_in, uint8_t *buf_out, DecIFConf dec_conf);
#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment