Files
openairinterface5g/openair1/PHY/LTE_TRANSPORT/dci.c
T

522 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 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_eNB.h"
#include "PHY/phy_extern.h"
#include "SCHED/sched_eNB.h"
#include "SIMULATION/TOOLS/sim.h" // for taus
#include "PHY/sse_intrin.h"
#include "transport_proto.h"
#include "transport_common_proto.h"
#include "assertions.h"
#include "T.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "PHY/LTE_TRANSPORT/transport_extern.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "targets/RT/USER/lte-softmodem.h"
//#define DEBUG_DCI_ENCODING 1
//#define DEBUG_DCI_DECODING 1
//#define DEBUG_PHY
//extern uint16_t phich_reg[MAX_NUM_PHICH_GROUPS][3];
//extern uint16_t pcfich_reg[4];
//static uint8_t d[3*(MAX_DCI_SIZE_BITS + 16) + 96];
//static uint8_t w[3*3*(MAX_DCI_SIZE_BITS+16)];
void dci_encoding(uint8_t *a,
uint8_t A,
uint16_t E,
uint8_t *e,
uint16_t rnti) {
uint8_t D = (A + 16);
uint32_t RCC;
uint8_t d[3*(MAX_DCI_SIZE_BITS + 16) + 96];
uint8_t w[3*3*(MAX_DCI_SIZE_BITS+16)];
#ifdef DEBUG_DCI_ENCODING
int32_t i;
printf("Doing DCI encoding for %d bits, e %p, rnti %x, E %d\n",A,e,rnti,E);
#endif
// encode dci
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)));
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
if (E>1000) 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 *generate_dci0(uint8_t *dci,
uint8_t *e,
uint8_t DCI_LENGTH,
uint16_t coded_bits,
uint16_t rnti) {
uint8_t dci_flip[8];
#ifdef DEBUG_DCI_ENCODING
for (int 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];
#ifdef DEBUG_DCI_ENCODING
printf("DCI => %x,%x,%x,%x\n",
dci_flip[0],dci_flip[1],dci_flip[2],dci_flip[3]);
#endif
} 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];
#ifdef DEBUG_DCI_ENCODING
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]);
#endif
}
dci_encoding(dci_flip,DCI_LENGTH,coded_bits,e,rnti);
return(e+coded_bits);
}
//uint32_t Y;
void pdcch_interleaving(LTE_DL_FRAME_PARMS *frame_parms,int32_t **z, int32_t **wbar,uint8_t n_symbols_pdcch,uint8_t mi) {
int32_t *wptr,*wptr2,*zptr;
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
int32_t nulled=0;
#endif
uint32_t Msymb=(DCI_BITS_MAX/2);
int32_t wtemp[2][Msymb];
// 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) {
for (a=0; a<frame_parms->nb_antenna_ports_eNB; a++) {
//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++) {
for (a=0; a<frame_parms->nb_antenna_ports_eNB; a++) {
//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_scrambling(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t subframe,
uint8_t *e,
uint32_t length) {
int i;
uint8_t reset;
uint32_t x1, x2, s=0;
//LOG_D(PHY, "%s(fp, subframe:%d, e, length:%d)\n", __FUNCTION__, subframe, length);
reset = 1;
// x1 is set in lte_gold_generic
x2 = (subframe<<9) + frame_parms->Nid_cell; //this is c_init in 36.211 Sec 6.8.2
for (i=0; i<length; i++) {
if ((i&0x1f)==0) {
s = lte_gold_generic(&x1, &x2, reset);
//printf("lte_gold[%d]=%x\n",i,s);
reset = 0;
}
// printf("scrambling %d : e %d, c %d\n",i,e[i],((s>>(i&0x1f))&1));
if (e[i] != 2) // <NIL> element is 2
e[i] = (e[i]&1) ^ ((s>>(i&0x1f))&1);
}
}
uint8_t generate_dci_top(uint8_t num_pdcch_symbols,
uint8_t num_dci,
DCI_ALLOC_t *dci_alloc,
uint32_t n_rnti,
int16_t amp,
LTE_DL_FRAME_PARMS *frame_parms,
int32_t **txdataF,
uint32_t subframe) {
uint8_t *e_ptr;
int8_t L;
uint32_t i, lprime;
uint32_t gain_lin_QPSK,kprime,kprime_mod12,mprime,nsymb,symbol_offset,tti_offset;
int16_t re_offset;
uint8_t mi = get_mi(frame_parms,subframe);
uint8_t e[DCI_BITS_MAX];
uint32_t Msymb=(DCI_BITS_MAX/2);
int32_t yseq0[Msymb],yseq1[Msymb],wbar0[Msymb],wbar1[Msymb];
int32_t *y[2];
int32_t *wbar[2];
int nushiftmod3 = frame_parms->nushift%3;
int Msymb2;
int split_flag=0;
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;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH,1);
generate_pcfich(num_pdcch_symbols,
amp,
frame_parms,
txdataF,
subframe);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH,0);
wbar[0] = &wbar0[0];
wbar[1] = &wbar1[0];
y[0] = &yseq0[0];
y[1] = &yseq1[0];
/* reset all bits to <NIL>, here we set <NIL> elements as 2 */
memset(e, 2, DCI_BITS_MAX);
e_ptr = e;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0,1);
// generate DCIs in order of decreasing aggregation level, then common/ue spec
// MAC is assumed to have ordered the UE spec DCI according to the RNTI-based randomization
for (L=8; L>=1; L>>=1) {
for (i=0; i<num_dci; i++) {
if (dci_alloc[i].L == (uint8_t)L) {
LOG_D(PHY,"Generating DCI %d/%d (nCCE %d) of length %d, aggregation %d (%x), rnti %x\n",
i,num_dci,dci_alloc[i].firstCCE,dci_alloc[i].dci_length,dci_alloc[i].L,
*(unsigned int *)dci_alloc[i].dci_pdu,
dci_alloc[i].rnti);
if (dci_alloc[i].firstCCE>=0) {
e_ptr = generate_dci0(dci_alloc[i].dci_pdu,
e+(72*dci_alloc[i].firstCCE),
dci_alloc[i].dci_length,
72*dci_alloc[i].L,
dci_alloc[i].rnti);
}
}
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0,0);
// Scrambling
#ifdef DEBUG_DCI_ENCODING
printf("pdcch scrambling\n");
#endif
//LOG_D(PHY, "num_pdcch_symbols:%d mi:%d nquad:%d\n", num_pdcch_symbols, mi, get_nquad(num_pdcch_symbols, frame_parms, mi));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING,1);
pdcch_scrambling(frame_parms,
subframe,
e,
8*get_nquad(num_pdcch_symbols, frame_parms, mi));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING,0);
//72*get_nCCE(num_pdcch_symbols,frame_parms,mi));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION,1);
// Now do modulation
if (frame_parms->nb_antenna_ports_eNB==1)
gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15);
else
gain_lin_QPSK = amp/2;
e_ptr = e;
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH Modulation, Msymb %d, Msymb2 %d,gain_lin_QPSK %d\n",Msymb,Msymb2,gain_lin_QPSK);
#endif
//LOG_D(PHY,"%s() Msymb2:%d\n", __FUNCTION__, Msymb2);
if (frame_parms->nb_antenna_ports_eNB==1) { //SISO
for (i=0; i<Msymb2; i++) {
//((int16_t*)(&(y[0][i])))[0] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
//((int16_t*)(&(y[1][i])))[0] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
((int16_t *)(&(y[0][i])))[0] = (*e_ptr == 2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
((int16_t *)(&(y[1][i])))[0] = (*e_ptr == 2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
e_ptr++;
//((int16_t*)(&(y[0][i])))[1] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
//((int16_t*)(&(y[1][i])))[1] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
((int16_t *)(&(y[0][i])))[1] = (*e_ptr == 2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
((int16_t *)(&(y[1][i])))[1] = (*e_ptr == 2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
e_ptr++;
}
} else { //ALAMOUTI
for (i=0; i<Msymb2; i+=2) {
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH Modulation (TX diversity): REG %d\n",i>>2);
#endif
// first antenna position n -> x0
((int16_t *)&y[0][i])[0] = (*e_ptr==2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
e_ptr++;
((int16_t *)&y[0][i])[1] = (*e_ptr==2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
e_ptr++;
// second antenna position n -> -x1*
((int16_t *)&y[1][i])[0] = (*e_ptr==2) ? 0 : (*e_ptr == 1) ? gain_lin_QPSK : -gain_lin_QPSK;
e_ptr++;
((int16_t *)&y[1][i])[1] = (*e_ptr==2) ? 0 : (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK;
e_ptr++;
// fill in the rest of the ALAMOUTI precoding
((int16_t *)&y[0][i+1])[0] = -((int16_t *)&y[1][i])[0];
((int16_t *)&y[0][i+1])[1] = ((int16_t *)&y[1][i])[1];
((int16_t *)&y[1][i+1])[0] = ((int16_t *)&y[0][i])[0];
((int16_t *)&y[1][i+1])[1] = -((int16_t *)&y[0][i])[1];
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION,0);
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH Interleaving\n");
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING,1);
// printf("y %p (%p,%p), wbar %p (%p,%p)\n",y,y[0],y[1],wbar,wbar[0],wbar[1]);
// This is the interleaving procedure defined in 36-211, first part of Section 6.8.5
pdcch_interleaving(frame_parms,&y[0],&wbar[0],num_pdcch_symbols,mi);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING,0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX,1);
mprime=0;
nsymb = (frame_parms->Ncp==0) ? 14:12;
re_offset = frame_parms->first_carrier_offset;
// This is the REG allocation algorithm from 36-211, second part of Section 6.8.5
// printf("DCI (SF %d) : txdataF %p (0 %p)\n",subframe,&txdataF[0][512*14*subframe],&txdataF[0][0]);
#ifdef DEBUG_DCI_ENCODING
printf("kprime loop - N_RB_DL:%d lprime:num_pdcch_symbols:%d Ncp:%d pcfich:%02x,%02x,%02x,%02x ofdm_symbol_size:%d first_carrier_offset:%d nb_antenna_ports_eNB:%d\n",
frame_parms->N_RB_DL, num_pdcch_symbols,frame_parms->Ncp,
frame_parms->pcfich_reg[0],
frame_parms->pcfich_reg[1],
frame_parms->pcfich_reg[2],
frame_parms->pcfich_reg[3],
frame_parms->ofdm_symbol_size,
frame_parms->first_carrier_offset,
frame_parms->nb_antenna_ports_eNB
);
#endif
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->ofdm_symbol_size*(lprime+(subframe*nsymb));
tti_offset = symbol_offset + re_offset;
(re_offset==(frame_parms->ofdm_symbol_size-2)) ? (split_flag=1) : (split_flag=0);
// printf("kprime %d, lprime %d => REG %d (symbol %d)\n",kprime,lprime,(lprime==0)?(kprime/6) : (kprime>>2),symbol_offset);
// if REG is allocated to PHICH, skip it
if (check_phich_reg(frame_parms,kprime,lprime,mi) == 1) {
#ifdef DEBUG_DCI_ENCODING
printf("generate_dci: skipping REG %d (kprime %d, lprime %d)\n",(lprime==0)?(kprime/6) : (kprime>>2),kprime,lprime);
#endif
} else {
// Copy REG to TX buffer
if ((lprime == 0)||
((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4))) {
// 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<6; i++) {
if ((i!=(nushiftmod3))&&(i!=(nushiftmod3+3))) {
txdataF[0][tti_offset+i] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset+i] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset+i,*(short *)&wbar[0][mprime],*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
}
}
}
} else { // no pilots in this symbol
kprime_mod12 = kprime%12;
if ((kprime_mod12 == 0) || (kprime_mod12 == 4) || (kprime_mod12 == 8)) {
// kprime represents REG
if (split_flag==0) {
for (i=0; i<4; i++) {
txdataF[0][tti_offset+i] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset+i] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
LOG_I(PHY," PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset+i,*(short *)&wbar[0][mprime],*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
}
} else {
txdataF[0][tti_offset+0] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset+0] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset,*(short *)&wbar[0][mprime],*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
txdataF[0][tti_offset+1] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset+1] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
printf("PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset+1,*(short *)&wbar[0][mprime],*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
txdataF[0][tti_offset-frame_parms->ofdm_symbol_size+3] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset-frame_parms->ofdm_symbol_size+3] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset-frame_parms->ofdm_symbol_size+3,*(short *)&wbar[0][mprime],
*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
txdataF[0][tti_offset-frame_parms->ofdm_symbol_size+4] = wbar[0][mprime];
if (frame_parms->nb_antenna_ports_eNB > 1)
txdataF[1][tti_offset-frame_parms->ofdm_symbol_size+4] = wbar[1][mprime];
#ifdef DEBUG_DCI_ENCODING
printf(" PDCCH mapping mprime %d => %d (symbol %d re %d) -> (%d,%d)\n",mprime,tti_offset,symbol_offset,re_offset-frame_parms->ofdm_symbol_size+4,*(short *)&wbar[0][mprime],
*(1+(short *)&wbar[0][mprime]));
#endif
mprime++;
}
}
}
if (mprime>=Msymb2)
return(num_pdcch_symbols);
} // check_phich_reg
} //lprime loop
re_offset++;
if (re_offset == (frame_parms->ofdm_symbol_size))
re_offset = 1;
} // kprime loop
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX,0);
return(num_pdcch_symbols);
}