Newer
Older
/*
* 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/LTE_TRANSPORT/dci.c
* \brief Implements PDCCH physical channel TX/RX procedures (36.211) and DCI encoding/decoding (36.212/36.213). Current LTE compliance V8.6 2009-03.
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#ifdef USER_MODE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SIMULATION/TOOLS/defs.h" // for taus
#include "UTIL/LOG/log.h"
David Price
committed
#include "UTIL/LOG/vcd_signal_dumper.h"
//#define DEBUG_DCI_ENCODING 1
//#define DEBUG_DCI_DECODING 1
//#define DEBUG_PHY
//#undef ALL_AGGREGATION
//extern uint16_t phich_reg[MAX_NUM_PHICH_GROUPS][3];
//extern uint16_t pcfich_reg[4];
uint32_t check_phich_reg(LTE_DL_FRAME_PARMS *frame_parms,uint32_t kprime,uint8_t lprime,uint8_t mi)
{
uint16_t i;
uint16_t Ngroup_PHICH = (frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)/48;
uint16_t mprime;
uint16_t *pcfich_reg = frame_parms->pcfich_reg;
if ((lprime>0) && (frame_parms->Ncp==0) )
return(0);
// printf("check_phich_reg : mi %d\n",mi);
// compute REG based on symbol
if ((lprime == 0)||
mprime = kprime/6;
else
mprime = kprime>>2;
// check if PCFICH uses mprime
if ((lprime==0) &&
((mprime == pcfich_reg[0]) ||
(mprime == pcfich_reg[1]) ||
(mprime == pcfich_reg[2]) ||
(mprime == pcfich_reg[3]))) {
#ifdef DEBUG_DCI_ENCODING
printf("[PHY] REG %d allocated to PCFICH\n",mprime);
#endif
return(1);
}
// handle Special subframe case for TDD !!!
// printf("Checking phich_reg %d\n",mprime);
if (mi > 0) {
if (((frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)%48) > 0)
Ngroup_PHICH++;
if (frame_parms->Ncp == 1) {
Ngroup_PHICH<<=1;
}
for (i=0; i<Ngroup_PHICH; i++) {
if ((mprime == frame_parms->phich_reg[i][0]) ||
(mprime == frame_parms->phich_reg[i][1]) ||
(mprime == frame_parms->phich_reg[i][2])) {
#ifdef DEBUG_DCI_ENCODING
printf("[PHY] REG %d (lprime %d) allocated to PHICH\n",mprime,lprime);
#endif
return(1);
}
}
}
return(0);
}
uint16_t extract_crc(uint8_t *dci,uint8_t dci_len)
{
/*
uint8_t crc;
crc = ((uint16_t *)dci)[DCI_LENGTH>>4];
printf("crc1: %x, shift %d (DCI_LENGTH %d)\n",crc,DCI_LENGTH&0xf,DCI_LENGTH);
crc = (crc>>(DCI_LENGTH&0xf));
// clear crc bits
((uint16_t *)dci)[DCI_LENGTH>>4] &= (0xffff>>(16-(DCI_LENGTH&0xf)));
printf("crc2: %x, dci0 %x\n",crc,((int16_t *)dci)[DCI_LENGTH>>4]);
crc |= (((uint16_t *)dci)[1+(DCI_LENGTH>>4)])<<(16-(DCI_LENGTH&0xf));
// clear crc bits
(((uint16_t *)dci)[1+(DCI_LENGTH>>4)]) = 0;
printf("extract_crc: crc %x\n",crc);
*/
#ifdef DEBUG_DCI_DECODING
LOG_I(PHY,"dci_crc (%x,%x,%x), dci_len&0x7=%d\n",dci[dci_len>>3],dci[1+(dci_len>>3)],dci[2+(dci_len>>3)],
dci_len&0x7);
#endif
if ((dci_len&0x7) > 0) {
((uint8_t *)&crc16)[0] = dci[1+(dci_len>>3)]<<(dci_len&0x7) | dci[2+(dci_len>>3)]>>(8-(dci_len&0x7));
((uint8_t *)&crc16)[1] = dci[(dci_len>>3)]<<(dci_len&0x7) | dci[1+(dci_len>>3)]>>(8-(dci_len&0x7));
} else {
((uint8_t *)&crc16)[0] = dci[1+(dci_len>>3)];
((uint8_t *)&crc16)[1] = dci[(dci_len>>3)];
}
#ifdef DEBUG_DCI_DECODING
LOG_I(PHY,"dci_crc =>%x\n",crc16);
#endif
// dci[(dci_len>>3)]&=(0xffff<<(dci_len&0xf));
// dci[(dci_len>>3)+1] = 0;
// dci[(dci_len>>3)+2] = 0;
}
static uint8_t d[3*(MAX_DCI_SIZE_BITS + 16) + 96];
static uint8_t w[3*3*(MAX_DCI_SIZE_BITS+16)];
uint8_t A,
uint16_t E,
uint8_t *e,
uint16_t rnti)
{
#ifdef DEBUG_DCI_ENCODING
#endif
// encode dci
#ifdef DEBUG_DCI_ENCODING
printf("Doing DCI encoding for %d bits, e %p, rnti %x\n",A,e,rnti);
#endif
memset((void *)d,LTE_NULL,96);
ccodelte_encode(A,2,a,d+96,rnti);
#ifdef DEBUG_DCI_ENCODING
for (i=0; i<16+A; i++)
printf("%d : (%d,%d,%d)\n",i,*(d+96+(3*i)),*(d+97+(3*i)),*(d+98+(3*i)));
#endif
#ifdef DEBUG_DCI_ENCODING
printf("Doing DCI interleaving for %d coded bits, e %p\n",D*3,e);
#endif
RCC = sub_block_interleaving_cc(D,d+96,w);
#ifdef DEBUG_DCI_ENCODING
printf("Doing DCI rate matching for %d channel bits, RCC %d, e %p\n",E,RCC,e);
#endif
lte_rate_matching_cc(RCC,E,w,e);
}
uint8_t *e,
uint8_t DCI_LENGTH,
uint8_t aggregation_level,
uint16_t rnti)
{
uint16_t coded_bits;
uint8_t dci_flip[8];
AssertFatal((aggregation_level==1) ||
(aggregation_level==2) ||
(aggregation_level==4) ||
(aggregation_level==8)
#ifdef Rel14 // Added for EPDCCH/MPDCCH
||
(aggregation_level==16) ||
(aggregation_level==24) ||
(aggregation_level==32)
#endif
,
"generate_dci FATAL, illegal aggregation_level %d\n",aggregation_level);
coded_bits = 72 * aggregation_level;
/*
#ifdef DEBUG_DCI_ENCODING
for (i=0;i<1+((DCI_LENGTH+16)/8);i++)
printf("i %d : %x\n",i,dci[i]);
#endif
if (DCI_LENGTH<=32) {
dci_flip[0] = dci[3];
dci_flip[1] = dci[2];
dci_flip[2] = dci[1];
dci_flip[3] = dci[0];
} else {
dci_flip[0] = dci[7];
dci_flip[1] = dci[6];
dci_flip[2] = dci[5];
dci_flip[3] = dci[4];
dci_flip[4] = dci[3];
dci_flip[5] = dci[2];
dci_flip[6] = dci[1];
dci_flip[7] = dci[0];
printf("DCI => %x,%x,%x,%x,%x,%x,%x,%x\n",
dci_flip[0],dci_flip[1],dci_flip[2],dci_flip[3],
dci_flip[4],dci_flip[5],dci_flip[6],dci_flip[7]);
dci_encoding(dci_flip,DCI_LENGTH,coded_bits,e,rnti);
return(e+coded_bits);
}
#define CCEBITS 72
#define CCEPERSYMBOL 33 // This is for 1200 RE
#define CCEPERSYMBOL0 22 // This is for 1200 RE
#define DCI_BITS_MAX ((2*CCEPERSYMBOL+CCEPERSYMBOL0)*CCEBITS)
#define Msymb (DCI_BITS_MAX/2)
//#define Mquad (Msymb/4)
static uint32_t bitrev_cc_dci[32] = {1,17,9,25,5,21,13,29,3,19,11,27,7,23,15,31,0,16,8,24,4,20,12,28,2,18,10,26,6,22,14,30};
static int32_t wtemp[2][Msymb];
void pdcch_interleaving(LTE_DL_FRAME_PARMS *frame_parms,int32_t **z, int32_t **wbar,uint8_t n_symbols_pdcch,uint8_t mi)
uint32_t Mquad = get_nquad(n_symbols_pdcch,frame_parms,mi);
uint32_t RCC = (Mquad>>5), ND;
uint32_t row,col,Kpi,index;
int32_t i,k,a;
#ifdef RM_DEBUG
#endif
// printf("[PHY] PDCCH Interleaving Mquad %d (Nsymb %d)\n",Mquad,n_symbols_pdcch);
if ((Mquad&0x1f) > 0)
RCC++;
Kpi = (RCC<<5);
ND = Kpi - Mquad;
k=0;
for (col=0; col<32; col++) {
index = bitrev_cc_dci[col];
for (row=0; row<RCC; row++) {
//printf("col %d, index %d, row %d\n",col,index,row);
if (index>=ND) {
//printf("a %d k %d\n",a,k);
wptr = &wtemp[a][k<<2];
zptr = &z[a][(index-ND)<<2];
//printf("wptr=%p, zptr=%p\n",wptr,zptr);
wptr[0] = zptr[0];
wptr[1] = zptr[1];
wptr[2] = zptr[2];
wptr[3] = zptr[3];
}
k++;
index+=32;
}
}
// permutation
for (i=0; i<Mquad; i++) {
//wptr = &wtemp[a][i<<2];
//wptr2 = &wbar[a][((i+frame_parms->Nid_cell)%Mquad)<<2];
wptr = &wtemp[a][((i+frame_parms->Nid_cell)%Mquad)<<2];
wptr2 = &wbar[a][i<<2];
wptr2[0] = wptr[0];
wptr2[1] = wptr[1];
wptr2[2] = wptr[2];
wptr2[3] = wptr[3];
}
}
}
void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parms,uint8_t num_pdcch_symbols,uint8_t mi)
{
uint32_t i, lprime;
uint16_t kprime,kprime_mod12,mprime,symbol_offset,tti_offset,tti_offset0;
int16_t re_offset,re_offset0;
// This is the REG allocation algorithm from 36-211, second part of Section 6.8.5
int Msymb2;
switch (frame_parms->N_RB_DL) {
case 100:
Msymb2 = Msymb;
break;
case 75:
Msymb2 = 3*Msymb/4;
break;
case 50:
Msymb2 = Msymb>>1;
break;
case 25:
Msymb2 = Msymb>>2;
break;
case 15:
Msymb2 = Msymb*15/100;
break;
case 6:
Msymb2 = Msymb*6/100;
break;
default:
Msymb2 = Msymb>>2;
break;
}
mprime=0;
re_offset = 0;
re_offset0 = 0; // counter for symbol with pilots (extracted outside!)
for (kprime=0; kprime<frame_parms->N_RB_DL*12; kprime++) {
for (lprime=0; lprime<num_pdcch_symbols; lprime++) {
symbol_offset = (uint32_t)frame_parms->N_RB_DL*12*lprime;
tti_offset = symbol_offset + re_offset;
tti_offset0 = symbol_offset + re_offset0;
// if REG is allocated to PHICH, skip it
if (check_phich_reg(frame_parms,kprime,lprime,mi) == 1) {
// printf("dci_demapping : skipping REG %d (RE %d)\n",(lprime==0)?kprime/6 : kprime>>2,kprime);
if ((lprime == 0)&&((kprime%6)==0))
re_offset0+=4;
} else { // not allocated to PHICH/PCFICH
// printf("dci_demapping: REG %d\n",(lprime==0)?kprime/6 : kprime>>2);
if (lprime == 0) {
// first symbol, or second symbol+4 TX antennas skip pilots
kprime_mod12 = kprime%12;
if ((kprime_mod12 == 0) || (kprime_mod12 == 6)) {
// kprime represents REG
for (i=0; i<4; i++) {
wbar[mprime] = llr[tti_offset0+i];
#ifdef DEBUG_DCI_DECODING
// LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset0+i,symbol_offset,re_offset0,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime]));
#endif
mprime++;
re_offset0++;
}
}
} else if ((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4)) {
// LATER!!!!
} else { // no pilots in this symbol
kprime_mod12 = kprime%12;
if ((kprime_mod12 == 0) || (kprime_mod12 == 4) || (kprime_mod12 == 8)) {
// kprime represents REG
for (i=0; i<4; i++) {
wbar[mprime] = llr[tti_offset+i];
#ifdef DEBUG_DCI_DECODING
// LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset+i,symbol_offset,re_offset+i,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime]));
#endif
mprime++;
}
} // is representative
} // no pilots case
} // not allocated to PHICH/PCFICH
// Stop when all REGs are copied in
if (mprime>=Msymb2)
break;
} //lprime loop
re_offset++;
} // kprime loop
}
void pdcch_deinterleaving(LTE_DL_FRAME_PARMS *frame_parms,uint16_t *z, uint16_t *wbar,uint8_t number_pdcch_symbols,uint8_t mi)
{
uint16_t Mquad=get_nquad(number_pdcch_symbols,frame_parms,mi);
uint32_t RCC = (Mquad>>5), ND;
uint32_t row,col,Kpi,index;
int32_t i,k;
// printf("Mquad %d, RCC %d\n",Mquad,RCC);
AssertFatal(z!=NULL,"dci.c: pdcch_deinterleaving: FATAL z is Null\n");
// undo permutation
for (i=0; i<Mquad; i++) {
wptr = &wtemp_rx[((i+frame_parms->Nid_cell)%Mquad)<<2];
wptr2 = &wbar[i<<2];
wptr[0] = wptr2[0];
wptr[1] = wptr2[1];
wptr[2] = wptr2[2];
wptr[3] = wptr2[3];
/*
printf("pdcch_deinterleaving (%p,%p): quad %d (%d) -> (%d,%d %d,%d %d,%d %d,%d)\n",wptr,wptr2,i,(i+frame_parms->Nid_cell)%Mquad,
((char*)wptr2)[0],
((char*)wptr2)[1],
((char*)wptr2)[2],
((char*)wptr2)[3],
((char*)wptr2)[4],
((char*)wptr2)[5],
((char*)wptr2)[6],
((char*)wptr2)[7]);
}
if ((Mquad&0x1f) > 0)
RCC++;
Kpi = (RCC<<5);
ND = Kpi - Mquad;
k=0;
for (col=0; col<32; col++) {
index = bitrev_cc_dci[col];
for (row=0; row<RCC; row++) {
// printf("row %d, index %d, Nd %d\n",row,index,ND);
if (index>=ND) {
wptr = &wtemp_rx[k<<2];
zptr = &z[(index-ND)<<2];
zptr[0] = wptr[0];
zptr[1] = wptr[1];
zptr[2] = wptr[2];
zptr[3] = wptr[3];
/*
printf("deinterleaving ; k %d, index-Nd %d => (%d,%d,%d,%d,%d,%d,%d,%d)\n",k,(index-ND),
((int8_t *)wptr)[0],
((int8_t *)wptr)[1],
((int8_t *)wptr)[2],
((int8_t *)wptr)[3],
((int8_t *)wptr)[4],
((int8_t *)wptr)[5],
((int8_t *)wptr)[6],
((int8_t *)wptr)[7]);
*/
k++;
index+=32;
}
}
for (i=0; i<Mquad; i++) {
zptr = &z[i<<2];
/*
printf("deinterleaving ; quad %d => (%d,%d,%d,%d,%d,%d,%d,%d)\n",i,
((int8_t *)zptr)[0],
((int8_t *)zptr)[1],
((int8_t *)zptr)[2],
((int8_t *)zptr)[3],
((int8_t *)zptr)[4],
((int8_t *)zptr)[5],
((int8_t *)zptr)[6],
((int8_t *)zptr)[7]);
*/
}
int32_t pdcch_qpsk_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int32_t **rxdataF_comp_i,
int32_t **rho_i,
int16_t *pdcch_llr16,
int16_t *pdcch_llr8in,
uint8_t symbol)
{

Florian Kaltenberger
committed
int16_t *rxF=(int16_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
int16_t *rxF_i=(int16_t*)&rxdataF_comp_i[0][(symbol*frame_parms->N_RB_DL*12)];
int16_t *rho=(int16_t*)&rho_i[0][(symbol*frame_parms->N_RB_DL*12)];
int16_t *llr128;
char *pdcch_llr8;
pdcch_llr8 = (char *)&pdcch_llr8in[symbol*frame_parms->N_RB_DL*12];
pdcch_llr = &pdcch_llr16[symbol*frame_parms->N_RB_DL*12];
// printf("dlsch_qpsk_qpsk: symbol %d\n",symbol);

Florian Kaltenberger
committed
llr128 = (int16_t*)pdcch_llr;
if (!llr128) {
printf("dlsch_qpsk_qpsk_llr: llr is null, symbol %d\n",symbol);
return -1;
}

Florian Kaltenberger
committed
qpsk_qpsk(rxF,
rxF_i,
llr128,
rho,
frame_parms->N_RB_DL*12);
//prepare for Viterbi which accepts 8 bit, but prefers 4 bit, soft input.
for (i=0; i<(frame_parms->N_RB_DL*24); i++) {
if (*pdcch_llr>7)
*pdcch_llr8=7;
else if (*pdcch_llr<-8)
*pdcch_llr8=-8;
else
*pdcch_llr8 = (char)(*pdcch_llr);
pdcch_llr++;
pdcch_llr8++;
}
return(0);
}
int32_t pdcch_llr(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
char *pdcch_llr,
uint8_t symbol)
{
int16_t *rxF= (int16_t*) &rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
int32_t i;
char *pdcch_llr8;
pdcch_llr8 = &pdcch_llr[2*symbol*frame_parms->N_RB_DL*12];
if (!pdcch_llr8) {
printf("pdcch_qpsk_llr: llr is null, symbol %d\n",symbol);
return(-1);
}
// printf("pdcch qpsk llr for symbol %d (pos %d), llr offset %d\n",symbol,(symbol*frame_parms->N_RB_DL*12),pdcch_llr8-pdcch_llr);
for (i=0; i<(frame_parms->N_RB_DL*((symbol==0) ? 16 : 24)); i++) {
if (*rxF>31)
*pdcch_llr8=31;
else if (*rxF<-32)
*pdcch_llr8=-32;
else
*pdcch_llr8 = (char)(*rxF);
// printf("%d %d => %d\n",i,*rxF,*pdcch_llr8);
rxF++;
pdcch_llr8++;
}
return(0);
}

Florian Kaltenberger
committed
//__m128i avg128P;
//compute average channel_level on each (TX,RX) antenna pair
void pdcch_channel_level(int32_t **dl_ch_estimates_ext,
LTE_DL_FRAME_PARMS *frame_parms,
int32_t *avg,
uint8_t nb_rb)
{

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128;

Florian Kaltenberger
committed
__m128i avg128P;
#elif defined(__arm__)
int16x8_t *dl_ch128;
int32x4_t *avg128P;
#endif
for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++)
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
//clear average level

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
dl_ch128=(__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][0];

Florian Kaltenberger
committed
#elif defined(__arm__)

Florian Kaltenberger
committed
#endif
for (rb=0; rb<nb_rb; rb++) {

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
avg128P = _mm_add_epi32(avg128P,_mm_madd_epi16(dl_ch128[0],dl_ch128[0]));
avg128P = _mm_add_epi32(avg128P,_mm_madd_epi16(dl_ch128[1],dl_ch128[1]));
avg128P = _mm_add_epi32(avg128P,_mm_madd_epi16(dl_ch128[2],dl_ch128[2]));

Florian Kaltenberger
committed
#elif defined(__arm__)

Florian Kaltenberger
committed
#endif
dl_ch128+=3;
/*
if (rb==0) {
print_shorts("dl_ch128",&dl_ch128[0]);
print_shorts("dl_ch128",&dl_ch128[1]);
print_shorts("dl_ch128",&dl_ch128[2]);
}
*/
}
DevAssert( nb_rb );
avg[(aatx<<1)+aarx] = (((int32_t*)&avg128P)[0] +
((int32_t*)&avg128P)[1] +
((int32_t*)&avg128P)[2] +
((int32_t*)&avg128P)[3])/(nb_rb*12);
// printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();

Florian Kaltenberger
committed
#endif
}

Florian Kaltenberger
committed
#if defined(__x86_64) || defined(__i386__)
__m128i mmtmpPD0,mmtmpPD1,mmtmpPD2,mmtmpPD3;

Florian Kaltenberger
committed
#elif defined(__arm__)

Florian Kaltenberger
committed
#endif
void pdcch_dual_stream_correlation(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t symbol,
int32_t **dl_ch_estimates_ext,
int32_t **dl_ch_estimates_ext_i,
int32_t **dl_ch_rho_ext,
uint8_t output_shift)
{

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128,*dl_ch128i,*dl_ch_rho128;

Florian Kaltenberger
committed
#elif defined(__arm__)
#endif
// printf("dlsch_dual_stream_correlation: symbol %d\n",symbol);
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
dl_ch128i = (__m128i *)&dl_ch_estimates_ext_i[aarx][symbol*frame_parms->N_RB_DL*12];
dl_ch_rho128 = (__m128i *)&dl_ch_rho_ext[aarx][symbol*frame_parms->N_RB_DL*12];

Florian Kaltenberger
committed
#elif defined(__arm__)
#endif
for (rb=0; rb<frame_parms->N_RB_DL; rb++) {
// multiply by conjugated channel

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
mmtmpPD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128i[0]);
// print_ints("re",&mmtmpPD0);
// mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpPD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_shufflehi_epi16(mmtmpPD1,_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_sign_epi16(mmtmpPD1,*(__m128i*)&conjugate[0]);
// print_ints("im",&mmtmpPD1);
mmtmpPD1 = _mm_madd_epi16(mmtmpPD1,dl_ch128i[0]);
// mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpPD0 = _mm_srai_epi32(mmtmpPD0,output_shift);
// print_ints("re(shift)",&mmtmpPD0);
mmtmpPD1 = _mm_srai_epi32(mmtmpPD1,output_shift);
// print_ints("im(shift)",&mmtmpPD1);
mmtmpPD2 = _mm_unpacklo_epi32(mmtmpPD0,mmtmpPD1);
mmtmpPD3 = _mm_unpackhi_epi32(mmtmpPD0,mmtmpPD1);
// print_ints("c0",&mmtmpPD2);
// print_ints("c1",&mmtmpPD3);
dl_ch_rho128[0] = _mm_packs_epi32(mmtmpPD2,mmtmpPD3);
//print_shorts("rx:",dl_ch128_2);
//print_shorts("ch:",dl_ch128);
//print_shorts("pack:",rho128);
// multiply by conjugated channel
mmtmpPD0 = _mm_madd_epi16(dl_ch128[1],dl_ch128i[1]);
// mmtmpPD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpPD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_shufflehi_epi16(mmtmpPD1,_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_sign_epi16(mmtmpPD1,*(__m128i*)conjugate);
mmtmpPD1 = _mm_madd_epi16(mmtmpPD1,dl_ch128i[1]);
// mmtmpPD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpPD0 = _mm_srai_epi32(mmtmpPD0,output_shift);
mmtmpPD1 = _mm_srai_epi32(mmtmpPD1,output_shift);
mmtmpPD2 = _mm_unpacklo_epi32(mmtmpPD0,mmtmpPD1);
mmtmpPD3 = _mm_unpackhi_epi32(mmtmpPD0,mmtmpPD1);
dl_ch_rho128[1] =_mm_packs_epi32(mmtmpPD2,mmtmpPD3);
//print_shorts("rx:",dl_ch128_2+1);
//print_shorts("ch:",dl_ch128+1);
//print_shorts("pack:",rho128+1);
// multiply by conjugated channel
mmtmpPD0 = _mm_madd_epi16(dl_ch128[2],dl_ch128i[2]);
// mmtmpPD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpPD1 = _mm_shufflelo_epi16(dl_ch128[2],_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_shufflehi_epi16(mmtmpPD1,_MM_SHUFFLE(2,3,0,1));
mmtmpPD1 = _mm_sign_epi16(mmtmpPD1,*(__m128i*)conjugate);
mmtmpPD1 = _mm_madd_epi16(mmtmpPD1,dl_ch128i[2]);
// mmtmpPD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpPD0 = _mm_srai_epi32(mmtmpPD0,output_shift);
mmtmpPD1 = _mm_srai_epi32(mmtmpPD1,output_shift);
mmtmpPD2 = _mm_unpacklo_epi32(mmtmpPD0,mmtmpPD1);
mmtmpPD3 = _mm_unpackhi_epi32(mmtmpPD0,mmtmpPD1);
dl_ch_rho128[2] = _mm_packs_epi32(mmtmpPD2,mmtmpPD3);
//print_shorts("rx:",dl_ch128_2+2);
//print_shorts("ch:",dl_ch128+2);
//print_shorts("pack:",rho128+2);
dl_ch128+=3;
dl_ch128i+=3;
dl_ch_rho128+=3;

Florian Kaltenberger
committed
#elif defined(__arm__)

Florian Kaltenberger
committed
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();

Florian Kaltenberger
committed
#endif
}
void pdcch_detection_mrc_i(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int32_t **rxdataF_comp_i,
int32_t **rho,
int32_t **rho_i,
uint8_t symbol)
{

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*rxdataF_comp128_i0,*rxdataF_comp128_i1,*rho128_0,*rho128_1,*rho128_i0,*rho128_i1;

Florian Kaltenberger
committed
#elif defined(__arm__)
int16x8_t *rxdataF_comp128_0,*rxdataF_comp128_1,*rxdataF_comp128_i0,*rxdataF_comp128_i1,*rho128_0,*rho128_1,*rho128_i0,*rho128_i1;
#endif
if (frame_parms->nb_antennas_rx>1) {
for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++) {
//if (frame_parms->mode1_flag && (aatx>0)) break;

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];

Florian Kaltenberger
committed
#elif defined(__arm__)
rxdataF_comp128_0 = (int16x8_t *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
#endif
// MRC on each re of rb on MF output
for (i=0; i<frame_parms->N_RB_DL*3; i++) {

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));

Florian Kaltenberger
committed
#elif defined(__arm__)
rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
#endif
}
}

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rho128_0 = (__m128i *) &rho[0][symbol*frame_parms->N_RB_DL*12];
rho128_1 = (__m128i *) &rho[1][symbol*frame_parms->N_RB_DL*12];

Florian Kaltenberger
committed
#elif defined(__arm__)
rho128_0 = (int16x8_t *) &rho[0][symbol*frame_parms->N_RB_DL*12];
rho128_1 = (int16x8_t *) &rho[1][symbol*frame_parms->N_RB_DL*12];
#endif
for (i=0; i<frame_parms->N_RB_DL*3; i++) {

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i],1),_mm_srai_epi16(rho128_1[i],1));

Florian Kaltenberger
committed
#elif defined(__arm__)
rho128_0[i] = vhaddq_s16(rho128_0[i],rho128_1[i]);
#endif

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rho128_i0 = (__m128i *) &rho_i[0][symbol*frame_parms->N_RB_DL*12];
rho128_i1 = (__m128i *) &rho_i[1][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_i0 = (__m128i *)&rxdataF_comp_i[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_i1 = (__m128i *)&rxdataF_comp_i[1][symbol*frame_parms->N_RB_DL*12];

Florian Kaltenberger
committed
#elif defined(__arm__)
rho128_i0 = (int16x8_t*) &rho_i[0][symbol*frame_parms->N_RB_DL*12];
rho128_i1 = (int16x8_t*) &rho_i[1][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_i0 = (int16x8_t *)&rxdataF_comp_i[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_i1 = (int16x8_t *)&rxdataF_comp_i[1][symbol*frame_parms->N_RB_DL*12];

Florian Kaltenberger
committed
#endif
// MRC on each re of rb on MF and rho
for (i=0; i<frame_parms->N_RB_DL*3; i++) {

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i],1),_mm_srai_epi16(rxdataF_comp128_i1[i],1));
rho128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i],1),_mm_srai_epi16(rho128_i1[i],1));

Florian Kaltenberger
committed
#elif defined(__arm__)
rxdataF_comp128_i0[i] = vhaddq_s16(rxdataF_comp128_i0[i],rxdataF_comp128_i1[i]);
rho128_i0[i] = vhaddq_s16(rho128_i0[i],rho128_i1[i]);
#endif
}
}

Florian Kaltenberger
committed
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();

Florian Kaltenberger
committed
#endif
}
void pdcch_extract_rbs_single(int32_t **rxdataF,
int32_t **dl_ch_estimates,
int32_t **rxdataF_ext,
int32_t **dl_ch_estimates_ext,
uint8_t symbol,
uint32_t high_speed_flag,
LTE_DL_FRAME_PARMS *frame_parms)
{
uint16_t rb,nb_rb=0;
uint8_t i,j,aarx;
int32_t *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext;
int nushiftmod3 = frame_parms->nushift%3;
symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
#ifdef DEBUG_DCI_DECODING
LOG_I(PHY, "extract_rbs_single: symbol_mod %d\n",symbol_mod);
#endif
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
if (high_speed_flag == 1)
dl_ch0 = &dl_ch_estimates[aarx][5+(symbol*(frame_parms->ofdm_symbol_size))];
else
dl_ch0 = &dl_ch_estimates[aarx][5];
dl_ch0_ext = &dl_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)];
rxF_ext = &rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)];
rxF = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol*(frame_parms->ofdm_symbol_size)))];
if ((frame_parms->N_RB_DL&1) == 0) { // even number of RBs
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
for (rb=0; rb<frame_parms->N_RB_DL; rb++) {
// For second half of RBs skip DC carrier
if (rb==(frame_parms->N_RB_DL>>1)) {
rxF = &rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))];
//dl_ch0++;
}
if (symbol_mod>0) {
memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int32_t));
for (i=0; i<12; i++) {
rxF_ext[i]=rxF[i];
}
nb_rb++;
dl_ch0_ext+=12;
rxF_ext+=12;
dl_ch0+=12;
rxF+=12;
} else {
j=0;
for (i=0; i<12; i++) {
if ((i!=nushiftmod3) &&
(i!=(nushiftmod3+3)) &&
(i!=(nushiftmod3+6)) &&
(i!=(nushiftmod3+9))) {
rxF_ext[j]=rxF[i];
// printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j]));
dl_ch0_ext[j++]=dl_ch0[i];
// printf("ch %d => (%d,%d)\n",i,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i]));
}
}
nb_rb++;
dl_ch0_ext+=8;
rxF_ext+=8;
dl_ch0+=12;
rxF+=12;
}
} else { // Odd number of RBs
for (rb=0; rb<frame_parms->N_RB_DL>>1; rb++) {
if (symbol_mod>0) {
memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int32_t));
for (i=0; i<12; i++)
rxF_ext[i]=rxF[i];
nb_rb++;
dl_ch0_ext+=12;
rxF_ext+=12;