Commit 6bec8779 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Enhance T2 Offload for gNB and UE

- Reworked nrLDPC_decoder_offload.c to process all segments in a TB with a single call to LDPCdecoder() or LDPCencoder().
- Perform CRC checks on the T2.
- Modified nr_ulsch_decoding (gNB decoder) to:
  - Count processed segments.
  - Properly perform CRC checks.
- Created a constant NR_LDPC_MAX_NUM_CB to define the maximum number of codeblocks.
- Conditional library loading:
  - On gNB: Load ldpc_t2 library if offload is enabled using the --ldpc-offload-enable flag.
  - On UE: Load both ldpc_t2 and ldpc libraries since only encoder offload is supported.
- General cleanup of nrLDPC_decoder_offload.c for improved readability and maintainability.
- Modified the structure of LDPC encoder/decoder/offload parameters:
  - Introduced a structure for code block (CB) related parameters.
  - Removed parameter E from the encoder and offload parameter structures for clarity.
  - Replaced E with perCB->E_cb in the UE encoder code.
parent e5fc1ebd
......@@ -286,6 +286,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
UE->rf_map.card = card_offset;
UE->rf_map.chain = CC_id + chain_offset;
UE->max_ldpc_iterations = nrUE_params.max_ldpc_iterations;
UE->ldpc_offload_enable = nrUE_params.ldpc_offload_flag;
UE->UE_scan_carrier = nrUE_params.UE_scan_carrier;
UE->UE_fo_compensation = nrUE_params.UE_fo_compensation;
UE->if_freq = nrUE_params.if_freq;
......@@ -491,7 +492,11 @@ int main(int argc, char **argv)
cpuf=get_cpu_freq_GHz();
itti_init(TASK_MAX, tasks_info);
init_opt() ;
init_opt();
if (nrUE_params.ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
load_LDPClib(NULL, &ldpc_interface);
if (ouput_vcd) {
......
......@@ -37,6 +37,7 @@
{"dlsch-parallel", CONFIG_HLP_DLSCH_PARA, 0, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \
{"offset-divisor", CONFIG_HLP_OFFSET_DIV, 0, .uptr=&nrUE_params.ofdm_offset_divisor, .defuintval=8, TYPE_UINT32, 0}, \
{"max-ldpc-iterations", CONFIG_HLP_MAX_LDPC_ITERATIONS, 0, .iptr=&nrUE_params.max_ldpc_iterations, .defuintval=8, TYPE_UINT8, 0}, \
{"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&(nrUE_params.ldpc_offload_flag), .defintval=0, TYPE_INT, 0}, \
{"nr-dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, .iptr=(int32_t *)&nr_dlsch_demod_shift, .defintval=0, TYPE_INT, 0}, \
{"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, .iptr=&vcdflag, .defintval=0, TYPE_INT, 0}, \
{"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \
......@@ -80,6 +81,7 @@ typedef struct {
int nb_antennas_tx;
int N_RB_DL;
int ssb_start_subcarrier;
int ldpc_offload_flag;
} nrUE_params_t;
extern uint64_t get_nrUE_optmask(void);
extern uint64_t set_nrUE_optmask(uint64_t bitmask);
......
......@@ -259,7 +259,7 @@ one_measurement_t test_ldpc(short max_iterations,
printf("To: %d\n", (Kb + nrows - no_punctured_columns) * Zc - removed_bit);
printf("number of undecoded bits: %d\n", (Kb + nrows - no_punctured_columns - 2) * Zc - removed_bit);
encoder_implemparams_t impp = {.Zc = Zc, .Kb = Kb, .E = block_length, .BG = BG, .Kr = block_length, .K = block_length};
encoder_implemparams_t impp = {.Zc = Zc, .Kb = Kb, .BG = BG, .Kr = block_length, .K = block_length};
impp.gen_code = 2;
if (ntrials==0)
......
......@@ -78,6 +78,15 @@ typedef enum nrLDPC_outMode {
nrLDPC_outMode_LLRINT8 /**< Single LLR value per int8_t output */
} e_nrLDPC_outMode;
/**
Structure containing LDPC parameters per CB
*/
typedef struct nrLDPC_params_per_cb {
uint32_t E_cb;
uint8_t status_cb;
uint8_t* p_status_cb;
} nrLDPC_params_per_cb_t;
/**
Structure containing LDPC decoder parameters.
*/
......@@ -94,18 +103,24 @@ typedef struct nrLDPC_dec_params {
int crc_type;
int (*check_crc)(uint8_t* decoded_bytes, uint32_t n, uint8_t crc_type);
uint8_t setCombIn;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
} t_nrLDPC_dec_params;
/**
Structure containing LDPC offload parameters.
*/
typedef struct nrLDPCoffload_params {
uint8_t BG; /**< Base graph */
uint16_t Z;
uint16_t Kr;
uint8_t rv;
uint32_t E;
uint16_t n_cb;
uint16_t F; /**< Filler bits */
uint8_t Qm; /**< Modulation */
uint8_t C;
uint8_t numMaxIter;
uint8_t setCombIn;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
} t_nrLDPCoffload_params;
/**
......
......@@ -99,6 +99,8 @@
/** Maximum number of possible input LLR = NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX */
#define NR_LDPC_MAX_NUM_LLR 27000
#define NR_LDPC_MAX_NUM_CB 72
// ==============================================================================
// GLOBAL CONSTANT VARIABLES
......
......@@ -59,8 +59,9 @@ typedef struct {
uint32_t F;
/// Modulation order
uint8_t Qm;
uint32_t E;
uint32_t Tbslbrm;
unsigned int G;
nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB];
// Redundancy version index
uint8_t rv;
} encoder_implemparams_t;
......
......@@ -137,6 +137,9 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB)
if (gNB->ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
else
load_LDPClib(NULL, &ldpc_interface);
gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB;
init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table);
......
......@@ -360,6 +360,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
impp.harq = harq;
if (gNB->ldpc_offload_flag) {
impp.Qm = rel15->qamModOrder[0];
impp.Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
impp.rv = rel15->rvIndex[0];
int nb_re_dmrs =
(rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData);
......@@ -370,13 +371,10 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
harq->unav_res,
rel15->qamModOrder[0],
rel15->nrOfLayers);
int r_offset = 0;
for (int r = 0; r < impp.n_segments; r++) {
impp.E = nr_get_E(impp.G, impp.n_segments, impp.Qm, rel15->nrOfLayers, r);
uint8_t *f = impp.output + r_offset;
ldpc_interface_offload.LDPCencoder(&harq->c[r], &f, &impp);
r_offset += impp.E;
impp.perCB[r].E_cb = nr_get_E(impp.G, impp.n_segments, impp.Qm, rel15->nrOfLayers, r);
}
ldpc_interface_offload.LDPCencoder(harq->c, &impp.output, &impp);
} else {
notifiedFIFO_t nf;
initNotifiedFIFO(&nf);
......
......@@ -232,64 +232,59 @@ int decode_offload(PHY_VARS_gNB *phy_vars_gNB,
{
NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process;
int16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
int8_t l_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
uint8_t Qm = pusch_pdu->qam_mod_order;
uint8_t n_layers = pusch_pdu->nrOfLayers;
int16_t z_ol[NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
int8_t l_ol[NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE] __attribute__((aligned(16)));
const int kc = decParams->BG == 2 ? 52 : 68;
uint32_t A = (harq_process->TBS) << 3;
const int Kr = harq_process->K;
const int Kr_bytes = Kr >> 3;
uint32_t A = (harq_process->TBS) << 3;
const int kc = decParams->BG == 2 ? 52 : 68;
ulsch->max_ldpc_iterations = 20;
int decodeIterations = 2;
int r_offset = 0, offset = 0;
int8_t decodeIterations = 0;
int r_offset = 0;
int offset = 0;
// new data received, set processedSegments to 0
if (!decParams->setCombIn)
harq_process->processedSegments = 0;
for (int r = 0; r < harq_process->C; r++) {
int E = nr_get_E(G, harq_process->C, Qm, n_layers, r);
memset(harq_process->c[r], 0, Kr_bytes);
decParams->R = nr_get_R_ldpc_decoder(pusch_pdu->pusch_data.rv_index,
E,
decParams->BG,
decParams->Z,
&harq_process->llrLen,
harq_process->round);
memcpy(z_ol, ulsch_llr + r_offset, E * sizeof(short));
simde__m128i *pv_ol128 = (simde__m128i *)&z_ol;
simde__m128i *pl_ol128 = (simde__m128i *)&l_ol;
decParams->perCB[r].E_cb = nr_get_E(G, harq_process->C, decParams->Qm, pusch_pdu->nrOfLayers, r);
memcpy(&z_ol[offset], ulsch_llr + r_offset, decParams->perCB[r].E_cb * sizeof(*z_ol));
simde__m128i *pv_ol128 = (simde__m128i *)&z_ol[offset];
simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset];
for (int i = 0, j = 0; j < ((kc * harq_process->Z) >> 4) + 1; i += 2, j++) {
pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]);
}
decParams->E = E;
decParams->rv = pusch_pdu->pusch_data.rv_index;
decParams->F = harq_process->F;
decParams->Qm = Qm;
decodeIterations =
ldpc_interface_offload
.LDPCdecoder(decParams, harq_pid, ULSCH_id, r, (int8_t *)&pl_ol128[0], (int8_t *)harq_process->c[r], NULL, NULL);
if (decodeIterations < 0) {
LOG_E(PHY, "ulsch_decoding.c: Problem in LDPC decoder offload\n");
return -1;
}
bool decodeSuccess = check_crc((uint8_t *)harq_process->c[r], lenWithCrc(harq_process->C, A), crcType(harq_process->C, A));
if (decodeSuccess) {
memcpy(harq_process->b + offset, harq_process->c[r], Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
offset += (Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
r_offset += decParams->perCB[r].E_cb;
offset += LDPC_MAX_CB_SIZE;
}
int8_t *p_outDec = calloc(harq_process->C * Kr_bytes, sizeof(int8_t));
decodeIterations =
ldpc_interface_offload.LDPCdecoder(decParams, harq_pid, ULSCH_id, harq_process->C, (int8_t *)l_ol, p_outDec, NULL, NULL);
if (decodeIterations < 0) {
LOG_E(PHY, "ulsch_decoding.c: Problem in LDPC decoder offload\n");
return -1;
}
int offset_b = 0;
for (int r = 0; r < harq_process->C; r++) {
if (decParams->perCB[r].status_cb == 0 || harq_process->C == 1) {
memcpy(harq_process->b + offset_b, &p_outDec[offset_b], Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
harq_process->processedSegments++;
} else {
LOG_D(PHY, "uplink segment error %d/%d\n", r, harq_process->C);
LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id);
}
r_offset += E;
offset_b += (Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
}
bool crc_valid = false;
// CRC check made by the T2, no need to perform CRC check for a single code block twice
if (harq_process->processedSegments == harq_process->C) {
// When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the
// CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block
crc_valid = true;
if (harq_process->C > 1) {
crc_valid = check_crc(harq_process->b, lenWithCrc(1, A), crcType(1, A));
crc_valid = check_crc(harq_process->b, lenWithCrc(1, A), crcType(1, A));
if (harq_process->C == 1 && !crc_valid) {
harq_process->processedSegments--;
}
}
if (crc_valid) {
LOG_D(PHY, "ULSCH: Setting ACK for slot %d TBS %d\n", ulsch->slot, harq_process->TBS);
nr_fill_indication(phy_vars_gNB, ulsch->frame, ulsch->slot, ULSCH_id, harq_pid, 0, 0);
......@@ -312,6 +307,7 @@ int decode_offload(PHY_VARS_gNB *phy_vars_gNB,
}
ulsch->last_iteration_cnt = decodeIterations;
free(p_outDec);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0);
return 0;
}
......@@ -349,7 +345,6 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
const uint8_t n_layers = pusch_pdu->nrOfLayers;
// ------------------------------------------------------------------
harq_process->processedSegments = 0;
harq_process->TBS = pusch_pdu->pusch_data.tb_size;
t_nrLDPC_dec_params decParams = {.check_crc = check_crc};
......@@ -418,6 +413,8 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
decParams.Z = harq_process->Z;
decParams.numMaxIter = ulsch->max_ldpc_iterations;
decParams.Qm = Qm;
decParams.rv = pusch_pdu->pusch_data.rv_index;
decParams.outMode = 0;
decParams.setCombIn = !harq_process->harq_to_be_cleared;
if (harq_process->harq_to_be_cleared) {
......@@ -428,7 +425,7 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
if (phy_vars_gNB->ldpc_offload_flag)
return decode_offload(phy_vars_gNB, ULSCH_id, ulsch_llr, pusch_pdu, &decParams, harq_pid, G);
harq_process->processedSegments = 0;
uint32_t offset = 0, r_offset = 0;
set_abort(&harq_process->abort_decode, false);
for (int r = 0; r < harq_process->C; r++) {
......
......@@ -151,16 +151,13 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
start_meas(&ue->ulsch_ldpc_encoding_stats);
if (ldpc_interface_offload.LDPCencoder) {
for (int j = 0; j < impp.n_segments; j++) {
impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
uint8_t *f = harq_process->f + r_offset;
ldpc_interface_offload.LDPCencoder(&harq_process->c[j], &f, &impp);
r_offset += impp.E;
impp.perCB[j].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
}
ldpc_interface_offload.LDPCencoder(harq_process->c, &harq_process->f, &impp);
} else {
if (ulsch->pusch_pdu.pusch_data.new_data_indicator) {
for (int j = 0; j < (impp.n_segments / 8 + 1); j++) {
impp.macro_num = j;
impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
impp.Kr = impp.K;
ldpc_interface.LDPCencoder(harq_process->c, harq_process->d, &impp);
}
......@@ -191,7 +188,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
ulsch->pusch_pdu.pusch_data.rv_index);
///////////////////////// d---->| Rate matching bit selection |---->e /////////////////////////
impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r);
impp.perCB[r].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN);
start_meas(&ue->ulsch_rate_matching_stats);
......@@ -204,7 +201,8 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
impp.F,
impp.Kr - impp.F - 2 * impp.Zc,
impp.rv,
impp.E) == -1)
impp.perCB[r].E_cb)
== -1)
return -1;
stop_meas(&ue->ulsch_rate_matching_stats);
......@@ -218,10 +216,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
///////////////////////// e---->| Rate matching bit interleaving |---->f /////////////////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN);
start_meas(&ue->ulsch_interleaving_stats);
nr_interleaving_ldpc(impp.E,
impp.Qm,
harq_process->e + r_offset,
harq_process->f + r_offset);
nr_interleaving_ldpc(impp.perCB[r].E_cb, impp.Qm, harq_process->e + r_offset, harq_process->f + r_offset);
stop_meas(&ue->ulsch_interleaving_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT);
......@@ -231,7 +226,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
if (r == impp.n_segments - 1)
write_output("enc_output.m","enc", harq_process->f, G, 1, 4);
#endif
r_offset += impp.E;
r_offset += impp.perCB[r].E_cb;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -504,6 +504,7 @@ typedef struct PHY_VARS_NR_UE_s {
uint8_t max_ldpc_iterations;
int ldpc_offload_enable;
/// SRS variables
nr_srs_info_t *nr_srs_info;
......
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