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 bbdda8c8bc..5d0e90e46b 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 @@ -44,60 +44,6 @@ #define DEBUG_LDPC_ENCODING //#define DEBUG_LDPC_ENCODING_FREE 1 -/** - * \typedef group_tail_t - * \struct group_tail_s - * \brief index and content of the last word written by a task to the encoding library output - * It is returned after task completion to fix the borders of segment groups - * \var index index of the last word written by the task - * \var content content of the last word written by the task - */ -typedef struct group_tail_s -{ - uint32_t index; -#if defined(__AVX512VBMI__) - uint64_t content; -#elif defined(__aarch64__) - uint16_t content; -#else - uint32_t content; -#endif -} group_tail_t; - -/** - * \brief fix segment groups first and last words - * The last word of a segment group is not written by encoding tasks in order to avoid race conditions - * This function fixes the segment group borders after encoding tasks completion - * \param group_tail store segment groups tail to fix segment borders - * \param nbGroups number of groups - * \params output encoding library output to write to - */ -static void fix_group_borders(group_tail_t *group_tail, int nbGroups, uint8_t *output) -{ - for(int i = 0; i < nbGroups; i++) { -#if defined(__AVX512VBMI__) - ((uint64_t *)output)[group_tail[i].index] = group_tail[i].content | ((uint64_t *)output)[group_tail[i].index]; -#elif defined(__aarch64__) - ((uint16_t *)output)[group_tail[i].index] = group_tail[i].content | ((uint16_t *)output)[group_tail[i].index]; -#else - ((uint32_t *)output)[group_tail[i].index] = group_tail[i].content | ((uint32_t *)output)[group_tail[i].index]; -#endif - } -} - -/** - * \brief determine the value of E for the current segment - * \param E number of bits per segment in f - * \param E2 number of bits per segment in f2 - * \param Eshift flag indicating if there was a E shift within the segment group - * \param segment index of the segment - * \param E2_first_segment index of the first segment of size E2 if there is a E shift in the segment group - */ -static inline uint32_t select_E(uint32_t E, uint32_t E2, bool Eshift, uint32_t segment, uint32_t E2_first_segment) -{ - return (Eshift && (segment >= E2_first_segment)) ? E2 : E; -} - /** * \brief write nrLDPC_coding_segment_encoder output with interleaver output * the interleaver output has 8 bits from 8 different segments per byte @@ -112,7 +58,6 @@ static inline uint32_t select_E(uint32_t E, uint32_t E2, bool Eshift, uint32_t s * \param nb_segments number of segments in the group * \param output nrLDPC_coding_segment_encoder with concatenated segments and packed bits * \param Eoffset offset in number of bits of the first segment of the segment group within output - * \param group_tail store segment group last words to fix segment group borders */ static void write_task_output(uint8_t *f, uint32_t E, @@ -122,77 +67,50 @@ static void write_task_output(uint8_t *f, uint32_t E2_first_segment, uint32_t nb_segments, uint8_t *output, - uint32_t Eoffset, - group_tail_t *group_tail) + uint32_t Eoffset) { #if defined(__AVX512VBMI__) uint64_t *output_p = (uint64_t*)output; - int i=0; - __m512i bitperm[8]; - uint32_t Eoffset2[8]; - uint32_t Eoffset2_bit[8]; - bitperm[0] = _mm512_set1_epi64(0x3830282018100800); __m512i inc = _mm512_set1_epi8(0x1); - Eoffset2[0] = Eoffset >> 6; - Eoffset2_bit[0] = Eoffset & 63; - Eoffset += select_E(E, E2, Eshift, 0, E2_first_segment); - for (int n = 1; n < nb_segments; n++) { - bitperm[n] = _mm512_add_epi8(bitperm[n-1] ,inc); - Eoffset2[n] = Eoffset >> 6; - Eoffset2_bit[n] = Eoffset & 63; - Eoffset += select_E(E, E2, Eshift, n, E2_first_segment); - } - group_tail->index = Eoffset2[nb_segments - 1]; - int i2=0; - __m64 tmp; - for (i=0;i>/<< because when the Eoffset2_bit is 64 or 0, the << // and >> operations are undefined and in fact don't give "0" which is // what we want here. The SIMD version do give 0 when the shift is 64 - tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f)[i2],bitperm[j]); - - *(__m64*)(output_p + Eoffset2[j]) = _mm_or_si64(*(__m64*)(output_p + Eoffset2[j]),_mm_slli_si64(tmp,Eoffset2_bit[j])); - - *(__m64*)(output_p + Eoffset2[j] + 1) = _mm_or_si64(*(__m64*)(output_p + Eoffset2[j]+1),_mm_srli_si64(tmp,(64-Eoffset2_bit[j]))); - - } //for (int j=0; - } // if (i < E) - for (int j=E2_first_segment; j < nb_segments && (j < (nb_segments - 1) || i < (E2 - 64)); j++) { - tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f2)[i2],bitperm[j]); - - *(__m64*)(output_p + Eoffset2[j]) = _mm_or_si64(*(__m64*)(output_p + Eoffset2[j]),_mm_slli_si64(tmp,Eoffset2_bit[j])); - - *(__m64*)(output_p + Eoffset2[j]+1) = _mm_or_si64(*(__m64*)(output_p + Eoffset2[j]+1),_mm_srli_si64(tmp,(64-Eoffset2_bit[j]))); + uint32_t Eoffset2_byte = Eoffset2 >> 6; + uint32_t Eoffset2_bit = Eoffset2 & 63; + __m64 tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f)[i >> 6],bitperm); + *(__m64*)(output_p + Eoffset2_byte) = _mm_or_si64(*(__m64*)(output_p + Eoffset2_byte),_mm_slli_si64(tmp,Eoffset2_bit)); + *(__m64*)(output_p + Eoffset2_byte+1) = _mm_or_si64(*(__m64*)(output_p + Eoffset2_byte+1),_mm_srli_si64(tmp,(64-Eoffset2_bit))); + Eoffset2 += E; + bitperm = _mm512_add_epi8(bitperm ,inc); + } + } else { + for (int j=0; j < E2_first_segment; j++) { + Eoffset2 += E; + bitperm = _mm512_add_epi8(bitperm ,inc); + } + } + for (int j=E2_first_segment; j < nb_segments; j++) { + uint32_t Eoffset2_byte = Eoffset2 >> 6; + uint32_t Eoffset2_bit = Eoffset2 & 63; + __m64 tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f2)[i >> 6],bitperm); + *(__m64*)(output_p + Eoffset2_byte) = _mm_or_si64(*(__m64*)(output_p + Eoffset2_byte),_mm_slli_si64(tmp,Eoffset2_bit)); + *(__m64*)(output_p + Eoffset2_byte+1) = _mm_or_si64(*(__m64*)(output_p + Eoffset2_byte+1),_mm_srli_si64(tmp,(64-Eoffset2_bit))); + Eoffset2 += E2; + bitperm = _mm512_add_epi8(bitperm ,inc); } output_p++; - group_tail->index++; } - // Do not write the last word of the segment group but keep it for fixing segment borders - if (Eshift) { - tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f2)[(E2 - 1) >> 6], bitperm[nb_segments - 1]); - } else { - tmp = (__m64)_mm512_bitshuffle_epi64_mask(((__m512i *)f)[(E2 - 1) >> 6], bitperm[nb_segments - 1]); - } - *(__m64*)(output_p - 1 + Eoffset2[nb_segments - 1]) = _mm_or_si64(*(__m64*)(output_p - 1 + Eoffset2[nb_segments - 1]), _mm_slli_si64(tmp, Eoffset2_bit[nb_segments - 1])); - group_tail->content = (uint64_t)_mm_srli_si64(tmp, (64 - Eoffset2_bit[nb_segments - 1])); - #elif defined(__aarch64__) uint16_t *output_p = (uint16_t*)output; - int i=0; - uint32_t Eoffset2[8]; - uint32_t Eoffset2_bit[8]; - for (int n = 0; n < nb_segments; n++) { - Eoffset2[n] = Eoffset >> 4; - Eoffset2_bit[n] = Eoffset & 15; - Eoffset += select_E(E, E2, Eshift, n, E2_first_segment); - } - group_tail->index = Eoffset2[nb_segments - 1]; - int i2=0; const int8_t __attribute__ ((aligned (16))) ucShift[8][16] = { {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7}, // segment 0 {-1,0,1,2,3,4,5,6,-1,0,1,2,3,4,5,6}, // segment 1 @@ -208,104 +126,99 @@ static void write_task_output(uint8_t *f, for (int n=0;n<8;n++) vshift[n] = vld1q_s8(ucShift[n]); uint8x16_t vmask = vld1q_u8(masks); - int32_t tmp; - uint8x16_t cshift; - for (i=0;i> 4; + uint32_t Eoffset2_bit = Eoffset2 & 15; + uint8x16_t cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f)[i >> 4],vshift[j]),vmask); + int32_t tmp = (int)vaddv_u8(vget_low_u8(cshift)); tmp += (int)(vaddv_u8(vget_high_u8(cshift))<<8); - *(output_p + Eoffset2[j]) |= (uint16_t)(tmp<>(16-Eoffset2_bit[j])); + *(output_p + Eoffset2_byte) |= (uint16_t)(tmp<>(16-Eoffset2_bit)); + Eoffset2 += E; + } + } else { + for (int j=0; j < E2_first_segment; j++) { + Eoffset2 += E; } } - for (int j=E2_first_segment; j < nb_segments && (j < (nb_segments - 1) || i < (E2 - 16)); j++) { - cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f2)[i2],vshift[j]),vmask); - tmp = (int)vaddv_u8(vget_low_u8(cshift)); + for (int j=E2_first_segment; j < nb_segments; j++) { + uint32_t Eoffset2_byte = Eoffset2 >> 4; + uint32_t Eoffset2_bit = Eoffset2 & 15; + uint8x16_t cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f2)[i >> 4],vshift[j]),vmask); + int32_t tmp = (int)vaddv_u8(vget_low_u8(cshift)); tmp += (int)(vaddv_u8(vget_high_u8(cshift))<<8); - *(output_p + Eoffset2[j]) |= (uint16_t)(tmp<>(16-Eoffset2_bit[j])); + *(output_p + Eoffset2_byte) |= (uint16_t)(tmp<>(16-Eoffset2_bit)); + Eoffset2 += E2; } output_p++; - group_tail->index++; } - - // Do not write the last word of the segment group but keep it for fixing segment borders - if (Eshift) { - cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f2)[(E2 - 1) >> 4], vshift[nb_segments - 1]), vmask); - } else { - cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f)[(E2 - 1) >> 4], vshift[nb_segments - 1]), vmask); - } - tmp = (int)vaddv_u8(vget_low_u8(cshift)); - tmp += (int)(vaddv_u8(vget_high_u8(cshift)) << 8); - *(output_p - 1 + Eoffset2[nb_segments - 1]) |= (uint16_t)(tmp << Eoffset2_bit[nb_segments - 1]); - group_tail->content = (uint16_t)(tmp >> (16 - Eoffset2_bit[nb_segments - 1])); #else uint32_t *output_p = (uint32_t*)output; - int i=0; - uint32_t Eoffset2[8]; - uint32_t Eoffset2_bit[8]; - for (int n = 0; n < nb_segments; n++) { - Eoffset2[n] = Eoffset >> 5; - Eoffset2_bit[n] = Eoffset & 31; - Eoffset += select_E(E, E2, Eshift, n, E2_first_segment); - } - group_tail->index = Eoffset2[nb_segments - 1]; - int i2 = 0; - int tmp; - __m64 tmp64, tmp64b, tmp64c, out64; - - for (i=0; i < E2; i += 32, i2++) { + + for (int i=0; i < E2; i += 32) { + uint32_t Eoffset2 = Eoffset; if (i < E) { - for (int j = 0; j < E2_first_segment && (j < (nb_segments - 1) || i < (E2 - 32)); j++) { + for (int j = 0; j < E2_first_segment; j++) { // Note: Here and below, we are using the 64-bit SIMD instruction // instead of C >>/<< because when the Eoffset2_bit is 64 or 0, the << // and >> operations are undefined and in fact don't give "0" which is // what we want here. The SIMD version do give 0 when the shift is 64 - tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f)[i2], 7 - j)); - tmp64 = _mm_set1_pi32(tmp); - out64 = _mm_set_pi32(*(output_p + Eoffset2[j] + 1), *(output_p + Eoffset2[j])); - tmp64b = _mm_or_si64(out64, _mm_slli_pi32(tmp64, Eoffset2_bit[j])); - tmp64c = _mm_or_si64(out64, _mm_srli_pi32(tmp64, (32 - Eoffset2_bit[j]))); - *(output_p + Eoffset2[j]) = _m_to_int(tmp64b); - *(output_p + Eoffset2[j] + 1) = _m_to_int(_mm_srli_si64(tmp64c, 32)); + uint32_t Eoffset2_byte = Eoffset2 >> 5; + uint32_t Eoffset2_bit = Eoffset2 & 31; + int tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f)[i >> 5], 7 - j)); + __m64 tmp64 = _mm_set1_pi32(tmp); + __m64 out64 = _mm_set_pi32(*(output_p + Eoffset2_byte + 1), *(output_p + Eoffset2_byte)); + __m64 tmp64b = _mm_or_si64(out64, _mm_slli_pi32(tmp64, Eoffset2_bit)); + __m64 tmp64c = _mm_or_si64(out64, _mm_srli_pi32(tmp64, (32 - Eoffset2_bit))); + *(output_p + Eoffset2_byte) = _m_to_int(tmp64b); + *(output_p + Eoffset2_byte + 1) = _m_to_int(_mm_srli_si64(tmp64c, 32)); + Eoffset2 += E; + } + } else { + for (int j = 0; j < E2_first_segment; j++) { + Eoffset2 += E; } } - for (int j = E2_first_segment; j < nb_segments && (j < (nb_segments - 1) || i < (E2 - 32)); j++) { - tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f2)[i2], 7 - j)); - tmp64 = _mm_set1_pi32(tmp); - out64 = _mm_set_pi32(*(output_p + Eoffset2[j] + 1), *(output_p + Eoffset2[j])); - tmp64b = _mm_or_si64(out64, _mm_slli_pi32(tmp64, Eoffset2_bit[j])); - tmp64c = _mm_or_si64(out64, _mm_srli_pi32(tmp64, (32 - Eoffset2_bit[j]))); - *(output_p + Eoffset2[j]) = _m_to_int(tmp64b); - *(output_p + Eoffset2[j] + 1) = _m_to_int(_mm_srli_si64(tmp64c, 32)); + for (int j = E2_first_segment; j < nb_segments; j++) { + uint32_t Eoffset2_byte = Eoffset2 >> 5; + uint32_t Eoffset2_bit = Eoffset2 & 31; + int tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f2)[i >> 5], 7 - j)); + __m64 tmp64 = _mm_set1_pi32(tmp); + __m64 out64 = _mm_set_pi32(*(output_p + Eoffset2_byte + 1), *(output_p + Eoffset2_byte)); + __m64 tmp64b = _mm_or_si64(out64, _mm_slli_pi32(tmp64, Eoffset2_bit)); + __m64 tmp64c = _mm_or_si64(out64, _mm_srli_pi32(tmp64, (32 - Eoffset2_bit))); + *(output_p + Eoffset2_byte) = _m_to_int(tmp64b); + *(output_p + Eoffset2_byte + 1) = _m_to_int(_mm_srli_si64(tmp64c, 32)); + Eoffset2 += E2; } output_p++; - group_tail->index++; } - // Do not write the last word of the segment group but keep it for fixing segment borders - if (Eshift) { - tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f2)[(E2 - 1) >> 5], 7 - nb_segments + 1)); - } else { - tmp = _mm256_movemask_epi8(_mm256_slli_epi16(((__m256i *)f)[(E2 - 1) >> 5], 7 - nb_segments + 1)); - } - tmp64 = _mm_set1_pi32(tmp); - out64 = _mm_set_pi32(*(output_p - 1 + Eoffset2[nb_segments - 1] + 1), *(output_p - 1 + Eoffset2[nb_segments - 1])); - tmp64b = _mm_or_si64(out64, _mm_slli_pi32(tmp64, Eoffset2_bit[nb_segments - 1])); - tmp64c = _mm_srli_pi32(tmp64, (32 - Eoffset2_bit[nb_segments - 1])); - *(output_p - 1 + Eoffset2[nb_segments - 1]) = _m_to_int(tmp64b); - group_tail->content = _m_to_int(tmp64c); #endif } +/** + * \typedef ldpc8blocks_args_t + * \struct ldpc8blocks_args_s + * \brief Arguments of an encoding task + * encode up to 8 code blocks + * \var nrLDPC_TB_encoding_parameters TB encoding parameters as defined in the coding library interface + * \var impp encoder implementation specific parameters for the task + * \var f first interleaver output to be filled by the task + * \var f2 second interleaver output to be filled by the task + * in case of a shift of E in the code blocks group processed by the task + */ typedef struct ldpc8blocks_args_s { nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters; encoder_implemparams_t impp; - group_tail_t *group_tail; + uint8_t *f; + uint8_t *f2; } ldpc8blocks_args_t; static void ldpc8blocks(void *p) @@ -341,14 +254,13 @@ static void ldpc8blocks(void *p) LOG_D(PHY, "rvidx in encoding = %d\n", nrLDPC_TB_encoding_parameters->rv_index); #endif const uint32_t E = nrLDPC_TB_encoding_parameters->segments[macro_segment].E; - uint32_t E2=E,E2_first_segment=macro_segment_end-macro_segment; + uint32_t E2=E; bool Eshift=false; uint32_t Emax = E; for (int s=macro_segment;ssegments[s].E != E) { E2=nrLDPC_TB_encoding_parameters->segments[s].E; Eshift=true; - E2_first_segment = s-macro_segment; if(E2 > Emax) Emax = E2; break; @@ -385,12 +297,13 @@ static void ldpc8blocks(void *p) uint32_t Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm; uint8_t e[Emax] __attribute__((aligned(64))); - uint8_t f[E+64] __attribute__((aligned(64))); - uint8_t f2[E2+64] __attribute__((aligned(64))); + // Interleaver outputs are stored in the output arrays + uint8_t *f = args->f; + uint8_t *f2 = args->f2; bzero(e, Emax); - bzero(f, E + 64); + bzero(f, ceil_mod(E, 64)); if (Eshift) { - bzero(f2, E2 + 64); + bzero(f2, ceil_mod(E2, 64)); } start_meas(&nrLDPC_TB_encoding_parameters->segments[macro_segment].ts_rate_match); nr_rate_matching_ldpc(Tbslbrm, @@ -439,44 +352,15 @@ static void ldpc8blocks(void *p) e, f2); stop_meas(&nrLDPC_TB_encoding_parameters->segments[macro_segment].ts_interleave); - if(impp->toutput != NULL) start_meas(impp->toutput); -/* - for (int i=0;i<16;i++) - for (int s=0;s>s)&1); -*/ - // information part and puncture columns - - uint32_t Eoffset=0; - for (int s=0; ssegments[s].E); - write_task_output(f, - E, - f2, - E2, - Eshift, - E2_first_segment, - macro_segment_end - macro_segment, - impp->output, - Eoffset, - args->group_tail); - - if(impp->toutput != NULL) stop_meas(impp->toutput); -/* - printf("E %d (mod16 %d) F %d\n",E,E&15,impp->F); - for (int i=0;i<16;i++) - for (int s=0;sans); } static int nrLDPC_launch_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, - int dlsch_id, - thread_info_tm_t *t_info, - group_tail_t *group_tail) + int dlsch_id, + thread_info_tm_t *t_info, + uint8_t **f, + uint8_t **f2) { nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; @@ -505,7 +389,8 @@ static int nrLDPC_launch_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_s perJobImpp->impp.first_seg = j * 8; perJobImpp->impp.ans = t_info->ans; perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters; - perJobImpp->group_tail = &group_tail[j]; + perJobImpp->f = f[j]; + perJobImpp->f2 = f2[j]; task_t t = {.func = ldpc8blocks, .args = perJobImpp}; pushTpool(nrLDPC_slot_encoding_parameters->threadPool, t); @@ -517,22 +402,48 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin { int nbTasks = 0; + uint32_t Emax = 0; for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { + // Compute number of tasks to encode TB nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1)); nbTasks += n_seg; + + // Search for maximum E for sizing encoder output f and f2 + for (int seg_id = 0; seg_id < nrLDPC_TB_encoding_parameters->C; seg_id++) { + uint32_t E = nrLDPC_TB_encoding_parameters->segments[seg_id].E; + Emax = E > Emax ? E : Emax; + } } + + // Create f and f2 to old encoding tasks outputs + uint32_t Emax_ceil_mod = ceil_mod(Emax, 64); + uint8_t f[nbTasks][Emax_ceil_mod] __attribute__((aligned(64))); + uint8_t f2[nbTasks][Emax_ceil_mod] __attribute__((aligned(64))); + ldpc8blocks_args_t arr[nbTasks]; task_ans_t ans; init_task_ans(&ans, nbTasks); thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbTasks, .ans = &ans}; - group_tail_t group_tail[nbTasks]; - memset(group_tail, 0, nbTasks * sizeof(group_tail_t)); - int nbEncode = 0; + nbTasks = 0; for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { - nbEncode += nrLDPC_launch_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info, &group_tail[dlsch_id]); + // For easier indexing we store the pointers to sub arrays of f and f2 in pointer arrays + // Then a function to which we pass the pointer arrays can directly use f_2d[j] ans f2_2d[j] + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; + size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1)); + uint8_t *f_2d[n_seg]; + uint8_t *f2_2d[n_seg]; + for (int j = 0; j < n_seg; j++) { + f_2d[j] = &f[nbTasks + j][0]; + f2_2d[j] = &f2[nbTasks + j][0]; + } + + // Launch tasks encoding TB + nbEncode += nrLDPC_launch_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info, f_2d, f2_2d); + + nbTasks += n_seg; } if (nbEncode < nbTasks) { completed_many_task_ans(&ans, nbTasks - nbEncode); @@ -540,12 +451,52 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin // Execute thread pool tasks join_task_ans(&ans); - int n_seg_sum = 0; + // Write output + nbTasks = 0; for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; - int n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1)); - fix_group_borders(&group_tail[n_seg_sum], n_seg, nrLDPC_TB_encoding_parameters->output); - n_seg_sum += n_seg; + uint32_t C = nrLDPC_TB_encoding_parameters->C; + size_t n_seg = (C / 8 + ((C & 7) == 0 ? 0 : 1)); + + time_stats_t *toutput = nrLDPC_slot_encoding_parameters->toutput; + + for (int j = 0; j < n_seg; j++) { + unsigned int macro_segment = j * 8; + unsigned int macro_segment_end = (C > macro_segment + 8) ? macro_segment + 8 : C; + const uint32_t E = nrLDPC_TB_encoding_parameters->segments[macro_segment].E; + uint32_t E2 = E, E2_first_segment = macro_segment_end - macro_segment; + bool Eshift = false; + uint32_t Emax = E; + for (int s = macro_segment; s < macro_segment_end; s++) { + if (nrLDPC_TB_encoding_parameters->segments[s].E != E) { + E2 = nrLDPC_TB_encoding_parameters->segments[s].E; + Eshift = true; + E2_first_segment = s-macro_segment; + if(E2 > Emax) + Emax = E2; + break; + } + } + + if(toutput != NULL) start_meas(toutput); + + uint32_t Eoffset=0; + for (int s=0; ssegments[s].E); + + write_task_output(&f[nbTasks + j][0], + E, + &f2[nbTasks + j][0], + E2, + Eshift, + E2_first_segment, + macro_segment_end - macro_segment, + nrLDPC_TB_encoding_parameters->output, + Eoffset); + + if(toutput != NULL) stop_meas(toutput); + } + nbTasks += n_seg; } return 0;