Commit 3bd7cd2d authored by laurent's avatar laurent

initial

parent 91dd7ed4
......@@ -1825,6 +1825,7 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
# lte-softmodem is both eNB and UE implementation
###################################################
include_directories (${OPENAIR_TARGETS}/tcri)
add_executable(lte-softmodem
${rrc_h}
${s1ap_h}
......@@ -1849,6 +1850,7 @@ add_executable(lte-softmodem
${T_SOURCE}
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
${OPENAIR_TARGETS}/tcri/thread-pool.c
)
target_link_libraries (lte-softmodem
......@@ -2323,3 +2325,10 @@ ADD_CUSTOM_TARGET(oarf
DEPENDS ${OCT_FILES}
)
add_executable(test_tcri
${OPENAIR_TARGETS}/tcri/thread-pool.c
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
)
target_compile_definitions(test_tcri PRIVATE TESTMAIN)
target_link_libraries(test_tcri pthread PHY UTIL ${ITTI_LIB} LFDS config rt dl)
......@@ -463,7 +463,21 @@ int32_t rate_matching_lte(uint32_t N_coded,
uint8_t *inPtr,
uint32_t off);
typedef uint8_t (turboDecoder)(int16_t *y,
uint8_t *,
uint16_t,
uint16_t,
uint16_t,
uint8_t,
uint8_t,
uint8_t,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *);
/*!
\brief This routine performs max-logmap detection for the 3GPP turbo code (with termination). It is optimized for SIMD processing and 16-bit
LLR arithmetic, and requires SSE2,SSSE3 and SSE4.1 (gcc >=4.3 and appropriate CPU)
......@@ -477,21 +491,7 @@ LLR arithmetic, and requires SSE2,SSSE3 and SSE4.1 (gcc >=4.3 and appropriate CP
@param F Number of filler bits at start of packet
@returns number of iterations used (this is 1+max if incorrect crc or if crc_len=0)
*/
uint8_t phy_threegpplte_turbo_decoder16(int16_t *y,
uint8_t *decoded_bytes,
uint16_t n,
uint16_t interleaver_f1,
uint16_t interleaver_f2,
uint8_t max_iterations,
uint8_t crc_type,
uint8_t F,
time_stats_t *init_stats,
time_stats_t *alpha_stats,
time_stats_t *beta_stats,
time_stats_t *gamma_stats,
time_stats_t *ext_stats,
time_stats_t *intl1_stats,
time_stats_t *intl2_stats);
turboDecoder phy_threegpplte_turbo_decoder16;
uint8_t phy_threegpplte_turbo_decoder16avx2(int16_t *y,
int16_t *y2,
......@@ -524,21 +524,7 @@ LLR arithmetic, and requires SSE2,SSSE3 and SSE4.1 (gcc >=4.3 and appropriate CP
@param F Number of filler bits at start of packet
@returns number of iterations used (this is 1+max if incorrect crc or if crc_len=0)
*/
uint8_t phy_threegpplte_turbo_decoder8(int16_t *y,
uint8_t *decoded_bytes,
uint16_t n,
uint16_t interleaver_f1,
uint16_t interleaver_f2,
uint8_t max_iterations,
uint8_t crc_type,
uint8_t F,
time_stats_t *init_stats,
time_stats_t *alpha_stats,
time_stats_t *beta_stats,
time_stats_t *gamma_stats,
time_stats_t *ext_stats,
time_stats_t *intl1_stats,
time_stats_t *intl2_stats);
turboDecoder phy_threegpplte_turbo_decoder8;
uint8_t phy_threegpplte_turbo_decoder_scalar(int16_t *y,
uint8_t *decoded_bytes,
......
......@@ -155,7 +155,7 @@ typedef struct {
/// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18)
uint8_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32)));
/// Turbo-code outputs (36-212 V8.6 2009-03, p.12
uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))];
//uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))];
/// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17)
uint8_t w[MAX_NUM_DLSCH_SEGMENTS][3*6144];
/// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9)
......@@ -461,7 +461,7 @@ typedef struct {
/// Pointer to the payload
uint8_t *b;
/// Pointers to transport block segments
uint8_t *c[MAX_NUM_ULSCH_SEGMENTS];
//uint8_t *c[MAX_NUM_ULSCH_SEGMENTS];
/// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15)
uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS];
/// Current Number of Symbols
......@@ -477,9 +477,12 @@ typedef struct {
/// 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)];
/// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15)
int16_t *d[MAX_NUM_ULSCH_SEGMENTS];
//int16_t *d[MAX_NUM_ULSCH_SEGMENTS];
/// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9)
uint32_t C;
uint32_t processedSegments;
uint32_t processedBadSegment;
/// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10)
uint32_t Cminus;
/// Number of "large" code segments (for definition see 36-212 V8.6 2009-03, p.10)
......
......@@ -96,11 +96,6 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch)
free16(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768);
dlsch->harq_processes[i]->c[r] = NULL;
}
if (dlsch->harq_processes[i]->d[r]) {
free16(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144)));
dlsch->harq_processes[i]->d[r] = NULL;
}
}
free16(dlsch->harq_processes[i],sizeof(LTE_DL_eNB_HARQ_t));
dlsch->harq_processes[i] = NULL;
......@@ -117,7 +112,7 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_
{
LTE_eNB_DLSCH_t *dlsch;
unsigned char exit_flag = 0,i,j,r,aa,layer;
unsigned char exit_flag = 0,i,r,aa,layer;
int re;
unsigned char bw_scaling =1;
......@@ -191,19 +186,12 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS/bw_scaling; r++) {
// account for filler in first segment and CRCs for multiple segment case
dlsch->harq_processes[i]->c[r] = (uint8_t*)malloc16(((r==0)?8:0) + 3+ 768);
dlsch->harq_processes[i]->d[r] = (uint8_t*)malloc16((96+12+3+(3*6144)));
if (dlsch->harq_processes[i]->c[r]) {
bzero(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+ 768);
} else {
printf("Can't get c\n");
exit_flag=2;
}
if (dlsch->harq_processes[i]->d[r]) {
bzero(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144)));
} else {
printf("Can't get d\n");
exit_flag=2;
}
}
}
} else {
......@@ -215,14 +203,6 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_
if (exit_flag==0) {
for (i=0; i<Mdlharq; i++) {
dlsch->harq_processes[i]->round=0;
for (j=0; j<96; j++)
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS/bw_scaling; r++) {
// printf("dlsch->harq_processes[%d]->d[%d] %p\n",i,r,dlsch->harq_processes[i]->d[r]);
if (dlsch->harq_processes[i]->d[r])
dlsch->harq_processes[i]->d[r][j] = LTE_NULL;
}
}
return(dlsch);
......@@ -241,26 +221,21 @@ void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch)
{
unsigned char Mdlharq;
unsigned char i,j,r;
if (dlsch) {
Mdlharq = dlsch->Mdlharq;
dlsch->rnti = 0;
dlsch->active = 0;
for (i=0; i<10; i++)
for (int i=0; i<10; i++)
dlsch->harq_ids[i] = Mdlharq;
for (i=0; i<Mdlharq; i++) {
for (int i=0; i<Mdlharq; i++) {
if (dlsch->harq_processes[i]) {
// dlsch->harq_processes[i]->Ndi = 0;
dlsch->harq_processes[i]->status = 0;
dlsch->harq_processes[i]->round = 0;
for (j=0; j<96; j++)
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS; r++)
if (dlsch->harq_processes[i]->d[r])
dlsch->harq_processes[i]->d[r][j] = LTE_NULL;
}
}
......@@ -309,17 +284,20 @@ int dlsch_encoding_2threads0(te_params *tep) {
}
uint8_t tmp[96+12+3+3*6144]= {0};
for (int j=0; j<96; j++)
tmp[j] = LTE_NULL;
threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r],
Kr>>3,
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
(r==0) ? dlsch->harq_processes[harq_pid]->F : 0,
f1f2mat_old[iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14)
);
dlsch->harq_processes[harq_pid]->RTC[r] =
sub_block_interleaving_turbo(4+(Kr_bytes*8),
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
dlsch->harq_processes[harq_pid]->w[r]);
}
......@@ -482,9 +460,12 @@ int dlsch_encoding_2threads(PHY_VARS_eNB *eNB,
start_meas(te_stats);
uint8_t tmp[96+12+3+3*6144]= {0};
for (int j=0; j<96; j++)
tmp[j] = LTE_NULL;
threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r],
Kr>>3,
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
(r==0) ? dlsch->harq_processes[harq_pid]->F : 0,
f1f2mat_old[iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14)
......@@ -494,7 +475,7 @@ int dlsch_encoding_2threads(PHY_VARS_eNB *eNB,
start_meas(i_stats);
dlsch->harq_processes[harq_pid]->RTC[r] =
sub_block_interleaving_turbo(4+(Kr_bytes*8),
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
dlsch->harq_processes[harq_pid]->w[r]);
stop_meas(i_stats);
}
......@@ -572,49 +553,14 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
time_stats_t *i_stats)
{
unsigned int G;
unsigned int crc=1;
unsigned short iind;
LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
unsigned char harq_pid = dlsch->harq_ids[subframe];
unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb;
unsigned int A;
unsigned char mod_order;
unsigned int Kr=0,Kr_bytes,r,r_offset=0;
unsigned int A=dlsch->harq_processes[harq_pid]->TBS;//6228
// unsigned short m=dlsch->harq_processes[harq_pid]->mcs;
uint8_t beamforming_mode=0;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN);
A = dlsch->harq_processes[harq_pid]->TBS; //6228
// printf("Encoder: A: %d\n",A);
mod_order = dlsch->harq_processes[harq_pid]->Qm;
if(dlsch->harq_processes[harq_pid]->mimo_mode == TM7)
beamforming_mode = 7;
else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM8)
beamforming_mode = 8;
else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM9_10)
beamforming_mode = 9;
G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,beamforming_mode);
// if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet
if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet
#ifdef DEBUG_DLSCH_CODING
printf("encoding thinks this is a new packet \n");
#endif
/*
int i;
printf("dlsch (tx): \n");
for (i=0;i<(A>>3);i++)
printf("%02x.",a[i]);
printf("\n");
*/
// Add 24-bit crc (polynomial A) to payload
crc = crc24a(a,
A)>>8;
unsigned int crc = crc24a(a, A)>>8;
a[A>>3] = ((uint8_t*)&crc)[2];
a[1+(A>>3)] = ((uint8_t*)&crc)[1];
a[2+(A>>3)] = ((uint8_t*)&crc)[0];
......@@ -634,8 +580,9 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
&dlsch->harq_processes[harq_pid]->Kminus,
&dlsch->harq_processes[harq_pid]->F)<0)
return(-1);
unsigned int Kr=0,Kr_bytes;
for (r=0; r<dlsch->harq_processes[harq_pid]->C; r++) {
for (int r=0; r<dlsch->harq_processes[harq_pid]->C; r++) {
if (r<dlsch->harq_processes[harq_pid]->Cminus)
Kr = dlsch->harq_processes[harq_pid]->Kminus;
......@@ -645,6 +592,7 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
Kr_bytes = Kr>>3;
// get interleaver index for Turbo code (lookup in Table 5.1.3-3 36-212, V8.6 2009-03, p. 13-14)
unsigned short iind;
if (Kr_bytes<=64)
iind = (Kr_bytes-5);
else if (Kr_bytes <=128)
......@@ -657,51 +605,82 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
printf("dlsch_coding: Illegal codeword size %d!!!\n",Kr_bytes);
return(-1);
}
#ifdef DEBUG_DLSCH_CODING
printf("Generating Code Segment %d (%d bits)\n",r,Kr);
// generate codewords
printf("bits_per_codeword (Kr)= %d, A %d\n",Kr,A);
printf("N_RB = %d\n",nb_rb);
printf("Ncp %d\n",frame_parms->Ncp);
printf("mod_order %d\n",mod_order);
#endif
#ifdef DEBUG_DLSCH_CODING
printf("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]);
#endif
request_t *req=createRequest(ENCODE,sizeof(turboEncode_t));
union turboReqUnion id={.s={dlsch->rnti,frame,subframe,r,0}};
req->id= id.p;
req->decodeIterations=0;
turboEncode_t * rdata=(turboEncode_t *) req->data;
rdata->input=dlsch->harq_processes[harq_pid]->c[r];
rdata->Kr_bytes=Kr>>3;
rdata->filler=(r==0) ? dlsch->harq_processes[harq_pid]->F : 0;
rdata->iind=iind;
rdata->r=r;
rdata->harq_pid=harq_pid;
rdata->dlsch=dlsch;
if ( eNB->proc.threadPool.activated) {
add_request(req, &eNB->proc.threadPool);
} else {
memset(rdata->output,LTE_NULL, TURBO_SIMD_SOFTBITS);
start_meas(te_stats);
threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r],
Kr>>3,
&dlsch->harq_processes[harq_pid]->d[r][96],
(r==0) ? dlsch->harq_processes[harq_pid]->F : 0,
f1f2mat_old[iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14)
req->creationTime=req->startProcessingTime=rdtsc();
threegpplte_turbo_encoder(rdata->input,
rdata->Kr_bytes,
rdata->output+96,//&dlsch->harq_processes[harq_pid]->d[r][96],
rdata->filler,
f1f2mat_old[rdata->iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(rdata->iind*2)+1] // f2 (see 36121-820, page 14)
);
stop_meas(te_stats);
#ifdef DEBUG_DLSCH_CODING
if (r==0)
write_output("enc_output0.m","enc0",&dlsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4);
#endif
start_meas(i_stats);
dlsch->harq_processes[harq_pid]->RTC[r] =
sub_block_interleaving_turbo(4+(Kr_bytes*8),
&dlsch->harq_processes[harq_pid]->d[r][96],
dlsch->harq_processes[harq_pid]->w[r]);
req->returnTime=req->endProcessingTime=rdtsc();
req->decodeIterations=0;
req->coreId=0;
req->processedBy[0]=0;
req->decodeIterations=0;
// Ignore write error (if no trace listner)
if (write(eNB->proc.threadPool.traceFd, req, sizeof(request_t)- 2*sizeof(void*))) {}; start_meas(i_stats);
rdata->dlsch->harq_processes[rdata->harq_pid]->RTC[rdata->r] =
sub_block_interleaving_turbo(4+(rdata->Kr_bytes*8),
rdata->output+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
rdata->dlsch->harq_processes[rdata->harq_pid]->w[rdata->r]);
stop_meas(i_stats);
free(req);
}
}
return 0;
}
int dlsch_encoding2(PHY_VARS_eNB *eNB,
unsigned char *a,
uint8_t num_pdcch_symbols,
LTE_eNB_DLSCH_t *dlsch,
int frame,
uint8_t subframe,
time_stats_t *rm_stats,
time_stats_t *te_stats,
time_stats_t *i_stats)
{
LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
unsigned char harq_pid = dlsch->harq_ids[subframe];
unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb;
// Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the
// outputs for each code segment, see Section 5.1.5 p.20
int r_offset=0;
unsigned int G;
{
unsigned char mod_order=dlsch->harq_processes[harq_pid]->Qm;
uint8_t beamforming_mode=0;
if(dlsch->harq_processes[harq_pid]->mimo_mode == TM7)
beamforming_mode = 7;
else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM8)
beamforming_mode = 8;
else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM9_10)
beamforming_mode = 9;
G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,beamforming_mode);
}
for (int r=0; r<dlsch->harq_processes[harq_pid]->C; r++) {
for (r=0; r<dlsch->harq_processes[harq_pid]->C; r++) {
#ifdef DEBUG_DLSCH_CODING
printf("Rate Matching, Code segment %d (coded bits (G) %d,unpunctured/repeated bits per code segment %d,mod_order %d, nb_rb %d)...\n",
r,
......@@ -856,9 +835,12 @@ int dlsch_encoding_SIC(PHY_VARS_UE *ue,
printf("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]);
#endif
start_meas(te_stats);
uint8_t tmp[96+12+3+3*6144]= {0};
for (int j=0; j<96; j++)
tmp[j] = LTE_NULL;
threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r],
Kr>>3,
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
(r==0) ? dlsch->harq_processes[harq_pid]->F : 0,
f1f2mat_old[iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14)
......@@ -867,13 +849,13 @@ int dlsch_encoding_SIC(PHY_VARS_UE *ue,
#ifdef DEBUG_DLSCH_CODING
if (r==0)
write_output("enc_output0.m","enc0",&dlsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4);
write_output("enc_output0.m","enc0",tmp, 0); //&dlsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4);
#endif
start_meas(i_stats);
dlsch->harq_processes[harq_pid]->RTC[r] =
sub_block_interleaving_turbo(4+(Kr_bytes*8),
&dlsch->harq_processes[harq_pid]->d[r][96],
tmp+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
dlsch->harq_processes[harq_pid]->w[r]);
stop_meas(i_stats);
}
......
......@@ -34,7 +34,7 @@
#include "PHY/defs.h"
#include <math.h>
#include "nfapi_interface.h"
#include <thread-pool.h>
// Functions below implement 36-211 and 36-212
/** @addtogroup _PHY_TRANSPORT_
......@@ -122,6 +122,16 @@ int32_t dlsch_encoding(PHY_VARS_eNB *eNB,
time_stats_t *te_stats,
time_stats_t *i_stats);
int32_t dlsch_encoding2(PHY_VARS_eNB *eNB,
uint8_t *a,
uint8_t num_pdcch_symbols,
LTE_eNB_DLSCH_t *dlsch,
int frame,
uint8_t subframe,
time_stats_t *rm_stats,
time_stats_t *te_stats,
time_stats_t *i_stats);
int32_t dlsch_encoding_SIC(PHY_VARS_UE *ue,
uint8_t *a,
uint8_t num_pdcch_symbols,
......@@ -1884,12 +1894,8 @@ int32_t ulsch_encoding_emul(uint8_t *ulsch_buffer,
@param llr8_flag If 1, indicate that the 8-bit turbo decoder should be used
@returns 0 on success
*/
unsigned int ulsch_decoding(PHY_VARS_eNB *phy_vars_eNB,
eNB_rxtx_proc_t *proc,
uint8_t UE_id,
uint8_t control_only_flag,
uint8_t Nbundled,
uint8_t llr8_flag);
ulsch_decoding_t ulsch_decoding;
/*!
\brief Decoding of ULSCH data component from 36-212. This one spawns 1 worker thread in parallel,half of the segments in each thread.
......@@ -1912,10 +1918,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,
@param llr8_flag If 1, indicate that the 8-bit turbo decoder should be used
@returns 0 on success
*/
int ulsch_decoding_data(PHY_VARS_eNB *eNB,
int UE_id,
int harq_pid,
int llr8_flag);
ulsch_decoding_data_t ulsch_decoding_data;
uint32_t ulsch_decoding_emul(PHY_VARS_eNB *phy_vars_eNB,
eNB_rxtx_proc_t *proc,
......
......@@ -50,32 +50,19 @@
#endif
#include "UTIL/LOG/vcd_signal_dumper.h"
#include <thread-pool.h>
//#define DEBUG_ULSCH_DECODING
void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch)
{
int i,r;
if (ulsch) {
for (i=0; i<8; i++) {
for (int i=0; i<8; i++) {
if (ulsch->harq_processes[i]) {
if (ulsch->harq_processes[i]->b) {
free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES);
ulsch->harq_processes[i]->b = NULL;
}
for (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 (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;
}
......@@ -90,8 +77,8 @@ LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uin
{
LTE_eNB_ULSCH_t *ulsch;
uint8_t exit_flag = 0,i,r;
unsigned char bw_scaling =1;
uint8_t exit_flag = 0;
unsigned char bw_scaling;
switch (N_RB_UL) {
case 6:
......@@ -118,7 +105,7 @@ LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uin
ulsch->max_turbo_iterations = max_turbo_iterations;
ulsch->Mlimit = 4;
for (i=0; i<8; i++) {
for (int 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));
......@@ -130,23 +117,6 @@ LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uin
memset(ulsch->harq_processes[i]->b,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling);
else
exit_flag=3;
if (abstraction_flag==0) {
for (r=0; r<MAX_NUM_ULSCH_SEGMENTS/bw_scaling; r++) {
ulsch->harq_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;
}
......@@ -247,28 +217,9 @@ int ulsch_decoding_data_2thread0(td_params* tdp) {
uint32_t Gp,GpmodC,Nl=1;
uint32_t C = ulsch_harq->C;
uint8_t (*tc)(int16_t *y,
uint8_t *,
uint16_t,
uint16_t,
uint16_t,
uint8_t,
uint8_t,
uint8_t,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *);
if (llr8_flag == 0)
tc = phy_threegpplte_turbo_decoder16;
else
tc = phy_threegpplte_turbo_decoder8;
turboDecoder * tc=llr8_flag?
phy_threegpplte_turbo_decoder8:
phy_threegpplte_turbo_decoder16 ;
// go through first half of segments to get r_offset
for (r=0; r<(ulsch_harq->C/2); r++) {
......@@ -378,8 +329,9 @@ int ulsch_decoding_data_2thread0(td_params* tdp) {
r_offset += E;
int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32)));
sub_block_deinterleaving_turbo(4+Kr,
&ulsch_harq->d[r][96],
soft_bits+96,
ulsch_harq->w[r]);
if (ulsch_harq->C == 1)
......@@ -388,8 +340,9 @@ int ulsch_decoding_data_2thread0(td_params* tdp) {
crc_type = CRC24_B;
ret = tc(&ulsch_harq->d[r][96],
ulsch_harq->c[r],
uint8_t decoded_bytes[3+768] __attribute__((aligned(32)));
ret = tc(soft_bits+96,
decoded_bytes,
Kr,
f1f2mat_old[iind*2],
f1f2mat_old[(iind*2)+1],
......@@ -415,7 +368,7 @@ int ulsch_decoding_data_2thread0(td_params* tdp) {
Kr_bytes = Kr>>3;
memcpy(ulsch_harq->b+offset,
ulsch_harq->c[r],
decoded_bytes,
Kr_bytes - ((ulsch_harq->C>1)?3:0));
offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0));
......@@ -468,32 +421,13 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr
unsigned int E;
int Cby2;
uint8_t (*tc)(int16_t *y,
uint8_t *,
uint16_t,
uint16_t,
uint16_t,
uint8_t,
uint8_t,
uint8_t,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *);
struct timespec wait;
wait.tv_sec=0;
wait.tv_nsec=5000000L;
if (llr8_flag == 0)
tc = phy_threegpplte_turbo_decoder16;
else
tc = phy_threegpplte_turbo_decoder8;
turboDecoder * tc=llr8_flag?
phy_threegpplte_turbo_decoder8:
phy_threegpplte_turbo_decoder16 ;
if (ulsch_harq->C>1) { // wakeup worker if more than 1 segment
if (pthread_mutex_timedlock(&proc->mutex_td,&wait) != 0) {
......@@ -598,9 +532,10 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr
stop_meas(&eNB->ulsch_rate_unmatching_stats);
r_offset += E;
int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32)));
start_meas(&eNB->ulsch_deinterleaving_stats);
sub_block_deinterleaving_turbo(4+Kr,
&ulsch_harq->d[r][96],
soft_bits+96,
ulsch_harq->w[r]);
stop_meas(&eNB->ulsch_deinterleaving_stats);
......@@ -611,8 +546,9 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr
start_meas(&eNB->ulsch_turbo_decoding_stats);
ret = tc(&ulsch_harq->d[r][96],
ulsch_harq->c[r],
uint8_t decoded_bytes[3+768] __attribute__((aligned(32)));
ret = tc(soft_bits+96,
decoded_bytes,
Kr,
f1f2mat_old[iind*2],
f1f2mat_old[(iind*2)+1],
......@@ -639,12 +575,12 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr
if (r==0) {
memcpy(ulsch_harq->b,
&ulsch_harq->c[0][(ulsch_harq->F>>3)],
decoded_bytes+(ulsch_harq->F>>3),
Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0));
offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0);
} else {
memcpy(ulsch_harq->b+offset,
ulsch_harq->c[r],
decoded_bytes,
Kr_bytes - ((ulsch_harq->C>1)?3:0));
offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0));
}
......@@ -662,85 +598,27 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr
return( (ret>proc->tdp.ret) ? ret : proc->tdp.ret );
}
int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) {
unsigned int r,r_offset=0,Kr,Kr_bytes,iind;
uint8_t crc_type;
request_t * ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag, int frame, int subframe) {
request_t * req=NULL;
unsigned int r_offset=0;
int offset = 0;
int ret = 1;
int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)];
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id];
LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid];
LTE_UL_eNB_HARQ_t *ulsch_harq = eNB->ulsch[UE_id]->harq_processes[harq_pid];
int G = ulsch_harq->G;
unsigned int E;
turboDecoder * td=llr8_flag?
phy_threegpplte_turbo_decoder8:
phy_threegpplte_turbo_decoder16 ;
uint8_t (*tc)(int16_t *y,
uint8_t *,
uint16_t,
uint16_t,
uint16_t,
uint8_t,
uint8_t,
uint8_t,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *);
if (llr8_flag == 0)
tc = phy_threegpplte_turbo_decoder16;
else
tc = phy_threegpplte_turbo_decoder8;
for (r=0; r<ulsch_harq->C; r++) {
// printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]);
for (int r=0; r<ulsch_harq->C; r++) {
// Get Turbo interleaver parameters
if (r<ulsch_harq->Cminus)
Kr = ulsch_harq->Kminus;
else
Kr = ulsch_harq->Kplus;
Kr_bytes = Kr>>3;
if (Kr_bytes<=64)
iind = (Kr_bytes-5);
else if (Kr_bytes <=128)
iind = 59 + ((Kr_bytes-64)>>1);
else if (Kr_bytes <= 256)
iind = 91 + ((Kr_bytes-128)>>2);
else if (Kr_bytes <= 768)
iind = 123 + ((Kr_bytes-256)>>3);
else {
LOG_E(PHY,"ulsch_decoding: Illegal codeword size %d!!!\n",Kr_bytes);
return(-1);
}
#ifdef DEBUG_ULSCH_DECODING
printf("f1 %d, f2 %d, F %d\n",f1f2mat_old[2*iind],f1f2mat_old[1+(2*iind)],(r==0) ? ulsch_harq->F : 0);
#endif
memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short));
int Kr=r<ulsch_harq->Cminus?ulsch_harq->Kminus:ulsch_harq->Kplus;
int Kr_bytes = Kr>>3;
int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)];
memset(dummy_w, 0, sizeof(dummy_w));
ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8),
(uint8_t*)&dummy_w[r][0],
(r==0) ? ulsch_harq->F : 0);
#ifdef DEBUG_ULSCH_DECODING
printf("Rate Matching Segment %d (coded bits (G) %d,unpunctured/repeated bits %d, Q_m %d, nb_rb %d, Nl %d)...\n",
r, G,
Kr*3,
Q_m,
nb_rb,
ulsch_harq->Nl);
#endif
start_meas(&eNB->ulsch_rate_unmatching_stats);
if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r],
G,
ulsch_harq->w[r],
......@@ -757,33 +635,62 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag)
r,
&E)==-1) {
LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n");
return(-1);
return NULL;
}
stop_meas(&eNB->ulsch_rate_unmatching_stats);
r_offset += E;
start_meas(&eNB->ulsch_deinterleaving_stats);
req=createRequest(DECODE,sizeof(turboDecode_t));
union turboReqUnion id= {.s={eNB->ulsch[UE_id]->rnti,frame,subframe,r,0}};
req->id= id.p;
turboDecode_t * rdata=(turboDecode_t *) req->data;
sub_block_deinterleaving_turbo(4+Kr,
&ulsch_harq->d[r][96],
rdata->soft_bits+96,
ulsch_harq->w[r]);
stop_meas(&eNB->ulsch_deinterleaving_stats);
if (ulsch_harq->C == 1)
crc_type = CRC24_A;
else
crc_type = CRC24_B;
start_meas(&eNB->ulsch_turbo_decoding_stats);
ret = tc(&ulsch_harq->d[r][96],
ulsch_harq->c[r],
Kr,
f1f2mat_old[iind*2],
f1f2mat_old[(iind*2)+1],
ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS,
crc_type,
(r==0) ? ulsch_harq->F : 0,
if (Kr_bytes<=64)
rdata->iind = (Kr_bytes-5);
else if (Kr_bytes <=128)
rdata->iind = 59 + ((Kr_bytes-64)>>1);
else if (Kr_bytes <= 256)
rdata->iind = 91 + ((Kr_bytes-128)>>2);
else if (Kr_bytes <= 768)
rdata->iind = 123 + ((Kr_bytes-256)>>3);
else {
LOG_E(PHY,"ulsch_decoding: Illegal codeword size %d!!!\n",Kr_bytes);
return NULL;
}
rdata->frame=frame;
rdata->subframe=subframe;
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->offset=offset;
rdata->function=td;
int Fbytes=rdata->Fbits>>3;
int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0);
if ( eNB->proc.threadPool.activated) {
add_request(req, &eNB->proc.threadPool);
req=NULL;
} else {
req->creationTime=req->startProcessingTime=rdtsc();
rdata->decodeIterations = td( rdata->soft_bits+96,
rdata->decoded_bytes,
rdata->Kr,
f1f2mat_old[rdata->iind*2],
f1f2mat_old[(rdata->iind*2)+1],
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,
......@@ -793,36 +700,29 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag)
&eNB->ulsch_tc_intl2_stats);
stop_meas(&eNB->ulsch_turbo_decoding_stats);
// Reassembly of Transport block here
if (ret != (1+ulsch->max_turbo_iterations)) {
if (r<ulsch_harq->Cminus)
Kr = ulsch_harq->Kminus;
else
Kr = ulsch_harq->Kplus;
Kr_bytes = Kr>>3;
if (r==0) {
memcpy(ulsch_harq->b,
&ulsch_harq->c[0][(ulsch_harq->F>>3)],
Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0));
offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0);
} else {
memcpy(ulsch_harq->b+offset,
ulsch_harq->c[r],
Kr_bytes - ((ulsch_harq->C>1)?3:0));
offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0));
req->returnTime=req->endProcessingTime=rdtsc();
req->decodeIterations=rdata->decodeIterations;
req->coreId=0;
req->processedBy[0]=0;
// Ignore write error (if no trace listner)
if (write(eNB->proc.threadPool.traceFd, req, sizeof(request_t)- 2*sizeof(void*))) {}; // Reassembly of Transport block here
if (rdata->decodeIterations <= eNB->ulsch[UE_id]->max_turbo_iterations ) {
// last block in a TDU is processed in caller
if ( rdata->segment_r < (rdata->nbSegments - 1) ) {
ulsch_harq->processedSegments++;
memcpy(ulsch_harq->b+rdata->offset,
rdata->decoded_bytes+Fbytes,
blockSize);
freeRequest(req);
}
} else {
}
else
// Entire TPU need retransmission
break;
}
offset += blockSize;
}
return(ret);
return(req);
}
static inline unsigned int lte_gold_unscram(unsigned int *x1, unsigned int *x2, unsigned char reset) __attribute__((always_inline));
......@@ -853,11 +753,14 @@ static inline unsigned int lte_gold_unscram(unsigned int *x1, unsigned int *x2,
}
unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
request_t* ulsch_decoding(PHY_VARS_eNB *eNB,
eNB_rxtx_proc_t *proc,
uint8_t UE_id,
uint8_t control_only_flag,
uint8_t Nbundled,
uint8_t llr8_flag)
uint8_t llr8_flag,
int frame,
int subframe)
{
......@@ -870,7 +773,6 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
uint8_t Q_m;
unsigned int i,i2,q,j,j2;
int iprime;
unsigned int ret=0;
// uint8_t dummy_channel_output[(3*8*block_length)+12];
int r,Kr;
......@@ -891,13 +793,11 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
int16_t cseq[6*14*1200] __attribute__((aligned(32)));
int off;
int frame = proc->frame_rx;
int subframe = proc->subframe_rx;
LTE_UL_eNB_HARQ_t *ulsch_harq;
harq_pid = subframe2harq_pid(frame_parms,frame,subframe);
harq_pid = subframe2harq_pid(frame_parms,proc->frame_rx,subframe);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING0+harq_pid,1);
......@@ -905,7 +805,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
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
ulsch_harq = ulsch->harq_processes[harq_pid];
AssertFatal(harq_pid!=255,
AssertFatal(harq_pid<8,
"FATAL ERROR: illegal harq_pid, returning\n");
AssertFatal(ulsch_harq->Nsymb_pusch != 0,
......@@ -1202,7 +1102,9 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
i2=(i2+(Cmux<<2)-3);
*/
// slightly more optimized version (equivalent to above) for 16QAM to improve computational performance
*(__m64 *)&y[i2] = _mm_sign_pi16(*(__m64*)&ulsch_llr[i],*(__m64*)&cseq[i]);i+=4;i2+=(Cmux<<2);
*(__m64 *)&y[i2] = _mm_sign_pi16(*(__m64*)&ulsch_llr[i],*(__m64*)&cseq[i]);
i+=4;
i2+=(Cmux<<2);
}
......@@ -1282,8 +1184,8 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
}
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);
LOG_E(PHY,"ulsch_decoding: FATAL, ACK cannot be more than 2 bits yet\n");
return NULL;
}
for (i=0; i<len_ACK; i++)
......@@ -1324,7 +1226,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
if (ulsch_harq->O_RI > 1) {
LOG_E(PHY,"ulsch_decoding: FATAL, RI cannot be more than 1 bit yet\n");
return(-1);
return NULL;
}
for (i=0; i<len_RI; i++)
......@@ -1598,7 +1500,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
// Do ULSCH Decoding for data portion
ret = eNB->td(eNB,UE_id,harq_pid,llr8_flag);
request_t * ret = eNB->td(eNB,UE_id,harq_pid,llr8_flag, frame, subframe);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING0+harq_pid,0);
......
......@@ -1361,8 +1361,6 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB,
eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS,eNB->ulsch[UE_id]->harq_processes[harq_pid]->Qm,
eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch);
//#ifndef OAI_EMU
write_output("/tmp/ulsch_d.m","ulsch_dseq",&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96],
eNB->ulsch[UE_id]->harq_processes[harq_pid]->Kplus*3,1,0);
if (eNB->common_vars.rxdata) write_output("/tmp/rxsig0.m","rxs0", &eNB->common_vars.rxdata[0][0],eNB->frame_parms.samples_per_tti*10,1,1);
if (eNB->frame_parms.nb_antennas_rx>1)
......
......@@ -56,6 +56,7 @@
#include <math.h>
#include "common_lib.h"
#include "msc.h"
#include <thread-pool.h>
#include "openair2/PHY_INTERFACE/IF_Module.h"
......@@ -197,7 +198,8 @@ enum transmission_access_mode {
CANCELED_ACCESS,
UNKNOWN_ACCESS,
SCHEDULED_ACCESS,
CBA_ACCESS};
CBA_ACCESS
};
typedef enum {
eNodeB_3GPP=0, // classical eNodeB function
......@@ -430,6 +432,7 @@ typedef struct eNB_proc_t_s {
uint8_t CC_id;
/// thread index
int thread_index;
tpool_t threadPool;
/// timestamp received from HW
openair0_timestamp timestamp_rx;
/// timestamp to send to "slave rru"
......@@ -927,6 +930,20 @@ typedef struct {
int prach_I0;
} PHY_MEASUREMENTS_eNB;
typedef request_t *(ulsch_decoding_t)(struct PHY_VARS_eNB_s *phy_vars_eNB,
eNB_rxtx_proc_t *proc,
uint8_t UE_id,
uint8_t control_only_flag,
uint8_t Nbundled,
uint8_t llr8_flag,
int frame,
int subframe);
typedef request_t *(ulsch_decoding_data_t)(struct PHY_VARS_eNB_s *eNB,
int UE_id,
int harq_pid,
int llr8_flag,
int frame,
int subframe);
/// Top-level PHY Data Structure for eNB
typedef struct PHY_VARS_eNB_s {
......@@ -944,7 +961,8 @@ typedef struct PHY_VARS_eNB_s {
/// Ethernet parameters for fronthaul interface
eth_params_t eth_params;
int rx_total_gain_dB;
int (*td)(struct PHY_VARS_eNB_s *eNB,int UE_id,int harq_pid,int llr8_flag);
//int (*td)(struct PHY_VARS_eNB_s *eNB,int UE_id,int harq_pid,int llr8_flag);
ulsch_decoding_data_t *td;
int (*te)(struct PHY_VARS_eNB_s *,uint8_t *,uint8_t,LTE_eNB_DLSCH_t *,int,uint8_t,time_stats_t *,time_stats_t *,time_stats_t *);
int (*start_if)(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB);
uint8_t local_flag;
......@@ -1615,6 +1633,55 @@ static inline int release_thread(pthread_mutex_t *mutex,int *instance_cnt,char *
return(0);
}
// OpenAir .h files are very very badly intricated, so we redeclare a type
// A major issue to fix in whole OAI: total crap (reprototype in .c, loops of includes, ...)
typedef uint8_t (turboDecoder)(int16_t *y,
uint8_t *,
uint16_t,
uint16_t,
uint16_t,
uint8_t,
uint8_t,
uint8_t,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *,
time_stats_t *);
typedef struct TurboDecode_s {
turboDecoder *function;
int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32)));
uint8_t decoded_bytes[3+768] __attribute__((aligned(32)));
int UEid;
int harq_pid;
int frame;
int subframe;
int iind;
int Fbits;
int Kr;
LTE_UL_eNB_HARQ_t *ulsch_harq;
PHY_VARS_eNB *eNB;
int nbSegments;
int segment_r;
int offset;
int maxIterations;
int decodeIterations;
} turboDecode_t;
#define TURBO_SIMD_SOFTBITS 96+12+3+3*6144
typedef struct turboEncode_s {
uint8_t * input;
uint8_t output[TURBO_SIMD_SOFTBITS];
int Kr_bytes;
int filler;
int iind;
int r;
int harq_pid;
LTE_eNB_DLSCH_t *dlsch;
} turboEncode_t;
#include "PHY/INIT/defs.h"
#include "PHY/LTE_REFSIG/defs.h"
......
......@@ -344,7 +344,8 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,
}
start_meas(&eNB->dlsch_encoding_stats);
AssertFatal(dlsch_harq->pdu!=NULL,"dlsch_harq->pdu == NULL (rnti %x)\n",dlsch->rnti);
if (dlsch->harq_processes[harq_pid]->round == 0) // this is a new packet
eNB->te(eNB,
dlsch_harq->pdu,
dlsch_harq->pdsch_start,
......@@ -354,7 +355,32 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,
&eNB->dlsch_turbo_encoding_stats,
&eNB->dlsch_interleaving_stats);
stop_meas(&eNB->dlsch_encoding_stats);
}
}
void pdsch_procedures2(PHY_VARS_eNB *eNB,
eNB_rxtx_proc_t *proc,
int harq_pid,
LTE_eNB_DLSCH_t *dlsch,
LTE_eNB_DLSCH_t *dlsch1,
LTE_eNB_UE_stats *ue_stats,
int ra_flag) {
// 36-211
int frame=proc->frame_tx;
int subframe=proc->subframe_tx;
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid];
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
if (nfapi_mode == 0 || nfapi_mode == 1) { // monolthic OR PNF - do not need turbo encoding on VNF
dlsch_encoding2(eNB,
dlsch_harq->pdu,
dlsch_harq->pdsch_start,
dlsch,
frame,subframe,
&eNB->dlsch_rate_matching_stats,
&eNB->dlsch_turbo_encoding_stats,
&eNB->dlsch_interleaving_stats);
start_meas(&eNB->dlsch_scrambling_stats);
dlsch_scrambling(fp,
0,
......@@ -519,6 +545,8 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1);
// Now scan UE specific DLSCH
LTE_eNB_DLSCH_t *dlsch0,*dlsch1;
if (eNB->proc.threadPool.notFinishedJobs != 0 )
LOG_E(PHY,"no finished = %d\n",eNB->proc.threadPool.notFinishedJobs);
for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++)
{
dlsch0 = eNB->dlsch[(uint8_t)UE_id][0];
......@@ -547,8 +575,67 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
&eNB->UE_stats[(uint32_t)UE_id],
0);
}
}
}
if ( eNB->proc.threadPool.activated ) {
// Wait all other threads finish to process
int nbRequest=0;
//printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc.threadPool.notFinishedJobs);
AssertFatal(pthread_mutex_lock(&eNB->proc.threadPool.lockReportDone)==0,"");
while ( eNB->proc.threadPool.notFinishedJobs > 0 ) {
// printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc.threadPool.notFinishedJobs);
struct timespec t;
clock_gettime(CLOCK_REALTIME,&t);
t.tv_nsec+=100*1000*1000;
if ( t.tv_nsec >= 1000*1000*1000 ) {
t.tv_nsec -= 1000*1000*1000;
t.tv_sec++;
}
int rr;
if ((rr=pthread_cond_timedwait(&eNB->proc.threadPool.notifDone,&eNB->proc.threadPool.lockReportDone, &t))!=0)
LOG_E(PHY,"timedwait1:%s,%p,%p,%p,%d\n", rr==ETIMEDOUT?"ETIMEDOUT":"other",
eNB->proc.threadPool.oldestRequests,
eNB->proc.threadPool.newestRequests,
eNB->proc.threadPool.doneRequests,
eNB->proc.threadPool.notFinishedJobs);
}
AssertFatal(pthread_mutex_unlock(&eNB->proc.threadPool.lockReportDone)==0,"");
request_t* tmp;
while ((tmp=eNB->proc.threadPool.doneRequests)!=NULL) {
tmp->returnTime=rdtsc();
// Ignore write error (if no trace listner)
if (write(eNB->proc.threadPool.traceFd, tmp, sizeof(request_t)- 2*sizeof(void*))) {};
eNB->proc.threadPool.doneRequests=tmp->next;
start_meas(&eNB->dlsch_interleaving_stats);
turboEncode_t * rdata=(turboEncode_t *) tmp->data;
rdata->dlsch->harq_processes[rdata->harq_pid]->RTC[rdata->r] =
sub_block_interleaving_turbo(4+(rdata->Kr_bytes*8),
rdata->output+96, //&dlsch->harq_processes[harq_pid]->d[r][96],
rdata->dlsch->harq_processes[rdata->harq_pid]->w[rdata->r]);
freeRequest(tmp);
stop_meas(&eNB->dlsch_interleaving_stats);
nbRequest++;
}
//if ( nbRequest ) printf("Done %d code blocks in %ld µsec\n", nbRequest, (rdtsc()-now)/eNB->proc.threadPool.cpuCyclesMicroSec);
}
for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
dlsch0 = eNB->dlsch[(uint8_t)UE_id][0];
dlsch1 = eNB->dlsch[(uint8_t)UE_id][1];
if ((dlsch0)&&
(dlsch0->rnti>0)&&
(dlsch0->active == 1)) {
// get harq_pid
harq_pid = dlsch0->harq_ids[subframe];
pdsch_procedures2(eNB,
proc,
harq_pid,
dlsch0,
dlsch1,
&eNB->UE_stats[(uint32_t)UE_id],
0);
}
......@@ -817,7 +904,7 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
{
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
uint8_t SR_payload = 0,pucch_b0b1[4][2]= {{0,0},{0,0},{0,0},{0,0}},harq_ack[4]={0,0,0,0};
int32_t metric[4]={0,0,0,0},metric_SR=0,max_metric;
int32_t metric[4]= {0,0,0,0},metric_SR=0,max_metric=0;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
int i;
......@@ -1312,201 +1399,140 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
}
}
void post_decode(request_t* decodeResult) {
turboDecode_t * rdata=(turboDecode_t *) decodeResult->data;
LTE_eNB_ULSCH_t *ulsch = rdata->eNB->ulsch[rdata->UEid];
LTE_UL_eNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
PHY_VARS_eNB *eNB=rdata->eNB;
bool decodeSucess=rdata->decodeIterations <= rdata->maxIterations;
ulsch_harq->processedSegments++;
if (decodeSucess) {
int Fbytes=rdata->Fbits>>3;
int Kr=rdata->segment_r < ulsch_harq->Cminus?
ulsch_harq->Kminus:
ulsch_harq->Kplus;
int Kr_bytes = Kr>>3;
int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0);
memcpy(ulsch_harq->b+rdata->offset,
rdata->decoded_bytes+Fbytes,
blockSize);
} else {
if (rdata->nbSegments > 1 ) {
// Purge pending decoding of the same TDU
union turboReqUnion idInFailure= {.p=decodeResult->id};
rnti_t rntiInFailure=idInFailure.s.rnti;
tpool_t * tp=&eNB->proc.threadPool;
AssertFatal(pthread_mutex_lock(&tp->lockRequests)==0,"");
request_t* pending=NULL;
while ( (pending=searchRNTI(tp, rntiInFailure)) != NULL) {
LOG_W(MAC,"removing a CB belonging to a bad TPU");
freeRequest(pending);
}
AssertFatal(pthread_mutex_unlock(&tp->lockRequests)==0,"");
}
}
// Check if TDU is complete: either we have all blocks in success
// either at least one block can't be decoded
// Maybe we receive decoded block alter a first failure,
// so we protect ourselves against multiple executions
if ( (rdata->nbSegments == ulsch_harq->processedSegments || decodeSucess==false) &&
ulsch_harq->processedBadSegment == 0 ) {
//compute the expected ULSCH RX power (for the stats)
ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,rdata->UEid,rdata->harq_pid, 0); // 0 means bw_factor is not considered
if (ulsch_harq->cqi_crc_status == 1)
fill_ulsch_cqi_indication(eNB,rdata->frame,rdata->subframe,
ulsch_harq,
ulsch->rnti);
fill_crc_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe,decodeSucess?0:1); // indicate result to MAC
fill_rx_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe); // indicate SDU to MAC
if (!decodeSucess) {
ulsch_harq->processedBadSegment =1;
if (ulsch_harq->round >= 3) {
ulsch_harq->status = SCH_IDLE;
ulsch_harq->handled = 0;
ulsch->harq_mask &= ~(1 << rdata->harq_pid);
ulsch_harq->round = 0;
}
/* Mark the HARQ process to release it later if max transmission reached
* (see below).
* MAC does not send the max transmission count, we have to deal with it
* locally in PHY.
*/
ulsch_harq->handled = 1;
} else {
ulsch_harq->status = SCH_IDLE;
ulsch->harq_mask &= ~(1 << rdata->harq_pid);
} // ulsch not in error
if (ulsch_harq->O_ACK>0)
fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,rdata->frame,rdata->subframe,ulsch->bundling);
}
freeRequest(decodeResult);
}
void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
{
uint32_t ret=0,i;
uint32_t harq_pid;
uint8_t nPRS;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
LTE_eNB_ULSCH_t *ulsch;
LTE_UL_eNB_HARQ_t *ulsch_harq;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
if (fp->frame_type == FDD) harq_pid = ((10*frame) + subframe)&7;
else harq_pid = subframe%10;
if (fp->frame_type == FDD)
harq_pid = ((10*frame) + subframe)&7;
else
harq_pid = subframe%10;
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
ulsch = eNB->ulsch[i];
ulsch_harq = ulsch->harq_processes[harq_pid];
if (ulsch->rnti>0) LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n",
i, harq_pid, frame,subframe,i,ulsch->rnti,
ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled);
if ((ulsch) &&
(ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
(ulsch_harq->handled == 0)) {
if (eNB->proc.threadPool.notFinishedJobs != 0 )
LOG_E(PHY,"no finisehd = %d\n",eNB->proc.threadPool.notFinishedJobs);
for (int i=0; i<NUMBER_OF_UE_MAX; i++) {
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i];
LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid];
if (ulsch && ulsch->rnti>0 &&
ulsch_harq->status == ACTIVE &&
ulsch_harq->frame == frame && ulsch_harq->subframe == subframe &&
ulsch_harq->handled == 0 ) {
// UE has ULSCH scheduling
for (int rb=0;
rb<=ulsch_harq->nb_rb;
rb++) {
for (int rb=0; rb<=ulsch_harq->nb_rb; rb++) {
int rb2 = rb+ulsch_harq->first_rb;
eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
}
LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i);
nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1];
ulsch->cyclicShift = (ulsch_harq->n_DMRS2 +
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift +
nPRS)%12;
LOG_D(PHY,
"[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n",
eNB->Mod_id,harq_pid,frame,subframe,
ulsch_harq->dci_alloc,
ulsch_harq->rar_alloc,
ulsch_harq->round,
ulsch_harq->first_rb,
ulsch_harq->nb_rb,
ulsch_harq->Qm,
ulsch_harq->TBS,
ulsch_harq->rvidx,
ulsch->cyclicShift,
ulsch_harq->n_DMRS2,
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift,
ulsch_harq->O_ACK,
ulsch->beta_offset_cqi_times8);
start_meas(&eNB->ulsch_demodulation_stats);
rx_ulsch(eNB,proc, i);
stop_meas(&eNB->ulsch_demodulation_stats);
ulsch_harq->processedSegments=0;
ulsch_harq->processedBadSegment=0;
request_t* ret;
start_meas(&eNB->ulsch_decoding_stats);
ret = ulsch_decoding(eNB,proc,
i,
0, // control_only_flag
ulsch_harq->V_UL_DAI,
ulsch_harq->nb_rb>20 ? 1 : 0);
ulsch_harq->nb_rb>20 ? 1 : 0,
frame,
subframe);
stop_meas(&eNB->ulsch_decoding_stats);
LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n",
eNB->Mod_id,harq_pid,
frame,subframe,
ulsch->rnti,
dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]),
dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]),
20,//eNB->measurements.n0_power_dB[0],
20,//eNB->measurements.n0_power_dB[1],
ulsch_harq->o_ACK[0],
ulsch_harq->o_ACK[1],
ret,
ulsch_harq->cqi_crc_status,
ulsch_harq->O_ACK,
eNB->ulsch_decoding_stats.diff_now, eNB->ulsch_decoding_stats.max);
//compute the expected ULSCH RX power (for the stats)
ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered
if (ulsch_harq->cqi_crc_status == 1) {
#ifdef DEBUG_PHY_PROC
//if (((frame%10) == 0) || (frame < 50))
print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL);
#endif
fill_ulsch_cqi_indication(eNB,frame,subframe,
ulsch_harq,
ulsch->rnti);
}
if (ret == (1+MAX_TURBO_ITERATIONS)) {
T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti),
T_INT(harq_pid));
fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC
fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC
LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n",
eNB->Mod_id,harq_pid,
frame,subframe, i,
ulsch_harq->round-1,
ulsch->Mlimit,
ulsch_harq->o_ACK[0],
ulsch_harq->o_ACK[1]);
if (ulsch_harq->round >= 3) {
ulsch_harq->status = SCH_IDLE;
ulsch_harq->handled = 0;
ulsch->harq_mask &= ~(1 << harq_pid);
ulsch_harq->round = 0;
}
#if defined(MESSAGE_CHART_GENERATOR_PHY)
MSC_LOG_RX_DISCARDED_MESSAGE(
MSC_PHY_ENB,MSC_PHY_UE,
NULL,0,
"%05u:%02u ULSCH received rnti %x harq id %u round %d",
frame,subframe,
ulsch->rnti,harq_pid,
ulsch_harq->round-1
);
#endif
/* Mark the HARQ process to release it later if max transmission reached
* (see below).
* MAC does not send the max transmission count, we have to deal with it
* locally in PHY.
*/
ulsch_harq->handled = 1;
} // ulsch in error
else {
fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC
fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC
ulsch_harq->status = SCH_IDLE;
ulsch->harq_mask &= ~(1 << harq_pid);
T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti),
T_INT(harq_pid));
#if defined(MESSAGE_CHART_GENERATOR_PHY)
MSC_LOG_RX_MESSAGE(
MSC_PHY_ENB,MSC_PHY_UE,
NULL,0,
"%05u:%02u ULSCH received rnti %x harq id %u",
frame,subframe,
ulsch->rnti,harq_pid
);
#endif
#ifdef DEBUG_PHY_PROC
#ifdef DEBUG_ULSCH
LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe,
harq_pid,ulsch_harq->TBS>>3);
for (j=0; j<ulsch_harq->TBS>>3; j++)
LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]);
LOG_T(PHY,"\n");
#endif
#endif
} // ulsch not in error
if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling);
LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n",
eNB->Mod_id,frame,subframe,
harq_pid,
i,
ret,
ulsch_harq->cqi_crc_status,
ulsch_harq->o_ACK[0],
ulsch_harq->o_ACK[1],
eNB->UE_stats[i].ulsch_errors[harq_pid],
eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]);
} // if ((ulsch) &&
// (ulsch->rnti>0) &&
// (ulsch_harq->status == ACTIVE))
else if ((ulsch) &&
(ulsch->rnti>0) &&
if ( ret != NULL )
post_decode(ret);
} else if (ulsch && ulsch->rnti>0 &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
......@@ -1518,7 +1544,42 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
LOG_W(PHY,"Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n",
ulsch->rnti, harq_pid, ulsch->harq_mask);
}
} // for (i=0; i<NUMBER_OF_UE_MAX; i++)
} // for (i=0; i<NUMBER_OF_UE_MAX; i++) {
if ( eNB->proc.threadPool.activated ) {
// Wait all other threads finish to process
//printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc.threadPool.notFinishedJobs);
AssertFatal(pthread_mutex_lock(&eNB->proc.threadPool.lockReportDone)==0,"");
while ( eNB->proc.threadPool.notFinishedJobs > 0 ) {
//printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc.threadPool.notFinishedJobs);
struct timespec t;
clock_gettime(CLOCK_REALTIME,&t);
t.tv_nsec+=100*1000*1000;
if ( t.tv_nsec >= 1000*1000*1000 ) {
t.tv_nsec -= 1000*1000*1000;
t.tv_sec++;
}
int rr;
if ((rr=pthread_cond_timedwait(&eNB->proc.threadPool.notifDone,&eNB->proc.threadPool.lockReportDone, &t))!=0)
LOG_E(PHY,"timedwait1:%s,%p,%p,%p,%d\n", rr==ETIMEDOUT?"ETIMEDOUT":"other",
eNB->proc.threadPool.oldestRequests,
eNB->proc.threadPool.newestRequests,
eNB->proc.threadPool.doneRequests,
eNB->proc.threadPool.notFinishedJobs);
}
AssertFatal(pthread_mutex_unlock(&eNB->proc.threadPool.lockReportDone)==0,"");
request_t* tmp;
while ((tmp=eNB->proc.threadPool.doneRequests)!=NULL) {
tmp->returnTime=rdtsc();
turboDecode_t * rdata=(turboDecode_t *) tmp->data;
tmp->decodeIterations=rdata->decodeIterations;
// Ignore write error (if no trace listner)
if (write(eNB->proc.threadPool.traceFd, tmp, sizeof(request_t)- 2*sizeof(void*))) {};
eNB->proc.threadPool.doneRequests=tmp->next;
post_decode(tmp);
}
}
}
extern int oai_exit;
......@@ -1587,13 +1648,25 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe)
// if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);}
// if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);}
switch (eNB->frame_parms.N_RB_DL) {
case 6: /* nothing to do */ break;
case 15: timing_advance_update /= 2; break;
case 25: timing_advance_update /= 4; break;
case 50: timing_advance_update /= 8; break;
case 75: timing_advance_update /= 12; break;
case 100: timing_advance_update /= 16; break;
default: abort();
case 6: /* nothing to do */
break;
case 15:
timing_advance_update /= 2;
break;
case 25:
timing_advance_update /= 4;
break;
case 50:
timing_advance_update /= 8;
break;
case 75:
timing_advance_update /= 12;
break;
case 100:
timing_advance_update /= 16;
break;
default:
abort();
}
// put timing advance command in 0..63 range
timing_advance_update += 31;
......
......@@ -101,6 +101,7 @@ unsigned short config_frames[4] = {2,9,11,13};
#endif
#include "lte-softmodem.h"
#include <thread-pool.h>
#ifdef XFORMS
// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
// at eNB 0, an UL scope for every UE
......@@ -133,6 +134,7 @@ volatile int start_UE = 0;
volatile int oai_exit = 0;
static clock_source_t clock_source = internal;
static char threadpool[1024]="";
static int wait_for_sync = 0;
static char UE_flag=0;
......@@ -1311,8 +1313,14 @@ int main( int argc, char **argv )
number_of_cards = 1;
printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst);
if (RC.nb_L1_inst > 0) {
printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync);
LOG_W(PHY, "Initializing eNB threads, single thread flag= %d, clock_source=%d\n", single_thread_flag, clock_source);
init_eNB(single_thread_flag,wait_for_sync);
if ( strlen(threadpool) > 0 ) {
LOG_W(PHY, "Creating turbo codec thread pool on cores: %s\n",threadpool);
init_tpool(threadpool, &RC.eNB[0][0]->proc.threadPool);
}
else
init_tpool("n", &RC.eNB[0][0]->proc.threadPool);
// for (inst=0;inst<RC.nb_L1_inst;inst++)
// for (CC_id=0;CC_id<RC.nb_L1_CC[inst];CC_id++) phy_init_lte_eNB(RC.eNB[inst][CC_id],0,0);
}
......
......@@ -138,6 +138,7 @@ extern int16_t dlsch_demod_shift;
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define CMDLINE_PARAMS_DESC { \
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)}, \
{"turbo-thread-pool", NULL, 0, strptr:(char **)&threadpool, defstrval:NULL, TYPE_STRING, sizeof(threadpool)}, \
{"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \
......
#define __USE_GNU
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
// OAI includes
uint64_t cpuCyclesMicroSec;
static __inline__ uint64_t rdtsc(void) {
uint64_t a, d;
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
return (d<<32) | a;
}
#include "thread-pool.h"
int main(int argc, char* argv[]) {
uint64_t deb=rdtsc();
usleep(100000);
cpuCyclesMicroSec=(rdtsc()-deb)/100000;
printf("Cycles per µs: %lu\n",cpuCyclesMicroSec);
#define SEP " "
printf("Frame" SEP "SubFrame" SEP "CodeBlock" SEP "RNTI" SEP "Iterations" SEP
"StartTime" SEP "RunTime" SEP "ReturnTime" SEP
"CPUcore" SEP "ThreadID" "\n");
mkfifo("/tmp/test-tcri",0666);
int fd=open("/tmp/test-tcri", O_RDONLY);
if ( fd == -1 ) {
perror("open read mode trace file:");
exit(1);
}
request_t doneRequest;
int s=sizeof(request_t) -2*sizeof(void*);
while ( 1 ) {
if ( read(fd,&doneRequest, s) == s ) {
union turboReqUnion id={.p=doneRequest.id};
doneRequest.processedBy[15]='\0';
printf("%u" SEP "%u" SEP "%u" SEP "%u" SEP "%lu" SEP
"%lu" SEP "%lu" SEP "%lu" SEP
"%u" SEP "%s" "\n",
id.s.frame,
id.s.subframe,
id.s.codeblock,
id.s.rnti,
doneRequest.decodeIterations,
(doneRequest.startProcessingTime-doneRequest.creationTime)/cpuCyclesMicroSec,
(doneRequest.endProcessingTime-doneRequest.startProcessingTime)/cpuCyclesMicroSec,
(doneRequest.returnTime-doneRequest.endProcessingTime)/cpuCyclesMicroSec,
doneRequest.coreId,
doneRequest.processedBy
);
} else {
printf("no measurements\n");
sleep(1);
}
}
}
#define __USE_GNU
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdbool.h>
// OAI includes
#include <assertions.h>
#include <log.h>
#include "PHY/TOOLS/time_meas.h"
#include "PHY/CODING/defs.h"
#include "PHY/CODING/extern.h"
#include <thread-pool.h>
#ifdef DEBUG
#define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#else
#define THREADINIT PTHREAD_MUTEX_INITIALIZER
#endif
request_t * createRequest(enum request_t type,int size) {
request_t* request;
AssertFatal( (request = (request_t*)aligned_alloc(32,sizeof(request_t)+size)) != NULL,"");
request->id = 0;
request->type=type;
request->next = NULL;
request->creationTime=rdtsc();
request->data=(void*)(request+1);
return request;
}
void freeRequest(request_t* request) {
free(request);
}
int add_request(request_t* request, tpool_t * tp) {
AssertFatal(pthread_mutex_lock(&tp->lockRequests)==0,"");
if (tp->oldestRequests == NULL)
tp->oldestRequests = request;
else {
AssertFatal(tp->newestRequests != NULL, "");
tp->newestRequests->next = request;
}
tp->newestRequests = request;
AssertFatal(pthread_mutex_lock(&tp->lockReportDone)==0,"");
tp->notFinishedJobs++;
//printf("added:%d\n", tp->notFinishedJobs);
AssertFatal(pthread_mutex_unlock(&tp->lockReportDone)==0,"");
AssertFatal(pthread_cond_broadcast(&tp->notifRequest)==0,"");
AssertFatal(pthread_mutex_unlock(&tp->lockRequests)==0,"");
return 0;
}
int add_requests(uint64_t request_num, tpool_t * tp) {
request_t* request;
int nbToAdd=((uint32_t)lrand48())%20+1;
for (int i=0; i<nbToAdd; i++) {
// simulate request
request=createRequest(DECODE,sizeof(turboDecode_t));
union turboReqUnion id= {.s={request_num*100+i,1000,i*10,111,222}};
request->id= id.p;
turboDecode_t * rdata=(turboDecode_t *) request->data;
rdata->function=phy_threegpplte_turbo_decoder8;
rdata->Kr=6144;
rdata->iind=0; // not used, OAI code need cleanup!!!
rdata->Fbits=0;
rdata->maxIterations=6;
if (tp->oldestRequests == NULL)
tp->oldestRequests = request;
else
tp->newestRequests->next = request;
tp->newestRequests = request;
}
return nbToAdd;
}
request_t * get_request(tpool_t * tp, uint16_t threadID ) {
int nb=0;
request_t* r=tp->oldestRequests;
while (r!=NULL) {
nb++;
r=r->next;
}
request_t* request=tp->oldestRequests;
if (request == NULL)
return NULL;
if ( tp->restrictRNTI ) {
request_t** start=&tp->oldestRequests;
request = NULL;
while(*start!=NULL && request==NULL) {
union turboReqUnion id= {.p=(*start)->id};
if ( id.s.rnti % tp->nbThreads == threadID ) {
request=*start;
*start=(*start)->next;
} else
start=&((*start)->next);
}
} else
tp->oldestRequests = request->next;
if ( tp->oldestRequests == NULL)
tp->newestRequests=NULL;
int nnb=0;
r=tp->oldestRequests;
while (r!=NULL) {
nnb++;
r=r->next;
}
//if ( ! ( nb == nnb && request == NULL))
//printf("getr:was=%d,is=%d,gotit=%p\n",nb,nnb,request);
return request;
}
request_t * searchRNTI(tpool_t * tp, rnti_t rnti) {
request_t * result=NULL;
request_t ** start=&tp->oldestRequests;
while(*start!=NULL && result==NULL) {
union turboReqUnion id= {.p=(*start)->id};
if ( id.s.rnti == rnti ) {
result=*start;
*start=(*start)->next;
if ( tp->oldestRequests == NULL)
tp->newestRequests=NULL;
} else
start=&((*start)->next);
}
return result;
}
void process_request(request_t* request) {
//printf("S:%s...",request->type==DECODE?"D":"E");
switch(request->type) {
case DECODE : {
time_stats_t oaitimes[7];
turboDecode_t * rdata=(turboDecode_t*) request->data;
rdata->decodeIterations=rdata->function(rdata->soft_bits+96,
rdata->decoded_bytes,
rdata->Kr,
f1f2mat_old[rdata->iind*2],
f1f2mat_old[(rdata->iind*2)+1],
rdata->maxIterations,
rdata->nbSegments == 1 ? CRC24_A: CRC24_B,
rdata->Fbits,
oaitimes+0,
oaitimes+1,
oaitimes+2,
oaitimes+3,
oaitimes+4,
oaitimes+5,
oaitimes+6);
};
break;
case ENCODE : {
turboEncode_t * rdata=(turboEncode_t*) request->data;
memset(rdata->output,LTE_NULL,TURBO_SIMD_SOFTBITS);
threegpplte_turbo_encoder(rdata->input,
rdata->Kr_bytes,
rdata->output+96,//&dlsch->harq_processes[harq_pid]->d[r][96],
rdata->filler,
f1f2mat_old[rdata->iind*2], // f1 (see 36121-820, page 14)
f1f2mat_old[(rdata->iind*2)+1] // f2 (see 36121-820, page 14)
);
};
break;
default:
AssertFatal(false,"");
}
//printf("..End\n");
}
void handle_request(tpool_t * tp, request_t* request) {
request->startProcessingTime=rdtsc();
process_request(request);
request->endProcessingTime=rdtsc();
AssertFatal(pthread_mutex_lock(&tp->lockReportDone)==0,"");
tp->notFinishedJobs--;
//printf("Removed:%d\n",tp->notFinishedJobs);
request->next=tp->doneRequests;
tp->doneRequests=request;
//printf("signaling ...");
AssertFatal(pthread_cond_signal(&tp->notifDone)==0,"");
//printf("...done\n");
AssertFatal(pthread_mutex_unlock(&tp->lockReportDone)==0,"");
/*
printf("Thread '%ld' handled request '%d' delay in µs:%ld\n",
syscall( SYS_gettid ),
request->id,
(rdtsc() - request->creationTime)/tp->cpuCyclesMicroSec);
*/
}
void* one_thread(void* data) {
struct one_thread * myThread=(struct one_thread *) data;
struct thread_pool* tp=myThread->pool;
// configure the thread core assignment
// TBD: reserve the core for us exclusively
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(myThread->coreID, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
//Configure the thread scheduler policy for Linux
struct sched_param sparam= {0};
sparam.sched_priority = sched_get_priority_max(SCHED_RR);
pthread_setschedparam(pthread_self(), SCHED_RR, &sparam);
// set the thread name for debugging
sprintf(myThread->name,"Tcodec_%d",myThread->coreID);
pthread_setname_np(pthread_self(), myThread->name );
// Infinite loop to process requests
do {
AssertFatal(pthread_mutex_lock(&tp->lockRequests)==0,"");
request_t* request = get_request(tp, myThread->id);
if (request == NULL) {
AssertFatal(pthread_cond_wait(&tp->notifRequest,&tp->lockRequests)==0,"");
request = get_request(tp, myThread->id);
}
AssertFatal(pthread_mutex_unlock(&tp->lockRequests)==0,"");
if (request!=NULL) {
strncpy(request->processedBy,myThread->name, 15);
request->coreId=myThread->coreID;
handle_request(tp, request);
}
} while (true);
}
void init_tpool(char * params,tpool_t * pool) {
mkfifo("/tmp/test-tcri",0666);
pool->dummyTraceFd=open("/tmp/test-tcri", O_RDONLY| O_NONBLOCK);
if ( pool->dummyTraceFd == -1 ) {
perror("open read mode trace file:");
exit(1);
}
pool->traceFd=open("/tmp/test-tcri", O_WRONLY|O_APPEND|O_NOATIME|O_NONBLOCK);
if ( pool->traceFd == -1 ) {
perror("open trace file:");
exit(1);
}
//Configure the thread scheduler policy for Linux
struct sched_param sparam= {0};
sparam.sched_priority = sched_get_priority_max(SCHED_RR)-1;
pthread_setschedparam(pthread_self(), SCHED_RR, &sparam);
pool->activated=true;
pthread_mutex_init(&pool->lockRequests,NULL);
pthread_cond_init (&pool->notifRequest,NULL);
pthread_mutex_init(&pool->lockReportDone,NULL);
pthread_cond_init (&pool->notifDone,NULL);
pool->oldestRequests=NULL;
pool->newestRequests=NULL;
pool->doneRequests=NULL;
pool->notFinishedJobs=0;
pool->allthreads=NULL;
char * saveptr, * curptr;
pool->nbThreads=0;
pool->restrictRNTI=false;
curptr=strtok_r(params,",",&saveptr);
while ( curptr!=NULL ) {
if (curptr[0] == 'u' || curptr[0] == 'U') {
pool->restrictRNTI=true;
} else if ( curptr[0]>='0' && curptr[0]<='9' ) {
struct one_thread *tmp=pool->allthreads;
pool->allthreads=(struct one_thread *)malloc(sizeof(struct one_thread));
pool->allthreads->next=tmp;
printf("create a thread for core %d\n", atoi(curptr));
pool->allthreads->coreID=atoi(curptr);
pool->allthreads->id=pool->nbThreads;
pool->allthreads->pool=pool;
pthread_create(&pool->allthreads->threadID, NULL, one_thread, (void*)pool->allthreads);
pool->nbThreads++;
} else if (curptr[0] == 'n' || curptr[0] == 'N') {
pool->activated=false;
} else
printf("Error in options for thread pool: %s\n",curptr);
curptr=strtok_r(NULL,",",&saveptr);
}
if (pool->activated && pool->nbThreads==0) {
printf("No servers created in the thread pool, exit\n");
exit(1);
}
uint64_t deb=rdtsc();
usleep(100000);
pool->cpuCyclesMicroSec=(rdtsc()-deb)/100000;
printf("Cycles per µs: %lu\n",pool->cpuCyclesMicroSec);
}
void displayList(request_t*start, request_t*end) {
int n=0;
while(start!=NULL) {
n++;
union turboReqUnion id= {.p=start->id};
printf("rnti:%u frame:%u-%u codeblock:%u\n",
id.s.rnti,
id.s.frame,
id.s.subframe,
id.s.codeblock);
if ( start->next==NULL && start!=end)
printf("Error of end pointer");
start=start->next;
}
printf("End of list: %d elements\n",n);
}
#ifdef TESTMAIN
#include "PHY/CODING/lte_interleaver.h"
#include "PHY/CODING/lte_interleaver2.h"
int main(int argc, char* argv[]) {
if (argc<2) {
printf("Usage: %s core,core,...\n",argv[0]);
exit(1);
}
// configure the thread core assignment: client thread on core 0
// TBD: reserve the core for us exclusively
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
tpool_t pool;
init_tpool(argv[1], &pool);
//initialize turbo decoder tables
init_td8();
uint64_t i=1;
// Test the lists
srand48(time(NULL));
AssertFatal(pthread_mutex_lock(&pool.lockRequests)==0,"");
int nbRequest=add_requests(i, &pool);
printf("These should be: %d elements in the list\n",nbRequest);
displayList(pool.oldestRequests, pool.newestRequests);
// remove in middle
request_t *req106=searchRNTI(&pool.oldestRequests, &pool.newestRequests, 106);
if (req106) {
union turboReqUnion id= {.p=req106->id};
printf("Removed: rnti:%u frame:%u-%u codeblock:%u, check it\n",
id.s.rnti,
id.s.frame,
id.s.subframe,
id.s.codeblock);
freeRequest(req106);
} else
printf("no rnti 106\n");
displayList(pool.oldestRequests, pool.newestRequests);
request_t *reqlast=searchRNTI(&pool.oldestRequests, &pool.newestRequests,
100+nbRequest-1);
if (reqlast) {
printf("Removed last item, check it\n");
freeRequest(reqlast);
} else
printf("tried to removed from empty list\n");
displayList(pool.oldestRequests, pool.newestRequests);
printf("Remove all jobs\n");
while(pool.oldestRequests!=NULL)
get_request(&pool);
printf("List should be empty now\n");
displayList(pool.oldestRequests, pool.newestRequests);
AssertFatal(pthread_mutex_unlock(&pool.lockRequests)==0,"");
while (1) {
uint64_t now=rdtsc();
/* run a loop that generates a lot of requests */
AssertFatal(pthread_mutex_lock(&pool.lockRequests)==0,"");
int nbRequest=add_requests(i, &pool);
AssertFatal(pthread_mutex_lock(&pool.lockReportDone)==0,"");
pool.notFinishedJobs+=nbRequest;
AssertFatal(pthread_mutex_unlock(&pool.lockReportDone)==0,"");
AssertFatal(pthread_cond_broadcast(&pool.notifRequest)==0,"");
AssertFatal(pthread_mutex_unlock(&pool.lockRequests)==0,"");
/*
// The main thread also process the queue
AssertFatal(pthread_mutex_lock(&pool.lockRequests)==0,"");
request_t* request= NULL;
while ( (request=get_request(&pool)) != NULL ) {
AssertFatal(pthread_mutex_unlock(&pool.lockRequests)==0,"");
strcpy(request->processedBy,"MainThread");
handle_request(&pool, request);
AssertFatal(pthread_mutex_lock(&pool.lockRequests)==0,"");
}
AssertFatal(pthread_mutex_unlock(&pool.lockRequests)==0,"");
*/
// Wait all other threads finish to process
AssertFatal(pthread_mutex_lock(&pool.lockReportDone)==0,"");
while ( pool.notFinishedJobs > 0 ) {
AssertFatal(pthread_cond_wait(&pool.notifDone,&pool.lockReportDone)==0,"");
}
AssertFatal(pthread_mutex_unlock(&pool.lockReportDone)==0,"");
while (pool.doneRequests!=NULL) {
pool.doneRequests->returnTime=rdtsc();
if(write(pool.traceFd,pool.doneRequests,sizeof(request_t))) {};
request_t* tmp=pool.doneRequests;
pool.doneRequests=pool.doneRequests->next;
free(tmp);
}
printf("Requests %lu Done %d requests in %ld µsec\n",i, nbRequest, (rdtsc()-now)/pool.cpuCyclesMicroSec);
i++;
};
return 0;
}
#endif
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#include <stdbool.h>
#include <openair2/COMMON/platform_types.h>
enum request_t {
DECODE,
ENCODE
};
struct turboReqId {
uint16_t rnti;
uint16_t frame;
uint8_t subframe;
uint8_t codeblock;
uint16_t spare;
} __attribute__((packed));
union turboReqUnion {
struct turboReqId s;
uint64_t p;
};
typedef struct request {
uint64_t id;
enum request_t type;
uint64_t creationTime;
uint64_t startProcessingTime;
uint64_t endProcessingTime;
uint64_t returnTime;
uint64_t decodeIterations;
int coreId;
char processedBy[16];
struct request* next;
void * data __attribute__((aligned(32)));
} request_t;
struct one_thread {
pthread_t threadID;
int id;
int coreID;
char name[256];
struct thread_pool * pool;
struct one_thread* next;
};
typedef struct thread_pool {
int activated;
pthread_mutex_t lockRequests;
pthread_cond_t notifRequest;
pthread_mutex_t lockReportDone;
pthread_cond_t notifDone;
request_t* oldestRequests;
request_t* newestRequests;
request_t* doneRequests;
int notFinishedJobs;
int traceFd;
int dummyTraceFd;
uint64_t cpuCyclesMicroSec;
int nbThreads;
bool restrictRNTI;
struct one_thread * allthreads;
} tpool_t;
void init_tpool(char*,tpool_t* );
request_t * createRequest(enum request_t type,int size);
void freeRequest(request_t* request);
int add_request(request_t* request, tpool_t * tp);
request_t * searchRNTI(tpool_t*, rnti_t rnti);
#endif
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