407 lines
15 KiB
C
407 lines
15 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_decoding_tools.c
|
|
* \brief
|
|
* \author Turker Yilmaz
|
|
* \date 2018
|
|
* \version 0.1
|
|
* \company EURECOM
|
|
* \email turker.yilmaz@eurecom.fr
|
|
* \note
|
|
* \warning
|
|
*/
|
|
|
|
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
|
|
#include "PHY/sse_intrin.h"
|
|
#include "PHY/impl_defs_top.h"
|
|
|
|
//#define DEBUG_NEW_IMPL 1
|
|
|
|
static inline void updateBit(uint8_t listSize,
|
|
uint16_t row,
|
|
uint16_t col,
|
|
uint16_t xlen,
|
|
uint8_t ylen,
|
|
int zlen,
|
|
uint8_t bit[xlen][ylen][zlen],
|
|
uint8_t bitU[xlen][ylen])
|
|
{
|
|
const uint offset = (xlen / (pow(2, (ylen - col))));
|
|
|
|
for (uint i = 0; i < listSize; i++) {
|
|
if (((row) % (2 * offset)) >= offset) {
|
|
if (bitU[row][col - 1] == 0)
|
|
updateBit(listSize, row, (col - 1), xlen, ylen, zlen, bit, bitU);
|
|
bit[row][col][i] = bit[row][col - 1][i];
|
|
} else {
|
|
if (bitU[row][col - 1] == 0)
|
|
updateBit(listSize, row, (col - 1), xlen, ylen, zlen, bit, bitU);
|
|
if (bitU[row + offset][col - 1] == 0)
|
|
updateBit(listSize, (row + offset), (col - 1), xlen, ylen, zlen, bit, bitU);
|
|
bit[row][col][i] = ((bit[row][col - 1][i] + bit[row + offset][col - 1][i]) % 2);
|
|
}
|
|
}
|
|
|
|
bitU[row][col] = 1;
|
|
}
|
|
|
|
static inline void computeLLR(uint16_t row,
|
|
uint16_t col,
|
|
uint8_t i,
|
|
uint16_t offset,
|
|
int xlen,
|
|
int ylen,
|
|
int zlen,
|
|
double llr[xlen][ylen][zlen])
|
|
{
|
|
double a = llr[row][col + 1][i];
|
|
double b = llr[row + offset][col + 1][i];
|
|
llr[row][col][i] = log((exp(a + b) + 1) / (exp(a) + exp(b))); //eq. (8a)
|
|
}
|
|
|
|
void updateLLR(uint8_t listSize,
|
|
uint16_t row,
|
|
uint16_t col,
|
|
uint16_t xlen,
|
|
uint8_t ylen,
|
|
int zlen,
|
|
double llr[xlen][ylen][zlen],
|
|
uint8_t llrU[xlen][ylen],
|
|
uint8_t bit[xlen][ylen][zlen],
|
|
uint8_t bitU[xlen][ylen])
|
|
{
|
|
const uint offset = (xlen / (pow(2, (ylen - col - 1))));
|
|
for (uint i = 0; i < listSize; i++) {
|
|
if ((row % (2 * offset)) >= offset) {
|
|
if (bitU[row - offset][col] == 0)
|
|
updateBit(listSize, (row - offset), col, xlen, ylen, zlen, bit, bitU);
|
|
if (llrU[row - offset][col + 1] == 0)
|
|
updateLLR(listSize, (row - offset), (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
|
|
if (llrU[row][col + 1] == 0)
|
|
updateLLR(listSize, row, (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
|
|
llr[row][col][i] = (pow((-1), bit[row - offset][col][i]) * llr[row - offset][col + 1][i]) + llr[row][col + 1][i];
|
|
} else {
|
|
if (llrU[row][col + 1] == 0)
|
|
updateLLR(listSize, row, (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
|
|
if (llrU[row + offset][col + 1] == 0)
|
|
updateLLR(listSize, (row + offset), (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
|
|
computeLLR(row, col, i, offset, xlen, ylen, zlen, llr);
|
|
}
|
|
}
|
|
llrU[row][col] = 1;
|
|
|
|
// printf("LLR (a %f, b %f): llr[%d][%d] %f\n",32*a,32*b,col,row,32*llr[col][row]);
|
|
}
|
|
|
|
void updatePathMetric(double *pathMetric,
|
|
uint8_t listSize,
|
|
uint8_t bitValue,
|
|
uint16_t row,
|
|
int xlen,
|
|
int ylen,
|
|
int zlen,
|
|
double llr[xlen][ylen][zlen]
|
|
)
|
|
{
|
|
const int multiplier = (2 * bitValue) - 1;
|
|
for (uint i = 0; i < listSize; i++)
|
|
pathMetric[i] += log(1 + exp(multiplier * llr[row][0][i])); // eq. (11b)
|
|
}
|
|
|
|
void updatePathMetric2(double *pathMetric,
|
|
uint8_t listSize,
|
|
uint16_t row,
|
|
int xlen,
|
|
int ylen,
|
|
int zlen,
|
|
double llr[xlen][ylen][zlen])
|
|
{
|
|
double tempPM[listSize];
|
|
memcpy(tempPM, pathMetric, (sizeof(double) * listSize));
|
|
|
|
uint bitValue = 0;
|
|
int multiplier = (2 * bitValue) - 1;
|
|
for (uint i = 0; i < listSize; i++)
|
|
pathMetric[i] += log(1 + exp(multiplier * llr[row][0][i])); // eq. (11b)
|
|
|
|
bitValue = 1;
|
|
multiplier = (2 * bitValue) - 1;
|
|
for (uint i = listSize; i < 2 * listSize; i++)
|
|
pathMetric[i] = tempPM[(i - listSize)] + log(1 + exp(multiplier * llr[row][0][(i - listSize)])); // eq. (11b)
|
|
}
|
|
|
|
static inline decoder_node_t *new_decoder_node(simde__m256i **buffer,
|
|
const int level,
|
|
const int first_leaf_index,
|
|
const bool leaf,
|
|
const bool frozen)
|
|
{
|
|
int leaf_sz = 1 << level;
|
|
// we will use SIMD128 minimum
|
|
leaf_sz = (leaf_sz + 7) & ~7;
|
|
if (leaf_sz > 15) // we will use SIMD256
|
|
leaf_sz = (leaf_sz + 15) & ~15;
|
|
const int tree_sz = (sizeof(decoder_node_t) + 31) & ~31;
|
|
uintptr_t tmp = (uintptr_t)*buffer;
|
|
tmp = (tmp + sizeof(**buffer) - 1) & ~(sizeof(**buffer) - 1);
|
|
decoder_node_t *node = (decoder_node_t *)tmp;
|
|
*buffer = (simde__m256i *)(tmp + tree_sz + leaf_sz * sizeof(int16_t) + leaf_sz);
|
|
*node = (decoder_node_t){.first_leaf_index = first_leaf_index,
|
|
.level = level,
|
|
.leaf = leaf,
|
|
.all_frozen = frozen,
|
|
.alpha = tree_sz,
|
|
.beta = tree_sz + leaf_sz * sizeof(int16_t),
|
|
.betaInit = false};
|
|
return(node);
|
|
}
|
|
|
|
static inline decoder_node_t *add_nodes(decoder_tree_t *tree,
|
|
int level,
|
|
int first_leaf_index,
|
|
const uint8_t *information_bit_pattern,
|
|
simde__m256i **buffer)
|
|
{
|
|
if (level==0) {
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("leaf %d (%s)\n", first_leaf_index, information_bit_pattern[first_leaf_index] == 1 ? "information or crc" : "frozen");
|
|
#endif
|
|
return new_decoder_node(buffer, level, first_leaf_index, true, information_bit_pattern[first_leaf_index] == 0);
|
|
}
|
|
|
|
int Nv = 1 << level;
|
|
const uint8_t *ptr = information_bit_pattern + first_leaf_index;
|
|
const uint8_t *end = ptr + Nv;
|
|
bool all_frozen_below = true;
|
|
while (ptr < end && all_frozen_below) {
|
|
all_frozen_below = *ptr++ <= 0;
|
|
}
|
|
|
|
if (all_frozen_below) {
|
|
return new_decoder_node(buffer, level, first_leaf_index, true, true);
|
|
}
|
|
|
|
decoder_node_t *new_node = new_decoder_node(buffer, level, first_leaf_index, false, false);
|
|
new_node->left = add_nodes(tree, level - 1, first_leaf_index, information_bit_pattern, buffer);
|
|
new_node->right = add_nodes(tree, level - 1, first_leaf_index + (Nv / 2), information_bit_pattern, buffer);
|
|
return(new_node);
|
|
}
|
|
|
|
void build_decoder_tree(t_nrPolar_params *pp)
|
|
{
|
|
uintptr_t tmp = (uintptr_t)pp->decoder.buffer;
|
|
tmp = (tmp + sizeof(*pp->decoder.buffer) - 1) & ~(sizeof(*pp->decoder.buffer) - 1);
|
|
simde__m256i *buffer = (simde__m256i *)tmp;
|
|
pp->decoder.root = add_nodes(&pp->decoder, pp->n, 0, pp->information_bit_pattern, &buffer);
|
|
AssertFatal(buffer < pp->decoder.buffer + sizeofArray(pp->decoder.buffer),
|
|
"Arbitrary size too small (also check arbitrary max size of the entire polar decoder) %ld instead of max %ld\n",
|
|
buffer - pp->decoder.buffer,
|
|
sizeofArray(pp->decoder.buffer));
|
|
}
|
|
|
|
static inline void applyFtoleft(const t_nrPolar_params *pp, decoder_node_t *node, uint8_t *output)
|
|
{
|
|
int16_t *alpha_v = treeAlpha(node);
|
|
int16_t *alpha_l = treeAlpha(node->left);
|
|
int8_t *betal = treeBeta(node->left);
|
|
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("applyFtoleft %d, Nv %d (level %d,node->left (leaf %d, AF %d))\n",node->first_leaf_index,node->Nv,node->level,node->left->leaf,node->left->all_frozen);
|
|
|
|
for (int i = 0; i < node->Nv; i++)
|
|
printf("i%d (frozen %d): alpha_v[i] = %d\n", i, 1 - pp->information_bit_pattern[node->first_leaf_index + i], alpha_v[i]);
|
|
#endif
|
|
assert(node->level);
|
|
const int sz = 1 << (node->level - 1);
|
|
if (node->left->all_frozen == 0) {
|
|
int avx2mod = sz & 15;
|
|
if (avx2mod == 0) {
|
|
int avx2len = sz / 16;
|
|
|
|
// printf("avx2len %d\n",avx2len);
|
|
for (int i=0;i<avx2len;i++) {
|
|
simde__m256i a256 = ((simde__m256i *)alpha_v)[i];
|
|
simde__m256i b256 = ((simde__m256i *)alpha_v)[i + avx2len];
|
|
simde__m256i absa256 = simde_mm256_abs_epi16(a256);
|
|
simde__m256i absb256 = simde_mm256_abs_epi16(b256);
|
|
simde__m256i minabs256 = simde_mm256_min_epi16(absa256, absb256);
|
|
((simde__m256i *)alpha_l)[i] = simde_mm256_sign_epi16(minabs256, simde_mm256_sign_epi16(a256, b256));
|
|
}
|
|
}
|
|
else if (avx2mod == 8) {
|
|
simde__m128i a128 = *((simde__m128i *)alpha_v);
|
|
simde__m128i b128 = ((simde__m128i *)alpha_v)[1];
|
|
simde__m128i absa128 = simde_mm_abs_epi16(a128);
|
|
simde__m128i absb128 = simde_mm_abs_epi16(b128);
|
|
simde__m128i minabs128 = simde_mm_min_epi16(absa128, absb128);
|
|
*((simde__m128i*)alpha_l) =simde_mm_sign_epi16(minabs128,simde_mm_sign_epi16(a128,b128));
|
|
}
|
|
else if (avx2mod == 4) {
|
|
simde__m64 a64 = *((simde__m64 *)alpha_v);
|
|
simde__m64 b64 = ((simde__m64 *)alpha_v)[1];
|
|
simde__m64 absa64 = simde_mm_abs_pi16(a64);
|
|
simde__m64 absb64 = simde_mm_abs_pi16(b64);
|
|
simde__m64 minabs64 = simde_mm_min_pi16(absa64, absb64);
|
|
*((simde__m64*)alpha_l) =simde_mm_sign_pi16(minabs64,simde_mm_sign_pi16(a64,b64));
|
|
} else { // equivalent scalar code to above, activated only on non x86/ARM architectures
|
|
for (int i = 0; i < sz; i++) {
|
|
int16_t a = alpha_v[i];
|
|
int16_t b = alpha_v[i + sz];
|
|
int16_t maska = a >> 15;
|
|
int16_t maskb = b >> 15;
|
|
int16_t absa = (a + maska) ^ maska;
|
|
int16_t absb = (b + maskb) ^ maskb;
|
|
int16_t minabs = absa < absb ? absa : absb;
|
|
alpha_l[i] = (maska ^ maskb) == 0 ? minabs : -minabs;
|
|
// printf("alphal[%d] %d (%d,%d)\n",i,alpha_l[i],a,b);
|
|
}
|
|
}
|
|
if (sz == 1) { // apply hard decision on left node
|
|
const int tmp = alpha_l[0] <= 0;
|
|
betal[0] = tmp * 2 - 1;
|
|
node->left->betaInit = true;
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("betal[0] %d (%p)\n",betal[0],&betal[0]);
|
|
#endif
|
|
output[node->first_leaf_index] = tmp;
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("Setting bit %d to %d (LLR %d)\n",node->first_leaf_index,(betal[0]+1)>>1,alpha_l[0]);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void applyGtoright(const t_nrPolar_params *pp, decoder_node_t *node, uint8_t *output)
|
|
{
|
|
int16_t *alpha_v = treeAlpha(node);
|
|
int16_t *alpha_r = treeAlpha(node->right);
|
|
int8_t *betal = treeBeta(node->left);
|
|
int8_t *betar = treeBeta(node->right);
|
|
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("applyGtoright %d, Nv %d (level %d), (leaf %d, AF %d)\n",node->first_leaf_index,node->Nv,node->level,node->right->leaf,node->right->all_frozen);
|
|
#endif
|
|
assert(node->level);
|
|
const int sz = 1 << (node->level - 1);
|
|
if (node->right->all_frozen == 0) {
|
|
if (!node->left->betaInit) {
|
|
for (int i = 0; i < sz; i++) {
|
|
int temp_alpha_r = alpha_v[i + sz] + alpha_v[i];
|
|
if (temp_alpha_r > SHRT_MAX) {
|
|
alpha_r[i] = SHRT_MAX;
|
|
} else if (temp_alpha_r < -SHRT_MAX) {
|
|
alpha_r[i] = -SHRT_MAX;
|
|
} else {
|
|
alpha_r[i] = temp_alpha_r;
|
|
}
|
|
}
|
|
} else {
|
|
int avx2mod = sz & 15;
|
|
if (avx2mod == 0) {
|
|
int avx2len = sz / 16;
|
|
|
|
for (int i = 0; i < avx2len; i++) {
|
|
simde__m256i tmp = simde_mm256_sign_epi16(((simde__m256i *)alpha_v)[i], _mm256_cvtepi8_epi16(((simde__m128i *)betal)[i]));
|
|
((simde__m256i *)alpha_r)[i] =
|
|
|
|
simde_mm256_subs_epi16(((simde__m256i *)alpha_v)[i + avx2len], tmp);
|
|
}
|
|
} else if (avx2mod == 8) {
|
|
simde__m128i tmp = simde_mm_sign_epi16(((simde__m128i *)alpha_v)[0], _mm_cvtepi8_epi16(((simde__m128i *)betal)[0]));
|
|
((simde__m128i *)alpha_r)[0] = simde_mm_subs_epi16(((simde__m128i *)alpha_v)[1], tmp);
|
|
} else {
|
|
for (int i = 0; i < sz; i++) {
|
|
int temp_alpha_r = alpha_v[i + sz] - (betal[i] * alpha_v[i]);
|
|
if (temp_alpha_r > SHRT_MAX) {
|
|
alpha_r[i] = SHRT_MAX;
|
|
} else if (temp_alpha_r < -SHRT_MAX) {
|
|
alpha_r[i] = -SHRT_MAX;
|
|
} else {
|
|
alpha_r[i] = temp_alpha_r;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (sz == 1) { // apply hard decision on right node
|
|
int tmp = alpha_r[0] <= 0;
|
|
betar[0] = tmp * 2 - 1;
|
|
node->right->betaInit = true;
|
|
output[node->first_leaf_index + 1] = tmp;
|
|
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("Setting bit %d to %d (LLR %d)\n",node->first_leaf_index+1,(betar[0]+1)>>1,alpha_r[0]);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static const int64_t all11[4] = {-1, -1, -1, -1};
|
|
|
|
static inline void computeBeta(decoder_node_t *node)
|
|
{
|
|
int8_t *betav = treeBeta(node);
|
|
int8_t *betal = treeBeta(node->left);
|
|
int8_t *betar = treeBeta(node->right);
|
|
#ifdef DEBUG_NEW_IMPL
|
|
printf("Computing beta @ level %d first_leaf_index %d (all_frozen %d)\n",node->level,node->first_leaf_index,node->left->all_frozen);
|
|
#endif
|
|
assert(node->level);
|
|
const int sz = 1 << (node->level - 1);
|
|
if (node->left->all_frozen==0) { // if left node is not aggregation of frozen bits
|
|
assert(node->left->betaInit && node->right->betaInit);
|
|
int avx2mod = sz & 31;
|
|
if (avx2mod == 0) {
|
|
int avx2len = sz / 16;
|
|
for (int i=0;i<avx2len;i++) {
|
|
((simde__m256i *)betav)[i] =
|
|
simde_mm256_xor_si256(simde_mm256_xor_si256(((simde__m256i *)betar)[i], ((simde__m256i *)betal)[i]),
|
|
*(simde__m256i *)all11);
|
|
}
|
|
} else {
|
|
((simde__m128i *)betav)[0] =
|
|
simde_mm_xor_si128(simde_mm_xor_si128(((simde__m128i *)betar)[0], ((simde__m128i *)betal)[0]), *((simde__m128i *)all11));
|
|
}
|
|
} else {
|
|
assert(node->right->betaInit);
|
|
memcpy(betav, betar, sz * sizeof(*betav));
|
|
node->betaInit = true;
|
|
}
|
|
assert(node->right->betaInit);
|
|
memcpy(&betav[sz], betar, sz * sizeof(*betav));
|
|
node->betaInit = true;
|
|
}
|
|
|
|
void generic_polar_decoder(const t_nrPolar_params *pp, decoder_node_t *node, uint8_t *nr_polar_U)
|
|
{
|
|
// Apply F to left
|
|
applyFtoleft(pp, node, nr_polar_U);
|
|
// if left is not a leaf recurse down to the left
|
|
if (node->left->leaf==0)
|
|
generic_polar_decoder(pp, node->left, nr_polar_U);
|
|
|
|
applyGtoright(pp, node, nr_polar_U);
|
|
if (node->right->leaf == 0)
|
|
generic_polar_decoder(pp, node->right, nr_polar_U);
|
|
|
|
computeBeta(node);
|
|
}
|