From 2b2b3cd3470ee344ebdeacf7bc2203452b882fd8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 19:26:02 +0100 Subject: [PATCH] Simplify gNB DLSCH type DLSCH encoding is not concerned with HARQ processes directly. Instead, it gets the redundancy version and encodes a specific redundancy version for a given TB. The rest is up to the MAC, the L1 is stateless in that regard. Hence, remove the HARQ type and put it into DLSCH, which also simplifies the code elsewhere. --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 16 ++--- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 71 ++++++++++----------- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 10 ++- openair1/PHY/defs_gNB.h | 29 ++++----- openair1/SIMULATION/NR_PHY/dlschsim.c | 4 +- openair1/SIMULATION/NR_PHY/dlsim.c | 6 +- 6 files changed, 60 insertions(+), 76 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 171aeec73f..55cd8fad11 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -555,8 +555,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats; time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB; const int symbol_sz=frame_parms->ofdm_symbol_size; const int dmrs_Type = rel15->dmrsConfigType; @@ -591,9 +590,9 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC #ifdef DEBUG_DLSCH printf("PDSCH encoding:\nPayload:\n"); - for (int i = 0; i < (harq->B >> 3); i += 16) { + for (int i = 0; i < (dlsch->B >> 3); i += 16) { for (int j = 0; j < 16; j++) - printf("0x%02x\t", harq->pdu[i + j]); + printf("0x%02x\t", dlsch->pdu[i + j]); printf("\n"); } printf("\nEncoded payload:\n"); @@ -606,7 +605,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC #endif if (IS_SOFTMODEM_DLSIM) - memcpy(harq->f, input_ptr, (encoded_length + 7) >> 3); + memcpy(dlsch->f, input_ptr, (encoded_length + 7) >> 3); c16_t mod_symbs[rel15->NrOfCodewords][encoded_length] __attribute__((aligned(64))); for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) { @@ -791,8 +790,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; LOG_D(PHY, "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", @@ -816,10 +814,10 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols); } - harq->unav_res = ptrsSymbPerSlot * n_ptrs; + dlsch->unav_res = ptrsSymbPerSlot * n_ptrs; /// CRC, coding, interleaving and rate matching - AssertFatal(harq->pdu != NULL, "%4d.%2d no HARQ PDU for PDSCH generation\n", msgTx->frame, msgTx->slot); + AssertFatal(dlsch->pdu != NULL, "%4d.%2d no PDU for PDSCH generation\n", msgTx->frame, msgTx->slot); /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * => size_output is a sum of parts sizes rounded up to a multiple of 8 * 64 diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 79538c52cd..eb70819ff4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -52,20 +52,19 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM a_segments = a_segments / 273 + 1; } - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - if (harq->b) { - free16(harq->b, a_segments * 1056); - harq->b = NULL; + if (dlsch->b) { + free16(dlsch->b, a_segments * 1056); + dlsch->b = NULL; } - if (harq->f) { - free16(harq->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); - harq->f = NULL; + if (dlsch->f) { + free16(dlsch->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + dlsch->f = NULL; } for (int r = 0; r < a_segments; r++) { - free(harq->c[r]); - harq->c[r] = NULL; + free(dlsch->c[r]); + dlsch->c[r] = NULL; } - free(harq->c); + free(dlsch->c); } NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) @@ -80,28 +79,26 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) LOG_D(PHY, "Allocating %d segments (MAX %d, N_PRB %d)\n", a_segments, MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER, N_RB); uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment - NR_gNB_DLSCH_t dlsch; + NR_gNB_DLSCH_t dlsch = {0}; - NR_DL_gNB_HARQ_t *harq = &dlsch.harq_process; - bzero(harq, sizeof(NR_DL_gNB_HARQ_t)); - harq->b = malloc16(dlsch_bytes); - AssertFatal(harq->b, "cannot allocate memory for harq->b\n"); - bzero(harq->b, dlsch_bytes); + dlsch.b = malloc16(dlsch_bytes); + AssertFatal(dlsch.b, "cannot allocate memory for dlsch.b\n"); + bzero(dlsch.b, dlsch_bytes); - harq->c = (uint8_t **)malloc16(a_segments * sizeof(uint8_t *)); + dlsch.c = (uint8_t **)malloc16(a_segments * sizeof(uint8_t *)); for (int r = 0; r < a_segments; r++) { // account for filler in first segment and CRCs for multiple segment case // [hna] 8448 is the maximum CB size in NR // 68*348 = 68*(maximum size of Zc) // In section 5.3.2 in 38.212, the for loop is up to N + 2*Zc (maximum size of N is 66*Zc, therefore 68*Zc) - harq->c[r] = malloc16(8448); - AssertFatal(harq->c[r], "cannot allocate harq->c[%d]\n", r); - bzero(harq->c[r], 8448); + dlsch.c[r] = malloc16(8448); + AssertFatal(dlsch.c[r], "cannot allocate dlsch.c[%d]\n", r); + bzero(dlsch.c[r], 8448); } - harq->f = malloc16(N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); - AssertFatal(harq->f, "cannot allocate harq->f\n"); - bzero(harq->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + dlsch.f = malloc16(N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + AssertFatal(dlsch.f, "cannot allocate dlsch->f\n"); + bzero(dlsch.f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); return (dlsch); } @@ -139,11 +136,10 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; unsigned int crc = 1; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; uint32_t A = rel15->TBSize[0] << 3; - unsigned char *a = harq->pdu; + unsigned char *a = dlsch->pdu; if (rel15->rnti != SI_RNTI) { ws_trace_t tmp = {.nr = true, .direction = DIRECTION_DOWNLINK, @@ -182,9 +178,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, // printf("CRC %x (A %d)\n",crc,A); // printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); B = A + 24; - // harq->b = a; AssertFatal((A / 8) + 4 <= max_bytes, "A %d is too big (A/8+4 = %d > %d)\n", A, (A / 8) + 4, max_bytes); - memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? + memcpy(dlsch->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? } else { // Add 16-bit crc (polynomial A) to payload crc = crc16(a, A) >> 16; @@ -193,9 +188,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, // printf("CRC %x (A %d)\n",crc,A); // printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); B = A + 16; - // harq->b = a; AssertFatal((A / 8) + 3 <= max_bytes, "A %d is too big (A/8+3 = %d > %d)\n", A, (A / 8) + 3, max_bytes); - memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc + memcpy(dlsch->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc } nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; @@ -205,8 +199,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph; TB_parameters->A = A; start_meas(dlsch_segmentation_stats); - TB_parameters->Kb = nr_segmentation(harq->b, - harq->c, + TB_parameters->Kb = nr_segmentation(dlsch->b, + dlsch->c, B, &TB_parameters->C, &TB_parameters->K, @@ -229,18 +223,17 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; #ifdef DEBUG_DLSCH_CODING for (int r = 0; r < TB_parameters->C; r++) { - LOG_D(PHY, "Encoder: B %d F %d \n", harq->B, TB_parameters->F); + LOG_D(PHY, "Encoder: B %d F %d \n", dlsch->B, TB_parameters->F); LOG_D(PHY, "start ldpc encoder segment %d/%d\n", r, TB_parameters->C); - LOG_D(PHY, "input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2], harq->c[r][3], harq->c[r][4]); + LOG_D(PHY, "input %d %d %d %d %d \n", dlsch->c[r][0], dlsch->c[r][1], dlsch->c[r][2], dlsch->c[r][3], dlsch->c[r][4]); for (int cnt = 0; cnt < 22 * (TB_parameters->Z) / 8; cnt++) { - LOG_D(PHY, "%d ", harq->c[r][cnt]); + LOG_D(PHY, "%d ", dlsch->c[r][cnt]); } LOG_D(PHY, "\n"); } @@ -258,7 +251,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, rel15->NrOfSymbols, nb_re_dmrs, get_num_dmrs(rel15->dlDmrsSymbPos), - harq->unav_res, + dlsch->unav_res, rel15->qamModOrder[0], rel15->nrOfLayers); @@ -269,7 +262,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int r = 0; r < TB_parameters->C; r++) { nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; - segment_parameters->c = harq->c[r]; + segment_parameters->c = dlsch->c[r]; segment_parameters->E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, rel15->nrOfLayers, r); reset_meas(&segment_parameters->ts_interleave); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 3f1d988c53..45a064f571 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -37,15 +37,14 @@ void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu) { NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[msgTx->num_pdsch_slot][0]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; /// DLSCH struct - memcpy((void*)&harq->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + memcpy((void*)&dlsch->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); AssertFatal(msgTx->num_pdsch_slot == pdsch_pdu->pdsch_pdu_rel15.pduIndex, "PDSCH PDU index %d does not match msgTx index %d\n", pdsch_pdu->pdsch_pdu_rel15.pduIndex, msgTx->num_pdsch_slot); msgTx->num_pdsch_slot++; - harq->pdu = NULL; + dlsch->pdu = NULL; } void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) @@ -55,8 +54,7 @@ void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. * for the moment, assume they are in the same order (and check!) */ NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[idx][0]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - nfapi_nr_dl_tti_pdsch_pdu *pdsch = &harq->pdsch_pdu; + nfapi_nr_dl_tti_pdsch_pdu *pdsch = &dlsch->pdsch_pdu; AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); - harq->pdu = sdu; + dlsch->pdu = sdu; } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 246d3aaa6f..fe4d3869d2 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -53,21 +53,6 @@ typedef struct { int lut[MAX_PUCCH0_NID][160][14]; } NR_gNB_PUCCH0_LUT_t; -typedef struct { - /// Nfapi DLSCH PDU - nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu; - /// pointer to pdu from MAC interface (this is "a" in 36.212) - uint8_t *pdu; - /// Pointer to the payload - uint8_t *b; - /// Pointers to transport block segments - uint8_t **c; - /// Interleaver outputs - uint8_t *f; - /// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.) - uint32_t unav_res; -} NR_DL_gNB_HARQ_t; - typedef struct { int dump_frame; int round_trials[8]; @@ -112,8 +97,18 @@ typedef struct { } NR_gNB_PHY_STATS_t; typedef struct { - /// Pointers to variables related to DLSCH harq process - NR_DL_gNB_HARQ_t harq_process; + /// Nfapi DLSCH PDU + nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu; + /// pointer to pdu from MAC interface (this is "a" in 36.212) + uint8_t *pdu; + /// Pointer to the payload + uint8_t *b; + /// Pointers to transport block segments + uint8_t **c; + /// Interleaver outputs + uint8_t *f; + /// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.) + uint32_t unav_res; } NR_gNB_DLSCH_t; typedef struct { diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index c475bfc039..7a2f120043 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -442,7 +442,7 @@ int main(int argc, char **argv) processingData_L1tx_t msgDataTx; init_DLSCH_struct(gNB, &msgDataTx); NR_gNB_DLSCH_t *dlsch = &msgDataTx.dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; uint8_t nb_re_dmrs = 6; // No data in dmrs symbol @@ -498,7 +498,7 @@ int main(int argc, char **argv) printf("harq process ue mcs = %d Qm = %d, symb %d\n", dlsch0_ue->dlsch_config.mcs, dlsch0_ue->dlsch_config.qamModOrder, nb_symb_sch); uint8_t test_input[TBS / 8 + 4]; // + 3 for CRC + 1 additional byte, see nr_dlsch_encoding() - dlsch->harq_process.pdu = test_input; + dlsch->pdu = test_input; //unsigned char test_input[TBS / 8] __attribute__ ((aligned(16))); for (i = 0; i < TBS / 8; i++) test_input[i] = (unsigned char) rand(); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 678b330513..cd8fef35ff 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1059,7 +1059,7 @@ int main(int argc, char **argv) if (n_trials== 1) num_rounds = 1; NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->pdsch_pdu.pdsch_pdu_rel15; for (trial = 0; trial < n_trials && !stop; trial++) { @@ -1255,7 +1255,7 @@ int main(int argc, char **argv) } for (i = 0; i < available_bits; i++) { - const uint8_t current_bit = (gNB_dlsch->harq_process.f[i / 8] & (1 << (i & 7))) >> (i & 7); + const uint8_t current_bit = (gNB_dlsch->f[i / 8] & (1 << (i & 7))) >> (i & 7); if (((current_bit == 0) && (UE_llr[i] <= 0)) || ((current_bit == 1) && (UE_llr[i] >= 0))) { if (errors_scrambling[round] == 0) { LOG_D(PHY,"First bit in error in unscrambling = %d\n",i); @@ -1275,7 +1275,7 @@ int main(int argc, char **argv) for (i = 0; i < TBS; i++) { estimated_output_bit[i] = (UE->phy_sim_dlsch_b[i/8] & (1 << (i & 7))) >> (i & 7); - test_input_bit[i] = (gNB_dlsch->harq_process.b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments + test_input_bit[i] = (gNB_dlsch->b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments if (estimated_output_bit[i] != test_input_bit[i]) { if(errors_bit == 0)