Commit ba0d2dae authored by yihongzheng's avatar yihongzheng

fpga_ldpc both decode and encode are OK

parent 3289c89f
......@@ -543,3 +543,490 @@ void clear_pdsch_stats(PHY_VARS_gNB *gNB) {
for (int i=0;i<gNB->number_of_nr_dlsch_max;i++)
memset((void*)&gNB->dlsch_stats[i],0,sizeof(gNB->dlsch_stats[i]));
}
void nr_pdsch_codeword_scrambling_optim_fpga_ldpc(uint8_t *in,
uint32_t size,
uint8_t q,
uint32_t Nid,
uint32_t n_RNTI,
uint32_t* out) {
uint32_t x1, x2, s=0;
uint32_t *pin32;
uint32_t byteSize = size/8;
x2 = (n_RNTI<<15) + (q<<14) + Nid;
s=lte_gold_generic(&x1, &x2, 1);
#if defined(__AVX2__)
//让FPGA输出的每个BYTE中的高低位bit翻转
LOG_D(PHY, "in = %02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n",in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]);
Byte_Reverse_11(in, in, byteSize);
pin32 = (uint32_t *)in;
for(int j = 0; j < (byteSize+3)/4; j++)
{
out[j]=(pin32[j]^s);
s=lte_gold_generic(&x1, &x2, 0);
}
#elif defined(__SSE4__)
uint32_t in32 = 0;
_m128i *in128;
for (int i=0; i<((size>>5)+((size&0x1f) > 0 ? 1 : 0)); i++) {
in128=&((__m128i*)in)[i<<1];
((uint16_t*)&in32)[0] = _mm128_movemask_epi8(_mm256_slli_epi16(in128[0],7));
((uint16_t*)&in32)[1] = _mm128_movemask_epi8(_mm256_slli_epi16(in128[1],7));
out[i]=(in32^s);
s=lte_gold_generic(&x1, &x2, 0);
}
//#elsif defined(__arm__) || defined(__aarch64)
#else
nr_pdsch_codeword_scrambling(in,
size,
q,
Nid,
n_RNTI,
out);
#endif
}
unsigned char Reverse8U(unsigned char x)
{
x = (x & 0xaa) >> 1 | (x & 0x55) << 1;
x = (x & 0xcc) >> 2 | (x & 0x33) << 2;
x = (x & 0xf0) >> 4 | (x & 0x0f) << 4;
return x;
}
void Byte_Reverse_11(unsigned char *Src, unsigned char *Dest, int Length)
{
int BlockSize = 16, Block = Length / BlockSize;
for (int Y = 0; Y < Block * BlockSize; Y += BlockSize)
{
__m128i V = _mm_loadu_si128((__m128i *)(Src + Y));
V = _mm_or_si128(_mm_srli_epi16(_mm_and_si128(V, _mm_set1_epi8(0xaa)), 1), _mm_slli_epi16(_mm_and_si128(V, _mm_set1_epi8(0x55)), 1));
V = _mm_or_si128(_mm_srli_epi16(_mm_and_si128(V, _mm_set1_epi8(0xcc)), 2), _mm_slli_epi16(_mm_and_si128(V, _mm_set1_epi8(0x33)), 2));
V = _mm_or_si128(_mm_srli_epi16(_mm_and_si128(V, _mm_set1_epi8(0xf0)), 4), _mm_slli_epi16(_mm_and_si128(V, _mm_set1_epi8(0x0f)), 4));
_mm_storeu_si128((__m128i *)(Dest + Y), V);
}
for (int Y = Block * BlockSize; Y < Length; Y++)
{
Dest[Y] = Reverse8U(Src[Y]);
}
}
uint8_t nr_generate_pdsch_fpga_ldpc(PHY_VARS_gNB *gNB,
int frame,
int slot) {
NR_gNB_DLSCH_t *dlsch;
uint32_t ***pdsch_dmrs = gNB->nr_gold_pdsch_dmrs[slot];
int32_t** txdataF = gNB->common_vars.txdataF;
int16_t amp = AMP;
int xOverhead = 0;
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
time_stats_t *dlsch_encoding_stats=&gNB->dlsch_encoding_stats;
time_stats_t *dlsch_scrambling_stats=&gNB->dlsch_scrambling_stats;
time_stats_t *dlsch_modulation_stats=&gNB->dlsch_modulation_stats;
time_stats_t *tinput=&gNB->tinput;
time_stats_t *tprep=&gNB->tprep;
time_stats_t *tparity=&gNB->tparity;
time_stats_t *toutput=&gNB->toutput;
time_stats_t *dlsch_rate_matching_stats=&gNB->dlsch_rate_matching_stats;
time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats;
time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats;
for (int dlsch_id=0;dlsch_id<gNB->number_of_nr_dlsch_max;dlsch_id++) {
dlsch = gNB->dlsch[dlsch_id][0];
if (dlsch->slot_tx[slot] == 0) continue;
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5];
int16_t **mod_symbs = (int16_t**)dlsch->mod_symbs;
int16_t **tx_layers = (int16_t**)dlsch->txdataF;
int16_t **txdataF_precoding = (int16_t**)dlsch->txdataF_precoding;
int8_t Wf[2], Wt[2], l0, l_prime, l_overline, delta;
uint8_t dmrs_Type = rel15->dmrsConfigType;
int nb_re_dmrs;
uint16_t n_dmrs;
if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) {
nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
}
else {
nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
}
n_dmrs = (rel15->BWPStart+rel15->rbStart+rel15->rbSize)*nb_re_dmrs;
uint16_t dmrs_symbol_map = rel15->dlDmrsSymbPos;//single DMRS: 010000100 Double DMRS 110001100
uint8_t dmrs_len = get_num_dmrs(rel15->dlDmrsSymbPos);
uint16_t nb_re = ((12*rel15->NrOfSymbols)-nb_re_dmrs*dmrs_len-xOverhead)*rel15->rbSize*rel15->nrOfLayers;
uint8_t Qm = rel15->qamModOrder[0];
uint32_t encoded_length = nb_re*Qm;
int16_t mod_dmrs[n_dmrs<<1] __attribute__ ((aligned(16)));
/* PTRS */
uint16_t beta_ptrs = 1;
uint8_t ptrs_symbol = 0;
uint16_t dlPtrsSymPos = 0;
uint16_t n_ptrs = 0;
uint16_t ptrs_idx = 0;
uint8_t is_ptrs_re = 0;
if(rel15->pduBitmap & 0x1) {
set_ptrs_symb_idx(&dlPtrsSymPos,
rel15->NrOfSymbols,
rel15->StartSymbolIndex,
1<<rel15->PTRSTimeDensity,
rel15->dlDmrsSymbPos);
n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1)/rel15->PTRSFreqDensity;
}
int16_t mod_ptrs[n_ptrs<<1] __attribute__ ((aligned(16)));
/// CRC, coding, interleaving and rate matching
AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
start_meas(dlsch_encoding_stats);
nr_dlsch_encoding_fpga_ldpc(gNB,
harq->pdu, frame, slot, dlsch, frame_parms,tinput,tprep,tparity,toutput,
dlsch_rate_matching_stats,
dlsch_interleaving_stats,
dlsch_segmentation_stats);
stop_meas(dlsch_encoding_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH encoding:\nPayload:\n");
for (int i=0; i<harq->B>>7; i++) {
for (int j=0; j<16; j++)
printf("0x%02x\t", harq->pdu[(i<<4)+j]);
printf("\n");
}
printf("\nEncoded payload:\n");
for (int i=0; i<encoded_length>>3; i++) {
for (int j=0; j<8; j++)
printf("%d", harq->f[(i<<3)+j]);
printf("\t");
}
printf("\n");
#endif
/// scrambling
start_meas(dlsch_scrambling_stats);
for (int q=0; q<rel15->NrOfCodewords; q++)
memset((void*)scrambled_output[q], 0, (encoded_length>>5)*sizeof(uint32_t));
for (int q=0; q<rel15->NrOfCodewords; q++)
nr_pdsch_codeword_scrambling_optim_fpga_ldpc(harq->f,
encoded_length,
q,
rel15->dlDmrsScramblingId,
rel15->rnti,
scrambled_output[q]);
stop_meas(dlsch_scrambling_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH scrambling:\n");
for (int i=0; i<encoded_length>>8; i++) {
for (int j=0; j<8; j++)
printf("0x%08x\t", scrambled_output[0][(i<<3)+j]);
printf("\n");
}
#endif
/// Modulation
start_meas(dlsch_modulation_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 1);
for (int q=0; q<rel15->NrOfCodewords; q++)
nr_modulation(scrambled_output[q],
encoded_length,
Qm,
mod_symbs[q]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
stop_meas(dlsch_modulation_stats);
#ifdef DEBUG_DLSCH
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
for (int i=0; i<nb_re>>3; i++) {
for (int j=0; j<8; j++) {
printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]);
}
printf("\n");
}
#endif
/// Layer mapping
nr_layer_mapping(mod_symbs,
rel15->nrOfLayers,
nb_re,
tx_layers);
#ifdef DEBUG_DLSCH
printf("Layer mapping (%d layers):\n", rel15->nrOfLayers);
for (int l=0; l<rel15->nrOfLayers; l++)
for (int i=0; i<(nb_re/rel15->nrOfLayers)>>3; i++) {
printf("layer %d, Re %d..%d : ",l,i<<3,(i<<3)+7);
for (int j=0; j<8; j++) {
printf("l%d %d\t", tx_layers[l][((i<<3)+j)<<1], tx_layers[l][(((i<<3)+j)<<1)+1]);
}
printf("\n");
}
#endif
/// Resource mapping
// Non interleaved VRB to PRB mapping
uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart+rel15->BWPStart)*NR_NB_SC_PER_RB;
if (start_sc >= frame_parms->ofdm_symbol_size)
start_sc -= frame_parms->ofdm_symbol_size;
int txdataF_offset = (slot%2)*frame_parms->samples_per_slot_wCP;
#ifdef DEBUG_DLSCH_MAPPING
printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n",
start_sc, rel15->StartSymbolIndex, rel15->rbSize, nb_re,rel15->nrOfLayers);
#endif
for (int ap=0; ap<rel15->nrOfLayers; ap++) {
// DMRS params for this ap
get_Wt(Wt, ap, dmrs_Type);
get_Wf(Wf, ap, dmrs_Type);
delta = get_delta(ap, dmrs_Type);
l_prime = 0; // single symbol ap 0
l0 = get_l0(rel15->dlDmrsSymbPos);
l_overline = l0;
#ifdef DEBUG_DLSCH_MAPPING
uint8_t dmrs_symbol = l0+l_prime;
printf("DMRS Type %d params for ap %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
1+dmrs_Type,ap, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime, l0, dmrs_symbol);
#endif
uint16_t m=0, dmrs_idx=0;
// Loop Over OFDM symbols:
for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
/// DMRS QPSK modulation
uint8_t k_prime=0;
uint16_t n=0;
if ((dmrs_symbol_map & (1 << l))){ // DMRS time occasion
// The reference point for is subcarrier 0 of the lowest-numbered resource block in CORESET 0 if the corresponding
// PDCCH is associated with CORESET 0 and Type0-PDCCH common search space and is addressed to SI-RNTI
// 3GPP TS 38.211 V15.8.0 Section 7.4.1.1.2 Mapping to physical resources
if (rel15->rnti==SI_RNTI) {
if (dmrs_Type==NFAPI_NR_DMRS_TYPE1) {
dmrs_idx = rel15->rbStart*6;
} else {
dmrs_idx = rel15->rbStart*4;
}
} else {
if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) {
dmrs_idx = (rel15->rbStart+rel15->BWPStart)*6;
} else {
dmrs_idx = (rel15->rbStart+rel15->BWPStart)*4;
}
}
}
// Update l_prime in the case of double DMRS config
if ((dmrs_symbol_map & (1 << l))){ //DMRS time occasion
if (l==(l_overline+1)) //take into account the double DMRS symbols
l_prime = 1;
else if (l>(l_overline+1)) {//new DMRS pair
l_overline = l;
l_prime = 0;
}
}
/// DMRS QPSK modulation
if (rel15->dlDmrsSymbPos & (1 << l)) {
nr_modulation(pdsch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
#ifdef DEBUG_DLSCH
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l, n_dmrs, dmrs_Type);
for (int i=0; i<n_dmrs>>4; i++) {
for (int j=0; j<8; j++) {
printf("%d %d\t", mod_dmrs[((i<<3)+j)<<1], mod_dmrs[(((i<<3)+j)<<1)+1]);
}
printf("\n");
}
#endif
}
/* calculate if current symbol is PTRS symbols */
ptrs_idx = 0;
if(rel15->pduBitmap & 0x1) {
ptrs_symbol = is_ptrs_symbol(l,dlPtrsSymPos);
if(ptrs_symbol) {
/* PTRS QPSK Modulation for each OFDM symbol in a slot */
nr_modulation(pdsch_dmrs[l][0], (n_ptrs<<1), DMRS_MOD_ORDER, mod_ptrs);
}
}
uint16_t k = start_sc;
// Loop Over SCs:
for (int i=0; i<rel15->rbSize*NR_NB_SC_PER_RB; i++) {
/* check if cuurent RE is PTRS RE*/
is_ptrs_re=0;
/* check for PTRS symbol and set flag for PTRS RE */
if(ptrs_symbol){
is_ptrs_re = is_ptrs_subcarrier(k,
rel15->rnti,
ap,
rel15->dmrsConfigType,
rel15->PTRSFreqDensity,
rel15->rbSize,
rel15->PTRSReOffset,
start_sc,
frame_parms->ofdm_symbol_size);
}
/* Map DMRS Symbol */
if ( ( dmrs_symbol_map & (1 << l) ) && (k == ((start_sc+get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type))%(frame_parms->ofdm_symbol_size)))) {
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (Wt[l_prime]*Wf[k_prime]*amp*mod_dmrs[dmrs_idx<<1]) >> 15;
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (Wt[l_prime]*Wf[k_prime]*amp*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
#ifdef DEBUG_DLSCH_MAPPING
printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
dmrs_idx, l, k, k_prime, n, txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
#endif
dmrs_idx++;
k_prime++;
k_prime&=1;
n+=(k_prime)?0:1;
}
/* Map PTRS Symbol */
else if(is_ptrs_re){
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (beta_ptrs*amp*mod_ptrs[ptrs_idx<<1]) >> 15;
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (beta_ptrs*amp*mod_ptrs[(ptrs_idx<<1) + 1])>> 15;
#ifdef DEBUG_DLSCH_MAPPING
printf("ptrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
ptrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
#endif
ptrs_idx++;
}
/* Map DATA Symbol */
else if( (!(dmrs_symbol_map & (1 << l))) || allowed_xlsch_re_in_dmrs_symbol(k,start_sc,frame_parms->ofdm_symbol_size,rel15->numDmrsCdmGrpsNoData,dmrs_Type)) {
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (amp * tx_layers[ap][m<<1]) >> 15;
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (amp * tx_layers[ap][(m<<1) + 1]) >> 15;
#ifdef DEBUG_DLSCH_MAPPING
printf("m %d\t l %d \t k %d \t txdataF: %d %d\n",
m, l, k, txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
#endif
m++;
}
/* mute RE */
else {
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = 0;
txdataF_precoding[ap][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = 0;
}
if (++k >= frame_parms->ofdm_symbol_size)
k -= frame_parms->ofdm_symbol_size;
} //RE loop
} // symbol loop
}// layer loop
///Layer Precoding and Antenna port mapping
// tx_layers 1-8 are mapped on antenna ports 1000-1007
// The precoding info is supported by nfapi such as num_prgs, prg_size, prgs_list and pm_idx
// The same precoding matrix is applied on prg_size RBs, Thus
// pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1
// The Precoding matrix:
// The Codebook Type I and Type II are not supported yet.
// We adopt the precoding matrices of PUSCH for 4 layers.
for (int ap=0; ap<frame_parms->nb_antennas_tx; ap++) {
for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
uint16_t k = start_sc;
for (int rb=0; rb<rel15->rbSize; rb++) {
//get pmi info
uint8_t pmi;
if (rel15->precodingAndBeamforming.prg_size > 0)
pmi = rel15->precodingAndBeamforming.prgs_list[(int)rb/rel15->precodingAndBeamforming.prg_size].pm_idx;
else
pmi = 0;//no precoding
if (pmi == 0) {//unitary Precoding
if(ap<rel15->nrOfLayers)
memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
(void*)&txdataF_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + txdataF_offset+ k)],
NR_NB_SC_PER_RB*sizeof(int32_t));
else
memset((void*)&txdataF[ap][rel15->StartSymbolIndex*frame_parms->ofdm_symbol_size + txdataF_offset +k],
0,
NR_NB_SC_PER_RB*sizeof(int32_t));
k += NR_NB_SC_PER_RB;
if (k >= frame_parms->ofdm_symbol_size) {
k -= frame_parms->ofdm_symbol_size;
}
}
else {
//get the precoding matrix weights:
char *W_prec;
switch (frame_parms->nb_antennas_tx) {
case 1://1 antenna port
W_prec = nr_W_1l_2p[pmi][ap];
break;
case 2://2 antenna ports
if (rel15->nrOfLayers == 1)//1 layer
W_prec = nr_W_1l_2p[pmi][ap];
else//2 layers
W_prec = nr_W_2l_2p[pmi][ap];
break;
case 4://4 antenna ports
if (rel15->nrOfLayers == 1)//1 layer
W_prec = nr_W_1l_4p[pmi][ap];
else if (rel15->nrOfLayers == 2)//2 layers
W_prec = nr_W_2l_4p[pmi][ap];
else if (rel15->nrOfLayers == 3)//3 layers
W_prec = nr_W_3l_4p[pmi][ap];
else//4 layers
W_prec = nr_W_4l_4p[pmi][ap];
break;
default:
LOG_D(PHY,"Precoding 1,2, or 4 antenna ports are currently supported\n");
W_prec = nr_W_1l_2p[pmi][ap];
break;
}
for (int i=0; i<NR_NB_SC_PER_RB; i++) {
int32_t re_offset = l*frame_parms->ofdm_symbol_size + k;
int32_t precodatatx_F = nr_layer_precoder(txdataF_precoding, W_prec, rel15->nrOfLayers, re_offset+txdataF_offset);
((int16_t*)txdataF[ap])[(re_offset<<1) + (2*txdataF_offset)] = ((int16_t *) &precodatatx_F)[0];
((int16_t*)txdataF[ap])[(re_offset<<1) + 1 + (2*txdataF_offset)] = ((int16_t *) &precodatatx_F)[1];
#ifdef DEBUG_DLSCH_MAPPING
printf("antenna %d\t l %d \t k %d \t txdataF: %d %d\n",
ap, l, k, ((int16_t*)txdataF[ap])[(re_offset<<1) + (2*txdataF_offset)],
((int16_t*)txdataF[ap])[(re_offset<<1) + 1 + (2*txdataF_offset)]);
#endif
if (++k >= frame_parms->ofdm_symbol_size) {
k -= frame_parms->ofdm_symbol_size;
}
}
}
} //RB loop
} // symbol loop
}// port loop
dlsch->slot_tx[slot]=0;
// TODO: handle precoding
// this maps the layers onto antenna ports
// handle beamforming ID
// each antenna port is assigned a beam_index
// since PHY can only handle BF on slot basis we set the whole slot
// first check if this slot has not already been allocated to another beam
if (gNB->common_vars.beam_id[0][slot*frame_parms->symbols_per_slot]==255) {
for (int j=0;j<frame_parms->symbols_per_slot;j++)
gNB->common_vars.beam_id[0][slot*frame_parms->symbols_per_slot+j] = rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
}
else {
LOG_D(PHY,"beam index for PDSCH allocation already taken\n");
}
}// dlsch loop
return 0;
}
\ No newline at end of file
......@@ -102,4 +102,34 @@ void dump_pdsch_stats(PHY_VARS_gNB *gNB);
void clear_pdsch_stats(PHY_VARS_gNB *gNB);
int nr_dlsch_encoding_fpga_ldpc(PHY_VARS_gNB *gNB,
unsigned char *a,int frame,
uint8_t slot,
NR_gNB_DLSCH_t *dlsch,
NR_DL_FRAME_PARMS* frame_parms,
time_stats_t *tinput,
time_stats_t *tprep,
time_stats_t *tparity,
time_stats_t *toutput,
time_stats_t *dlsch_rate_matching_stats,
time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats);
void dl_find_iLS_lsIndex(unsigned int *LDPC_lifting_size, uint32_t *iLS_out, uint32_t *lsIndex_out);
void nr_pdsch_codeword_scrambling_optim_fpga_ldpc(uint8_t *in,
uint32_t size,
uint8_t q,
uint32_t Nid,
uint32_t n_RNTI,
uint32_t* out);
unsigned char Reverse8U(unsigned char x);
void Byte_Reverse_11(unsigned char *Src, unsigned char *Dest, int Length);
uint8_t nr_generate_pdsch_fpga_ldpc(PHY_VARS_gNB *gNB,
int frame,
int slot);
#endif
......@@ -462,3 +462,197 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
return 0;
}
//FPGA加速,删除了部分OAI中的encode函数
int nr_dlsch_encoding_fpga_ldpc(PHY_VARS_gNB *gNB,
unsigned char *a,
int frame,
uint8_t slot,
NR_gNB_DLSCH_t *dlsch,
NR_DL_FRAME_PARMS* frame_parms,
time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput,
time_stats_t *dlsch_rate_matching_stats,time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats)
{
unsigned int G;
NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
uint16_t nb_rb = rel15->rbSize;
uint8_t nb_symb_sch = rel15->NrOfSymbols;
uint32_t A = 0;
uint32_t *Zc = &dlsch->harq_process.Z;
uint8_t mod_order = rel15->qamModOrder[0];
uint16_t r = 0;
uint8_t nb_re_dmrs = 0;
if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1)
nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
else
nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
uint16_t length_dmrs = get_num_dmrs(rel15->dlDmrsSymbPos);
uint16_t R=rel15->targetCodeRate[0];
float Coderate = 0.0;
EncodeInHeadStruct EncodeHead;
uint8_t *pEnDataIn = NULL;
uint8_t *pEnDataOut = NULL;
uint32_t iLS = 0;
uint32_t lsIndex = 0;
uint32_t dl_E0 = 0, dl_E1 = 0;
pEnDataIn = a;
pEnDataOut = harq->f;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN);
A = rel15->TBSize[0]<<3;
NR_gNB_SCH_STATS_t *stats=NULL;
int first_free=-1;
for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++) {
if (gNB->dlsch_stats[i].rnti == 0 && first_free == -1) {
first_free = i;
stats=&gNB->dlsch_stats[i];
}
if (gNB->dlsch_stats[i].rnti == dlsch->rnti) {
stats=&gNB->dlsch_stats[i];
break;
}
}
if (stats) {
stats->rnti = dlsch->rnti;
stats->total_bytes_tx += rel15->TBSize[0];
stats->current_RI = rel15->nrOfLayers;
stats->current_Qm = rel15->qamModOrder[0];
}
G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs,mod_order,rel15->nrOfLayers);
LOG_D(PHY,"dlsch coding A %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n", A,G, nb_rb,nb_symb_sch,nb_re_dmrs,length_dmrs,mod_order);
if (A > 3824)
{
harq->B = A+24;
}
else
{
harq->B = A+16;
}
if (R<1000)
Coderate = (float) R /(float) 1024;
else // to scale for mcs 20 and 26 in table 5.1.3.1-2 which are decimal and input 2* in nr_tbs_tools
Coderate = (float) R /(float) 2048;
if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25)
harq->BG = 2;
else
harq->BG = 1;
start_meas(dlsch_segmentation_stats);
nr_segmentation(NULL, NULL, harq->B, &harq->C, &harq->K, Zc, &harq->F, harq->BG);
stop_meas(dlsch_segmentation_stats);
//FPGA加速的头部
//word 0
EncodeHead.pktType = 0x12;
EncodeHead.rsv0 = 0x00;
EncodeHead.chkCode = 0xFAFA;
//word 1
EncodeHead.rsv1 = 0x0000;
//word 2
EncodeHead.rsv2 = 0x0;
EncodeHead.sectorId = 0x0;
//=0表示单小区
EncodeHead.rsv3 = 0x0;
//word 3
EncodeHead.sfn = frame;
EncodeHead.rsv4 = 0x0;
EncodeHead.slotNum = slot;
EncodeHead.subfn = EncodeHead.slotNum/2;
EncodeHead.pduIdx = 0x0;
//=0表示第一个码字,总共一个码字
EncodeHead.rev5 = 0x0;
//word 4
EncodeHead.tbSizeB = rel15->TBSize[0];
EncodeHead.pktLen = 32+((EncodeHead.tbSizeB+32-1)/32)*32;
//Byte,pktLen=encoder header(32byte)+ tbszie (byte),并且32Byte对齐,是32的整数倍
EncodeHead.rev6 = 0x0;
EncodeHead.lastTb = 0x1;
EncodeHead.firstTb = 0x1;
//=1表示本slot只有一个TB
EncodeHead.rev7 = 0x0;
EncodeHead.cbNum = harq->C;
//word 5
EncodeHead.qm = rel15->qamModOrder[0]/2;
//规定是BPSK qm=0,QPSK qm=1,其他floor(调制阶数/2);OAI的Qm为2/4/6/8
EncodeHead.rev8 = 0x0;
EncodeHead.fillbit = harq->F;
EncodeHead.rev9 = 0x0;
if( EncodeHead.cbNum == 1){
EncodeHead.kpInByte = ((harq->B)/ EncodeHead.cbNum)>>3;
}
else{
EncodeHead.kpInByte = ((harq->B+(( EncodeHead.cbNum)*24))/ EncodeHead.cbNum)>>3;
}
EncodeHead.rev10 = 0x0;
//word 6
EncodeHead.gamma = EncodeHead.cbNum - (G/(rel15->nrOfLayers*(2*EncodeHead.qm)))%EncodeHead.cbNum;
//=1表示本slot只有一个TB
EncodeHead.rev11 = 0x0;
EncodeHead.rvIdx = rel15->rvIndex[0];
EncodeHead.rev12 = 0x0;
//查找iLS和lfSizeIx
dl_find_iLS_lsIndex(Zc, &iLS, &lsIndex);
EncodeHead.iLs = iLS;
EncodeHead.lfSizeIx = lsIndex;
EncodeHead.rev13 = 0x0;
// EncodeHead.iLs = *iLS_out;
EncodeHead.bg = harq->BG-1; //规定选择协议base grape1 bg=0; base grape2 bg=1;OAI的BG大了1
if( EncodeHead.bg == 0){
EncodeHead.codeRate = 46;
}
else{
EncodeHead.codeRate = 42;
}
//word 7
//计算并获得e0和e1
nr_get_E0_E1(G, harq->C, mod_order, rel15->nrOfLayers, r, &dl_E0, &dl_E1);
EncodeHead.e0 = dl_E0;
EncodeHead.e1 = dl_E1;
//调用FPGA的.so中的编码函数
encoder_load( &EncodeHead, pEnDataIn, pEnDataOut );
LOG_D(PHY,"encoder_load_OK!\n");
//LOG_M("pEnDataOut.m","pEnDataOut", pEnDataOut, G+32, 1, 9);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_OUT);
return 0;
}
void dl_find_iLS_lsIndex(unsigned int *LDPC_lifting_size, uint32_t *iLS_out, uint32_t *lsIndex_out)
{
unsigned int Set_of_LDPC_lifting_size[8][8] = {
{2,4,8,16,32,64,128,256},
{3,6,12,24,48,96,192,384},
{5,10,20,40,80,160,320},
{7,14,28,56,112,224},
{9,18,36,72,144,288},
{11,22,44,88,176,352},
{13,26,52,104,208},
{15,30,60,120,240}};
uint32_t iLS,lsIndex;
for(iLS = 0; iLS < 8; iLS++) {
for(lsIndex = 0; lsIndex < 8; lsIndex++){
if(*LDPC_lifting_size == Set_of_LDPC_lifting_size[iLS][lsIndex]){
*iLS_out = iLS;
*lsIndex_out = lsIndex;
}
}
}
}
\ No newline at end of file
......@@ -815,6 +815,7 @@ uint32_t nr_ulsch_decoding_fpga_ldpc(PHY_VARS_gNB *phy_vars_gNB,
//调用FPGA的decode,并输出CRC
// clock_gettime( CLOCK_REALTIME, &decode_start );
decoder_load( &DecodeHead, pDeDataIn, pDeDataOut, pcrc );
LOG_D(PHY," decoder_load_OK\n");
// clock_gettime( CLOCK_REALTIME, &decode_stop );
if (*pcrc == 1) {
LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for slot %d TBS %d\n",
......@@ -825,6 +826,7 @@ uint32_t nr_ulsch_decoding_fpga_ldpc(PHY_VARS_gNB *phy_vars_gNB,
LOG_D(PHY, "ULSCH received ok \n");
nr_fill_indication(phy_vars_gNB,harq_process->frame, harq_process->slot, ULSCH_id, harq_pid, 0);
LOG_D(PHY,"crc = 1!\n");
} else {
LOG_D(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d) r %d\n",
......
......@@ -194,6 +194,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1);
LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", gNB->num_pdsch_rnti[slot],frame,slot);
nr_generate_pdsch(gNB,frame, slot);
// nr_generate_pdsch_fpga_ldpc(gNB,frame, slot); //上面是OAI的代码,fpga_ldpc的encode切换到该行即可
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0);
}
......@@ -699,7 +700,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
//LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX,1);
nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid);
// nr_ulsch_procedures_fpga_ldpc(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); //上面是OAI的代码,pga_ldpc的decode切换到该行即可
// nr_ulsch_procedures_fpga_ldpc(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); //上面是OAI的代码,fpga_ldpc的decode切换到该行即可
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX,0);
break;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment