diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index ad84245f86..3285dab149 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -318,10 +318,10 @@ void nr_layer_mapping(int nbCodes, } } -void nr_ue_layer_mapping(const c16_t *mod_symbs, const int n_layers, const int n_symbs, int sz, c16_t tx_layers[][sz]) +void nr_ue_layer_mapping(const c16_t *mod_symbs, const int n_layers, const int n_symbs, c16_t tx_layers[][n_symbs]) { - for (int i=0; iZ, &harq_process->F, harq_process->BG); + stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); impp.n_segments = harq_process->C; impp.K = harq_process->K; impp.Kr = impp.K; @@ -126,7 +127,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B); return(-1); } - stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT); #ifdef DEBUG_ULSCH_CODING @@ -149,19 +149,22 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN); } - start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); if (ldpc_interface_offload.LDPCencoder) { for (int j = 0; j < impp.n_segments; j++) { impp.perCB[j].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j); } + start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); ldpc_interface_offload.LDPCencoder(harq_process->c, &harq_process->f, &impp); + stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); } else { if (ulsch->pusch_pdu.pusch_data.new_data_indicator) { + start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); for (int j = 0; j < (impp.n_segments / 8 + 1); j++) { impp.macro_num = j; impp.Kr = impp.K; ldpc_interface.LDPCencoder(harq_process->c, harq_process->d, &impp); } + stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT); #ifdef DEBUG_ULSCH_CODING @@ -169,7 +172,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, write_output("ulsch_enc_output0.m", "enc0", &harq_process->d[0][0], (3 * 8 * Kr_bytes) + 12, 1, 4); #endif } - stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); /////////////////////////////////////////////////////////////////////////////// for (int r = 0; r < impp.n_segments; r++) { // looping over C segments if (impp.F > 0) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index efd77d8cbe..bef7724e5d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -85,6 +85,382 @@ void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t size, uint32_t Nid, uint nr_codeword_scrambling(in, size, 0, Nid, n_RNTI, out); } +/* +The function pointers are set once before calling the mapping funcion for +all symbols based on different parameters. Then the mapping is done for +each symbol by calling the function pointers. +*/ +static void (*map_dmrs_ptr)(const unsigned int, const c16_t *, c16_t *); +static void (*map_data_dmrs_ptr)(const unsigned int num_cdm_no_data, const c16_t *, c16_t *); + +/* +The following set of functions map dmrs and/or data REs in one RB based on +configuration of DMRS type, number of CDM groups with no data and delta. +For all other combinations of the parameters not present below is not +applicable. +*/ + +/* +DMRS mapping in a RB for Type 1. +Mapping as in TS 38.211 6.4.1.1.3 k = 4n + 2k^prime + delta +*/ +static void map_dmrs_type1_cdm1_rb(const unsigned int delta, const c16_t *dmrs, c16_t *out) +{ + *(out + delta) = *dmrs++; + *(out + delta + 2) = *dmrs++; + *(out + delta + 4) = *dmrs++; + *(out + delta + 6) = *dmrs++; + *(out + delta + 8) = *dmrs++; + *(out + delta + 10) = *dmrs++; +} + +/* +Data in DMRS symbol for Type 1, NumCDMGroupNoData = 1 and delta 0 (antenna port 0 and 1). +There is no data in DMRS symbol for other scenarios in type 1. +*/ +static void map_data_dmrs_type1_cdm1_rb(const unsigned int num_cdm_no_data, const c16_t *data, c16_t *out) +{ + *(out + 1) = *data++; + *(out + 3) = *data++; + *(out + 5) = *data++; + *(out + 7) = *data++; + *(out + 9) = *data++; + *(out + 11) = *data++; +} + +#define NR_DMRS_TYPE2_CDM_GRP_SIZE 2 +#define NR_DMRS_TYPE2_NUM_CDM_GRP 3 + +/* +Map DMRS for type 2 +Mapping as in TS 38.211 6.4.1.1.3 k = 6n + k^prime + delta +*/ +static void map_dmrs_type2_rb(const unsigned int delta, const c16_t *dmrs, c16_t *out) +{ + memcpy(out + delta, dmrs, sizeof(c16_t) * NR_DMRS_TYPE2_CDM_GRP_SIZE); + out += (NR_DMRS_TYPE2_CDM_GRP_SIZE * NR_DMRS_TYPE2_NUM_CDM_GRP); + dmrs += NR_DMRS_TYPE2_CDM_GRP_SIZE; + memcpy(out + delta, dmrs, sizeof(c16_t) * NR_DMRS_TYPE2_CDM_GRP_SIZE); +} + +/* +Map data for type 2 DMRS +*/ +static void map_data_dmrs_type2_rb(const unsigned int num_cdm_no_data, const c16_t *data, c16_t *out) +{ + unsigned int offset = num_cdm_no_data * NR_DMRS_TYPE2_CDM_GRP_SIZE; + const unsigned int size = (NR_DMRS_TYPE2_NUM_CDM_GRP - num_cdm_no_data) * NR_DMRS_TYPE2_CDM_GRP_SIZE; + memcpy(out + offset, data, sizeof(c16_t) * size); + offset += NR_DMRS_TYPE2_CDM_GRP_SIZE * NR_DMRS_TYPE2_NUM_CDM_GRP; + data += size; + memcpy(out + offset, data, sizeof(c16_t) * size); +} + +/* +Map data and PTRS in RB +*/ +static void map_data_ptrs(const unsigned int ptrsIdx, const c16_t *data, const c16_t *ptrs, c16_t *out) +{ + memcpy(out, data, sizeof(c16_t) * ptrsIdx); + data += ptrsIdx; + *(out + ptrsIdx) = *ptrs; + memcpy(out + ptrsIdx + 1, data, sizeof(c16_t) * NR_NB_SC_PER_RB - ptrsIdx - 1); +} + +/* +Map data only in RB +*/ +static void map_data_rb(const c16_t *data, c16_t *out) +{ + memcpy(out, data, sizeof(c16_t) * NR_NB_SC_PER_RB); +} + +/* +This function is used when a PRB is on both sides of DC. +The destination buffer in this case in not contiguous so REs are mapped on to a temporary buffer +so that we can reuse the existing functions. Then it is copied to the destination buffer. +*/ +static void map_over_dc(const unsigned int right_dc, + const unsigned int num_cdm_no_data, + const unsigned int fft_size, + const unsigned int dmrs_per_rb, + const unsigned int data_per_rb, + const unsigned int delta, + const unsigned int ptrsIdx, + const c16_t **ptrs, + const c16_t **dmrs, + const c16_t **data, + c16_t **out) +{ + // if first RE is DC no need to map in this function + if (right_dc == 0) + return; + + c16_t *out_tmp = *out; + c16_t tmp_out_buf[NR_NB_SC_PER_RB]; + const unsigned int left_dc = NR_NB_SC_PER_RB - right_dc; + /* copy out to temp buffer. incase we want to preserve the REs in the out buffer + as we call mapping of data in DMRS symbol after mapping DMRS REs + */ + memcpy(tmp_out_buf, out_tmp, sizeof(c16_t) * left_dc); + out_tmp -= (fft_size - left_dc); + memcpy(tmp_out_buf + left_dc, out_tmp, sizeof(c16_t) * right_dc); + + /* map on to temp buffer */ + if (dmrs && data) { + map_data_dmrs_ptr(num_cdm_no_data, *data, tmp_out_buf); + *data += data_per_rb; + } else if (dmrs) { + map_dmrs_ptr(delta, *dmrs, tmp_out_buf); + *dmrs += dmrs_per_rb; + } else if (ptrs) { + map_data_ptrs(ptrsIdx, *data, *ptrs, tmp_out_buf); + *data += (NR_NB_SC_PER_RB - 1); + *ptrs += 1; + } else if (data) { + map_data_rb(*data, tmp_out_buf); + *data += NR_NB_SC_PER_RB; + } else { + DevAssert(false); + } + + /* copy back to out buffer */ + out_tmp = *out; + memcpy(out_tmp, tmp_out_buf, sizeof(c16_t) * left_dc); + out_tmp -= (fft_size - left_dc); + memcpy(out_tmp, tmp_out_buf + left_dc, sizeof(c16_t) * right_dc); + out_tmp += right_dc; + *out = out_tmp; +} + +/* +Holds params needed for PUSCH resoruce mapping +*/ +typedef struct { + rnti_t rnti; + unsigned int K_ptrs; + unsigned int k_RE_ref; + unsigned int first_sc_offset; + unsigned int fft_size; + unsigned int num_rb_max; + unsigned int symbols_per_slot; + unsigned int slot; + unsigned int dmrs_scrambling_id; + unsigned int scid; + unsigned int dmrs_port; + int Wt; + int *Wf; + unsigned int dmrs_symb_pos; + unsigned int ptrs_symb_pos; + unsigned int pdu_bit_map; + transformPrecoder_t transform_precoding; + unsigned int bwp_start; + unsigned int start_rb; + unsigned int nb_rb; + unsigned int start_symbol; + unsigned int num_symbols; + pusch_dmrs_type_t dmrs_type; + unsigned int delta; + unsigned int num_cdm_no_data; +} nr_phy_pxsch_params_t; + +/* +Map all REs in one OFDM symbol +This function operation is as follows: +mapping is done on RB basis. if RB contains DC and if DC is in middle +of the RB, then the mapping is done via map_over_dc(). +*/ +static void map_current_symbol(const nr_phy_pxsch_params_t p, + const bool dmrs_symbol, + const bool ptrs_symbol, + const c16_t *dmrs_seq, + const c16_t *ptrs_seq, + const c16_t **data, + c16_t *out) +{ + const unsigned int abs_start_rb = p.bwp_start + p.start_rb; + const unsigned int start_sc = (p.first_sc_offset + abs_start_rb * NR_NB_SC_PER_RB) % p.fft_size; + const unsigned int dc_rb = (p.fft_size - start_sc) / NR_NB_SC_PER_RB; + const unsigned int rb_over_dc = (p.fft_size - start_sc) % NR_NB_SC_PER_RB; + const unsigned int n_cdm = p.num_cdm_no_data; + const c16_t *data_tmp = *data; + /* If current symbol is DMRS symbol */ + if (dmrs_symbol) { + const unsigned int dmrs_per_rb = (p.dmrs_type == pusch_dmrs_type1) ? 6 : 4; + const unsigned int data_per_rb = NR_NB_SC_PER_RB - dmrs_per_rb; + + const c16_t *p_mod_dmrs = dmrs_seq + abs_start_rb * dmrs_per_rb; + c16_t *out_tmp = out + start_sc; + for (unsigned int rb = 0; rb < p.nb_rb; rb++) { + if (rb == dc_rb) { + // map RB at DC + if (rb_over_dc) { + // if DC is in middle of RB, the following function handles it. + map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, NULL, &out_tmp); + continue; + } else { + // else just move the pointer and following function will map the rb + out_tmp -= p.fft_size; + } + } + map_dmrs_ptr(p.delta, p_mod_dmrs, out_tmp); + p_mod_dmrs += dmrs_per_rb; + out_tmp += NR_NB_SC_PER_RB; + } + + /* if there is data in current DMRS symbol, we map it here. */ + if (map_data_dmrs_ptr) { + c16_t *out_tmp = out + start_sc; + for (unsigned int rb = 0; rb < p.nb_rb; rb++) { + if (rb == dc_rb) { + if (rb_over_dc) { + map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, &data_tmp, &out_tmp); + continue; + } else { + out_tmp -= p.fft_size; + } + } + map_data_dmrs_ptr(n_cdm, data_tmp, out_tmp); + data_tmp += data_per_rb; + out_tmp += NR_NB_SC_PER_RB; + } + } + /* If current symbol is a PTRS symbol */ + } else if (ptrs_symbol) { + const unsigned int first_ptrs_re = get_first_ptrs_re(p.rnti, p.K_ptrs, p.nb_rb, p.k_RE_ref) + start_sc; + const unsigned int ptrs_idx_re = (start_sc - first_ptrs_re) % NR_NB_SC_PER_RB; // PTRS RE index within RB + unsigned int non_ptrs_rb = (start_sc - first_ptrs_re) / NR_NB_SC_PER_RB; // number of RBs before the first PTRS RB + int ptrs_idx_rb = -non_ptrs_rb; // RB count to check for PTRS RB + c16_t *out_tmp = out + start_sc; + const c16_t *p_mod_ptrs = ptrs_seq; + /* map data to RBs before the first PTRS RB or if current RB has no PTRS */ + for (unsigned int rb = 0; rb < p.nb_rb; rb++) { + if (rb < non_ptrs_rb || ptrs_idx_rb % p.K_ptrs) { + if (rb == dc_rb) { + if (rb_over_dc) { + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp); + continue; + } else { + out_tmp -= p.fft_size; + } + } + map_data_rb(data_tmp, out_tmp); + data_tmp += NR_NB_SC_PER_RB; + out_tmp += NR_NB_SC_PER_RB; + } else { + if (rb == dc_rb) { + if (rb_over_dc) { + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, ptrs_idx_re, &p_mod_ptrs, NULL, &data_tmp, &out_tmp); + continue; + } else { + out_tmp -= p.fft_size; + } + } + map_data_ptrs(ptrs_idx_re, data_tmp, p_mod_ptrs, out_tmp); + p_mod_ptrs++; // increament once as only one PTRS RE per RB + data_tmp += (NR_NB_SC_PER_RB - 1); + out_tmp += NR_NB_SC_PER_RB; + } + ptrs_idx_rb++; + } + } else { + /* only data in this symbol */ + c16_t *out_tmp = out + start_sc; + for (unsigned int rb = 0; rb < p.nb_rb; rb++) { + if (rb == dc_rb) { + if (rb_over_dc) { + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp); + continue; + } else { + out_tmp -= p.fft_size; + } + } + map_data_rb(data_tmp, out_tmp); + data_tmp += NR_NB_SC_PER_RB; + out_tmp += NR_NB_SC_PER_RB; + } + } + *data = data_tmp; +} + +/* +TS 38.211 table 6.4.1.1.3-1 and 2 +*/ +static void dmrs_amp_mult(const uint32_t dmrs_port, + const int Wt, + const int Wf[2], + const c16_t *mod_dmrs, + c16_t *mod_dmrs_out, + const uint32_t n_dmrs, + const pusch_dmrs_type_t dmrs_type) +{ + /* short array that hold amplitude for k_prime = 0 and k_prime = 1 */ + int32_t alpha_dmrs[2] __attribute((aligned(16))); + for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) { + const int32_t a = Wf[i] * Wt * AMP; + alpha_dmrs[i] = a; + } + + /* multiply amplitude with complex DMRS vector */ + for (int_fast16_t i = 0; i < n_dmrs; i++) { + mod_dmrs_out[i] = c16mulRealShift(mod_dmrs[i], alpha_dmrs[i % 2], 15); + } +} + +/* +Map ULSCH data and DMRS in all of the scheduled symbols and PRBs +*/ +static void map_symbols(const nr_phy_pxsch_params_t p, + const unsigned int slot, + const c16_t *dmrs_seq, + const c16_t *data, + c16_t *out) +{ + // asign the function pointers + if (p.dmrs_type == pusch_dmrs_type1) { + map_dmrs_ptr = map_dmrs_type1_cdm1_rb; + map_data_dmrs_ptr = (p.num_cdm_no_data == 1) ? map_data_dmrs_type1_cdm1_rb : NULL; + } else { + map_dmrs_ptr = map_dmrs_type2_rb; + map_data_dmrs_ptr = (p.num_cdm_no_data < 3) ? map_data_dmrs_type2_rb : NULL; + } + // for all symbols + const unsigned int n_dmrs = (p.bwp_start + p.start_rb + p.nb_rb) * ((p.dmrs_type == pusch_dmrs_type1) ? 6 : 4); + const c16_t *cur_data = data; + for (int l = p.start_symbol; l < p.start_symbol + p.num_symbols; l++) { + const bool dmrs_symbol = is_dmrs_symbol(l, p.dmrs_symb_pos); + const bool ptrs_symbol = is_ptrs_symbol(l, p.ptrs_symb_pos); + c16_t mod_dmrs_amp[ALNARS_16_4(n_dmrs)] __attribute((aligned(16))); + c16_t mod_ptrs_amp[ALNARS_16_4(p.nb_rb)] __attribute((aligned(16))); + const uint32_t *gold = NULL; + if (dmrs_symbol || ptrs_symbol) { + gold = nr_gold_pusch(p.num_rb_max, p.symbols_per_slot, p.dmrs_scrambling_id, p.scid, slot, l); + } + if (dmrs_symbol) { + c16_t mod_dmrs[ALNARS_16_4(n_dmrs)] __attribute((aligned(16))); + if (p.transform_precoding == transformPrecoder_disabled) { + nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs); + dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type); + } else { + dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type); + } + } else if ((p.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && ptrs_symbol) { + AssertFatal(p.transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); + c16_t mod_ptrs[ALNARS_16_4(p.nb_rb)] __attribute((aligned(16))); + nr_modulation(gold, p.nb_rb, DMRS_MOD_ORDER, (int16_t *)mod_ptrs); + const unsigned int beta_ptrs = 1; // temp value until power control is implemented + multadd_complex_vector_real_scalar((int16_t *)mod_ptrs, beta_ptrs * AMP, (int16_t *)mod_ptrs_amp, 1, p.nb_rb); + } + map_current_symbol(p, + dmrs_symbol, + ptrs_symbol, + mod_dmrs_amp, + mod_ptrs_amp, + &cur_data, // increments every symbol + out + l * p.fft_size); + } +} + void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, const unsigned char harq_pid, const uint32_t frame, @@ -95,11 +471,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, { LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); - int Wf[2], Wt[2]; - int l_prime[2], delta; + int l_prime[2]; uint8_t nb_dmrs_re_per_rb; - int i; - int sample_offsetF, N_RE_prime; NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; @@ -143,17 +516,18 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); // TbD num_of_mod_symbols is set but never used - N_RE_prime = NR_NB_SC_PER_RB*number_of_symbols - nb_dmrs_re_per_rb*number_dmrs_symbols - N_PRB_oh; + const uint32_t N_RE_prime = NR_NB_SC_PER_RB * number_of_symbols - nb_dmrs_re_per_rb * number_dmrs_symbols - N_PRB_oh; harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb; /////////////////////////PTRS parameters' initialization///////////////////////// /////////// - uint8_t L_ptrs, K_ptrs = 0; + unsigned int K_ptrs = 0, k_RE_ref = 0; uint32_t unav_res = 0; if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { K_ptrs = pusch_pdu->pusch_ptrs.ptrs_freq_density; - L_ptrs = 1 << pusch_pdu->pusch_ptrs.ptrs_time_density; + k_RE_ref = pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; + uint8_t L_ptrs = 1 << pusch_pdu->pusch_ptrs.ptrs_time_density; ulsch_ue->ptrs_symbols = 0; @@ -197,8 +571,11 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, .oob_event_value = 0}; trace_pdu(&tmp); - if (nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, tb_size, G) == -1) + if (nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, tb_size, G) == -1) { + NR_UL_UE_HARQ_t *harq_process_ulsch = &UE->ul_harq_processes[harq_pid]; + harq_process_ulsch->ULstatus = SCH_IDLE; return; + } /////////// //////////////////////////////////////////////////////////////////// @@ -236,23 +613,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////// //////////////////////////////////////////////////////////////////////// - /////////////////////////DMRS Modulation///////////////////////// - /////////// - - uint16_t n_dmrs = (pusch_pdu->bwp_start + start_rb + nb_rb)*((dmrs_type == pusch_dmrs_type1) ? 6:4); - c16_t mod_dmrs[n_dmrs] __attribute((aligned(16))); - - /////////// - //////////////////////////////////////////////////////////////////////// - - /////////////////////////ULSCH layer mapping///////////////////////// /////////// - const int sz = available_bits / mod_order; - c16_t tx_layers[Nl][sz]; - memset(tx_layers, 0, sizeof(tx_layers)); + const int sz = available_bits / mod_order / Nl; + c16_t ulsch_mod[Nl][sz]; - nr_ue_layer_mapping(d_mod, Nl, available_bits / mod_order, sz, tx_layers); + nr_ue_layer_mapping(d_mod, Nl, sz, ulsch_mod); /////////// //////////////////////////////////////////////////////////////////////// @@ -266,8 +632,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t u = 0, v = 0; c16_t *dmrs_seq = NULL; /// Transform-coded "y"-sequences (for definition see 38-211 V15.3.0 2018-09, subsection 6.3.1.4) - c16_t y[max_num_re] __attribute__((aligned(16))); - memset(y, 0, sizeof(y)); + c16_t ulsch_mod_tp[max_num_re] __attribute__((aligned(16))); + memset(ulsch_mod_tp, 0, sizeof(ulsch_mod_tp)); if (pusch_pdu->transform_precoding == transformPrecoder_enabled) { @@ -292,7 +658,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ continue; - nr_dft(&y[y_offset], &tx_layers[0][y_offset], nb_re_pusch); + nr_dft(&ulsch_mod_tp[y_offset], &ulsch_mod[0][y_offset], nb_re_pusch); y_offset = y_offset + nb_re_pusch; @@ -310,7 +676,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits,mod_order); for (int ll = 0; ll < (available_bits/mod_order); ll++) { - debug_symbols[ll] = ulsch_ue->y[ll]; + debug_symbols[ll] = ulsch_ue->ulsch_mod_tp[ll]; } printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols,number_dmrs_symbols); @@ -318,8 +684,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, nr_idft(&debug_symbols[offset], nb_re_pusch); offset = offset + nb_re_pusch; } - LOG_M("preDFT_all_symbols.m","UE_preDFT", tx_layers[0],number_of_symbols*nb_re_pusch,1,1); - LOG_M("postDFT_all_symbols.m","UE_postDFT", y,number_of_symbols*nb_re_pusch,1,1); + LOG_M("preDFT_all_symbols.m", "UE_preDFT", ulsch_mod[0], number_of_symbols * nb_re_pusch, 1, 1); + LOG_M("postDFT_all_symbols.m", "UE_postDFT", ulsch_mod_tp, number_of_symbols * nb_re_pusch, 1, 1); LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1); LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); #endif @@ -334,157 +700,57 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH RE mapping///////////////////////// /////////// - const int encoded_length = frame_parms->N_RB_UL * 14 * NR_NB_SC_PER_RB * mod_order * Nl; - c16_t tx_precoding[Nl][encoded_length]; + const int slot_sz = frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot; + c16_t tx_precoding[Nl][slot_sz]; memset(tx_precoding, 0, sizeof(tx_precoding)); - for (int nl=0; nl < Nl; nl++) { - uint8_t k_prime = 0; - uint16_t m = 0; - + for (int nl = 0; nl < Nl; nl++) { #ifdef DEBUG_PUSCH_MAPPING printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); #endif - int dmrs_port = get_dmrs_port(nl,pusch_pdu->dmrs_ports); - // DMRS params for this dmrs port + const uint8_t dmrs_port = get_dmrs_port(nl, pusch_pdu->dmrs_ports); + const uint8_t delta = get_delta(dmrs_port, dmrs_type); + int Wt[2]; + int Wf[2]; get_Wt(Wt, dmrs_port, dmrs_type); get_Wf(Wf, dmrs_port, dmrs_type); - delta = get_delta(dmrs_port, dmrs_type); - for (int l=start_symbol; ltransform_precoding == transformPrecoder_enabled) ? ulsch_mod_tp : ulsch_mod[nl]; - uint16_t k = start_sc; - uint16_t n = 0; - uint8_t is_dmrs_sym = 0; - uint8_t is_ptrs_sym = 0; - uint16_t dmrs_idx = 0, ptrs_idx = 0; + nr_phy_pxsch_params_t params = {.rnti = rnti, + .K_ptrs = K_ptrs, + .k_RE_ref = k_RE_ref, + .first_sc_offset = frame_parms->first_carrier_offset, + .fft_size = frame_parms->ofdm_symbol_size, + .num_rb_max = frame_parms->N_RB_UL, + .symbols_per_slot = frame_parms->symbols_per_slot, + .dmrs_scrambling_id = pusch_pdu->ul_dmrs_scrambling_id, + .scid = pusch_pdu->scid, + .dmrs_port = dmrs_port, + .Wt = Wt[l_prime[0]], + .Wf = Wf, + .dmrs_symb_pos = ul_dmrs_symb_pos, + .ptrs_symb_pos = ulsch_ue->ptrs_symbols, + .pdu_bit_map = pusch_pdu->pdu_bit_map, + .transform_precoding = pusch_pdu->transform_precoding, + .bwp_start = pusch_pdu->bwp_start, + .start_rb = start_rb, + .nb_rb = nb_rb, + .start_symbol = start_symbol, + .num_symbols = number_of_symbols, + .dmrs_type = dmrs_type, + .delta = delta, + .num_cdm_no_data = cdm_grps_no_data}; - c16_t mod_ptrs[nb_rb] __attribute((aligned(16))); // assume maximum number of PTRS per pusch allocation + map_symbols(params, slot, dmrs_seq, data, tx_precoding[nl]); - if ((ul_dmrs_symb_pos >> l) & 0x01) { - is_dmrs_sym = 1; - - if (pusch_pdu->transform_precoding == transformPrecoder_disabled){ - - if (dmrs_type == pusch_dmrs_type1) - dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6; - else - dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4; - - // TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part - // Perform this on gold sequence, not required when SC FDMA operation is done, - LOG_D(PHY,"DMRS in symbol %d\n",l); - const uint32_t *gold = nr_gold_pusch(frame_parms->N_RB_UL, - frame_parms->symbols_per_slot, - pusch_pdu->ul_dmrs_scrambling_id, - pusch_pdu->scid, - slot, - l); - nr_modulation(gold, - n_dmrs * 2, - DMRS_MOD_ORDER, - (int16_t *)mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated - } else { - dmrs_idx = 0; - } - } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - - AssertFatal(pusch_pdu->transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); - - if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { - is_ptrs_sym = 1; - const uint32_t *gold = nr_gold_pusch(frame_parms->N_RB_UL, - frame_parms->symbols_per_slot, - pusch_pdu->ul_dmrs_scrambling_id, - pusch_pdu->scid, - slot, - l); - nr_modulation(gold, nb_rb, DMRS_MOD_ORDER, (int16_t *)mod_ptrs); - } - } - - for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) { - uint8_t is_dmrs = 0; - uint8_t is_ptrs = 0; - - sample_offsetF = l*frame_parms->ofdm_symbol_size + k; - - if (is_dmrs_sym) { - if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size)) - is_dmrs = 1; - } else if (is_ptrs_sym) { - is_ptrs = is_ptrs_subcarrier(k, - rnti, - K_ptrs, - nb_rb, - pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, - start_sc, - frame_parms->ofdm_symbol_size); - } - - if (is_dmrs == 1) { - // if transform precoding is enabled - const int tmp = Wt[l_prime[0]] * Wf[k_prime] * AMP; - if (pusch_pdu->transform_precoding == transformPrecoder_enabled) - tx_precoding[nl][sample_offsetF] = c16mulRealShift(dmrs_seq[dmrs_idx], tmp, 15); - else - tx_precoding[nl][sample_offsetF] = c16mulRealShift(mod_dmrs[dmrs_idx], tmp, 15); - -#ifdef DEBUG_PUSCH_MAPPING - printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", - nl, - dmrs_idx, - l, - k, - k_prime, - n, - tx_precoding[nl][sample_offsetF].r, - tx_precoding[nl][sample_offsetF].i); -#endif - - dmrs_idx++; - k_prime++; - k_prime &= 1; - n += (k_prime) ? 0 : 1; - - } else if (is_ptrs == 1) { - uint16_t beta_ptrs = 1; // temp value until power control is implemented - tx_precoding[nl][sample_offsetF] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * AMP, 15); - ptrs_idx++; - } else if (!is_dmrs_sym - || allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) { - if (pusch_pdu->transform_precoding == transformPrecoder_disabled) - tx_precoding[nl][sample_offsetF] = tx_layers[nl][m]; - else - tx_precoding[nl][sample_offsetF] = y[m]; - -#ifdef DEBUG_PUSCH_MAPPING - printf("DATA: layer %d\t m %d\t l %d \t k %d \t tx_precoding: %d %d\n", - nl, - m, - l, - k, - tx_precoding[nl][sample_offsetF].r, - tx_precoding[nl][sample_offsetF].i); -#endif - - m++; - - } else { - tx_precoding[nl][sample_offsetF] = (c16_t){0}; - } - - if (++k >= frame_parms->ofdm_symbol_size) - k -= frame_parms->ofdm_symbol_size; - } // for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) - } // for (l=start_symbol; lofdm_symbol_size + k; - txdataF[ap][re_offset] = nr_layer_precoder(encoded_length, tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); + txdataF[ap][re_offset] = nr_layer_precoder(slot_sz, tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset); if (++k >= frame_parms->ofdm_symbol_size) { k -= frame_parms->ofdm_symbol_size; } diff --git a/openair1/PHY/TOOLS/cmult_sv.c b/openair1/PHY/TOOLS/cmult_sv.c index b1c9de34ba..c20bd24f71 100644 --- a/openair1/PHY/TOOLS/cmult_sv.c +++ b/openair1/PHY/TOOLS/cmult_sv.c @@ -30,27 +30,30 @@ void multadd_complex_vector_real_scalar(int16_t *x, uint8_t zero_flag, uint32_t N) { - simd_q15_t alpha_128,*x_128=(simd_q15_t *)x,*y_128=(simd_q15_t*)y; int n; alpha_128 = set1_int16(alpha); + const uint32_t num_simd_adds = N / 4; + const uint32_t num_adds = N % 4; - if (zero_flag == 1) - for (n=0; n>2; n++) { - // print_shorts("x_128[n]=", &x_128[n]); - // print_shorts("alpha_128", &alpha_128); + if (zero_flag == 1) { + for (n = 0; n < num_simd_adds; n++) { y_128[n] = mulhi_int16(x_128[n],alpha_128); - // print_shorts("y_128[n]=", &y_128[n]); } - - else - for (n=0; n>2; n++) { + for (n = 0; n < num_adds; n++) { + const uint32_t offset = num_simd_adds * 4; + y[offset + n] = (x[offset + n] * alpha) >> 16; + } + } else { + for (n = 0; n < num_simd_adds; n++) { y_128[n] = adds_int16(y_128[n],mulhi_int16(x_128[n],alpha_128)); } - - simde_mm_empty(); - simde_m_empty(); + for (n = 0; n < num_adds; n++) { + const uint32_t offset = num_simd_adds * 4; + y[offset + n] += (x[offset + n] * alpha) >> 16; + } + } } void multadd_real_vector_complex_scalar(const int16_t *x, const int16_t *alpha, int16_t *y, uint32_t N) diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index aa57627362..d219760586 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -52,6 +52,9 @@ extern "C" { #endif +#define ALIGNARRAYSIZE(a, b) (((a + b - 1) / b) * b) +#define ALNARS_16_4(a) ALIGNARRAYSIZE(a, 4) + typedef struct complexd { double r; double i; diff --git a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h index 6c667e3c1d..f89320087c 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h +++ b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h @@ -45,11 +45,13 @@ FN(PHY_RX_PDCCH_STATS),\ FN(DLSCH_PROCEDURES_STATS),\ FN(PHY_PROC_TX),\ + FN(PUSCH_PROC_STATS),\ FN(ULSCH_SEGMENTATION_STATS),\ FN(ULSCH_LDPC_ENCODING_STATS),\ FN(ULSCH_RATE_MATCHING_STATS),\ FN(ULSCH_INTERLEAVING_STATS),\ - FN(ULSCH_ENCODING_STATS) + FN(ULSCH_ENCODING_STATS),\ + FN(OFDM_MOD_STATS) typedef enum { FOREACH_NR_PHY_CPU_MEAS(NOOP), diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 76fbad3f9e..30953f04d7 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -287,21 +287,26 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n start_meas_nr_ue_phy(ue, PHY_PROC_TX); - int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id; - if (ue->ul_harq_processes[harq_pid].ULstatus == ACTIVE) + const int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id; + if (ue->ul_harq_processes[harq_pid].ULstatus == ACTIVE) { + start_meas_nr_ue_phy(ue, PUSCH_PROC_STATS); nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, gNB_id, phy_data, (c16_t **)&txdataF); + stop_meas_nr_ue_phy(ue, PUSCH_PROC_STATS); + } ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF); pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF); LOG_D(PHY, "Sending Uplink data \n"); + start_meas_nr_ue_phy(ue, OFDM_MOD_STATS); nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, &ue->frame_parms, ue->frame_parms.nb_antennas_tx, (c16_t **)txdataF, link_type_ul); + stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS); nr_ue_prach_procedures(ue, proc); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 702e50927c..b4a44f4130 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1421,17 +1421,6 @@ int main(int argc, char *argv[]) errors_decoding++; } } - if (n_trials == 1) { - for (int r = 0; r < UE->ul_harq_processes[harq_pid].C; r++) - for (int i = 0; i < UE->ul_harq_processes[harq_pid].K >> 3; i++) { - if ((UE->ul_harq_processes[harq_pid].c[r][i] ^ ulsch_gNB->harq_process->c[r][i]) != 0) - printf("************"); - /*printf("r %d: in[%d] %x, out[%d] %x (%x)\n",r, - i,UE->ul_harq_processes[harq_pid].c[r][i], - i,ulsch_gNB->harq_process->c[r][i], - UE->ul_harq_processes[harq_pid].c[r][i]^ulsch_gNB->harq_process->c[r][i]);*/ - } - } if (errors_decoding > 0 && error_flag == 0) { n_false_positive++; if (n_trials==1)