Commit fe95f0f4 authored by knopp's avatar knopp
Browse files

created new directories for NBIoT and NR and split eNB/gNB/UE

parent d943cd28
/*
* 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SIMULATION/TOOLS/defs.h" // for taus
#include "PHY/sse_intrin.h"
#include "assertions.h"
#include "T.h"
#include "UTIL/LOG/log.h"
#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)||
((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4)))
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)
{
uint16_t crc16;
// uint8_t i;
/*
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;
return((uint16_t)crc16);
}
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
}
static uint16_t wtemp_rx[Msymb];
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 *wptr,*zptr,*wptr2;
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)
{
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;
int32_t i;
char *pdcch_llr8;
int16_t *pdcch_llr;
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);
llr128 = (int16_t*)pdcch_llr;
if (!llr128) {
printf("dlsch_qpsk_qpsk_llr: llr is null, symbol %d\n",symbol);
return -1;
}
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);
}
//__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)
{
int16_t rb;
uint8_t aatx,aarx;
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128;
__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
#if defined(__x86_64__) || defined(__i386__)
avg128P = _mm_setzero_si128();
dl_ch128=(__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][0];
#elif defined(__arm__)
#endif
for (rb=0; rb<nb_rb; rb++) {
#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]));
#elif defined(__arm__)
#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]);
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
#if defined(__x86_64) || defined(__i386__)
__m128i mmtmpPD0,mmtmpPD1,mmtmpPD2,mmtmpPD3;
#elif defined(__arm__)
#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)
{
uint16_t rb;
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128,*dl_ch128i,*dl_ch_rho128;
#elif defined(__arm__)
#endif
uint8_t aarx;
// printf("dlsch_dual_stream_correlation: symbol %d\n",symbol);
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#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];
#elif defined(__arm__)
#endif
for (rb=0; rb<frame_parms->N_RB_DL; rb++) {
// multiply by conjugated channel
#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);