Commands used:
clang-format -i openair1/PHY/CODING/TESTBENCH/polartest.c
clang-format -i openair1/PHY/CODING/nr_polar_init.c
clang-format -i openair1/PHY/CODING/nrPolar_tools/*
707 lines
24 KiB
C
707 lines
24 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/*!\file PHY/CODING/nrPolar_tools/nr_polar_encoder.c
|
|
* \brief
|
|
* \author Raymond Knopp, Turker Yilmaz
|
|
* \date 2018
|
|
* \version 0.1
|
|
* \company EURECOM
|
|
* \email raymond.knopp@eurecom.fr, turker.yilmaz@eurecom.fr
|
|
* \note
|
|
* \warning
|
|
*/
|
|
|
|
// #define DEBUG_POLAR_ENCODER
|
|
// #define DEBUG_POLAR_ENCODER_DCI
|
|
// #define DEBUG_POLAR_MATLAB
|
|
// #define POLAR_CODING_DEBUG
|
|
|
|
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
|
|
#include "assertions.h"
|
|
#include <stdint.h>
|
|
|
|
// input [a_31 a_30 ... a_0]
|
|
// output [f_31 f_30 ... f_0] [f_63 f_62 ... f_32] ...
|
|
|
|
void polar_encoder(uint32_t *in, uint32_t *out, int8_t messageType, uint16_t messageLength, uint8_t aggregation_level)
|
|
{
|
|
t_nrPolar_params *polarParams = nr_polar_params(messageType, messageLength, aggregation_level);
|
|
uint8_t nr_polar_A[polarParams->payloadBits];
|
|
nr_bit2byte_uint32_8(in, polarParams->payloadBits, nr_polar_A);
|
|
/*
|
|
* Bytewise operations
|
|
*/
|
|
// Calculate CRC.
|
|
uint8_t nr_polar_crc[polarParams->crcParityBits];
|
|
nr_matrix_multiplication_uint8_1D_uint8_2D(nr_polar_A,
|
|
polarParams->crc_generator_matrix,
|
|
nr_polar_crc,
|
|
polarParams->payloadBits,
|
|
polarParams->crcParityBits);
|
|
|
|
for (uint i = 0; i < polarParams->crcParityBits; i++)
|
|
nr_polar_crc[i] %= 2;
|
|
|
|
uint8_t nr_polar_B[polarParams->K];
|
|
// Attach CRC to the Transport Block. (a to b)
|
|
memcpy(nr_polar_B, nr_polar_A, polarParams->payloadBits);
|
|
for (uint i = polarParams->payloadBits; i < polarParams->K; i++)
|
|
nr_polar_B[i] = nr_polar_crc[i - (polarParams->payloadBits)];
|
|
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
uint64_t B2 = 0;
|
|
|
|
for (int i = 0; i < polarParams->K; i++)
|
|
B2 |= ((uint64_t)nr_polar_B[i] << i);
|
|
|
|
printf("polar_B %lx\n", B2);
|
|
for (int i = 0; i < polarParams->payloadBits; i++)
|
|
printf("a[%d]=%d\n", i, nr_polar_A[i]);
|
|
for (int i = 0; i < polarParams->K; i++)
|
|
printf("b[%d]=%d\n", i, nr_polar_B[i]);
|
|
#endif
|
|
|
|
// Interleaving (c to c')
|
|
uint8_t nr_polar_CPrime[polarParams->K];
|
|
nr_polar_interleaver(nr_polar_B, nr_polar_CPrime, polarParams->interleaving_pattern, polarParams->K);
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
uint64_t Cprime = 0;
|
|
|
|
for (int i = 0; i < polarParams->K; i++) {
|
|
Cprime = Cprime | ((uint64_t)nr_polar_CPrime[i] << i);
|
|
if (nr_polar_CPrime[i] == 1)
|
|
printf("pos %d : %lx\n", i, Cprime);
|
|
}
|
|
|
|
printf("polar_Cprime %lx\n", Cprime);
|
|
#endif
|
|
// Bit insertion (c' to u)
|
|
uint8_t nr_polar_U[polarParams->N];
|
|
nr_polar_bit_insertion(nr_polar_CPrime,
|
|
nr_polar_U,
|
|
polarParams->N,
|
|
polarParams->K,
|
|
polarParams->Q_I_N,
|
|
polarParams->Q_PC_N,
|
|
polarParams->n_pc);
|
|
uint8_t nr_polar_D[polarParams->N];
|
|
nr_matrix_multiplication_uint8_1D_uint8_2D(nr_polar_U, polarParams->G_N, nr_polar_D, polarParams->N, polarParams->N);
|
|
|
|
for (uint i = 0; i < polarParams->N; i++)
|
|
nr_polar_D[i] %= 2;
|
|
|
|
uint64_t D[8];
|
|
memset(D, 0, sizeof(D));
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
|
|
for (int i = 0; i < polarParams->N; i++)
|
|
D[i / 64] |= ((uint64_t)nr_polar_D[i]) << (i & 63);
|
|
|
|
printf("D %llx,%llx,%llx,%llx,%llx,%llx,%llx,%llx\n", D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7]);
|
|
#endif
|
|
// Rate matching
|
|
// Sub-block interleaving (d to y) and Bit selection (y to e)
|
|
uint8_t nr_polar_E[polarParams->encoderLength];
|
|
nr_polar_interleaver(nr_polar_D, nr_polar_E, polarParams->rate_matching_pattern, polarParams->encoderLength);
|
|
/*
|
|
* Return bits.
|
|
*/
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
|
|
for (int i = 0; i < polarParams->encoderLength; i++)
|
|
printf("f[%d]=%d\n", i, nr_polar_E[i]);
|
|
|
|
#endif
|
|
nr_byte2bit_uint8_32(nr_polar_E, polarParams->encoderLength, out);
|
|
|
|
polarReturn(polarParams);
|
|
}
|
|
|
|
void polar_encoder_dci(uint32_t *in,
|
|
uint32_t *out,
|
|
uint16_t n_RNTI,
|
|
int8_t messageType,
|
|
uint16_t messageLength,
|
|
uint8_t aggregation_level)
|
|
{
|
|
t_nrPolar_params *polarParams = nr_polar_params(messageType, messageLength, aggregation_level);
|
|
|
|
#ifdef DEBUG_POLAR_ENCODER_DCI
|
|
printf("[polar_encoder_dci] in: [0]->0x%08x \t [1]->0x%08x \t [2]->0x%08x \t [3]->0x%08x\n", in[0], in[1], in[2], in[3]);
|
|
#endif
|
|
/*
|
|
* Bytewise operations
|
|
*/
|
|
//(a to a')
|
|
uint8_t nr_polar_A[polarParams->payloadBits];
|
|
nr_bit2byte_uint32_8(in, polarParams->payloadBits, nr_polar_A);
|
|
uint8_t nr_polar_APrime[polarParams->K];
|
|
for (int i = 0; i < polarParams->crcParityBits; i++)
|
|
nr_polar_APrime[i] = 1;
|
|
const int end = polarParams->crcParityBits + polarParams->payloadBits;
|
|
for (int i = polarParams->crcParityBits; i < end; i++)
|
|
nr_polar_APrime[i] = nr_polar_A[i];
|
|
|
|
#ifdef DEBUG_POLAR_ENCODER_DCI
|
|
printf("[polar_encoder_dci] A: ");
|
|
for (int i = 0; i < polarParams->payloadBits; i++)
|
|
printf("%d-", nr_polar_A[i]);
|
|
printf("\n");
|
|
|
|
printf("[polar_encoder_dci] APrime: ");
|
|
for (int i = 0; i < polarParams->K; i++)
|
|
printf("%d-", nr_polar_APrime[i]);
|
|
printf("\n");
|
|
|
|
printf("[polar_encoder_dci] GP: ");
|
|
for (int i = 0; i < polarParams->crcParityBits; i++)
|
|
printf("%d-", polarParams->crc_generator_matrix[0][i]);
|
|
printf("\n");
|
|
#endif
|
|
// Calculate CRC.
|
|
uint8_t nr_polar_crc[polarParams->crcParityBits];
|
|
nr_matrix_multiplication_uint8_1D_uint8_2D(nr_polar_APrime,
|
|
polarParams->crc_generator_matrix,
|
|
nr_polar_crc,
|
|
polarParams->K,
|
|
polarParams->crcParityBits);
|
|
|
|
for (uint i = 0; i < polarParams->crcParityBits; i++)
|
|
nr_polar_crc[i] %= 2;
|
|
|
|
#ifdef DEBUG_POLAR_ENCODER_DCI
|
|
printf("[polar_encoder_dci] CRC: ");
|
|
for (int i = 0; i < polarParams->crcParityBits; i++)
|
|
printf("%d-", nr_polar_crc[i]);
|
|
printf("\n");
|
|
#endif
|
|
uint8_t nr_polar_B[polarParams->payloadBits + 8 + 16];
|
|
// Attach CRC to the Transport Block. (a to b)
|
|
memcpy(nr_polar_B, nr_polar_A, polarParams->payloadBits);
|
|
|
|
for (uint i = polarParams->payloadBits; i < polarParams->K; i++)
|
|
nr_polar_B[i] = nr_polar_crc[i - polarParams->payloadBits];
|
|
|
|
// Scrambling (b to c)
|
|
for (int i = 0; i < 16; i++)
|
|
nr_polar_B[polarParams->payloadBits + 8 + i] = (nr_polar_B[polarParams->payloadBits + 8 + i] + ((n_RNTI >> (15 - i)) & 1)) % 2;
|
|
|
|
#ifdef DEBUG_POLAR_ENCODER_DCI
|
|
printf("[polar_encoder_dci] B: ");
|
|
for (int i = 0; i < polarParams->K; i++)
|
|
printf("%d-", nr_polar_B[i]);
|
|
printf("\n");
|
|
#endif
|
|
// Interleaving (c to c')
|
|
uint8_t nr_polar_CPrime[polarParams->K];
|
|
nr_polar_interleaver(nr_polar_B, nr_polar_CPrime, polarParams->interleaving_pattern, polarParams->K);
|
|
// Bit insertion (c' to u)
|
|
uint8_t nr_polar_U[polarParams->N];
|
|
nr_polar_bit_insertion(nr_polar_CPrime,
|
|
nr_polar_U,
|
|
polarParams->N,
|
|
polarParams->K,
|
|
polarParams->Q_I_N,
|
|
polarParams->Q_PC_N,
|
|
polarParams->n_pc);
|
|
// Encoding (u to d)
|
|
uint8_t nr_polar_D[polarParams->N];
|
|
nr_matrix_multiplication_uint8_1D_uint8_2D(nr_polar_U, polarParams->G_N, nr_polar_D, polarParams->N, polarParams->N);
|
|
for (uint i = 0; i < polarParams->N; i++)
|
|
nr_polar_D[i] %= 2;
|
|
|
|
// Rate matching
|
|
// Sub-block interleaving (d to y) and Bit selection (y to e)
|
|
uint8_t nr_polar_E[polarParams->encoderLength];
|
|
nr_polar_interleaver(nr_polar_D, nr_polar_E, polarParams->rate_matching_pattern, polarParams->encoderLength);
|
|
/*
|
|
* Return bits.
|
|
*/
|
|
nr_byte2bit_uint8_32(nr_polar_E, polarParams->encoderLength, out);
|
|
#ifdef DEBUG_POLAR_ENCODER_DCI
|
|
printf("[polar_encoder_dci] E: ");
|
|
for (int i = 0; i < polarParams->encoderLength; i++)
|
|
printf("%d-", nr_polar_E[i]);
|
|
|
|
uint8_t outputInd = ceil(polarParams->encoderLength / 32.0);
|
|
printf("\n[polar_encoder_dci] out: ");
|
|
for (int i = 0; i < outputInd; i++)
|
|
printf("[%d]->0x%08x\t", i, out[i]);
|
|
#endif
|
|
polarReturn(polarParams);
|
|
}
|
|
|
|
/*
|
|
* Interleaving of coded bits implementation
|
|
* TS 138.212: Section 5.4.1.3 - Interleaving of coded bits
|
|
*/
|
|
void nr_polar_rm_interleaving_cb(void *in, void *out, uint16_t E)
|
|
{
|
|
int T = ceil((sqrt(8 * E + 1) - 1) / 2);
|
|
int v[T][T];
|
|
int k = 0;
|
|
uint64_t *in64 = (uint64_t *)in;
|
|
for (int i = 0; i < T; i++) {
|
|
for (int j = 0; j < T - i; j++) {
|
|
if (k < E) {
|
|
int k1 = k >> 6;
|
|
int k2 = k - (k1 << 6);
|
|
v[i][j] = (in64[k1] >> k2) & 1;
|
|
} else {
|
|
v[i][j] = -1;
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
k = 0;
|
|
uint64_t *out64 = (uint64_t *)out;
|
|
memset(out64, 0, E >> 3);
|
|
for (int j = 0; j < T; j++) {
|
|
for (int i = 0; i < T - j; i++) {
|
|
if (v[i][j] != -1) {
|
|
int k1 = k >> 6;
|
|
int k2 = k - (k1 << 6);
|
|
out64[k1] |= (uint64_t)v[i][j] << k2;
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
__attribute__((always_inline)) static inline void polar_rate_matching(const t_nrPolar_params *polarParams, void *in, void *out)
|
|
{
|
|
// handle rate matching with a single 128 bit word using bit shuffling
|
|
// can be done with SIMD intrisics if needed
|
|
if (polarParams->groupsize < 8) {
|
|
AssertFatal(polarParams->encoderLength <= 512,
|
|
"Need to handle groupsize(%d)<8 and N(%d)>512\n",
|
|
polarParams->groupsize,
|
|
polarParams->encoderLength);
|
|
uint128_t *out128 = (uint128_t *)out;
|
|
uint128_t *in128 = (uint128_t *)in;
|
|
for (int i = 0; i < polarParams->encoderLength >> 7; i++)
|
|
out128[i] = 0;
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
uint128_t tmp1;
|
|
#endif
|
|
for (int i = 0; i < polarParams->encoderLength; i++) {
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
printf("%d<-%u : %llx.%llx =>", i, polarParams->rate_matching_pattern[i], ((uint64_t *)out)[1], ((uint64_t *)out)[0]);
|
|
#endif
|
|
uint8_t pi = polarParams->rate_matching_pattern[i];
|
|
uint8_t pi7 = pi >> 7;
|
|
uint8_t pimod128 = pi & 127;
|
|
uint8_t imod128 = i & 127;
|
|
uint8_t i7 = i >> 7;
|
|
uint128_t tmp0 = (in128[pi7] & (((uint128_t)1) << (pimod128)));
|
|
|
|
if (tmp0 != 0) {
|
|
out128[i7] = out128[i7] | ((uint128_t)1) << imod128;
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
printf("%llx.%llx<->%llx.%llx => %llx.%llx\n",
|
|
((uint64_t *)&tmp0)[1],
|
|
((uint64_t *)&tmp0)[0],
|
|
((uint64_t *)&tmp1)[1],
|
|
((uint64_t *)&tmp1)[0],
|
|
((uint64_t *)out)[1],
|
|
((uint64_t *)out)[0]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
// These are based on LUTs for byte and short word groups
|
|
else if (polarParams->groupsize == 8)
|
|
for (int i = 0; i < polarParams->encoderLength >> 3; i++)
|
|
((uint8_t *)out)[i] = ((uint8_t *)in)[polarParams->rm_tab[i]];
|
|
else // groupsize==16
|
|
for (int i = 0; i < polarParams->encoderLength >> 4; i++) {
|
|
((uint16_t *)out)[i] = ((uint16_t *)in)[polarParams->rm_tab[i]];
|
|
}
|
|
|
|
if (polarParams->i_bil == 1) {
|
|
nr_polar_rm_interleaving_cb(out, out, polarParams->encoderLength);
|
|
}
|
|
}
|
|
|
|
void build_polar_tables(t_nrPolar_params *polarParams)
|
|
{
|
|
// build table b -> c'
|
|
AssertFatal(polarParams->K > 17, "K = %d < 18, is not possible\n", polarParams->K);
|
|
AssertFatal(polarParams->K < 129, "K = %d > 128, is not supported yet\n", polarParams->K);
|
|
const int numbytes = (polarParams->K + 7) / 8;
|
|
const int residue = polarParams->K & 7;
|
|
uint deinterleaving_pattern[polarParams->K];
|
|
|
|
for (int i = 0; i < polarParams->K; i++)
|
|
deinterleaving_pattern[polarParams->interleaving_pattern[i]] = i;
|
|
|
|
for (int byte = 0; byte < numbytes; byte++) {
|
|
int numbits = byte < (polarParams->K >> 3) ? 8 : residue;
|
|
for (uint64_t val = 0; val < 256LU; val++) {
|
|
// uint16_t * tmp=polarParams->deinterleaving_pattern+polarParams->K - 1 - 8 * byte;
|
|
union {
|
|
uint128_t full;
|
|
uint64_t pieces[2];
|
|
} tab = {0};
|
|
uint *tmp = deinterleaving_pattern + polarParams->K - 8 * byte - 1;
|
|
for (int i = 0; i < numbits; i++) {
|
|
// flip bit endian of B bitstring
|
|
const int ip = *tmp--;
|
|
AssertFatal(ip < 128, "ip = %d\n", ip);
|
|
const uint128_t bit_i = (val >> i) & 1;
|
|
tab.full |= bit_i << ip;
|
|
}
|
|
polarParams->cprime_tab0[byte][val] = tab.pieces[0];
|
|
polarParams->cprime_tab1[byte][val] = tab.pieces[1];
|
|
}
|
|
}
|
|
|
|
AssertFatal(polarParams->N == 512 || polarParams->N == 256 || polarParams->N == 128 || polarParams->N == 64,
|
|
"N = %d, not done yet\n",
|
|
polarParams->N);
|
|
|
|
// rate matching table
|
|
int iplast = polarParams->rate_matching_pattern[0];
|
|
int ccnt = 0;
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
int groupcnt = 0;
|
|
int firstingroup_out = 0;
|
|
int firstingroup_in = iplast;
|
|
#endif
|
|
int mingroupsize = 1024;
|
|
|
|
// compute minimum group size of rate-matching pattern
|
|
for (int outpos = 1; outpos < polarParams->encoderLength; outpos++) {
|
|
int ip = polarParams->rate_matching_pattern[outpos];
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
printf("rm: outpos %d, inpos %d\n", outpos, ip);
|
|
#endif
|
|
if ((ip - iplast) == 1)
|
|
ccnt++;
|
|
else {
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
groupcnt++;
|
|
printf("group %d (size %d): (%d:%d) => (%d:%d)\n",
|
|
groupcnt,
|
|
ccnt + 1,
|
|
firstingroup_in,
|
|
firstingroup_in + ccnt,
|
|
firstingroup_out,
|
|
firstingroup_out + ccnt);
|
|
#endif
|
|
|
|
if ((ccnt + 1) < mingroupsize)
|
|
mingroupsize = ccnt + 1;
|
|
|
|
ccnt = 0;
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
firstingroup_out = outpos;
|
|
firstingroup_in = ip;
|
|
#endif
|
|
}
|
|
|
|
iplast = ip;
|
|
}
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
groupcnt++;
|
|
#endif
|
|
if ((ccnt + 1) < mingroupsize)
|
|
mingroupsize = ccnt + 1;
|
|
#ifdef DEBUG_POLAR_ENCODER
|
|
printf("group %d (size %d): (%d:%d) => (%d:%d)\n",
|
|
groupcnt,
|
|
ccnt + 1,
|
|
firstingroup_in,
|
|
firstingroup_in + ccnt,
|
|
firstingroup_out,
|
|
firstingroup_out + ccnt);
|
|
#endif
|
|
|
|
polarParams->groupsize = mingroupsize;
|
|
|
|
int shift = 0;
|
|
switch (mingroupsize) {
|
|
case 2:
|
|
shift = 1;
|
|
break;
|
|
case 4:
|
|
shift = 2;
|
|
break;
|
|
case 8:
|
|
shift = 3;
|
|
break;
|
|
case 16:
|
|
shift = 4;
|
|
break;
|
|
default:
|
|
AssertFatal(false, "mingroupsize = %i is not supported\n", mingroupsize);
|
|
break;
|
|
}
|
|
|
|
polarParams->rm_tab = malloc(sizeof(*polarParams->rm_tab) * (polarParams->encoderLength >> shift));
|
|
|
|
// rerun again to create groups
|
|
for (int outpos = 0, tcnt = 0; outpos < polarParams->encoderLength; outpos += mingroupsize, tcnt++)
|
|
polarParams->rm_tab[tcnt] = polarParams->rate_matching_pattern[outpos] >> shift;
|
|
|
|
build_decoder_tree(polarParams);
|
|
}
|
|
|
|
void polar_encoder_fast(uint64_t *A,
|
|
void *out,
|
|
int32_t crcmask,
|
|
uint8_t ones_flag,
|
|
int8_t messageType,
|
|
uint16_t messageLength,
|
|
uint8_t aggregation_level)
|
|
{
|
|
t_nrPolar_params *polarParams = nr_polar_params(messageType, messageLength, aggregation_level);
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
printf("polarParams->payloadBits = %i\n", polarParams->payloadBits);
|
|
printf("polarParams->crcParityBits = %i\n", polarParams->crcParityBits);
|
|
printf("polarParams->K = %i\n", polarParams->K);
|
|
printf("polarParams->N = %i\n", polarParams->N);
|
|
printf("polarParams->encoderLength = %i\n", polarParams->encoderLength);
|
|
printf("polarParams->n_pc = %i\n", polarParams->n_pc);
|
|
printf("polarParams->n_pc_wm = %i\n", polarParams->n_pc_wm);
|
|
printf("polarParams->groupsize = %i\n", polarParams->groupsize);
|
|
printf("polarParams->i_il = %i\n", polarParams->i_il);
|
|
printf("polarParams->i_bil = %i\n", polarParams->i_bil);
|
|
printf("polarParams->n_max = %i\n", polarParams->n_max);
|
|
#endif
|
|
|
|
// AssertFatal(polarParams->K > 32, "K = %d < 33, is not supported yet\n",polarParams->K);
|
|
AssertFatal(polarParams->K < 129, "K = %d > 128, is not supported yet\n", polarParams->K);
|
|
AssertFatal(polarParams->payloadBits < 65, "payload bits = %d > 64, is not supported yet\n", polarParams->payloadBits);
|
|
int bitlen = polarParams->payloadBits;
|
|
// append crc
|
|
AssertFatal(bitlen < 129, "support for payloads <= 128 bits\n");
|
|
// AssertFatal(polarParams->crcParityBits == 24,"support for 24-bit crc only for now\n");
|
|
// int bitlen0=bitlen;
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
printf("\nTX\n");
|
|
printf("a: ");
|
|
for (int n = (bitlen + 63) / 64; n >= 0; n--) {
|
|
if (n % 4 == 0)
|
|
printf(" ");
|
|
if (n < bitlen)
|
|
printf("%lu", (A[n / 64] >> (n % 64)) & 1);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
uint64_t tcrc = 0;
|
|
uint offset = 0;
|
|
|
|
// appending 24 ones before a0 for DCI as stated in 38.212 7.3.2
|
|
if (ones_flag)
|
|
offset = 3;
|
|
|
|
// A bit string should be stored as 0, 0, ..., 0, a'_0, a'_1, ..., a'_A-1,
|
|
//???a'_{N-1} a'_{N-2} ... a'_{N-A} 0 .... 0, where N=64,128,192,..., N is smallest multiple of 64 greater than or equal to A
|
|
|
|
// First flip A bitstring byte endian for CRC routines (optimized for DLSCH/ULSCH, not PBCH/PDCCH)
|
|
// CRC reads in each byte in bit positions 7 down to 0, for PBCH/PDCCH we need to read in a_{A-1} down to a_{0}, A = length of bit
|
|
// string (e.g. 32 for PBCH)
|
|
if (bitlen <= 32) {
|
|
uint8_t A32_flip[4 + offset];
|
|
if (ones_flag) {
|
|
A32_flip[0] = 0xff;
|
|
A32_flip[1] = 0xff;
|
|
A32_flip[2] = 0xff;
|
|
}
|
|
uint32_t Aprime = (uint32_t)(((uint32_t)*A) << (32 - bitlen));
|
|
A32_flip[0 + offset] = ((uint8_t *)&Aprime)[3];
|
|
A32_flip[1 + offset] = ((uint8_t *)&Aprime)[2];
|
|
A32_flip[2 + offset] = ((uint8_t *)&Aprime)[1];
|
|
A32_flip[3 + offset] = ((uint8_t *)&Aprime)[0];
|
|
if (polarParams->crcParityBits == 24)
|
|
tcrc = (uint64_t)(((crcmask ^ (crc24c(A32_flip, 8 * offset + bitlen) >> 8))) & 0xffffff);
|
|
else if (polarParams->crcParityBits == 11)
|
|
tcrc = (uint64_t)(((crcmask ^ (crc11(A32_flip, bitlen) >> 21))) & 0x7ff);
|
|
else if (polarParams->crcParityBits == 6)
|
|
tcrc = (uint64_t)(((crcmask ^ (crc6(A32_flip, bitlen) >> 26))) & 0x3f);
|
|
} else if (bitlen <= 64) {
|
|
uint8_t A64_flip[8 + offset];
|
|
if (ones_flag) {
|
|
A64_flip[0] = 0xff;
|
|
A64_flip[1] = 0xff;
|
|
A64_flip[2] = 0xff;
|
|
}
|
|
uint64_t Aprime = (uint64_t)(((uint64_t)*A) << (64 - bitlen));
|
|
A64_flip[0 + offset] = ((uint8_t *)&Aprime)[7];
|
|
A64_flip[1 + offset] = ((uint8_t *)&Aprime)[6];
|
|
A64_flip[2 + offset] = ((uint8_t *)&Aprime)[5];
|
|
A64_flip[3 + offset] = ((uint8_t *)&Aprime)[4];
|
|
A64_flip[4 + offset] = ((uint8_t *)&Aprime)[3];
|
|
A64_flip[5 + offset] = ((uint8_t *)&Aprime)[2];
|
|
A64_flip[6 + offset] = ((uint8_t *)&Aprime)[1];
|
|
A64_flip[7 + offset] = ((uint8_t *)&Aprime)[0];
|
|
if (polarParams->crcParityBits == 24)
|
|
tcrc = (uint64_t)((crcmask ^ (crc24c(A64_flip, 8 * offset + bitlen) >> 8))) & 0xffffff;
|
|
else if (polarParams->crcParityBits == 11)
|
|
tcrc = (uint64_t)((crcmask ^ (crc11(A64_flip, bitlen) >> 21))) & 0x7ff;
|
|
} else if (bitlen <= 128) {
|
|
uint8_t A128_flip[16 + offset];
|
|
if (ones_flag) {
|
|
A128_flip[0] = 0xff;
|
|
A128_flip[1] = 0xff;
|
|
A128_flip[2] = 0xff;
|
|
}
|
|
uint128_t Aprime = (uint128_t)(((uint128_t)*A) << (128 - bitlen));
|
|
for (int i = 0; i < 16; i++)
|
|
A128_flip[i + offset] = ((uint8_t *)&Aprime)[15 - i];
|
|
if (polarParams->crcParityBits == 24)
|
|
tcrc = (uint64_t)((crcmask ^ (crc24c(A128_flip, 8 * offset + bitlen) >> 8))) & 0xffffff;
|
|
else if (polarParams->crcParityBits == 11)
|
|
tcrc = (uint64_t)((crcmask ^ (crc11(A128_flip, bitlen) >> 21))) & 0x7ff;
|
|
}
|
|
|
|
// this is number of quadwords in the bit string
|
|
int quadwlen = (polarParams->K + 63) / 64;
|
|
|
|
// Create the B bit string as
|
|
// 0, 0, ..., 0, a'_0, a'_1, ..., a'_A-1, p_0, p_1, ..., p_{N_parity-1}
|
|
|
|
//??? b_{N'-1} b_{N'-2} ... b_{N'-A} b_{N'-A-1} ... b_{N'-A-Nparity} = a_{N-1} a_{N-2} ... a_{N-A} p_{N_parity-1} ... p_0
|
|
uint64_t B[4] = {0};
|
|
B[0] = (A[0] << polarParams->crcParityBits) | tcrc;
|
|
for (int n = 1; n < quadwlen; n++)
|
|
if ((bitlen + 63) / 64 > n)
|
|
B[n] = (A[n] << polarParams->crcParityBits) | (A[n - 1] >> (64 - polarParams->crcParityBits));
|
|
else
|
|
B[n] = (A[n - 1] >> (64 - polarParams->crcParityBits));
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
int bitlen_B = bitlen + polarParams->crcParityBits;
|
|
int B_array = (bitlen_B + 63) >> 6;
|
|
int n_start = (B_array << 6) - bitlen_B;
|
|
printf("b: ");
|
|
for (int n = 0; n < bitlen_B; n++) {
|
|
if (n % 4 == 0) {
|
|
printf(" ");
|
|
}
|
|
int n1 = (n + n_start) >> 6;
|
|
int n2 = (n + n_start) - (n1 << 6);
|
|
printf("%lu", (B[B_array - 1 - n1] >> (63 - n2)) & 1);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
// TS 38.212 - Section 5.3.1.1 Interleaving
|
|
// For each byte of B, lookup in corresponding table for 64-bit word corresponding to that byte and its position
|
|
uint64_t Cprime[4] = {0};
|
|
uint8_t *Bbyte = (uint8_t *)B;
|
|
if (polarParams->K < 65) {
|
|
Cprime[0] = polarParams->cprime_tab0[0][Bbyte[0]] | polarParams->cprime_tab0[1][Bbyte[1]]
|
|
| polarParams->cprime_tab0[2][Bbyte[2]] | polarParams->cprime_tab0[3][Bbyte[3]]
|
|
| polarParams->cprime_tab0[4][Bbyte[4]] | polarParams->cprime_tab0[5][Bbyte[5]]
|
|
| polarParams->cprime_tab0[6][Bbyte[6]] | polarParams->cprime_tab0[7][Bbyte[7]];
|
|
} else if (polarParams->K < 129) {
|
|
for (int i = 0; i < 1 + (polarParams->K / 8); i++) {
|
|
Cprime[0] |= polarParams->cprime_tab0[i][Bbyte[i]];
|
|
Cprime[1] |= polarParams->cprime_tab1[i][Bbyte[i]];
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_POLAR_MATLAB
|
|
// Cprime = pbchCprime
|
|
for (int i = 0; i < quadwlen; i++)
|
|
printf("[polar_encoder_fast]C'[%d]= 0x%llx\n", i, (unsigned long long)(Cprime[i]));
|
|
#endif
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
printf("c: ");
|
|
for (int n = 0; n < bitlen_B; n++) {
|
|
if (n % 4 == 0) {
|
|
printf(" ");
|
|
}
|
|
int n1 = n >> 6;
|
|
int n2 = n - (n1 << 6);
|
|
printf("%lu", (Cprime[n1] >> n2) & 1);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
uint64_t u[16] = {0};
|
|
nr_polar_generate_u(u,
|
|
Cprime,
|
|
polarParams->information_bit_pattern,
|
|
polarParams->parity_check_bit_pattern,
|
|
polarParams->N,
|
|
polarParams->n_pc);
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
int N_array = polarParams->N >> 6;
|
|
printf("u: ");
|
|
for (int n = 0; n < polarParams->N; n++) {
|
|
if (n % 4 == 0) {
|
|
printf(" ");
|
|
}
|
|
int n1 = n >> 6;
|
|
int n2 = n - (n1 << 6);
|
|
printf("%lu", (u[N_array - 1 - n1] >> (63 - n2)) & 1);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
uint64_t D[8];
|
|
nr_polar_uxG((uint8_t *)u, polarParams->N, (uint8_t *)D);
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
printf("d: ");
|
|
for (int n = 0; n < polarParams->N; n++) {
|
|
if (n % 4 == 0) {
|
|
printf(" ");
|
|
}
|
|
int n1 = n >> 6;
|
|
int n2 = n - (n1 << 6);
|
|
printf("%lu", (D[n1] >> n2) & 1);
|
|
}
|
|
printf("\n");
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
memset((void *)out, 0, polarParams->encoderLength >> 3);
|
|
polar_rate_matching(polarParams, (void *)D, out);
|
|
|
|
#ifdef POLAR_CODING_DEBUG
|
|
uint64_t *out64 = (uint64_t *)out;
|
|
printf("rm:");
|
|
for (int n = 0; n < polarParams->encoderLength; n++) {
|
|
if (n % 4 == 0) {
|
|
printf(" ");
|
|
}
|
|
int n1 = n >> 6;
|
|
int n2 = n - (n1 << 6);
|
|
printf("%lu", (out64[n1] >> n2) & 1);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
polarReturn(polarParams);
|
|
}
|