From 9947a6bccd3508ac75c50e360bcdf09a2590c7ff Mon Sep 17 00:00:00 2001 From: Ahmed Date: Fri, 1 Mar 2019 16:58:47 +0100 Subject: [PATCH] ULSCH decoding functionality at gNB side Added the following structs and enums in "defs_gNB.h" - NR_UL_gNB_HARQ_t - NR_gNB_ULSCH_t - NR_SCH_status_t added the following structs in "nfapi_nr_interface.h" - nfapi_nr_ul_config_ulsch_pdu - nfapi_nr_ul_config_ulsch_pdu_rel15_t - nfapi_nr_ul_srs_config_t - nr_pusch_freq_hopping_t added nr_ulsch.h for the ulsch decoding function declarations - free_gNB_ulsch - new_gNB_ulsch - nr_ulsch_decoding added nr_ulsch_decoding.c for the implementation of the ulsch decoding functions - free_gNB_ulsch - new_gNB_ulsch - nr_ulsch_decoding --- cmake_targets/CMakeLists.txt | 1 + .../nfapi/public_inc/nfapi_nr_interface.h | 41 ++ openair1/PHY/NR_TRANSPORT/nr_ulsch.h | 49 ++ openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 583 ++++++++++++++++++ openair1/PHY/defs_gNB.h | 195 +++++- 5 files changed, 860 insertions(+), 9 deletions(-) create mode 100644 openair1/PHY/NR_TRANSPORT/nr_ulsch.h create mode 100644 openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 6ed11eebfa..79f057c29e 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1275,6 +1275,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding.c + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 94b7121998..b953a715ef 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -673,4 +673,45 @@ typedef struct { nfapi_vendor_extension_tlv_t vendor_extension; } nfapi_nr_dl_config_request_t; + +typedef enum {nr_pusch_freq_hopping_disabled = 0 , + nr_pusch_freq_hopping_enabled = 1 + } nr_pusch_freq_hopping_t; + +typedef struct{ + uint8_t aperiodicSRS_ResourceTrigger; +} nfapi_nr_ul_srs_config_t; + +typedef struct { + uint8_t bandwidth_part_ind; + uint16_t number_rbs; + uint16_t start_rb; + uint8_t frame_offset; + uint16_t number_symbols; + uint16_t start_symbol; + nr_pusch_freq_hopping_t pusch_freq_hopping; + uint8_t mcs; + uint8_t Qm; + uint8_t ndi; + uint8_t rv; + uint8_t harq_process_nbr; + int8_t accumulated_delta_PUSCH; + int8_t absolute_delta_PUSCH; + uint8_t n_layers; + uint8_t tpmi; + uint8_t n_dmrs_cdm_groups; + uint8_t dmrs_ports[4]; + uint8_t n_front_load_symb; + nfapi_nr_ul_srs_config_t srs_config; + uint8_t csi_reportTriggerSize; + uint8_t maxCodeBlockGroupsPerTransportBlock; + uint8_t ptrs_dmrs_association_port; + uint8_t beta_offset_ind; +} nfapi_nr_ul_config_ulsch_pdu_rel15_t; + +typedef struct { + uint16_t rnti; + nfapi_nr_ul_config_ulsch_pdu_rel15_t ulsch_pdu_rel15; +} nfapi_nr_ul_config_ulsch_pdu; + #endif diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h new file mode 100644 index 0000000000..77cc101679 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h @@ -0,0 +1,49 @@ +/* + * 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.0 (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/NR_TRANSPORT/nr_ulsch.h +* \brief functions used for PUSCH/ULSCH physical and transport channels for gNB +* \author Ahmed Hussein +* \date 2019 +* \version 0.1 +* \company Fraunhofer IIS +* \email: ahmed.hussein@iis.fraunhofer.de +* \note +* \warning +*/ + +#include "PHY/defs_gNB.h" + +void free_gNB_ulsch(NR_gNB_ULSCH_t *ulsch); + +NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag); + +uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, + uint8_t UE_id, + short *ulsch_llr, + NR_DL_FRAME_PARMS *frame_parms, + uint32_t frame, + uint16_t nb_symb_sch, + uint8_t nr_tti_rx, + uint8_t harq_pid, + uint8_t is_crnti, + uint8_t llr8_flag); + diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c new file mode 100644 index 0000000000..1d72507de9 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -0,0 +1,583 @@ +/* + * 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.0 (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/NR_TRANSPORT/nr_ulsch_decoding.c +* \brief Top-level routines for decoding LDPC (ULSCH) transport channels from 38.212, V15.4.0 2018-12 +* \author Ahmed Hussein +* \date 2019 +* \version 0.1 +* \company Fraunhofer IIS +* \email: ahmed.hussein@iis.fraunhofer.de +* \note +* \warning +*/ + + +// [from gNB coding] +#include "PHY/defs_gNB.h" +#include "PHY/phy_extern.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" +#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_ulsch.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "SCHED_NR/sched_nr.h" +#include "defs.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "common/utils/LOG/log.h" +#include +//#define DEBUG_ULSCH_DECODING + +#define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 + +static uint64_t nb_total_decod =0; +static uint64_t nb_error_decod =0; + +//extern double cpuf; + +void free_gNB_ulsch(NR_gNB_ULSCH_t *ulsch) +{ + + int i,r; + + if (ulsch) { + for (i=0; iharq_processes[i]) { + if (ulsch->harq_processes[i]->b) { + free16(ulsch->harq_processes[i]->b,MAX_NR_ULSCH_PAYLOAD_BYTES); + ulsch->harq_processes[i]->b = NULL; + } + for (r=0; rharq_processes[i]->c[r],(8448)*sizeof(uint8_t)); + ulsch->harq_processes[i]->c[r] = NULL; + } + for (r=0; rharq_processes[i]->d[r]) { + free16(ulsch->harq_processes[i]->d[r],(68*384)*sizeof(int16_t)); + ulsch->harq_processes[i]->d[r] = NULL; + } + } + for (r=0; r<(MAX_NUM_NR_ULSCH_SEGMENTS); r++) { + if (ulsch->harq_processes[i]->p_nrLDPC_procBuf[r]){ + nrLDPC_free_mem(ulsch->harq_processes[i]->p_nrLDPC_procBuf[r]); + ulsch->harq_processes[i]->p_nrLDPC_procBuf[r] = NULL; + } + } + free16(ulsch->harq_processes[i],sizeof(NR_UL_gNB_HARQ_t)); + ulsch->harq_processes[i] = NULL; + } + } + free16(ulsch,sizeof(NR_gNB_ULSCH_t)); + ulsch = NULL; + } +} + + +NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag) +{ + + NR_gNB_ULSCH_t *ulsch; + uint8_t exit_flag = 0,i,r; + unsigned char bw_scaling =1; + + switch (N_RB_UL) { + case 106: + bw_scaling =2; + break; + + default: + bw_scaling =1; + break; + } + + ulsch = (NR_gNB_ULSCH_t *)malloc16(sizeof(NR_gNB_ULSCH_t)); + + if (ulsch) { + + memset(ulsch,0,sizeof(NR_gNB_ULSCH_t)); + + ulsch->max_ldpc_iterations = max_ldpc_iterations; + ulsch->Mlimit = 4; + + for (i=0; iharq_processes[i] = (NR_UL_gNB_HARQ_t *)malloc16(sizeof(NR_UL_gNB_HARQ_t)); + + if (ulsch->harq_processes[i]) { + + memset(ulsch->harq_processes[i],0,sizeof(NR_UL_gNB_HARQ_t)); + + ulsch->harq_processes[i]->b = (uint8_t*)malloc16(MAX_NR_ULSCH_PAYLOAD_BYTES/bw_scaling); + + if (ulsch->harq_processes[i]->b) + memset(ulsch->harq_processes[i]->b,0,MAX_NR_ULSCH_PAYLOAD_BYTES/bw_scaling); + else + exit_flag=3; + + if (abstraction_flag == 0) { + for (r=0; rharq_processes[i]->p_nrLDPC_procBuf[r] = nrLDPC_init_mem(); + + ulsch->harq_processes[i]->c[r] = (uint8_t*)malloc16(8448*sizeof(uint8_t)); + + if (ulsch->harq_processes[i]->c[r]) + memset(ulsch->harq_processes[i]->c[r],0,8448*sizeof(uint8_t)); + else + exit_flag=2; + + ulsch->harq_processes[i]->d[r] = (int16_t*)malloc16((68*384)*sizeof(int16_t)); + + if (ulsch->harq_processes[i]->d[r]) + memset(ulsch->harq_processes[i]->d[r],0,(68*384)*sizeof(int16_t)); + else + exit_flag=2; + } + } + } else { + exit_flag=1; + } + } + + if (exit_flag==0) + return(ulsch); + } + + printf("new_gNB_ulsch with size %zu: exit_flag = %u\n",sizeof(NR_UL_gNB_HARQ_t), exit_flag); + free_gNB_ulsch(ulsch); + + return(NULL); +} + + +uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, + uint8_t UE_id, + short *ulsch_llr, + NR_DL_FRAME_PARMS *frame_parms, + uint32_t frame, + uint16_t nb_symb_sch, + uint8_t nr_tti_rx, + uint8_t harq_pid, + uint8_t is_crnti, + uint8_t llr8_flag) +{ + + uint32_t A,E; + uint32_t G; + uint32_t ret,offset; + int32_t no_iteration_ldpc; + uint32_t r,r_offset=0,Kr=8424,Kr_bytes,K_bytes_F,err_flag=0; + uint8_t crc_type; + int8_t llrProcBuf[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))); + + + NR_gNB_ULSCH_t *ulsch = phy_vars_gNB->ulsch[UE_id][0]; + NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_processes[harq_pid]; + nfapi_nr_ul_config_ulsch_pdu_rel15_t *nfapi_ulsch_pdu_rel15 = &harq_process->ulsch_pdu.ulsch_pdu_rel15; + + t_nrLDPC_dec_params decParams; + t_nrLDPC_dec_params* p_decParams = &decParams; + t_nrLDPC_time_stats procTime; + t_nrLDPC_time_stats* p_procTime = &procTime ; + t_nrLDPC_procBuf** p_nrLDPC_procBuf = harq_process->p_nrLDPC_procBuf; + + int16_t z [68*384]; + int8_t l [68*384]; + int16_t inv_d [68*384]; + uint8_t kb, kc; + uint8_t Ilbrm = 0; + uint32_t Tbslbrm = 950984; + uint16_t nb_rb = 30; //to update + uint8_t nb_re_dmrs = 6; + uint16_t length_dmrs = 1; + + uint32_t i,j; + + __m128i *pv = (__m128i*)&z; + __m128i *pl = (__m128i*)&l; + + + if (!ulsch_llr) { + printf("ulsch_decoding.c: NULL ulsch_llr pointer\n"); + return(ulsch->max_ldpc_iterations); + } + + if (!harq_process) { + printf("ulsch_decoding.c: NULL harq_process pointer\n"); + return(ulsch->max_ldpc_iterations); + } + + if (!frame_parms) { + printf("ulsch_decoding.c: NULL frame_parms pointer\n"); + return(ulsch->max_ldpc_iterations); + } + + nb_rb = nfapi_ulsch_pdu_rel15->number_rbs; + + // harq_process->trials[nfapi_ulsch_pdu_rel15->round]++; + + harq_process->TBS = nr_compute_tbs(nfapi_ulsch_pdu_rel15->mcs, nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, nfapi_ulsch_pdu_rel15->n_layers); + + A = harq_process->TBS; + ret = ulsch->max_ldpc_iterations; + + harq_process->G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, nfapi_ulsch_pdu_rel15->Qm,nfapi_ulsch_pdu_rel15->n_layers); + G = harq_process->G; + + LOG_I(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, nfapi_ulsch_pdu_rel15->mcs, nfapi_ulsch_pdu_rel15->n_layers, nb_symb_sch,nb_rb); + + if (harq_process->round == 0) { + // This is a new packet, so compute quantities regarding segmentation + harq_process->B = A+24; + + // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (B, C, K, Z, F) + nr_segmentation(NULL, + NULL, + harq_process->B, + &harq_process->C, + &harq_process->K, + &harq_process->Z, // [hna] Z is Zc + &harq_process->F); + + p_decParams->Z = harq_process->Z; + +#ifdef DEBUG_ULSCH_DECODING + printf("ulsch decoding nr segmentation Z %d\n", p_decParams->Z); + if (!frame%100) + printf("K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, p_decParams->Z, harq_process->Nl); +#endif + } + + kb = harq_process->K/harq_process->Z; + + if ( kb==22) { + p_decParams->BG = 1; + p_decParams->R = 13; + kc = 68; + } else { + p_decParams->BG = 2; + p_decParams->R = 13; + kc = 52; + } + + p_decParams->numMaxIter = ulsch->max_ldpc_iterations; + Kr = p_decParams->Z*kb; + p_decParams->outMode= 0; + + err_flag = 0; + r_offset = 0; + + unsigned char bw_scaling =1; + + switch (frame_parms->N_RB_UL) { + + case 106: + bw_scaling =2; + break; + + default: + bw_scaling =1; + break; + } + + if (harq_process->C > MAX_NUM_NR_ULSCH_SEGMENTS/bw_scaling) { + LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,MAX_NUM_NR_ULSCH_SEGMENTS/bw_scaling); + return((1+ulsch->max_ldpc_iterations)); + } +#ifdef DEBUG_ULSCH_DECODING + printf("Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); +#endif + + opp_enabled=1; + + Kr = harq_process->K; // [hna] overwrites this line "Kr = p_decParams->Z*kb" + Kr_bytes = Kr>>3; + + K_bytes_F = Kr_bytes-(harq_process->F>>3); + + Tbslbrm = nr_compute_tbs(28,nb_rb,frame_parms->symbols_per_slot,0,0, nfapi_ulsch_pdu_rel15->n_layers); + + for (r=0; rC; r++) { + + E = nr_get_E(G, harq_process->C, nfapi_ulsch_pdu_rel15->Qm, nfapi_ulsch_pdu_rel15->n_layers, r); + +#if gNB_TIMING_TRACE + start_meas(ulsch_deinterleaving_stats); +#endif + + //////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// nr_deinterleaving_ldpc /////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////// ulsch_llr =====> harq_process->e ////////////////////////////// + + nr_deinterleaving_ldpc(E, + nfapi_ulsch_pdu_rel15->Qm, + harq_process->e[r], + ulsch_llr+r_offset); + + //for (int i =0; i<16; i++) + // printf("rx output deinterleaving w[%d]= %d r_offset %d\n", i,harq_process->w[r][i], r_offset); + +#if gNB_TIMING_TRACE + stop_meas(ulsch_deinterleaving_stats); +#endif + +#if gNB_TIMING_TRACE + start_meas(ulsch_rate_unmatching_stats); +#endif + +#ifdef DEBUG_ULSCH_DECODING + LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", + harq_pid,r, G, + Kr*3, + harq_process->TBS, + nfapi_ulsch_pdu_rel15->Qm, + nfapi_ulsch_pdu_rel15->number_rbs, + nfapi_ulsch_pdu_rel15->n_layers, + nfapi_ulsch_pdu_rel15->rv, + harq_process->round); +#endif + ////////////////////////////////////////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////// nr_rate_matching_ldpc_rx //////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////// harq_process->e =====> harq_process->d ///////////////////////// + + if (nr_rate_matching_ldpc_rx(Ilbrm, + Tbslbrm, + p_decParams->BG, + p_decParams->Z, + harq_process->d[r], + harq_process->e[r], + harq_process->C, + nfapi_ulsch_pdu_rel15->rv, + (harq_process->round==0)?1:0, + E)==-1) { +#if gNB_TIMING_TRACE + stop_meas(ulsch_rate_unmatching_stats); +#endif + LOG_E(PHY,"ulsch_decoding.c: Problem in rate_matching\n"); + return(ulsch->max_ldpc_iterations); + } else { +#if gNB_TIMING_TRACE + stop_meas(ulsch_rate_unmatching_stats); +#endif + } + + r_offset += E; + +#ifdef DEBUG_ULSCH_DECODING + if (r==0) { + write_output("decoder_llr.m","decllr",ulsch_llr,G,1,0); + write_output("decoder_in.m","dec",&harq_process->d[0][0],(3*8*Kr_bytes)+12,1,0); + } + + printf("decoder input(segment %d) :",r); + int i; + for (i=0;i<(3*8*Kr_bytes)+12;i++) + printf("%d : %d\n",i,harq_process->d[r][i]); + printf("\n"); +#endif + + + // printf("Clearing c, %p\n",harq_process->c[r]); + memset(harq_process->c[r],0,Kr_bytes); + + // printf("done\n"); + if (harq_process->C == 1) + crc_type = CRC24_A; + else + crc_type = CRC24_B; + + if (err_flag == 0) { + +#if gNB_TIMING_TRACE + start_meas(ulsch_turbo_decoding_stats); +#endif + + for (int cnt =0; cnt < (kc-2)*p_decParams->Z; cnt++) { + inv_d[cnt] = (1)*harq_process->d[r][cnt]; + } + + memset(pv,0,2*harq_process->Z*sizeof(int16_t)); + memset((pv+K_bytes_F),127,harq_process->F*sizeof(int16_t)); + + for (i=((2*p_decParams->Z)>>3), j = 0; i < K_bytes_F+((2*p_decParams->Z)>>3); i++, j++) { + pv[i]= _mm_loadu_si128((__m128i*)(&inv_d[8*j])); + } + + for (i=Kr_bytes+((2*p_decParams->Z)>>3),j=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++, j++) { + pv[i]= _mm_loadu_si128((__m128i*)(&inv_d[8*j])); + } + + for (i=0, j=0; j < ((kc*p_decParams->Z)>>4); i+=2, j++) { + pl[j] = _mm_packs_epi16(pv[i],pv[i+1]); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////// nrLDPC_decoder ///////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// + + no_iteration_ldpc = nrLDPC_decoder(p_decParams, + (int8_t*)&pl[0], + llrProcBuf, + p_nrLDPC_procBuf[r], + p_procTime); + + if (check_crc(llrProcBuf,harq_process->B,harq_process->F,crc_type)) { + printf("CRC OK\n"); + ret = 2; + } else { + printf("CRC NOK\n"); + ret = 1+ulsch->max_ldpc_iterations; + } + + nb_total_decod++; + if (no_iteration_ldpc > ulsch->max_ldpc_iterations){ + nb_error_decod++; + } + + ret=no_iteration_ldpc; + + for (int m=0; m < Kr>>3; m ++) { + harq_process->c[r][m]= (uint8_t) llrProcBuf[m]; + } + +#ifdef DEBUG_ULSCH_DECODING + //printf("output decoder %d %d %d %d %d \n", harq_process->c[r][0], harq_process->c[r][1], harq_process->c[r][2],harq_process->c[r][3], harq_process->c[r][4]); + for (int k=0;k>3;k++) + printf("output decoder [%d] = 0x%02x \n", k, harq_process->c[r][k]); + printf("no_iterations_ldpc %d (ret %d)\n",no_iteration_ldpc,ret); + //write_output("dec_output.m","dec0",harq_process->c[0],Kr_bytes,1,4); +#endif + +#if gNB_TIMING_TRACE + stop_meas(ulsch_turbo_decoding_stats); +#endif + } + + if ((err_flag == 0) && (ret>=(1+ulsch->max_ldpc_iterations))) { + // a Code segment is in error so break; + LOG_D(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_tti_rx,r,harq_process->C-1); + err_flag = 1; + } + ////////////////////////////////////////////////////////////////////////////////////////// + } + + int32_t frame_rx_prev = frame; + int32_t tti_rx_prev = nr_tti_rx - 1; + if (tti_rx_prev < 0) { + frame_rx_prev--; + tti_rx_prev += 10*frame_parms->ttis_per_subframe; + } + frame_rx_prev = frame_rx_prev%1024; + + if (err_flag == 1) { + +#if gNB_DEBUG_TRACE + LOG_I(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d, mcs %d) Kr %d r %d harq_process->round %d\n", + phy_vars_gNB->Mod_id, frame, nr_tti_rx, harq_pid,harq_process->status, harq_process->round,harq_process->TBS,harq_process->mcs,Kr,r,harq_process->round); +#endif + + // harq_process->harq_ack.ack = 0; + // harq_process->harq_ack.harq_id = harq_pid; + // harq_process->harq_ack.send_harq_status = 1; + // harq_process->errors[harq_process->round]++; + harq_process->round++; + + if (harq_process->round >= ulsch->Mlimit) { + harq_process->status = SCH_IDLE; + harq_process->round = 0; + harq_process->handled = 0; + ulsch->harq_mask &= ~(1 << harq_pid); + } + + if(is_crnti) { + LOG_D(PHY,"[gNB %d] ULSCH: Setting NACK for nr_tti_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", + phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->status,harq_process->round,ulsch->Mlimit,harq_process->TBS); + } + + harq_process->handled = 1; + return((1+ulsch->max_ldpc_iterations)); + + } else { + +#if gNB_DEBUG_TRACE + LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d TBS %d mcs %d nb_rb %d harq_process->round %d\n", + phy_vars_gNB->Mod_id,nr_tti_rx,harq_process->TBS,harq_process->mcs,harq_process->nb_rb, harq_process->round); +#endif + + harq_process->status = SCH_IDLE; + harq_process->round = 0; + // harq_process->handled = 0; + ulsch->harq_mask &= ~(1 << harq_pid); + // harq_process->harq_ack.ack = 1; + // harq_process->harq_ack.harq_id = harq_pid; + // harq_process->harq_ack.send_harq_status = 1; + + if(is_crnti) + { + LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d (pid %d, round %d, TBS %d)\n",phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->round,harq_process->TBS); + } + } + + // Reassembly of Transport block here + offset = 0; + Kr = harq_process->K; + Kr_bytes = Kr>>3; + + for (r=0; rC; r++) { + + memcpy(harq_process->b+offset, + harq_process->c[r], + Kr_bytes- - (harq_process->F>>3) -((harq_process->C>1)?3:0)); + + offset += (Kr_bytes - (harq_process->F>>3) - ((harq_process->C>1)?3:0)); + +#ifdef DEBUG_ULSCH_DECODING + printf("Segment %d : Kr= %d bytes\n",r,Kr_bytes); + printf("copied %d bytes to b sequence (harq_pid %d)\n", + (Kr_bytes - (harq_process->F>>3)-((harq_process->C>1)?3:0)),harq_pid); + printf("b[0] = %x,c[%d] = %x\n", + harq_process->b[offset], + harq_process->F>>3, + harq_process->c[r]); +#endif + + } + + ulsch->last_iteration_cnt = ret; + + return(ret); +} \ No newline at end of file diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 10b99eb113..24be9688dc 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -38,6 +38,10 @@ #include "CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/impl_defs_top.h" +#include "PHY/defs_common.h" +#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h" +#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" #define MAX_NUM_RU_PER_gNB MAX_NUM_RU_PER_eNB @@ -72,6 +76,7 @@ typedef struct { uint64_t dci_pdu[2]; } NR_gNB_DCI_ALLOC_t; + typedef struct { uint8_t num_dci; uint8_t num_pdsch_rnti; @@ -79,6 +84,14 @@ typedef struct { } NR_gNB_PDCCH; +typedef enum { + NR_SCH_IDLE, + NR_ACTIVE, + NR_CBA_ACTIVE, + NR_DISABLED +} NR_SCH_status_t; + + typedef struct { /// Nfapi DLSCH PDU nfapi_nr_dl_config_dlsch_pdu dlsch_pdu; @@ -114,7 +127,6 @@ typedef struct { typedef struct { - /// Pointers to 16 HARQ processes for the DLSCH NR_DL_gNB_HARQ_t *harq_processes[NR_MAX_NB_HARQ_PROCESSES]; /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) @@ -160,6 +172,170 @@ typedef struct { } NR_gNB_DLSCH_t; +typedef struct { + /// Nfapi ULSCH PDU + nfapi_nr_ul_config_ulsch_pdu ulsch_pdu; + /// Frame where current HARQ round was sent + uint32_t frame; + /// Subframe where current HARQ round was sent + uint32_t subframe; + /// Index of current HARQ round for this DLSCH + uint8_t round; + /// Last TPC command + uint8_t TPC; + /// MIMO mode for this DLSCH + MIMO_mode_t mimo_mode; + /// Flag indicating that this ULSCH has been allocated by a DCI (otherwise it is a retransmission based on PHICH NAK) + uint8_t dci_alloc; + /// Flag indicating that this ULSCH has been allocated by a RAR (otherwise it is a retransmission based on PHICH NAK or DCI) + uint8_t rar_alloc; + /// Status Flag indicating for this ULSCH (idle,active,disabled) + NR_SCH_status_t status; + /// Subframe scheduling indicator (i.e. Transmission opportunity indicator) + uint8_t subframe_scheduling_flag; + /// Subframe cba scheduling indicator (i.e. CBA Transmission opportunity indicator) + uint8_t subframe_cba_scheduling_flag; + /// PHICH active flag + uint8_t phich_active; + /// PHICH ACK + uint8_t phich_ACK; + /// First Allocated RB - previous scheduling. This is needed for PHICH generation which is done after a new scheduling + uint16_t previous_first_rb; + /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around + uint8_t handled; + /// Flag to indicate that this ULSCH is for calibration information sent from UE (i.e. no MAC SDU to pass up) + // int calibration_flag; + /// delta_TF for power control + int32_t delta_TF; + + + /////////////////////// ulsch decoding /////////////////////// + /// Transport block size (This is A from 38.212 V15.4.0 section 5.1) + uint32_t TBS; + /// Pointer to the payload (38.212 V15.4.0 section 5.1) + uint8_t *b; + /// The payload + CRC (24 bits) in bits (38.212 V15.4.0 section 5.1) + uint32_t B; + /// Pointers to code blocks after code block segmentation and CRC attachment (38.212 V15.4.0 section 5.2.2) + uint8_t *c[MAX_NUM_NR_ULSCH_SEGMENTS]; + /// Number of bits in each code block (38.212 V15.4.0 section 5.2.2) + uint32_t K; + /// Number of "Filler" bits added in the code block segmentation (38.212 V15.4.0 section 5.2.2) + uint32_t F; + /// Number of code blocks after code block segmentation (38.212 V15.4.0 section 5.2.2) + uint32_t C; + /// Pointers to code blocks after LDPC coding (38.212 V15.4.0 section 5.3.2) + int16_t *d[MAX_NUM_NR_ULSCH_SEGMENTS]; + /// LDPC processing buffer + t_nrLDPC_procBuf* p_nrLDPC_procBuf[MAX_NUM_NR_ULSCH_SEGMENTS]; + /// LDPC lifting size (38.212 V15.4.0 table 5.3.2-1) + uint32_t Z; + /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t e[MAX_NUM_NR_DLSCH_SEGMENTS][3*8448]; + /// Number of bits in each code block after rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + uint32_t E; + /// Number of soft channel bits after code block concatenation (38.212 V15.4.0 section 5.5) + uint32_t G; + ////////////////////////////////////////////////////////////// + + + /////////////////////////// DMRS ///////////////////////////// + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) + uint8_t n_DMRS; + /// n_DMRS 2 for cyclic shift of DMRS (36.211 Table 5.5.1.1.-1) + uint8_t n_DMRS2; + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) - previous scheduling + /// This is needed for PHICH generation which + /// is done after a new scheduling + uint8_t previous_n_DMRS; + ////////////////////////////////////////////////////////////// + + + ///////////////////// UCI multiplexing /////////////////////// + /// CQI CRC status + uint8_t cqi_crc_status; + /// Pointer to CQI data + uint8_t o[MAX_CQI_BYTES]; + /// Format of CQI data + UCI_format_t uci_format; + /// Length of CQI data under RI=1 assumption(bits) + uint8_t Or1; + /// Length of CQI data under RI=2 assumption(bits) + uint8_t Or2; + /// Rank information + uint8_t o_RI[2]; + /// Length of rank information (bits) + uint8_t O_RI; + /// Pointer to ACK + uint8_t o_ACK[4]; + /// Length of ACK information (bits) + uint8_t O_ACK; + /// The value of DAI in DCI format 0 + uint8_t V_UL_DAI; + /// "q" sequences for CQI/PMI (for definition see 36-212 V8.6 2009-03, p.27) + int8_t q[MAX_CQI_PAYLOAD]; + /// number of coded CQI bits after interleaving + uint8_t o_RCC; + /// coded and interleaved CQI bits + int8_t o_w[(MAX_CQI_BITS+8)*3]; + /// coded CQI bits + int8_t o_d[96+((MAX_CQI_BITS+8)*3)]; + /// coded ACK bits + int16_t q_ACK[MAX_ACK_PAYLOAD]; + /// coded RI bits + int16_t q_RI[MAX_RI_PAYLOAD]; + /// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled + uint8_t h[MAX_NUM_CHANNEL_BITS]; + /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + int16_t w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; + ////////////////////////////////////////////////////////////// +} NR_UL_gNB_HARQ_t; + + +typedef struct { + /// Pointers to 16 HARQ processes for the ULSCH + NR_UL_gNB_HARQ_t *harq_processes[NR_MAX_ULSCH_HARQ_PROCESSES]; + /// Current HARQ process id + int harq_process_id[NR_MAX_SLOTS_PER_FRAME]; + /// HARQ process mask, indicates which processes are currently active + uint16_t harq_mask; + /// ACK/NAK Bundling flag + uint8_t bundling; + /// beta_offset_cqi times 8 + uint16_t beta_offset_cqi_times8; + /// beta_offset_ri times 8 + uint16_t beta_offset_ri_times8; + /// beta_offset_harqack times 8 + uint16_t beta_offset_harqack_times8; + /// Flag to indicate that gNB awaits UE Msg3 + uint8_t Msg3_active; + /// Flag to indicate that gNB should decode UE Msg3 + uint8_t Msg3_flag; + /// Subframe for Msg3 + uint8_t Msg3_subframe; + /// Frame for Msg3 + uint32_t Msg3_frame; + /// Allocated RNTI for this ULSCH + uint16_t rnti; + /// RNTI type + uint8_t rnti_type; + /// cyclic shift for DM RS + uint8_t cyclicShift; + /// for cooperative communication + uint8_t cooperation_flag; + /// Maximum number of HARQ rounds + uint8_t Mlimit; + /// Maximum number of LDPC iterations + uint8_t max_ldpc_iterations; + /// number of iterations used in last LDPC decoding + uint8_t last_iteration_cnt; + /// num active cba group + uint8_t num_active_cba_groups; + /// num active cba group + uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; +} NR_gNB_ULSCH_t; + + typedef struct { /// \brief Pointers (dynamic) to the received data in the time domain. /// - first index: rx antenna [0..nb_antennas_rx[ @@ -394,17 +570,18 @@ typedef struct PHY_VARS_gNB_s { LTE_eNB_PHICH phich_vars[2]; NR_gNB_COMMON common_vars; - LTE_eNB_UCI uci_vars[NUMBER_OF_UE_MAX]; - LTE_eNB_SRS srs_vars[NUMBER_OF_UE_MAX]; - LTE_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; - LTE_eNB_PRACH prach_vars; - NR_gNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX][2]; // Nusers times two spatial streams - LTE_eNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA + LTE_eNB_UCI uci_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_SRS srs_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_PRACH prach_vars; + NR_gNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX][2]; // Nusers times two spatial streams + NR_gNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1][2]; // [Nusers times + number of RA][2 codewords], index 0 in [NUMBER_OF_UE_MAX+1] is for RA + // LTE_eNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA NR_gNB_DLSCH_t *dlsch_SI,*dlsch_ra,*dlsch_p; NR_gNB_DLSCH_t *dlsch_MCH; NR_gNB_DLSCH_t *dlsch_PCH; - LTE_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX]; - LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX]; + LTE_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX]; + LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX]; uint8_t pbch_configured; uint8_t pbch_pdu[4]; //PBCH_PDU_SIZE