From 15fc29843c255ea7cf75230d03eb90ee9be33b80 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Fri, 3 Jan 2025 14:43:26 +0000 Subject: [PATCH] fix(nrLDPC_coding): cleanup the naming of the K, Kprime and Zc variables to comply with the standard 38.212-5.2.2 --- openair1/PHY/CODING/TESTBENCH/ldpctest.c | 2 +- .../nrLDPC_coding/nrLDPC_coding_interface.h | 2 +- .../nrLDPC_coding_segment_decoder.c | 24 ++++----- .../nrLDPC_coding_segment_encoder.c | 6 +-- .../nrLDPC_coding_xdma/nrLDPC_coding_xdma.c | 51 +++++++++---------- openair1/PHY/CODING/nrLDPC_defs.h | 50 +++++++++++------- 6 files changed, 74 insertions(+), 61 deletions(-) diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 1d0bdfb16b..71c2f1af27 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -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, .BG = BG, .Kr = block_length, .K = block_length}; + encoder_implemparams_t impp = {.Zc = Zc, .Kb = Kb, .BG = BG, .K = block_length}; impp.gen_code = 2; if (ntrials==0) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h index 6492131df3..7544f8cf55 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h @@ -173,7 +173,7 @@ typedef struct nrLDPC_segment_encoding_parameters_s{ * \var G Available radio resource bits * \var tbslbrm Transport block size LBRM * \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1) - * \var Kb Code block size divided by lifting size + * \var Kb Number of time the lifting size needed to fit the payload of a code block * \var K Code block size at input of encoder * \var Z lifting size * \var F filler bits size diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index 29d155e95c..df7ba73aed 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -64,7 +64,8 @@ * \brief decoding parameter of transport blocks * \var decoderParms decoder parameters * \var Qm modulation order - * \var Kc size of base graph input + * \var Kc ratio between the number of columns in the parity check matrix and the lifting size + * it is fixed for a given base graph while the lifting size is chosen to have a sufficient number of columns * \var rv_index * \var max_number_iterations maximum number of LDPC iterations * \var abort_decode pointer to decode abort flag @@ -127,14 +128,13 @@ static void nr_process_decode_segment(void *arg) { nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg; t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms; - const int Kr = rdata->K; - const int Kr_bytes = Kr >> 3; - const int K_bits_F = Kr - rdata->F; + const int K = rdata->K; + const int Kprime = K - rdata->F; const int A = rdata->A; const int E = rdata->E; const int Qm = rdata->Qm; const int rv_index = rdata->rv_index; - const uint8_t kc = rdata->Kc; + const uint8_t Kc = rdata->Kc; short *ulsch_llr = rdata->llr; int8_t llrProcBuf[OAI_LDPC_DECODER_MAX_NUM_LLR] __attribute__((aligned(32))); @@ -177,7 +177,7 @@ static void nr_process_decode_segment(void *arg) *rdata->d_to_be_cleared, E, rdata->F, - Kr - rdata->F - 2 * (p_decoderParms->Z)) + K - rdata->F - 2 * (p_decoderParms->Z)) == -1) { stop_meas(rdata->p_ts_rate_unmatch); @@ -191,7 +191,7 @@ static void nr_process_decode_segment(void *arg) *rdata->d_to_be_cleared = false; - memset(rdata->c, 0, Kr_bytes); + memset(rdata->c, 0, K >> 3); p_decoderParms->crc_type = crcType(rdata->C, A); p_decoderParms->Kprime = lenWithCrc(rdata->C, A); @@ -203,16 +203,16 @@ static void nr_process_decode_segment(void *arg) memset(z, 0, 2 * rdata->Z * sizeof(*z)); // set Filler bits - memset(z + K_bits_F, 127, rdata->F * sizeof(*z)); + memset(z + Kprime, 127, rdata->F * sizeof(*z)); // Move coded bits before filler bits - memcpy(z + 2 * rdata->Z, rdata->d, (K_bits_F - 2 * rdata->Z) * sizeof(*z)); + memcpy(z + 2 * rdata->Z, rdata->d, (Kprime - 2 * rdata->Z) * sizeof(*z)); // skip filler bits - memcpy(z + Kr, rdata->d + (Kr - 2 * rdata->Z), (kc * rdata->Z - Kr) * sizeof(*z)); + memcpy(z + K, rdata->d + (K - 2 * rdata->Z), (Kc * rdata->Z - K) * sizeof(*z)); // Saturate coded bits before decoding into 8 bits values simde__m128i *pv = (simde__m128i *)&z; int8_t l[68 * 384 + 16] __attribute__((aligned(16))); simde__m128i *pl = (simde__m128i *)&l; - for (int i = 0, j = 0; j < ((kc * rdata->Z) >> 4) + 1; i += 2, j++) { + for (int i = 0, j = 0; j < ((Kc * rdata->Z) >> 4) + 1; i += 2, j++) { pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -226,7 +226,7 @@ static void nr_process_decode_segment(void *arg) ldpc_interface_segment.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); if (decodeIterations <= p_decoderParms->numMaxIter) { - memcpy(rdata->c,llrProcBuf, Kr>>3); + memcpy(rdata->c,llrProcBuf, K>>3); *rdata->decodeSuccess = true; } else { *rdata->decodeSuccess = false; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c index 6c66edeb82..8a3291eeae 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c @@ -61,7 +61,7 @@ static void ldpc8blocks_coding_segment(void *p) uint32_t A = nrLDPC_TB_encoding_parameters->A; unsigned int G = nrLDPC_TB_encoding_parameters->G; - LOG_D(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + LOG_D(PHY,"dlsch coding A %d K %d G %d (nb_rb %d, mod_order %d)\n", A,impp->K,G, nb_rb,(int)mod_order); // nrLDPC_encoder output is in "d" @@ -123,7 +123,7 @@ static void ldpc8blocks_coding_segment(void *p) stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match); if (impp->K - impp->F - 2 * impp->Zc > E) { LOG_E(PHY, - "dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + "dlsch coding A %d K %d G %d (nb_rb %d, mod_order %d)\n", A, impp->K, G, @@ -131,7 +131,7 @@ static void ldpc8blocks_coding_segment(void *p) (int)mod_order); LOG_E(NR_PHY, - "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, " + "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, K %d, Filler bits %d, Filler offset %d mod_order %d, " "nb_rb %d)...\n", rr, impp->n_segments, 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 index 057fb58f6a..11fcd31424 100644 --- 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 @@ -83,8 +83,8 @@ typedef struct args_fpga_decode_prepare_s { 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; /*!< */ + int Kc; /*!< ratio between the number of columns in the parity check graph and the lifting size */ + int Kprime; /*!< size of payload and CRC bits in a code block */ task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */ } args_fpga_decode_prepare_t; @@ -143,11 +143,10 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, 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; + const uint32_t K = TB_params->K; + const int Kc = TB_params->BG == 2 ? 52 : 68; int r_offset = 0, offset = 0; - int K_bits_F = Kr - TB_params->F; + int Kprime = K - TB_params->F; // FPGA parameter preprocessing static uint8_t multi_indata[27000 * 25]; // FPGA input data @@ -156,7 +155,7 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int bg_len = TB_params->BG == 1 ? 22 : 10; // Calc input CB offset - int input_CBoffset = TB_params->Z * kc * 8; + int input_CBoffset = TB_params->Z * Kc * 8; if ((input_CBoffset & 0x7F) == 0) input_CBoffset = input_CBoffset / 8; else @@ -168,7 +167,7 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, 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); + dec_conf.numChannelLls = (Kprime - 2 * TB_params->Z) + (Kc * TB_params->Z - K); // filler bits length dec_conf.numFillerBits = TB_params->F; dec_conf.max_schedule = 0; @@ -196,11 +195,11 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, 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, + Kprime, TB_params->Z, - kc, + Kc, TB_params->Z, - Kr); + K); printf("numFillerBits:\t %d\n", TB_params->F); printf("------------------------\n"); // =================================== @@ -265,8 +264,8 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, 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; + args->Kc = Kc; + args->Kprime = Kprime; r_remaining = r_span; @@ -276,7 +275,7 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, 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)); + offset += ((K >> 3) - (TB_params->F >> 3) - ((TB_params->C > 1) ? 3 : 0)); r_remaining -= 1; } @@ -353,7 +352,7 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) uint8_t max_ldpc_iterations = TB_params->max_ldpc_iterations; uint32_t tbslbrm = TB_params->tbslbrm; - uint32_t Kr = TB_params->K; + uint32_t K = TB_params->K; uint32_t Z = TB_params->Z; uint32_t F = TB_params->F; @@ -369,8 +368,8 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) 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; + int Kc = arguments->Kc; + int Kprime = arguments->Kprime; int16_t z[68 * 384 + 16] __attribute__((aligned(16))); simde__m128i *pv = (simde__m128i *)&z; @@ -405,7 +404,7 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) *segment_params->d_to_be_cleared, segment_params->E, F, - Kr - F - 2 * Z) + K - F - 2 * Z) == -1) { stop_meas(&segment_params->ts_rate_unmatch); LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n"); @@ -418,33 +417,33 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) *segment_params->d_to_be_cleared = false; - memset(segment_params->c, 0, Kr >> 3); + memset(segment_params->c, 0, K >> 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)); + memset((&z[0] + Kprime), 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)); + memcpy((&z[0] + 2 * Z), segment_params->d, (Kprime - 2 * Z) * sizeof(int16_t)); // skip filler bits - memcpy((&z[0] + Kr), segment_params->d + (Kr - 2 * Z), (kc * Z - Kr) * sizeof(int16_t)); + memcpy((&z[0] + K), segment_params->d + (K - 2 * Z), (Kc * Z - K) * 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++) { + 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 + // 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_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++) { + for (int i = 0, j = ((Kc * Z) & 0xfffffff0); j < Kc * Z; i++, j++) { multi_indata[r * input_CBoffset + j] = tmp_p[i]; } diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h index 471498be74..fe386ce6d7 100644 --- a/openair1/PHY/CODING/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_defs.h @@ -26,37 +26,51 @@ #include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" /** - \brief LDPC encoder - \param 1 input - \param 2 channel_input - \param 3 int Zc - \param 4 int Kb - \param 5 short block_length - \param 6 short BG - \param 7 int n_segment - \param 8 unsigned int macro_num - \param 9-12 time_stats_t *tinput,*tprep, *tparity,*toutput + \brief LDPC encoder parameter structure + \var n_segments number of segments in the transport block + \var macro_num index of the subset of segments to encode + within the transport block + \var gen_code flag to generate parity check code + 0 -> encoding + 1 -> generate parity check code with AVX2 + 2 -> generate parity check code without AVX2 + \var tinput time statistics for data input in the encoder + \var tprep time statistics for data preparation in the encoder + \var tparity time statistics for adding parity bits + \var toutput time statistics for data output from the encoder + \var K size of the complete code segment before encoding + including payload, CRC bits and filler bit + (also known as Kr, see 38.212-5.2.2) + \var Kb number of lifting sizes to fit the payload (see 38.212-5.2.2) + \var Zc lifting size (see 38.212-5.2.2) + \var F number of filler bits (see 38.212-5.2.2) + \var harq pointer to the HARQ process structure + \var BG base graph index + \var output output buffer after INTERLEAVING + \var ans pointer to the task answer + to notify thread pool about completion of the task */ typedef struct { - unsigned int n_segments; // optim8seg - unsigned int macro_num; // optim8segmulti - unsigned char gen_code; //orig + unsigned int n_segments; // optim8seg + unsigned int macro_num; // optim8segmulti + unsigned char gen_code; //orig time_stats_t *tinput; time_stats_t *tprep; time_stats_t *tparity; time_stats_t *toutput; - int Kr; + /// Size in bits of the code segments + uint32_t K; + /// Number of lifting sizes to fit the payload uint32_t Kb; + /// Lifting size uint32_t Zc; + /// Number of "Filler" bits + uint32_t F; void *harq; /// Encoder BG uint8_t BG; /// Interleaver outputs unsigned char *output; - /// Number of bits in "small" code segments - uint32_t K; - /// Number of "Filler" bits - uint32_t F; task_ans_t *ans; } encoder_implemparams_t;