/* * 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/ulsch_decoding.c * \brief Top-level routines for decoding the ULSCH transport channel from 36.212 V8.6 2009-03 * \author R. Knopp * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr * \note * \warning */ //#define DEBUG_ULSCH_DECODING #include #include "PHY/defs_eNB.h" #include "PHY/phy_extern.h" #include "PHY/CODING/coding_extern.h" #include "SCHED/sched_eNB.h" #include "LAYER2/MAC/mac.h" #include "RRC/LTE/rrc_extern.h" #include "PHY_INTERFACE/phy_interface.h" #include "transport_proto.h" static const int wACK_RX[5][4] = {{-1, -1, -1, -1}, {-1, 1, -1, 1}, {-1, -1, 1, 1}, {-1, 1, 1, -1}, {1, 1, 1, 1}}; void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch) { if (ulsch) { for (int i = 0; i < 8; i++) { if (ulsch->harq_processes[i]) { if (ulsch->harq_processes[i]->decodedBytes) { free16(ulsch->harq_processes[i]->decodedBytes,MAX_ULSCH_PAYLOAD_BYTES); ulsch->harq_processes[i]->decodedBytes = NULL; } for (int r = 0; r < MAX_NUM_ULSCH_SEGMENTS; r++) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 768); ulsch->harq_processes[i]->c[r] = NULL; } for (int r = 0; r < MAX_NUM_ULSCH_SEGMENTS; r++) if (ulsch->harq_processes[i]->d[r]) { free16(ulsch->harq_processes[i]->d[r],((3*8*6144)+12+96)*sizeof(short)); ulsch->harq_processes[i]->d[r] = NULL; } free16(ulsch->harq_processes[i],sizeof(LTE_UL_eNB_HARQ_t)); ulsch->harq_processes[i] = NULL; } } free16(ulsch,sizeof(LTE_eNB_ULSCH_t)); } } LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag) { LTE_eNB_ULSCH_t *ulsch; uint8_t exit_flag = 0,i,r; unsigned char bw_scaling =1; switch (N_RB_UL) { case 6: bw_scaling =16; break; case 25: bw_scaling =4; break; case 50: bw_scaling =2; break; default: bw_scaling =1; break; } ulsch = (LTE_eNB_ULSCH_t *)malloc16(sizeof(LTE_eNB_ULSCH_t)); if (ulsch) { memset(ulsch,0,sizeof(LTE_eNB_ULSCH_t)); ulsch->max_turbo_iterations = max_turbo_iterations; ulsch->Mlimit = 4; for (i=0; i<8; i++) { // printf("new_ue_ulsch: Harq process %d\n",i); ulsch->harq_processes[i] = (LTE_UL_eNB_HARQ_t *)malloc16(sizeof(LTE_UL_eNB_HARQ_t)); if (ulsch->harq_processes[i]) { memset(ulsch->harq_processes[i],0,sizeof(LTE_UL_eNB_HARQ_t)); init_abort(&ulsch->harq_processes[i]->abort_decode); ulsch->harq_processes[i]->decodedBytes = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); if (ulsch->harq_processes[i]->decodedBytes) memset(ulsch->harq_processes[i]->decodedBytes,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); else exit_flag=3; if (abstraction_flag==0) { for (r=0; rharq_processes[i]->c[r] = (uint8_t *)malloc16(((r==0)?8:0) + 3+768); if (ulsch->harq_processes[i]->c[r]) memset(ulsch->harq_processes[i]->c[r],0,((r==0)?8:0) + 3+768); else exit_flag=2; ulsch->harq_processes[i]->d[r] = (short *)malloc16(((3*8*6144)+12+96)*sizeof(short)); if (ulsch->harq_processes[i]->d[r]) memset(ulsch->harq_processes[i]->d[r],0,((3*8*6144)+12+96)*sizeof(short)); else exit_flag=2; } } } else { exit_flag=1; } } if (exit_flag==0) return(ulsch); } LOG_E(PHY,"new_ue_ulsch: exit_flag = %d\n",exit_flag); free_eNB_ulsch(ulsch); return(NULL); } void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch) { unsigned char i; //ulsch = (LTE_eNB_ULSCH_t *)malloc16(sizeof(LTE_eNB_ULSCH_t)); if (ulsch) { ulsch->rnti = 0; ulsch->harq_mask = 0; for (i=0; i<8; i++) { if (ulsch->harq_processes[i]) { // ulsch->harq_processes[i]->Ndi = 0; ulsch->harq_processes[i]->status = 0; //ulsch->harq_processes[i]->phich_active = 0; //this will be done later after transmission of PHICH ulsch->harq_processes[i]->phich_ACK = 0; ulsch->harq_processes[i]->round = 0; ulsch->harq_processes[i]->rar_alloc = 0; ulsch->harq_processes[i]->first_rb = 0; ulsch->harq_processes[i]->nb_rb = 0; ulsch->harq_processes[i]->TBS = 0; ulsch->harq_processes[i]->Or1 = 0; ulsch->harq_processes[i]->Or2 = 0; for ( int j = 0; j < 2; j++ ) { ulsch->harq_processes[i]->o_RI[j] = 0; } ulsch->harq_processes[i]->O_ACK = 0; ulsch->harq_processes[i]->srs_active = 0; ulsch->harq_processes[i]->rvidx = 0; ulsch->harq_processes[i]->Msc_initial = 0; ulsch->harq_processes[i]->Nsymb_initial = 0; } } ulsch->beta_offset_cqi_times8 = 0; ulsch->beta_offset_ri_times8 = 0; ulsch->beta_offset_harqack_times8 = 0; ulsch->Msg3_active = 0; } } uint8_t extract_cqi_crc(uint8_t *cqi,uint8_t CQI_LENGTH) { uint8_t crc; crc = cqi[CQI_LENGTH>>3]; // printf("crc1: %x, shift %d\n",crc,CQI_LENGTH&0x7); crc = (crc<<(CQI_LENGTH&0x7)); // clear crc bits // ((char *)cqi)[CQI_LENGTH>>3] &= 0xff>>(8-(CQI_LENGTH&0x7)); // printf("crc2: %x, cqi0 %x\n",crc,cqi[1+(CQI_LENGTH>>3)]); crc |= (cqi[1+(CQI_LENGTH>>3)])>>(8-(CQI_LENGTH&0x7)); // clear crc bits //(((char *)cqi)[1+(CQI_LENGTH>>3)]) = 0; // printf("crc : %x\n",crc); return(crc); } void processULSegment(void * arg) { turboDecode_t* rdata=(turboDecode_t*) arg; PHY_VARS_eNB *eNB=rdata->eNB; LTE_UL_eNB_HARQ_t *ulsch_harq=rdata->ulsch_harq; int r=rdata->segment_r; int G=ulsch_harq->G; int Kr_bytes=rdata->Kr>>3; int16_t dummy_w[3*(6144+64)]; memset(&dummy_w[0],0,3*(6144+64)*sizeof(short)); ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[0], (r==0) ? ulsch_harq->F : 0); start_meas(&eNB->ulsch_deinterleaving_stats); unsigned int E; if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[0], ulsch_harq->eUL+rdata->r_offset, ulsch_harq->C, NSOFT, 0, //Uplink 1, ulsch_harq->rvidx, (ulsch_harq->rvidx==0)?1:0, // clear ulsch_harq->Qm, 1, r, &E)==-1) { // Task completed in parallel completed_task_ans(rdata->ans); LOG_E(PHY, "ulsch_decoding.c: Problem in rate matching\n"); return; } stop_meas(&eNB->ulsch_rate_unmatching_stats); int max_Ncb = 3*ulsch_harq->RTC[r]*32 ; if(ulsch_harq->repetition_number == 1) { memset(ulsch_harq->pusch_rep_buffer[r],0,(sizeof(int32_t)*3*(6144+64))) ; // reset the buffer every new repetitions } if(ulsch_harq->total_number_of_repetitions > 1) { if (ulsch_harq->rvidx==1) { LOG_E(PHY,"Adding HARQ data for segment: %d\n", r); // Store the result of HARQ combining in the last emtc repetitions of sequence 0,2,3,1 for (int nn=0; nnpusch_rep_buffer[r][nn] += ulsch_harq->w[r][nn] ; } if (ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions) { LOG_E(PHY,"Will use HARQ data sum up for segment: %d\n", r); for (int nn=0; nnw[r][nn] = ulsch_harq->pusch_rep_buffer[r][nn] ; } } int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32))); sub_block_deinterleaving_turbo(4+rdata->Kr, soft_bits+96, ulsch_harq->w[r]); stop_meas(&eNB->ulsch_deinterleaving_stats); rdata->decodeIterations = rdata->function(soft_bits + 96, NULL, rdata->decoded_bytes, NULL, rdata->Kr, rdata->maxIterations, rdata->nbSegments == 1 ? CRC24_A : CRC24_B, rdata->Fbits, &eNB->ulsch_tc_init_stats, &eNB->ulsch_tc_alpha_stats, &eNB->ulsch_tc_beta_stats, &eNB->ulsch_tc_gamma_stats, &eNB->ulsch_tc_ext_stats, &eNB->ulsch_tc_intl1_stats, &eNB->ulsch_tc_intl2_stats, &ulsch_harq->abort_decode); // Task completed in parallel completed_task_ans(rdata->ans); } /*! \brief Decoding of ULSCH data component from 36-212. This one is single thread. @param phy_vars_eNB Pointer to eNB top-level descriptor @param UE_id ID of UE transmitting this PUSCH @param harq_pid HARQ process ID @param llr8_flag If 1, indicate that the 8-bit turbo decoder should be used @returns 0 on success */ static int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int UE_id, int harq_pid, int llr8_flag, thread_info_tm_t *t_info) { unsigned int r_offset=0; int offset = 0; LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int G = ulsch_harq->G; unsigned int E; int ret=0; decoder_if_t * td=llr8_flag == 0 ? *decoder16 : *decoder8; ulsch_harq->processedSegments=0; set_abort(&ulsch_harq->abort_decode, false); for (int r=0; rC; r++) { // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); // Get Turbo interleaver parameters unsigned int Kr= rCminus ? ulsch_harq->Kminus :ulsch_harq->Kplus; unsigned int Kr_bytes = Kr>>3; #ifdef DEBUG_ULSCH_DECODING printf("Rate Matching Segment %d (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %u)...\n", r, G, Kr*3, ulsch_harq->Qm, ulsch_harq->Nl, r_offset); #endif int Gp=G/ulsch_harq->Qm; int GpmodC = Gp%ulsch_harq->C; if (r < (ulsch_harq->C-(GpmodC))) E = ulsch_harq->Qm * (Gp/ulsch_harq->C); else E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C)); turboDecode_t *rdata = &((turboDecode_t *)t_info->buf)[t_info->len]; DevAssert(t_info->len < t_info->cap); rdata->ans = t_info->ans; t_info->len += 1; rdata->eNB=eNB; rdata->frame=proc->frame_rx; rdata->subframe=proc->subframe_rx; rdata->UEid=UE_id; rdata->harq_pid=harq_pid; rdata->Kr=Kr; rdata->maxIterations=eNB->ulsch[UE_id]->max_turbo_iterations; rdata->ulsch_harq=ulsch_harq; rdata->eNB=eNB; rdata->nbSegments=ulsch_harq->C; rdata->segment_r=r; rdata->Fbits=(r==0) ? ulsch_harq->F : 0; rdata->r_offset=r_offset; rdata->offset=offset; rdata->function=td; int Fbytes=(r==0) ? rdata->Fbits>>3 : 0; int sz=Kr_bytes - Fbytes - ((ulsch_harq->C>1)?3:0); task_t t = {.func = &processULSegment, .args = rdata}; pushTpool(proc->threadPool, t); proc->nbDecode++; LOG_D(PHY,"Added a block to decode, in pipe: %d\n",proc->nbDecode); r_offset+=E; offset+=sz; } return(ret); } static inline unsigned int lte_gold_unscram(unsigned int *x1, unsigned int *x2, unsigned char reset) __attribute__((always_inline)); static inline unsigned int lte_gold_unscram(unsigned int *x1, unsigned int *x2, unsigned char reset) { int n; if (reset) { *x1 = 1+ (1U<<31); *x2=*x2 ^ ((*x2 ^ (*x2>>1) ^ (*x2>>2) ^ (*x2>>3))<<31); // skip first 50 double words (1600 bits) // printf("n=0 : x1 %x, x2 %x\n",x1,x2); for (n=1; n<50; n++) { *x1 = (*x1>>1) ^ (*x1>>4); *x1 = *x1 ^ (*x1<<31) ^ (*x1<<28); *x2 = (*x2>>1) ^ (*x2>>2) ^ (*x2>>3) ^ (*x2>>4); *x2 = *x2 ^ (*x2<<31) ^ (*x2<<30) ^ (*x2<<29) ^ (*x2<<28); } } *x1 = (*x1>>1) ^ (*x1>>4); *x1 = *x1 ^ (*x1<<31) ^ (*x1<<28); *x2 = (*x2>>1) ^ (*x2>>2) ^ (*x2>>3) ^ (*x2>>4); *x2 = *x2 ^ (*x2<<31) ^ (*x2<<30) ^ (*x2<<29) ^ (*x2<<28); return(*x1^*x2); // printf("n=%d : c %x\n",n,x1^x2); } unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, uint8_t UE_id, uint8_t control_only_flag, uint8_t Nbundled, uint8_t llr8_flag, thread_info_tm_t *t_info) { int16_t *ulsch_llr = eNB->pusch_vars[UE_id]->llr; LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms; LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; uint8_t harq_pid; unsigned int ret = 0; const uint8_t *columnset; unsigned int Qprime,L,G,Q_CQI,Q_RI,H,Hprime,Hpp,Cmux,Rmux_prime,O_RCC; unsigned int Qprime_ACK, Qprime_RI, len_ACK = 0, len_RI = 0; uint8_t dummy_w_cc[3*(MAX_CQI_BITS+8+32)]; int16_t y[6*14*1200] __attribute__((aligned(32))); uint8_t ytag[14*1200]; // uint8_t ytag2[6*14*1200],*ytag2_ptr; int16_t cseq[6*14*1200] __attribute__((aligned(32))); const int frame = proc->frame_rx; const int subframe = proc->subframe_rx; LOG_D(PHY,"ue_type %d\n",ulsch->ue_type); if (ulsch->ue_type>0) harq_pid = 0; else harq_pid = subframe2harq_pid(frame_parms,proc->frame_rx,subframe); // x1 is set in lte_gold_generic uint32_t x2 = ((uint32_t)ulsch->rnti << 14) + ((uint32_t)subframe << 9) + frame_parms->Nid_cell; // this is c_init in 36.211 Sec 6.3.1 LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; AssertFatal(harq_pid!=255, "FATAL ERROR: illegal harq_pid, returning\n"); AssertFatal(ulsch_harq->Nsymb_pusch != 0, "FATAL ERROR: harq_pid %d, Nsymb 0!\n",harq_pid); const int nb_rb = ulsch_harq->nb_rb; const uint A = ulsch_harq->TBS; const uint Q_m = ulsch_harq->Qm; G = nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; LOG_D(PHY, "PUSCH nb_rb %d Q_m %d ulsch_harq->Nsymb_pusch %d\n",nb_rb, Q_m, ulsch_harq->Nsymb_pusch); //#ifdef DEBUG_ULSCH_DECODING LOG_D(PHY,"[PUSCH harq %d] Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): TBS %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d, Q_m %d Nsymb_pusch %d nb_rb %d\n", harq_pid, proc->frame_rx,subframe, frame_parms->Nid_cell,ulsch->rnti,x2, A, ulsch_harq->round, ulsch_harq->rvidx, ulsch_harq->Or1, ulsch_harq->O_RI, ulsch_harq->O_ACK, G, ulsch_harq->Qm, ulsch_harq->Nsymb_pusch, nb_rb); //#endif eNB_SCH_STATS_t *stats=NULL; int first_free=-1; for (int i=0;iulsch_stats[i].rnti == 0 && first_free == -1) { first_free = i; stats=&eNB->ulsch_stats[i]; } if (eNB->ulsch_stats[i].rnti == ulsch->rnti) { stats=&eNB->ulsch_stats[i]; break; } } if (stats) { stats->rnti = ulsch->rnti; stats->round_trials[ulsch_harq->round]++; stats->frame=proc->frame_rx; } if (ulsch_harq->round == 0) { if (stats) { stats->current_Qm = Q_m; stats->current_RI = 1; stats->total_bytes_tx += ulsch_harq->TBS; stats->current_TBS = ulsch_harq->TBS; stats->current_G = ulsch_harq->G; } } //if (ulsch_harq->round == 0) { // delete for RB shortage pattern // This is a new packet, so compute quantities regarding segmentation ulsch_harq->B = A+24; lte_segmentation(NULL, NULL, ulsch_harq->B, &ulsch_harq->C, &ulsch_harq->Cplus, &ulsch_harq->Cminus, &ulsch_harq->Kplus, &ulsch_harq->Kminus, &ulsch_harq->F); // CLEAR LLR's HERE for first packet in process //} // printf("after segmentation c[%d] = %p\n",0,ulsch_harq->c[0]); unsigned int sumKr = 0; for (int r = 0; r < ulsch_harq->C; r++) { if (rCminus) sumKr += ulsch_harq->Kminus; else sumKr += ulsch_harq->Kplus; } AssertFatal(sumKr>0, "[eNB] ulsch_decoding.c: FATAL sumKr is 0! (Nid_cell %d, rnti %x, x2 %x): harq_pid %d round %d, RV %d, O_RI %d, O_ACK %d, G %u, subframe %d\n", frame_parms->Nid_cell,ulsch->rnti,x2, harq_pid, ulsch_harq->round, ulsch_harq->rvidx, ulsch_harq->O_RI, ulsch_harq->O_ACK, G, subframe); // Compute Q_ri Qprime = ulsch_harq->O_RI*ulsch_harq->Msc_initial*ulsch_harq->Nsymb_initial * ulsch->beta_offset_ri_times8; LOG_D(PHY, "Qprime %d, O_RI %d, Msc %d, Nym %d beta %d\n", Qprime, ulsch_harq->O_RI, ulsch_harq->Msc_initial, ulsch_harq->Nsymb_initial, ulsch->beta_offset_ri_times8); if (Qprime > 0 ) { if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); if (Qprime > 4*nb_rb * 12) Qprime = 4*nb_rb * 12; } Q_RI = Q_m*Qprime; Qprime_RI = Qprime; // Compute Q_ack Qprime = ulsch_harq->O_ACK*ulsch_harq->Msc_initial*ulsch_harq->Nsymb_initial * ulsch->beta_offset_harqack_times8; if (Qprime > 0) { if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); if (Qprime > (4*nb_rb * 12)) Qprime = 4*nb_rb * 12; } // Q_ACK = Qprime * Q_m; Qprime_ACK = Qprime; #ifdef DEBUG_ULSCH_DECODING printf("ulsch_decoding.c: Qprime_ACK %u, Msc_initial %d, Nsymb_initial %d, sumKr %u\n", Qprime_ACK,ulsch_harq->Msc_initial,ulsch_harq->Nsymb_initial,sumKr); #endif // Compute Q_cqi if (ulsch_harq->Or1 < 12) L=0; else L=8; // NOTE: we have to handle the case where we have a very small number of bits (condition on pg. 26 36.212) if (ulsch_harq->Or1 > 0) Qprime = (ulsch_harq->Or1 + L) * ulsch_harq->Msc_initial*ulsch_harq->Nsymb_initial * ulsch->beta_offset_cqi_times8; else Qprime=0; if (Qprime > 0) { // check if ceiling is larger than floor in Q' expression if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); } G = nb_rb * (12 * Q_m) * (ulsch_harq->Nsymb_pusch); Q_CQI = Q_m * Qprime; #ifdef DEBUG_ULSCH_DECODING printf("ulsch_decoding: G %u, Q_RI %u, Q_CQI %u (L %u, Or1 %d) O_ACK %d\n",G,Q_RI,Q_CQI,L,ulsch_harq->Or1,ulsch_harq->O_ACK); #endif G = G - Q_RI - Q_CQI; ulsch_harq->G = G; AssertFatal((int)G > 0, "FATAL: ulsch_decoding.c G < 0 (%u) : Q_RI %u, Q_CQI %u, nb_rb %u, Q_m %u, ulsch_harq->Nsymb_pusch %u, Qprime %u\n", G, Q_RI, Q_CQI, nb_rb, Q_m, ulsch_harq->Nsymb_pusch, Qprime); H = G + Q_CQI; Hprime = H/Q_m; // Demultiplexing/Deinterleaving of PUSCH/ACK/RI/CQI start_meas(&eNB->ulsch_demultiplexing_stats); Hpp = Hprime + Qprime_RI; Cmux = ulsch_harq->Nsymb_pusch; Rmux_prime = Hpp/Cmux; // Clear "tag" interleaving matrix to allow for CQI/DATA identification memset(ytag, 0, Cmux * Rmux_prime); memset(y,LTE_NULL,Q_m*Hpp); // read in buffer and unscramble llrs for everything but placeholder bits // llrs stored per symbol correspond to columns of interleaving matrix uint32_t x1 = 0; uint32_t s = lte_gold_unscram(&x1, &x2, 1); for (int i = 0, i2 = 0; i < ((Hpp * Q_m) >> 5); i++) { /* for (j=0; j<32; j++) { cseq[i2++] = (int16_t)((((s>>j)&1)<<1)-1); } */ ((simde__m256i *)cseq)[i2++] = ((simde__m256i *)unscrambling_lut)[s & 65535]; ((simde__m256i *)cseq)[i2++] = ((simde__m256i *)unscrambling_lut)[(s >> 16) & 65535]; s = lte_gold_unscram(&x1, &x2, 0); } // printf("after unscrambling c[%d] = %p\n",0,ulsch_harq->c[0]); if (frame_parms->Ncp == 0) columnset = cs_ri_normal; else columnset = cs_ri_extended; int j = 0; for (int i = 0; i < Qprime_RI; i++) { int r = Rmux_prime - 1 - (i >> 2); /* for (q=0;qc[0]); // HARQ-ACK Bits (Note these overwrite some bits) if (frame_parms->Ncp == 0) columnset = cs_ack_normal; else columnset = cs_ack_extended; j=0; for (int i = 0; i < Qprime_ACK; i++) { int r = Rmux_prime - 1 - (i >> 2); int off = ((Rmux_prime * Q_m * columnset[j]) + (r * Q_m)); if (ulsch_harq->O_ACK == 1) { if (ulsch->bundling==0) cseq[off+1] = cseq[off]; // PUSCH_y for (int q = 2; q < Q_m; q++) cseq[off+q] = -1; // PUSCH_x } else if (ulsch_harq->O_ACK == 2) { for (int q = 2; q < Q_m; q++) cseq[off+q] = -1; // PUSCH_x } #ifdef DEBUG_ULSCH_DECODING printf("ulsch_decoding.c: ACK i %d, r %d, j %d, ColumnSet[j] %d\n", i, r, j, columnset[j]); #endif j=(j+3)&3; } int16_t *in = ulsch_llr; int16_t *cseqp = cseq; switch (Q_m) { case 2: for (j = 0; j < Cmux; j++) { int i2 = j << 1; for (int r = 0; r < Rmux_prime; r++) { y[i2] = *cseqp++ * *in++; y[i2 + 1] = *cseqp++ * *in++; i2 += Cmux << 1; } } break; case 4: for (j = 0; j < Cmux; j++) { int i2 = j << 2; for (int r = 0; r < Rmux_prime; r++) { y[i2] = *cseqp++ * *in++; y[i2 + 1] = *cseqp++ * *in++; y[i2 + 2] = *cseqp++ * *in++; y[i2 + 3] = *cseqp++ * *in++; i2 += Cmux << 2; } } break; case 6: for (j = 0; j < Cmux; j++) { int i2 = j * 6; for (int r = 0; r < Rmux_prime; r++) { y[i2] = *cseqp++ * *in++; y[i2 + 1] = *cseqp++ * *in++; y[i2 + 2] = *cseqp++ * *in++; y[i2 + 3] = *cseqp++ * *in++; y[i2 + 4] = *cseqp++ * *in++; y[i2 + 5] = *cseqp++ * *in++; i2 += Cmux * 6; } } break; } if ((in - ulsch_llr) != (H + Q_RI)) LOG_D(PHY, "ulsch_decoding.c: Error in input buffer length (j %ld, H+Q_RI %d)\n", in - ulsch_llr, H + Q_RI); // HARQ-ACK Bits (LLRs are nulled in overwritten bits after copying HARQ-ACK LLR) if (frame_parms->Ncp == 0) columnset = cs_ack_normal; else columnset = cs_ack_extended; j=0; if (ulsch_harq->O_ACK == 1) { switch (Q_m) { case 2: len_ACK = 2; break; case 4: len_ACK = 4; break; case 6: len_ACK = 6; break; } } if (ulsch_harq->O_ACK == 2) { switch (Q_m) { case 2: len_ACK = 6; break; case 4: len_ACK = 12; break; case 6: len_ACK = 18; break; } } if (ulsch_harq->O_ACK > 2) { LOG_E(PHY,"ulsch_decoding: FATAL, ACK cannot be more than 2 bits yet O_ACK:%d SFN/SF:%04d%d UE_id:%d rnti:%x\n",ulsch_harq->O_ACK,proc->frame_rx,proc->subframe_rx,UE_id,ulsch->rnti); return(-1); } for (int i = 0; i < len_ACK; i++) ulsch_harq->q_ACK[i] = 0; for (int i = 0; i < Qprime_ACK; i++) { int r = Rmux_prime - 1 - (i >> 2); for (int q = 0; q < Q_m; q++) { if (y[q + Q_m * (r * Cmux + columnset[j])] != 0) ulsch_harq->q_ACK[(q + (Q_m * i)) % len_ACK] += y[q + Q_m * (r * Cmux + columnset[j])]; y[q + Q_m * (r * Cmux + columnset[j])] = 0; // NULL LLRs in ACK positions } j=(j+3)&3; } // printf("after ACKNAK c[%d] = %p\n",0,ulsch_harq->c[0]); // RI BITS if (ulsch_harq->O_RI == 1) { switch (Q_m) { case 2: len_RI=2; break; case 4: len_RI=4; break; case 6: len_RI=6; break; } } if (ulsch_harq->O_RI > 1) { LOG_E(PHY,"ulsch_decoding: FATAL, RI cannot be more than 1 bit yet\n"); return(-1); } for (int i = 0; i < len_RI; i++) ulsch_harq->q_RI[i] = 0; if (frame_parms->Ncp == 0) columnset = cs_ri_normal; else columnset = cs_ri_extended; j=0; for (int i = 0; i < Qprime_RI; i++) { int r = Rmux_prime - 1 - (i >> 2); for (int q = 0; q < Q_m; q++) ulsch_harq->q_RI[(q+(Q_m*i))%len_RI] += y[q+(Q_m*((r*Cmux) + columnset[j]))]; ytag[(r*Cmux) + columnset[j]] = LTE_NULL; j=(j+3)&3; } // printf("after RI2 c[%d] = %p\n",0,ulsch_harq->c[0]); // CQI and Data bits j=0; int j2 = 0; // r=0; if (Q_RI>0) { for (int i = 0; i < (Q_CQI / Q_m); i++) { while (ytag[j]==LTE_NULL) { j++; j2+=Q_m; } for (int q = 0; q < Q_m; q++) { // ys = y[q+(Q_m*((r*Cmux)+j))]; int ys = y[q + j2]; if (ys>127) ulsch_harq->q[q+(Q_m*i)] = 127; else if (ys<-128) ulsch_harq->q[q+(Q_m*i)] = -128; else ulsch_harq->q[q+(Q_m*i)] = ys; } j2+=Q_m; } switch (Q_m) { case 2: for (int iprime = 0; iprime < G;) { while (ytag[j]==LTE_NULL) { j++; j2+=2; } ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; } break; case 4: for (int iprime = 0; iprime < G;) { while (ytag[j]==LTE_NULL) { j++; j2+=4; } ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; } break; case 6: for (int iprime = 0; iprime < G;) { while (ytag[j]==LTE_NULL) { j++; j2+=6; } ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; ulsch_harq->eUL[iprime++] = y[j2++]; } break; } } // Q_RI>0 else { for (int i = 0; i < (Q_CQI / Q_m); i++) { for (int q = 0; q < Q_m; q++) { int ys = y[q + j2]; if (ys>127) ulsch_harq->q[q+(Q_m*i)] = 127; else if (ys<-128) ulsch_harq->q[q+(Q_m*i)] = -128; else ulsch_harq->q[q+(Q_m*i)] = ys; } j2+=Q_m; } int16_t *yp = &y[j2], *ep = ulsch_harq->eUL; memcpy(ep, yp, G * sizeof(*yp)); } stop_meas(&eNB->ulsch_demultiplexing_stats); // printf("after ACKNAK2 c[%d] = %p (iprime %d, G %d)\n",0,ulsch_harq->c[0],iprime,G); // Do CQI/RI/HARQ-ACK Decoding first and pass to MAC // HARQ-ACK const uint32_t wACK_idx = ulsch->bundling == 0 ? 4 : (Nbundled - 1) & 3; const int *wACK = wACK_RX[wACK_idx]; uint8_t *o_ACK = ulsch_harq->o_ACK; int16_t *q_ACK = ulsch_harq->q_ACK; if (ulsch_harq->O_ACK == 1) { q_ACK[0] *= wACK[0]; q_ACK[0] += (ulsch->bundling == 0) ? q_ACK[1] * wACK[0] : q_ACK[1] * wACK[1]; if (q_ACK[0] < 0) o_ACK[0] = 0; else o_ACK[0] = 1; } if (ulsch_harq->O_ACK == 2) { switch (Q_m) { case 2: q_ACK[0] = q_ACK[0] * wACK[0] + q_ACK[3] * wACK[1]; q_ACK[1] = q_ACK[1] * wACK[0] + q_ACK[4] * wACK[1]; q_ACK[2] = q_ACK[2] * wACK[0] + q_ACK[5] * wACK[1]; break; case 4: q_ACK[0] = q_ACK[0] * wACK[0] + q_ACK[5] * wACK[1]; q_ACK[1] = q_ACK[1] * wACK[0] + q_ACK[8] * wACK[1]; q_ACK[2] = q_ACK[4] * wACK[0] + q_ACK[9] * wACK[1]; break; case 6: q_ACK[0] = q_ACK[0] * wACK[0] + q_ACK[7] * wACK[1]; q_ACK[1] = q_ACK[1] * wACK[0] + q_ACK[12] * wACK[1]; q_ACK[2] = q_ACK[6] * wACK[0] + q_ACK[13] * wACK[1]; break; } o_ACK[0] = 1; o_ACK[1] = 1; int metric = q_ACK[0] + q_ACK[1] - q_ACK[2]; int metric_new = -q_ACK[0] + q_ACK[1] + q_ACK[2]; if (metric_new > metric) { o_ACK[0] = 0; o_ACK[1] = 1; metric = metric_new; } metric_new = q_ACK[0] - q_ACK[1] + q_ACK[2]; if (metric_new > metric) { o_ACK[0] = 1; o_ACK[1] = 0; metric = metric_new; } metric_new = -q_ACK[0] - q_ACK[1] - q_ACK[2]; if (metric_new > metric) { o_ACK[0] = 0; o_ACK[1] = 0; metric = metric_new; } } // RI // rank 1 if ((ulsch_harq->O_RI == 1) && (Qprime_RI > 0)) { ulsch_harq->o_RI[0] = ((ulsch_harq->q_RI[0] + ulsch_harq->q_RI[Q_m/2]) > 0) ? 0 : 1; } // CQI // printf("before cqi c[%d] = %p\n",0,ulsch_harq->c[0]); ulsch_harq->cqi_crc_status = 0; if (Q_CQI>0) { memset((void *)&dummy_w_cc[0],0,3*(ulsch_harq->Or1+8+32)); O_RCC = generate_dummy_w_cc(ulsch_harq->Or1+8, &dummy_w_cc[0]); lte_rate_matching_cc_rx(O_RCC, Q_CQI, ulsch_harq->o_w, dummy_w_cc, ulsch_harq->q); sub_block_deinterleaving_cc((unsigned int)(ulsch_harq->Or1+8), &ulsch_harq->o_d[96], &ulsch_harq->o_w[0]); memset(ulsch_harq->o,0,(7+8+ulsch_harq->Or1) / 8); phy_viterbi_lte_sse2(ulsch_harq->o_d+96,ulsch_harq->o,8+ulsch_harq->Or1); if (extract_cqi_crc(ulsch_harq->o,ulsch_harq->Or1) == (crc8(ulsch_harq->o,ulsch_harq->Or1)>>24)) ulsch_harq->cqi_crc_status = 1; #ifdef DEBUG_ULSCH_DECODING printf("ulsch_decoding: Or1=%d\n",ulsch_harq->Or1); for (i=0; i<1+((8+ulsch_harq->Or1)/8); i++) printf("ulsch_decoding: O[%u] %d\n",i,ulsch_harq->o[i]); if (ulsch_harq->cqi_crc_status == 1) printf("RX CQI CRC OK (%x)\n",extract_cqi_crc(ulsch_harq->o,ulsch_harq->Or1)); else printf("RX CQI CRC NOT OK (%x)\n",extract_cqi_crc(ulsch_harq->o,ulsch_harq->Or1)); #endif } LOG_D(PHY,"frame %d subframe %d O_ACK:%d o_ACK[]=%d:%d:%d:%d\n",frame,subframe,ulsch_harq->O_ACK,ulsch_harq->o_ACK[0],ulsch_harq->o_ACK[1],ulsch_harq->o_ACK[2],ulsch_harq->o_ACK[3]); // Do ULSCH Decoding for data portion ret = ulsch_decoding_data(eNB, proc, UE_id, harq_pid, llr8_flag, t_info); return(ret); } #define STATSTRLEN 16384 void dump_ulsch_stats(FILE *fd,PHY_VARS_eNB *eNB,int frame) { char output[16384]; char *str = output; *str = 0; for (eNB_SCH_STATS_t *st = eNB->ulsch_stats; st < eNB->ulsch_stats + sizeofArray(eNB->ulsch_stats); st++) if (st->rnti > 0 && st->round_trials[0] > 100) { for (int aa = 0; aa < eNB->frame_parms.nb_antennas_rx; aa++) str += sprintf(str, "ULSCH RNTI %x: ulsch_power[%d] %d, ulsch_noise_power[%d] %d\n", st->rnti, aa, st->ulsch_power[aa], aa, st->ulsch_noise_power[aa]); AssertFatal((str - output) < (STATSTRLEN - 1000), "Increase STATSTRLEN\n"); str += sprintf(str, "ULSCH RNTI %x: round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d\n", st->rnti, st->round_trials[0], (double)st->round_trials[1] / st->round_trials[0], st->round_trials[1], (double)st->round_trials[2] / st->round_trials[0], st->round_trials[2], (double)st->round_trials[3] / st->round_trials[0], st->round_trials[3]); str += sprintf(str, "ULSCH RNTI %x: current_Qm %d, current_G %d, current_TBS %d, current_rate %f,current_RI %d, timing_offset " "%d, total_bytes RX/SCHED %d/%d\n", st->rnti, st->current_Qm, st->current_G, st->current_TBS, (double)st->current_G / st->current_TBS, st->current_RI, st->timing_offset, st->total_bytes_rx, st->total_bytes_tx); } fprintf(fd,"%s",output); } void clear_ulsch_stats(PHY_VARS_eNB *eNB) { memset(eNB->ulsch_stats, 0, sizeof(eNB->ulsch_stats)); }