Files
openairinterface5g/openair1/PHY/CODING/3gpplte_sse.c
T

403 lines
18 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: 3gpplte_sse.c
purpose: Encoding routines for implementing Turbo-coded (DLSCH) transport channels from 36-212, V8.6 2009-03
author: Laurent Thomas
maintainer: raymond.knopp@eurecom.fr
date: 09.2012
*/
#ifndef TC_MAIN
#include "coding_defs.h"
#else
#include <stdint.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common/oai_version.h"
#include "PHY/sse_intrin.h"
#define print_bytes(s,x) printf("%s %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",s,(x)[0],(x)[1],(x)[2],(x)[3],(x)[4],(x)[5],(x)[6],(x)[7],(x)[8],(x)[9],(x)[10],(x)[11],(x)[12],(x)[13],(x)[14],(x)[15])
#define print_shorts(s,x) printf("%s %x,%x,%x,%x,%x,%x,%x,%x\n",s,(x)[0],(x)[1],(x)[2],(x)[3],(x)[4],(x)[5],(x)[6],(x)[7])
#define print_ints(s,x) printf("%s %x %x %x %x\n",s,(x)[0],(x)[1],(x)[2],(x)[3])
#define print_bytes2(s,x) printf("%s %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",s,(x)[0],(x)[1],(x)[2],(x)[3],(x)[4],(x)[5],(x)[6],(x)[7],(x)[8],(x)[9],(x)[10],(x)[11],(x)[12],(x)[13],(x)[14],(x)[15],(x)[16],(x)[17],(x)[18],(x)[19],(x)[20],(x)[21],(x)[22],(x)[23],(x)[24],(x)[25],(x)[26],(x)[27],(x)[28],(x)[29],(x)[30],(x)[31])
//#define DEBUG_TURBO_ENCODER 1
//#define CALLGRIND 1
struct treillis {
uint8_t systematic_andp1[24] __attribute__((aligned(32)));
uint8_t parity2[24] __attribute__((aligned(32)));
int exit_state;
} __attribute__ ((aligned(64)));
struct treillis all_treillis[8][256];
int all_treillis_initialized=0;
static inline unsigned char threegpplte_rsc(unsigned char input,unsigned char *state) {
unsigned char output;
output = (input ^ (*state>>2) ^ (*state>>1))&1;
*state = (((input<<2)^(*state>>1))^((*state>>1)<<2)^((*state)<<2))&7;
return(output);
}
static inline void threegpplte_rsc_termination(unsigned char *x,unsigned char *z,unsigned char *state) {
*z = ((*state>>2) ^ (*state)) &1;
*x = ((*state) ^ (*state>>1)) &1;
*state = (*state)>>1;
}
static void treillis_table_init(void) {
//struct treillis t[][]=all_treillis;
//t=memalign(16,sizeof(struct treillis)*8*256);
int i, j,b;
unsigned char v, current_state;
// clear all_treillis
for (i=0; i<8; i++) {
bzero( all_treillis[i], sizeof(all_treillis[0]) );
}
for (i=0; i<8; i++) { //all possible initial states
for (j=0; j<=255; j++) { // all possible values of a byte
current_state=i;
for (b=0; b<8 ; b++ ) { // pre-compute the image of the byte j in _m128i vector right place
all_treillis[i][j].systematic_andp1[b * 3] = (j & (1 << (7 - b))) >> (7 - b);
v = threegpplte_rsc(all_treillis[i][j].systematic_andp1[b * 3], &current_state);
all_treillis[i][j].systematic_andp1[b * 3 + 1] = v; // for the yparity1
// all_treillis[i][j].parity1_8[b*3+1]=v; // for the yparity1
all_treillis[i][j].parity2[b * 3 + 2] = v; // for the yparity2
}
all_treillis[i][j].exit_state=current_state;
}
}
all_treillis_initialized=1;
return ;
}
char interleave_compact_byte(short *base_interleaver,unsigned char *input, unsigned char *output, int n) {
char expandInput[768*8] __attribute__((aligned(32)));
int i, loop = n >> 4;
simde__m256i *i_256 = (simde__m256i *)input, *o_256 = (simde__m256i *)expandInput;
simde__m256i tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
simde__m256i BIT_MASK = simde_mm256_set_epi8(0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000);
loop=n>>5;
if ((n&31) > 0)
loop++;
for (i=0; i<loop ; i++ ) {
// int cur_byte=i<<3;
// for (b=0;b<8;b++)
// expandInput[cur_byte+b] = (input[i]&(1<<(7-b)))>>(7-b);
tmp1=simde_mm256_load_si256(i_256++); // tmp1 = B0,B1,...,B15,...,B31
//print_bytes2("in",(uint8_t*)&tmp1);
tmp2=simde_mm256_unpacklo_epi8(tmp1,tmp1); // tmp2 = B0,B0,B1,B1,...,B7,B7,B16,B16,B17,B17,...,B23,B23
tmp3=simde_mm256_unpacklo_epi16(tmp2,tmp2); // tmp3 = B0,B0,B0,B0,B1,B1,B1,B1,B2,B2,B2,B2,B3,B3,B3,B3,B16,B16,B16,B16,...,B19,B19,B19,B19
tmp4=simde_mm256_unpacklo_epi32(tmp3,tmp3); // tmp4 - B0,B0,B0,B0,B0,B0,B0,B0,B1,B1,B1,B1,B1,B1,B1,B1,B16,B16...,B17..,B17
tmp5=simde_mm256_unpackhi_epi32(tmp3,tmp3); // tmp5 - B2,B2,B2,B2,B2,B2,B2,B2,B3,B3,B3,B3,B3,B3,B3,B3,B18...,B18,B19,...,B19
tmp6=simde_mm256_insertf128_si256(tmp4,simde_mm256_extracti128_si256(tmp5,0),1); // tmp6 = B0 B1 B2 B3
tmp7=simde_mm256_insertf128_si256(tmp5,simde_mm256_extracti128_si256(tmp4,1),0); // tmp7 = B16 B17 B18 B19
//print_bytes2("tmp2",(uint8_t*)&tmp2);
//print_bytes2("tmp3",(uint8_t*)&tmp3);
//print_bytes2("tmp4",(uint8_t*)&tmp4);
//print_bytes2("tmp5",(uint8_t*)&tmp4);
//print_bytes2("tmp6",(uint8_t*)&tmp6);
//print_bytes2("tmp7",(uint8_t*)&tmp7);
o_256[0]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp6,BIT_MASK),BIT_MASK);
//print_bytes2("out",(uint8_t*)o_256);
o_256[4]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp7,BIT_MASK),BIT_MASK);;
//print_bytes2("out",(uint8_t*)(o_256+4));
tmp3=simde_mm256_unpackhi_epi16(tmp2,tmp2); // tmp3 = B4,B4,B4,B4,B5,B5,B5,B5,B6,B6,B6,B6,B7,B7,B7,B7,B20,B20,B20,B20,...,B23,B23,B23,B23
tmp4=simde_mm256_unpacklo_epi32(tmp3,tmp3); // tmp4 - B4,B4,B4,B4,B4,B4,B4,B4,B5,B5,B5,B5,B5,B5,B5,B5,B20,B20...,B21..,B21
tmp5=simde_mm256_unpackhi_epi32(tmp3,tmp3); // tmp5 - B6,B6,B6,B6,B6,B6,B6,B6,B7,B7,B7,B7,B7,B7,B7,B7,B22...,B22,B23,...,B23
tmp6=simde_mm256_insertf128_si256(tmp4,simde_mm256_extracti128_si256(tmp5,0),1); // tmp6 = B4 B5 B6 B7
tmp7=simde_mm256_insertf128_si256(tmp5,simde_mm256_extracti128_si256(tmp4,1),0); // tmp7 = B20 B21 B22 B23
//print_bytes2("tmp2",(uint8_t*)&tmp2);
//print_bytes2("tmp3",(uint8_t*)&tmp3);
//print_bytes2("tmp4",(uint8_t*)&tmp4);
//print_bytes2("tmp5",(uint8_t*)&tmp4);
//print_bytes2("tmp6",(uint8_t*)&tmp6);
//print_bytes2("tmp7",(uint8_t*)&tmp7);
o_256[1]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp6,BIT_MASK),BIT_MASK);
//print_bytes2("out",(uint8_t*)(o_256+1));
o_256[5]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp7,BIT_MASK),BIT_MASK);;
//print_bytes2("out",(uint8_t*)(o_256+4));
tmp2=simde_mm256_unpackhi_epi8(tmp1,tmp1); // tmp2 = B8 B9 B10 B11 B12 B13 B14 B15 B25 B26 B27 B28 B29 B30 B31
tmp3=simde_mm256_unpacklo_epi16(tmp2,tmp2); // tmp3 = B8,B9,B10,B11,B26,B27,B28,B29
tmp4=simde_mm256_unpacklo_epi32(tmp3,tmp3); // tmp4 - B8,B9,B26,B27
tmp5=simde_mm256_unpackhi_epi32(tmp3,tmp3); // tmp5 - B10,B11,B28,B29
tmp6=simde_mm256_insertf128_si256(tmp4,simde_mm256_extracti128_si256(tmp5,0),1); // tmp6 = B8 B9 B10 B11
tmp7=simde_mm256_insertf128_si256(tmp5,simde_mm256_extracti128_si256(tmp4,1),0); // tmp7 = B26 B27 B28 B29
//print_bytes2("tmp2",(uint8_t*)&tmp2);
//print_bytes2("tmp3",(uint8_t*)&tmp3);
//print_bytes2("tmp4",(uint8_t*)&tmp4);
//print_bytes2("tmp5",(uint8_t*)&tmp4);
//print_bytes2("tmp6",(uint8_t*)&tmp6);
//print_bytes2("tmp7",(uint8_t*)&tmp7);
o_256[2]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp6,BIT_MASK),BIT_MASK);
//print_bytes2("out",(uint8_t*)(o_256+2));
o_256[6]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp7,BIT_MASK),BIT_MASK);;
//print_bytes2("out",(uint8_t*)(o_256+4));
tmp3=simde_mm256_unpackhi_epi16(tmp2,tmp2); // tmp3 = B12 B13 B14 B15 B28 B29 B30 B31
tmp4=simde_mm256_unpacklo_epi32(tmp3,tmp3); // tmp4 = B12 B13 B28 B29
tmp5=simde_mm256_unpackhi_epi32(tmp3,tmp3); // tmp5 = B14 B15 B30 B31
tmp6=simde_mm256_insertf128_si256(tmp4,simde_mm256_extracti128_si256(tmp5,0),1); // tmp6 = B12 B13 B14 B15
tmp7=simde_mm256_insertf128_si256(tmp5,simde_mm256_extracti128_si256(tmp4,1),0); // tmp7 = B28 B29 B30 B31
//print_bytes2("tmp2",(uint8_t*)&tmp2);
//print_bytes2("tmp3",(uint8_t*)&tmp3);
//print_bytes2("tmp4",(uint8_t*)&tmp4);
//print_bytes2("tmp5",(uint8_t*)&tmp4);
//print_bytes2("tmp6",(uint8_t*)&tmp6);
//print_bytes2("tmp7",(uint8_t*)&tmp7);
o_256[3]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp6,BIT_MASK),BIT_MASK);
//print_bytes2("out",(uint8_t*)(o_256+3));
o_256[7]=simde_mm256_cmpeq_epi8(simde_mm256_and_si256(tmp7,BIT_MASK),BIT_MASK);;
//print_bytes2("out",(uint8_t*)(o_256+7));
o_256 += 8;
}
short *ptr_intl = base_interleaver;
simde__m256i tmp = {0};
uint32_t *systematic2_ptr = (uint32_t *)output;
int input_length_words=1+((n-1)>>2);
for (i = 0; i < input_length_words; i++) {
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],7);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],6);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],5);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],4);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],3);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],2);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],1);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],0);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+7);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+6);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+5);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+4);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+3);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+2);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+1);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],8+0);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+7);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+6);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+5);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+4);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+3);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+2);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+1);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],16+0);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+7);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+6);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+5);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+4);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+3);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+2);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+1);
tmp=simde_mm256_insert_epi8(tmp,expandInput[*ptr_intl++],24+0);
*systematic2_ptr++ = (unsigned int)simde_mm256_movemask_epi8(tmp);
}
return n;
}
/*
#define simde_mm_expand_si128(xmmx, out, bit_mask) \
{ \
simde__m128i loc_mm; \
loc_mm=(xmmx); \
loc_mm=simde_mm_and_si128(loc_mm,bit_mask); \
out=simde_mm_cmpeq_epi8(loc_mm,bit_mask); \
}
*/
void threegpplte_turbo_encoder_sse(unsigned char *input, unsigned short input_length_bytes, unsigned char *output, unsigned char F)
{
unsigned char *x;
unsigned short input_length_bits = input_length_bytes<<3;
short *base_interleaver;
if ( all_treillis_initialized == 0 ) {
treillis_table_init();
}
// look for f1 and f2 precomputed interleaver values
int i;
for (i=0; i < 188 && f1f2mat[i].nb_bits != input_length_bits; i++);
if ( i == 188 ) {
printf("Illegal frame length!\n");
return;
} else {
base_interleaver=il_tb+f1f2mat[i].beg_index;
}
unsigned char systematic2[768] __attribute__((aligned(32)));
interleave_compact_byte(base_interleaver, input, systematic2, input_length_bytes);
unsigned char *ptr_output = output;
unsigned char state0 = 0, state1 = 0;
for (int i = 0; i < input_length_bytes; i++) {
int cur_s1 = input[i];
uint8_t *systematic_andp1 = all_treillis[state0][cur_s1].systematic_andp1;
int cur_s2 = systematic2[i];
uint8_t *parity2 = all_treillis[state1][cur_s2].parity2;
simde_mm_storeu_si128((simde__m128i *)ptr_output,
simde_mm_add_epi8(*(simde__m128i *)systematic_andp1, *(simde__m128i *)parity2));
ptr_output += 16;
for (int code_rate = 16; code_rate < 24; code_rate++) {
*ptr_output++ = systematic_andp1[code_rate] + parity2[code_rate];
}
state0=all_treillis[state0][cur_s1].exit_state;
state1=all_treillis[state1][cur_s2].exit_state;
}
x=output+(input_length_bits*3);
// Trellis termination
threegpplte_rsc_termination(&x[0],&x[1],&state0);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state0 %d\n",x[0],x[1],state0);
#endif //DEBUG_TURBO_ENCODER
threegpplte_rsc_termination(&x[2],&x[3],&state0);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state0 %d\n",x[2],x[3],state0);
#endif //DEBUG_TURBO_ENCODER
threegpplte_rsc_termination(&x[4],&x[5],&state0);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state0 %d\n",x[4],x[5],state0);
#endif //DEBUG_TURBO_ENCODER
threegpplte_rsc_termination(&x[6],&x[7],&state1);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state1 %d\n",x[6],x[7],state1);
#endif //DEBUG_TURBO_ENCODER
threegpplte_rsc_termination(&x[8],&x[9],&state1);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state1 %d\n",x[8],x[9],state1);
#endif //DEBUG_TURBO_ENCODER
threegpplte_rsc_termination(&x[10],&x[11],&state1);
#ifdef DEBUG_TURBO_ENCODER
printf("term: x0 %u, x1 %u, state1 %d\n",x[10],x[11],state1);
#endif // DEBUG_TURBO_ENCODER
}
void init_encoder_sse (void) {
treillis_table_init();
}
/* function which will be called by the shared lib loader, to check shared lib version
against main exec version. version mismatch no considered as fatal (interfaces not supposed to change)
*/
int coding_checkbuildver(char *mainexec_buildversion, char **shlib_buildversion) {
*shlib_buildversion = OAI_PACKAGE_VERSION;
if (strcmp(mainexec_buildversion, *shlib_buildversion) != 0) {
fprintf(stderr,"[CODING] shared lib version %s, doesn't match main version %s, compatibility should be checked\n",
mainexec_buildversion,*shlib_buildversion);
}
return 0;
}
#ifdef TC_MAIN
#define INPUT_LENGTH 20
#define F1 21
#define F2 120
int main(int argc,char **argv) {
unsigned char input[INPUT_LENGTH+32],state,state2;
unsigned char output[12+(3*(INPUT_LENGTH<<3))],x,z;
int i;
unsigned char out;
for (state=0; state<8; state++) {
for (i=0; i<2; i++) {
state2=state;
out = threegpplte_rsc(i,&state2);
printf("State (%d->%d) : (%d,%d)\n",state,state2,i,out);
}
}
printf("\n");
for (state=0; state<8; state++) {
state2=state;
threegpplte_rsc_termination(&x,&z,&state2);
printf("Termination: (%d->%d) : (%d,%d)\n",state,state2,x,z);
}
memset((void *)input,0,INPUT_LENGTH+16);
for (i=0; i<INPUT_LENGTH; i++) {
input[i] = i*219;
printf("Input %d : %u\n",i,input[i]);
}
threegpplte_turbo_encoder_sse(&input[0],
INPUT_LENGTH,
&output[0],
0);
for (i=0; i<12+(INPUT_LENGTH*24); i++)
printf("%u",output[i]);
printf("\n");
return(0);
}
#endif // MAIN