feat(nrLDPC_coding_segment): Encoding with sequential output write
1. The encoder writes the output in sequence after the encoding tasks completed instead of writing within the tasks. 2. Simplify the output writing to make it more readable. Co-authored-by: Laurent Thomas <laurent.thomas@open-cells.com>
This commit is contained in:
co-authored by
Laurent Thomas
parent
b1e1c161ec
commit
0aa3dba5b7
+178
-227
@@ -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<E2;i+=64,i2++) {
|
||||
|
||||
for (int i=0;i<E2;i+=64) {
|
||||
uint32_t Eoffset2 = Eoffset;
|
||||
__m512i bitperm = _mm512_set1_epi64(0x3830282018100800);
|
||||
if (i<E) {
|
||||
for (int j=0; j < E2_first_segment && (j < (nb_segments - 1) || i < (E2 - 64)); j++) {
|
||||
for (int j=0; j < E2_first_segment; j++) {
|
||||
// Note: Here and below for AVX2, 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 = (__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<E2;i+=16,i2++) {
|
||||
for (int i=0;i<E2;i+=16) {
|
||||
uint32_t Eoffset2 = Eoffset;
|
||||
if (i<E) {
|
||||
for (int j=0; j < E2_first_segment && (j < (nb_segments - 1) || i < (E2 - 16)); j++) {
|
||||
cshift = vandq_u8(vshlq_u8(((uint8x16_t*)f)[i2],vshift[j]),vmask);
|
||||
tmp = (int)vaddv_u8(vget_low_u8(cshift));
|
||||
for (int j=0; j < E2_first_segment; j++) {
|
||||
uint32_t Eoffset2_byte = Eoffset2 >> 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<<Eoffset2_bit[j]);
|
||||
*(output_p + Eoffset2[j] + 1) |= (uint16_t)(tmp>>(16-Eoffset2_bit[j]));
|
||||
*(output_p + Eoffset2_byte) |= (uint16_t)(tmp<<Eoffset2_bit);
|
||||
*(output_p + Eoffset2_byte+1) |= (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<<Eoffset2_bit[j]);
|
||||
*(output_p + Eoffset2[j] + 1) |= (uint16_t)(tmp>>(16-Eoffset2_bit[j]));
|
||||
*(output_p + Eoffset2_byte) |= (uint16_t)(tmp<<Eoffset2_bit);
|
||||
*(output_p + Eoffset2_byte+1) |= (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;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;
|
||||
@@ -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<macro_segment_end-macro_segment;s++)
|
||||
printf("i %d: segment %d : f[%d] %d\n",i,macro_segment+s,i,(f[i]>>s)&1);
|
||||
*/
|
||||
// information part and puncture columns
|
||||
|
||||
uint32_t Eoffset=0;
|
||||
for (int s=0; s<macro_segment; s++)
|
||||
Eoffset += (nrLDPC_TB_encoding_parameters->segments[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;s<macro_segment_end-macro_segment;s++)
|
||||
printf("i %d: segment %d : output[%d] %d\n",i,macro_segment+s,i,output_offset[i+s*E]);
|
||||
*/
|
||||
// Task running in // completed
|
||||
completed_task_ans(impp->ans);
|
||||
}
|
||||
|
||||
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; s<macro_segment; s++)
|
||||
Eoffset += (nrLDPC_TB_encoding_parameters->segments[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;
|
||||
|
||||
Reference in New Issue
Block a user