/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "PHY/sse_intrin.h"
// Mask for identifying subframe for MBMS
#define MBSFN_TDD_SF3 0x80// for TDD
#define MBSFN_TDD_SF4 0x40
#define MBSFN_TDD_SF7 0x20
#define MBSFN_TDD_SF8 0x10
#define MBSFN_TDD_SF9 0x08
#include "PHY/defs.h"
#define MBSFN_FDD_SF1 0x80// for FDD
#define MBSFN_FDD_SF2 0x40
#define MBSFN_FDD_SF3 0x20
#define MBSFN_FDD_SF6 0x10
#define MBSFN_FDD_SF7 0x08
#define MBSFN_FDD_SF8 0x04
void dump_mch(PHY_VARS_UE *ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,int subframe)
{
unsigned int nsymb_pmch=12;
char fname[32],vname[32];
int N_RB_DL=ue->frame_parms.N_RB_DL;
sprintf(fname,"mch_rxF_ext0.m");
sprintf(vname,"pmch_rxF_ext0");
write_output(fname,vname,ue->pdsch_vars_MCH[eNB_id]->rxdataF_ext[0],12*N_RB_DL*nsymb_pmch,1,1);
sprintf(fname,"mch_ch_ext00.m");
sprintf(vname,"pmch_ch_ext00");
write_output(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_estimates_ext[0],12*N_RB_DL*nsymb_pmch,1,1);
/*
write_output("dlsch%d_ch_ext01.m","dl01_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_ch_ext10.m","dl10_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_ch_ext11.m","dl11_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[3],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_rho.m","dl_rho",pdsch_vars[eNB_id]->rho[0],12*N_RB_DL*nsymb_pmch,1,1);
*/
sprintf(fname,"mch_rxF_comp0.m");
sprintf(vname,"pmch_rxF_comp0");
write_output(fname,vname,ue->pdsch_vars_MCH[eNB_id]->rxdataF_comp0[0],12*N_RB_DL*nsymb_pmch,1,1);
sprintf(fname,"mch_rxF_llr.m");
sprintf(vname,"pmch_llr");
write_output(fname,vname, ue->pdsch_vars_MCH[eNB_id]->llr[0],coded_bits_per_codeword,1,0);
sprintf(fname,"mch_mag1.m");
sprintf(vname,"pmch_mag1");
write_output(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_mag0[0],12*N_RB_DL*nsymb_pmch,1,1);
sprintf(fname,"mch_mag2.m");
sprintf(vname,"pmch_mag2");
write_output(fname,vname,ue->pdsch_vars_MCH[eNB_id]->dl_ch_magb0[0],12*N_RB_DL*nsymb_pmch,1,1);
write_output("mch00_ch0.m","pmch00_ch0",
&(ue->common_vars.dl_ch_estimates[eNB_id][0][0]),
ue->frame_parms.ofdm_symbol_size*12,1,1);
write_output("rxsig_mch.m","rxs_mch",
&ue->common_vars.rxdata[0][subframe*ue->frame_parms.samples_per_tti],
ue->frame_parms.samples_per_tti,1,1);
if (PHY_vars_eNB_g)
write_output("txsig_mch.m","txs_mch",
&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][0][subframe*ue->frame_parms.samples_per_tti],
ue->frame_parms.samples_per_tti,1,1);
}
int is_pmch_subframe(uint32_t frame, int subframe, LTE_DL_FRAME_PARMS *frame_parms)
{
uint32_t period;
uint8_t i;
// LOG_D(PHY,"is_pmch_subframe: frame %d, subframe %d, num_MBSFN_config %d\n",
// frame,subframe,frame_parms->num_MBSFN_config);
for (i=0; inum_MBSFN_config; i++) { // we have at least one MBSFN configuration
period = 1<MBSFN_config[i].radioframeAllocationPeriod;
if ((frame % period) == frame_parms->MBSFN_config[i].radioframeAllocationOffset) {
if (frame_parms->MBSFN_config[i].fourFrames_flag == 0) {
if (frame_parms->frame_type == FDD) {
switch (subframe) {
case 1:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF1) > 0)
return(1);
break;
case 2:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF2) > 0)
return(1);
break;
case 3:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF3) > 0)
return(1);
break;
case 6:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF6) > 0)
return(1);
break;
case 7:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF7) > 0)
return(1);
break;
case 8:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_FDD_SF8) > 0)
return(1);
break;
}
} else {
switch (subframe) {
case 3:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_TDD_SF3) > 0)
return(1);
break;
case 4:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_TDD_SF4) > 0)
return(1);
break;
case 7:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_TDD_SF7) > 0)
return(1);
break;
case 8:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_TDD_SF8) > 0)
return(1);
break;
case 9:
if ((frame_parms->MBSFN_config[i].mbsfn_SubframeConfig & MBSFN_TDD_SF9) > 0)
return(1);
break;
}
}
} else { // handle 4 frames case
}
}
}
return(0);
}
void fill_eNB_dlsch_MCH(PHY_VARS_eNB *eNB,int mcs,int ndi,int rvidx, int abstraction_flag)
{
LTE_eNB_DLSCH_t *dlsch = eNB->dlsch_MCH;
LTE_DL_FRAME_PARMS *frame_parms=&eNB->frame_parms;
// dlsch->rnti = M_RNTI;
dlsch->harq_processes[0]->mcs = mcs;
// dlsch->harq_processes[0]->Ndi = ndi;
dlsch->harq_processes[0]->rvidx = rvidx;
dlsch->harq_processes[0]->Nl = 1;
dlsch->harq_processes[0]->TBS = TBStable[get_I_TBS(dlsch->harq_processes[0]->mcs)][frame_parms->N_RB_DL-1];
dlsch->current_harq_pid = 0;
dlsch->harq_processes[0]->nb_rb = frame_parms->N_RB_DL;
switch(frame_parms->N_RB_DL) {
case 6:
dlsch->harq_processes[0]->rb_alloc[0] = 0x3f;
break;
case 25:
dlsch->harq_processes[0]->rb_alloc[0] = 0x1ffffff;
break;
case 50:
dlsch->harq_processes[0]->rb_alloc[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc[1] = 0x3ffff;
break;
case 100:
dlsch->harq_processes[0]->rb_alloc[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc[1] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc[2] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc[3] = 0xf;
break;
}
if (abstraction_flag) {
eNB_transport_info[eNB->Mod_id][eNB->CC_id].cntl.pmch_flag=1;
eNB_transport_info[eNB->Mod_id][eNB->CC_id].num_pmch=1; // assumption: there is always one pmch in each SF
eNB_transport_info[eNB->Mod_id][eNB->CC_id].num_common_dci=0;
eNB_transport_info[eNB->Mod_id][eNB->CC_id].num_ue_spec_dci=0;
eNB_transport_info[eNB->Mod_id][eNB->CC_id].dlsch_type[0]=5;// put at the reserved position for PMCH
eNB_transport_info[eNB->Mod_id][eNB->CC_id].harq_pid[0]=0;
eNB_transport_info[eNB->Mod_id][eNB->CC_id].ue_id[0]=255;//broadcast
eNB_transport_info[eNB->Mod_id][eNB->CC_id].tbs[0]=dlsch->harq_processes[0]->TBS>>3;
}
}
void fill_UE_dlsch_MCH(PHY_VARS_UE *ue,int mcs,int ndi,int rvidx,int eNB_id)
{
LTE_UE_DLSCH_t *dlsch = ue->dlsch_MCH[eNB_id];
LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
// dlsch->rnti = M_RNTI;
dlsch->harq_processes[0]->mcs = mcs;
dlsch->harq_processes[0]->rvidx = rvidx;
// dlsch->harq_processes[0]->Ndi = ndi;
dlsch->harq_processes[0]->Nl = 1;
dlsch->harq_processes[0]->TBS = TBStable[get_I_TBS(dlsch->harq_processes[0]->mcs)][frame_parms->N_RB_DL-1];
dlsch->current_harq_pid = 0;
dlsch->harq_processes[0]->nb_rb = frame_parms->N_RB_DL;
switch(frame_parms->N_RB_DL) {
case 6:
dlsch->harq_processes[0]->rb_alloc_even[0] = 0x3f;
dlsch->harq_processes[0]->rb_alloc_odd[0] = 0x3f;
break;
case 25:
dlsch->harq_processes[0]->rb_alloc_even[0] = 0x1ffffff;
dlsch->harq_processes[0]->rb_alloc_odd[0] = 0x1ffffff;
break;
case 50:
dlsch->harq_processes[0]->rb_alloc_even[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_odd[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_even[1] = 0x3ffff;
dlsch->harq_processes[0]->rb_alloc_odd[1] = 0x3ffff;
break;
case 100:
dlsch->harq_processes[0]->rb_alloc_even[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_odd[0] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_even[1] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_odd[1] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_even[2] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_odd[2] = 0xffffffff;
dlsch->harq_processes[0]->rb_alloc_even[3] = 0xf;
dlsch->harq_processes[0]->rb_alloc_odd[3] = 0xf;
break;
}
}
void generate_mch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t *a,int abstraction_flag)
{
int G;
int subframe = proc->subframe_tx;
if (abstraction_flag != 0) {
if (eNB_transport_info_TB_index[eNB->Mod_id][eNB->CC_id]!=0)
printf("[PHY][EMU] PMCH transport block position is different than zero %d \n", eNB_transport_info_TB_index[eNB->Mod_id][eNB->CC_id]);
memcpy(eNB->dlsch_MCH->harq_processes[0]->b,
a,
eNB->dlsch_MCH->harq_processes[0]->TBS>>3);
LOG_D(PHY, "[eNB %d] dlsch_encoding_emul pmch , tbs is %d \n",
eNB->Mod_id,
eNB->dlsch_MCH->harq_processes[0]->TBS>>3);
memcpy(&eNB_transport_info[eNB->Mod_id][eNB->CC_id].transport_blocks[eNB_transport_info_TB_index[eNB->Mod_id][eNB->CC_id]],
a,
eNB->dlsch_MCH->harq_processes[0]->TBS>>3);
eNB_transport_info_TB_index[eNB->Mod_id][eNB->CC_id]+= eNB->dlsch_MCH->harq_processes[0]->TBS>>3;//=eNB_transport_info[eNB->Mod_id].tbs[0];
} else {
G = get_G(&eNB->frame_parms,
eNB->frame_parms.N_RB_DL,
eNB->dlsch_MCH->harq_processes[0]->rb_alloc,
get_Qm(eNB->dlsch_MCH->harq_processes[0]->mcs),1,
2,proc->frame_tx,subframe);
generate_mbsfn_pilot(eNB,proc,
eNB->common_vars.txdataF[0],
AMP);
if (dlsch_encoding(a,
&eNB->frame_parms,
1,
eNB->dlsch_MCH,
proc->frame_tx,
subframe,
&eNB->dlsch_rate_matching_stats,
&eNB->dlsch_turbo_encoding_stats,
&eNB->dlsch_interleaving_stats
)<0)
mac_xface->macphy_exit("problem in dlsch_encoding");
dlsch_scrambling(&eNB->frame_parms,1,eNB->dlsch_MCH,G,0,subframe<<1);
mch_modulation(eNB->common_vars.txdataF[0],
AMP,
subframe,
&eNB->frame_parms,
eNB->dlsch_MCH);
}
}
void mch_extract_rbs(int **rxdataF,
int **dl_ch_estimates,
int **rxdataF_ext,
int **dl_ch_estimates_ext,
unsigned char symbol,
unsigned char subframe,
LTE_DL_FRAME_PARMS *frame_parms)
{
int pilots=0,i,j,offset,aarx;
// printf("Extracting PMCH: symbol %d\n",symbol);
if ((symbol==2)||
(symbol==10)) {
pilots = 1;
offset = 1;
} else if (symbol==6) {
pilots = 1;
offset = 0;
}
for (aarx=0; aarxnb_antennas_rx; aarx++) {
if (pilots==1) {
for (i=offset,j=0; iN_RB_DL*6; i+=2,j++) {
/* printf("MCH with pilots: i %d, j %d => %d,%d\n",i,j,
*(int16_t*)&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)],
*(int16_t*)(1+&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)]));
*/
rxdataF_ext[aarx][j+symbol*(frame_parms->N_RB_DL*12)] = rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)];
rxdataF_ext[aarx][(frame_parms->N_RB_DL*3)+j+symbol*(frame_parms->N_RB_DL*12)] = rxdataF[aarx][i+1+ (symbol*frame_parms->ofdm_symbol_size)];
dl_ch_estimates_ext[aarx][j+symbol*(frame_parms->N_RB_DL*12)] = dl_ch_estimates[aarx][i+(symbol*frame_parms->ofdm_symbol_size)];
dl_ch_estimates_ext[aarx][(frame_parms->N_RB_DL*3)+j+symbol*(frame_parms->N_RB_DL*12)] = dl_ch_estimates[aarx][i+(frame_parms->N_RB_DL*6)+(symbol*frame_parms->ofdm_symbol_size)];
}
} else {
memcpy((void*)&rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)],
(void*)&rxdataF[aarx][frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)],
frame_parms->N_RB_DL*24);
memcpy((void*)&rxdataF_ext[aarx][(frame_parms->N_RB_DL*6) + symbol*(frame_parms->N_RB_DL*12)],
(void*)&rxdataF[aarx][1 + (symbol*frame_parms->ofdm_symbol_size)],
frame_parms->N_RB_DL*24);
memcpy((void*)&dl_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)],
(void*)&dl_ch_estimates[aarx][(symbol*frame_parms->ofdm_symbol_size)],
frame_parms->N_RB_DL*48);
}
}
}
void mch_channel_level(int **dl_ch_estimates_ext,
LTE_DL_FRAME_PARMS *frame_parms,
int *avg,
uint8_t symbol,
unsigned short nb_rb)
{
int i,aarx,nre;
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128,avg128;
#elif defined(__arm__)
int32x4_t avg128;
#endif
for (aarx=0; aarxnb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
//clear average level
avg128 = _mm_setzero_si128();
// 5 is always a symbol with no pilots for both normal and extended prefix
dl_ch128=(__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
#endif
if ((symbol == 2) || (symbol == 6) || (symbol == 10))
nre = (frame_parms->N_RB_DL*6);
else
nre = (frame_parms->N_RB_DL*12);
for (i=0; i<(nre>>2); i++) {
#if defined(__x86_64__) || defined(__i386__)
avg128 = _mm_add_epi32(avg128,_mm_madd_epi16(dl_ch128[0],dl_ch128[0]));
#elif defined(__arm__)
#endif
}
avg[aarx] = (((int*)&avg128)[0] +
((int*)&avg128)[1] +
((int*)&avg128)[2] +
((int*)&avg128)[3])/nre;
// printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
void mch_channel_compensation(int **rxdataF_ext,
int **dl_ch_estimates_ext,
int **dl_ch_mag,
int **dl_ch_magb,
int **rxdataF_comp,
LTE_DL_FRAME_PARMS *frame_parms,
unsigned char symbol,
unsigned char mod_order,
unsigned char output_shift)
{
int aarx,nre,i;
#if defined(__x86_64__) || defined(__i386__)
__m128i *dl_ch128,*dl_ch_mag128,*dl_ch_mag128b,*rxdataF128,*rxdataF_comp128;
__m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128,QAM_amp128b;
#elif defined(__arm__)
#endif
if ((symbol == 2) || (symbol == 6) || (symbol == 10))
nre = frame_parms->N_RB_DL*6;
else
nre = frame_parms->N_RB_DL*12;
#if defined(__x86_64__) || defined(__i386__)
if (mod_order == 4) {
QAM_amp128 = _mm_set1_epi16(QAM16_n1); // 2/sqrt(10)
QAM_amp128b = _mm_setzero_si128();
} else if (mod_order == 6) {
QAM_amp128 = _mm_set1_epi16(QAM64_n1); //
QAM_amp128b = _mm_set1_epi16(QAM64_n2);
}
#elif defined(__arm__)
#endif
for (aarx=0; aarxnb_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_ch_mag128 = (__m128i *)&dl_ch_mag[aarx][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128b = (__m128i *)&dl_ch_magb[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF128 = (__m128i *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128 = (__m128i *)&rxdataF_comp[aarx][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
#endif
for (i=0; i<(nre>>2); i+=2) {
if (mod_order>2) {
// get channel amplitude if not QPSK
#if defined(__x86_64__) || defined(__i386__)
mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128[0]);
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
mmtmpD1 = _mm_madd_epi16(dl_ch128[1],dl_ch128[1]);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
mmtmpD0 = _mm_packs_epi32(mmtmpD0,mmtmpD1);
// store channel magnitude here in a new field of dlsch
dl_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpD0,mmtmpD0);
dl_ch_mag128b[0] = dl_ch_mag128[0];
dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
dl_ch_mag128b[1] = dl_ch_mag128[1];
dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
dl_ch_mag128[1] = _mm_slli_epi16(dl_ch_mag128[1],1);
dl_ch_mag128b[0] = _mm_mulhi_epi16(dl_ch_mag128b[0],QAM_amp128b);
dl_ch_mag128b[0] = _mm_slli_epi16(dl_ch_mag128b[0],1);
dl_ch_mag128b[1] = _mm_mulhi_epi16(dl_ch_mag128b[1],QAM_amp128b);
dl_ch_mag128b[1] = _mm_slli_epi16(dl_ch_mag128b[1],1);
#elif defined(__arm__)
#endif
}
#if defined(__x86_64__) || defined(__i386__)
// multiply by conjugated channel
mmtmpD0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]);
// print_ints("re",&mmtmpD0);
// mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate[0]);
// print_ints("im",&mmtmpD1);
mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[0]);
// mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
// print_ints("re(shift)",&mmtmpD0);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
// print_ints("im(shift)",&mmtmpD1);
mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
// print_ints("c0",&mmtmpD2);
// print_ints("c1",&mmtmpD3);
rxdataF_comp128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
// print_shorts("rx:",rxdataF128);
// print_shorts("ch:",dl_ch128);
// print_shorts("pack:",rxdataF_comp128);
// multiply by conjugated channel
mmtmpD0 = _mm_madd_epi16(dl_ch128[1],rxdataF128[1]);
// mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate);
mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[1]);
// mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
rxdataF_comp128[1] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
// print_shorts("rx:",rxdataF128+1);
// print_shorts("ch:",dl_ch128+1);
// print_shorts("pack:",rxdataF_comp128+1);
dl_ch128+=2;
dl_ch_mag128+=2;
dl_ch_mag128b+=2;
rxdataF128+=2;
rxdataF_comp128+=2;
#elif defined(__arm__)
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
void mch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
int **rxdataF_comp,
int **dl_ch_mag,
int **dl_ch_magb,
unsigned char symbol)
{
int i;
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#elif defined(__arm__)
int16x8_t *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#endif
if (frame_parms->nb_antennas_rx>1) {
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_0 = (__m128i *)&dl_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_1 = (__m128i *)&dl_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_0b = (__m128i *)&dl_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_1b = (__m128i *)&dl_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
rxdataF_comp128_0 = (int16x8_t *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_0 = (int16x8_t *)&dl_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_1 = (int16x8_t *)&dl_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_0b = (int16x8_t *)&dl_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
dl_ch_mag128_1b = (int16x8_t *)&dl_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
#endif
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
for (i=0; iN_RB_DL*3; i++) {
#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));
dl_ch_mag128_0[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_1[i],1));
dl_ch_mag128_0b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_1b[i],1));
#elif defined(__arm__)
rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
dl_ch_mag128_0[i] = vhaddq_s16(dl_ch_mag128_0[i],dl_ch_mag128_1[i]);
dl_ch_mag128_0b[i] = vhaddq_s16(dl_ch_mag128_0b[i],dl_ch_mag128_1b[i]);
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
int mch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
int **rxdataF_comp,
short *dlsch_llr,
unsigned char symbol,
short **llr32p)
{
uint32_t *rxF = (uint32_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
uint32_t *llr32;
int i,len;
if (symbol==2) {
llr32 = (uint32_t*)dlsch_llr;
} else {
llr32 = (uint32_t*)(*llr32p);
}
if (!llr32) {
msg("dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p\n",symbol, llr32);
return(-1);
}
if ((symbol==2) || (symbol==6) || (symbol==10)) {
len = frame_parms->N_RB_DL*6;
} else {
len = frame_parms->N_RB_DL*12;
}
// printf("dlsch_qpsk_llr: symbol %d,len %d,pbch_pss_sss_adjust %d\n",symbol,len,pbch_pss_sss_adjust);
for (i=0; iN_RB_DL*12)];
__m128i *ch_mag;
__m128i llr128[2],xmm0;
uint32_t *llr32;
#elif defined(__arm__)
int16x8_t *rxF = (int16x8_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
int16x8_t *ch_mag;
int16x8_t llr128[2],xmm0;
int16_t *llr16;
#endif
int i,len;
unsigned char len_mod4=0;
#if defined(__x86_64__) || defined(__i386__)
if (symbol==2) {
llr32 = (uint32_t*)dlsch_llr;
} else {
llr32 = (uint32_t*)*llr32p;
}
#elif defined(__arm__)
if (symbol==2) {
llr16 = (int16_t*)dlsch_llr;
} else {
llr16 = (int16_t*)*llr32p;
}
#endif
#if defined(__x86_64__) || defined(__i386__)
ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
#elif defined(__arm__)
ch_mag = (int16x8_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
#endif
if ((symbol==2) || (symbol==6) || (symbol==10)) {
len = frame_parms->N_RB_DL*6;
} else {
len = frame_parms->N_RB_DL*12;
}
// update output pointer according to number of REs in this symbol (<<2 because 4 bits per RE)
if (symbol==2)
*llr32p = dlsch_llr + (len<<2);
else
*llr32p += (len<<2);
len_mod4 = len&3;
len>>=2; // length in quad words (4 REs)
len+=(len_mod4==0 ? 0 : 1);
for (i=0; iN_RB_DL*12)];
#elif defined(__arm__)
int16x8_t xmm1,xmm2,*ch_mag,*ch_magb;
int16x8_t *rxF = (int16x8_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
#endif
int i,len,len2;
// int j=0;
unsigned char len_mod4;
short *llr;
int16_t *llr2;
if (symbol==2)
llr = dlsch_llr;
else
llr = *llr_save;
#if defined(__x86_64__) || defined(__i386__)
ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
ch_magb = (__m128i*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
#elif defined(__arm__)
ch_mag = (int16x8_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
ch_magb = (int16x8_t*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
#endif
if ((symbol==2) || (symbol==6) || (symbol==10)) {
len = frame_parms->N_RB_DL*6;
} else {
len = frame_parms->N_RB_DL*12;
}
llr2 = llr;
llr += (len*6);
len_mod4 =len&3;
len2=len>>2; // length in quad words (4 REs)
len2+=(len_mod4?0:1);
for (i=0; i mag (%d,%d) (%d,%d)\n",i,((short *)&ch_mag[i])[0],((short *)&ch_magb[i])[0],
((short *)&rxF[i])[0],((short *)&rxF[i])[1]);
*/
// loop over all LLRs in quad word (24 coded bits)
/*
for (j=0;j<8;j+=2) {
llr2[0] = ((short *)&rxF[i])[j];
llr2[1] = ((short *)&rxF[i])[j+1];
llr2[2] = _mm_extract_epi16(xmm1,j);
llr2[3] = _mm_extract_epi16(xmm1,j+1);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,j);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,j+1);//((short *)&xmm2)[j+1];
llr2+=6;
}
*/
llr2[0] = ((short *)&rxF[i])[0];
llr2[1] = ((short *)&rxF[i])[1];
#if defined(__x86_64__) || defined(__i386__)
llr2[2] = _mm_extract_epi16(xmm1,0);
llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2[2] = vgetq_lane_s16(xmm1,0);
llr2[3] = vgetq_lane_s16(xmm1,1);//((short *)&xmm1)[j+1];
llr2[4] = vgetq_lane_s16(xmm2,0);//((short *)&xmm2)[j];
llr2[5] = vgetq_lane_s16(xmm2,1);//((short *)&xmm2)[j+1];
#endif
llr2+=6;
llr2[0] = ((short *)&rxF[i])[2];
llr2[1] = ((short *)&rxF[i])[3];
#if defined(__x86_64__) || defined(__i386__)
llr2[2] = _mm_extract_epi16(xmm1,2);
llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2[2] = vgetq_lane_s16(xmm1,2);
llr2[3] = vgetq_lane_s16(xmm1,3);//((short *)&xmm1)[j+1];
llr2[4] = vgetq_lane_s16(xmm2,2);//((short *)&xmm2)[j];
llr2[5] = vgetq_lane_s16(xmm2,3);//((short *)&xmm2)[j+1];
#endif
llr2+=6;
llr2[0] = ((short *)&rxF[i])[4];
llr2[1] = ((short *)&rxF[i])[5];
#if defined(__x86_64__) || defined(__i386__)
llr2[2] = _mm_extract_epi16(xmm1,4);
llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2[2] = vgetq_lane_s16(xmm1,4);
llr2[3] = vgetq_lane_s16(xmm1,5);//((short *)&xmm1)[j+1];
llr2[4] = vgetq_lane_s16(xmm2,4);//((short *)&xmm2)[j];
llr2[5] = vgetq_lane_s16(xmm2,5);//((short *)&xmm2)[j+1];
#endif
llr2+=6;
llr2[0] = ((short *)&rxF[i])[6];
llr2[1] = ((short *)&rxF[i])[7];
#if defined(__x86_64__) || defined(__i386__)
llr2[2] = _mm_extract_epi16(xmm1,6);
llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2[2] = vgetq_lane_s16(xmm1,6);
llr2[3] = vgetq_lane_s16(xmm1,7);//((short *)&xmm1)[j+1];
llr2[4] = vgetq_lane_s16(xmm2,6);//((short *)&xmm2)[j];
llr2[5] = vgetq_lane_s16(xmm2,7);//((short *)&xmm2)[j+1];
#endif
llr2+=6;
}
*llr_save = llr;
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
int avg_pmch[4];
int rx_pmch(PHY_VARS_UE *ue,
unsigned char eNB_id,
uint8_t subframe,
unsigned char symbol)
{
LTE_UE_COMMON *common_vars = &ue->common_vars;
LTE_UE_PDSCH **pdsch_vars = &ue->pdsch_vars_MCH[eNB_id];
LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
LTE_UE_DLSCH_t **dlsch = &ue->dlsch_MCH[eNB_id];
int avgs,aarx;
//printf("*********************mch: symbol %d\n",symbol);
mch_extract_rbs(common_vars->rxdataF,
common_vars->dl_ch_estimates[eNB_id],
pdsch_vars[eNB_id]->rxdataF_ext,
pdsch_vars[eNB_id]->dl_ch_estimates_ext,
symbol,
subframe,
frame_parms);
if (symbol == 2) {
mch_channel_level(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
frame_parms,
avg_pmch,
symbol,
frame_parms->N_RB_DL);
}
avgs = 0;
for (aarx=0; aarxnb_antennas_rx; aarx++)
avgs = cmax(avgs,avg_pmch[aarx]);
if (get_Qm(dlsch[0]->harq_processes[0]->mcs)==2)
pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2) ;// + 2
else
pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2); // + 5;// + 2
mch_channel_compensation(pdsch_vars[eNB_id]->rxdataF_ext,
pdsch_vars[eNB_id]->dl_ch_estimates_ext,
pdsch_vars[eNB_id]->dl_ch_mag0,
pdsch_vars[eNB_id]->dl_ch_magb0,
pdsch_vars[eNB_id]->rxdataF_comp0,
frame_parms,
symbol,
get_Qm(dlsch[0]->harq_processes[0]->mcs),
pdsch_vars[eNB_id]->log2_maxh);
if (frame_parms->nb_antennas_rx > 1)
mch_detection_mrc(frame_parms,
pdsch_vars[eNB_id]->rxdataF_comp0,
pdsch_vars[eNB_id]->dl_ch_mag0,
pdsch_vars[eNB_id]->dl_ch_magb0,
symbol);
switch (get_Qm(dlsch[0]->harq_processes[0]->mcs)) {
case 2 :
mch_qpsk_llr(frame_parms,
pdsch_vars[eNB_id]->rxdataF_comp0,
pdsch_vars[eNB_id]->llr[0],
symbol,
pdsch_vars[eNB_id]->llr128);
break;
case 4:
mch_16qam_llr(frame_parms,
pdsch_vars[eNB_id]->rxdataF_comp0,
pdsch_vars[eNB_id]->llr[0],
pdsch_vars[eNB_id]->dl_ch_mag0,
symbol,
pdsch_vars[eNB_id]->llr128);
break;
case 6:
mch_64qam_llr(frame_parms,
pdsch_vars[eNB_id]->rxdataF_comp0,
pdsch_vars[eNB_id]->llr[0],
pdsch_vars[eNB_id]->dl_ch_mag0,
pdsch_vars[eNB_id]->dl_ch_magb0,
symbol,
pdsch_vars[eNB_id]->llr128);
break;
}
return(0);
}