Compare commits

..

5 Commits

Author SHA1 Message Date
Onur Yener
2707062b2e lte-ue errors 2022-06-16 11:45:05 +02:00
Onur Yener
2ae8159137 ue_decode_si error 2022-06-16 11:19:22 +02:00
Onur Yener
1d990120b9 MAX_MESSAGE_SIZE 2022-06-16 11:01:48 +02:00
Onur Yener
04e91c56a6 lte_frame_type_t error 2022-06-16 10:51:47 +02:00
Onur Yener
f97177c98f d2d merge on develop 2022-06-16 10:32:35 +02:00
358 changed files with 28048 additions and 147151 deletions

20
.gitignore vendored
View File

@@ -9,29 +9,9 @@ cmake_targets/nas_sim_tools/build/
log/
lte_build_oai/
targets/bin/
core
*.lseq
*.lcheck
*.out
# object files
*.o
*.obj
*.orig
# vscode
.vscode
.vscode/launch.json
# python virtual env
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Tags for vim/global
GPATH

View File

@@ -1 +0,0 @@
include ../Makefile

View File

@@ -21,6 +21,8 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
servingCellConfigCommon = (
{
#spCellConfigCommon

View File

@@ -32,6 +32,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (
{

View File

@@ -21,6 +21,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (

View File

@@ -32,6 +32,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (

View File

@@ -21,6 +21,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
servingCellConfigCommon = (

View File

@@ -44,6 +44,7 @@ gNBs =
local_s_portd = 2152;
remote_s_portc = 500;
remote_s_portd = 2152;
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (

View File

@@ -36,6 +36,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (

View File

@@ -37,6 +37,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;

View File

@@ -38,6 +38,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;

View File

@@ -21,6 +21,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
servingCellConfigCommon = (

View File

@@ -21,6 +21,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
servingCellConfigCommon = (

View File

@@ -19,6 +19,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
ul_prbblacklist = "51,52,53,54"

View File

@@ -41,6 +41,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pusch_AntennaPorts = 2;
ul_prbblacklist = "51,52,53,54"
do_SRS = 1;

View File

@@ -37,6 +37,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
ul_prbblacklist = "51,52,53,54"

View File

@@ -37,6 +37,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pusch_AntennaPorts = 2;
ul_prbblacklist = "51,52,53,54"
do_SRS = 1;

View File

@@ -37,6 +37,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
#pusch_TargetSNRx10 = 200;
#pucch_TargetSNRx10 = 200;
ul_prbblacklist = "51,52,53,54"

View File

@@ -37,6 +37,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 2;
#pusch_TargetSNRx10 = 200;

View File

@@ -21,6 +21,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
servingCellConfigCommon = (

View File

@@ -19,6 +19,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
servingCellConfigCommon = (
{

View File

@@ -20,6 +20,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
min_rxtxtime = 6;
servingCellConfigCommon = (

View File

@@ -32,6 +32,7 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (

View File

@@ -32,6 +32,9 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 0;
pdsch_AntennaPorts = 1;
pusch_AntennaPorts = 1;
sib1_tda = 15;
min_rxtxtime = 6;

View File

@@ -1,240 +0,0 @@
Active_eNBs = ( "eNB-Eurecom-LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB-Eurecom-LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } );
tr_s_preference = "local_mac"
////////// Physical parameters:
component_carriers = (
{
node_function = "3GPP_eNODEB";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2680000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 50;
Nid_cell_mbsfn = 0;
nb_antenna_ports = 1;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
tx_gain = 90;
rx_gain = 125;
pbch_repetition = "FALSE";
prach_root = 0;
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 0;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -27;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -96;
pusch_alpha = "AL1";
pucch_p0_Nominal = -104;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
ue_TransmissionMode = 1;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "10.193.4.249";
ipv6 = "";
active = "yes";
preference = "ipv4";
}
);
enable_measurement_reports = "no";
///X2
enable_x2 = "no";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
ENB_IPV4_ADDRESS_FOR_S1_MME = "10.193.4.248";
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
ENB_IPV4_ADDRESS_FOR_S1U = "10.193.4.248";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
ENB_IPV4_ADDRESS_FOR_X2C = "10.193.4.248";
ENB_PORT_FOR_X2C = 36422; # Spec 36422
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 160;
puCch10xSnr = 160;
#scheduler_mode = "fairRR";
#scheduler_mode = "default";
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 120;
eNB_instances = [0];
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_DISABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
FLEXRAN_INTERFACE_NAME = "lo";
FLEXRAN_IPV4_ADDRESS = "127.0.0.1";
FLEXRAN_PORT = 2210;
FLEXRAN_CACHE = "/mnt/oai_agent_cache";
FLEXRAN_AWAIT_RECONF = "no";
};
log_config :
{
global_log_level ="warn";
global_log_verbosity ="high";
hw_log_level ="warn";
hw_log_verbosity ="high";
phy_log_level ="warn";
phy_log_verbosity ="high";
mac_log_level ="warn";
mac_log_verbosity ="high";
rlc_log_level ="warn";
rlc_log_verbosity ="high";
pdcp_log_level ="warn";
pdcp_log_verbosity ="high";
rrc_log_level ="warn";
rrc_log_verbosity ="high";
};

View File

@@ -1,238 +0,0 @@
Active_eNBs = ( "eNB-Eurecom-LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB-Eurecom-LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } );
tr_s_preference = "local_mac"
////////// Physical parameters:
component_carriers = (
{
node_function = "3GPP_eNODEB";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2680000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 50;
Nid_cell_mbsfn = 0;
nb_antenna_ports = 1;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
tx_gain = 90;
rx_gain = 125;
pbch_repetition = "FALSE";
prach_root = 0;
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 0;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -27;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -96;
pusch_alpha = "AL1";
pucch_p0_Nominal = -104;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
ue_TransmissionMode = 1;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "10.193.4.249";
ipv6 = "";
active = "yes";
preference = "ipv4";
}
);
enable_measurement_reports = "no";
///X2
enable_x2 = "no";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
ENB_IPV4_ADDRESS_FOR_S1_MME = "10.193.4.248";
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
ENB_IPV4_ADDRESS_FOR_S1U = "10.193.4.248";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
ENB_IPV4_ADDRESS_FOR_X2C = "10.193.4.248";
ENB_PORT_FOR_X2C = 36422; # Spec 36422
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 116;
eNB_instances = [0];
sdr_addrs = "type=x300";
}
);
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_DISABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
FLEXRAN_INTERFACE_NAME = "lo";
FLEXRAN_IPV4_ADDRESS = "127.0.0.1";
FLEXRAN_PORT = 2210;
FLEXRAN_CACHE = "/mnt/oai_agent_cache";
FLEXRAN_AWAIT_RECONF = "no";
};
log_config :
{
global_log_level ="warn";
global_log_verbosity ="high";
hw_log_level ="warn";
hw_log_verbosity ="high";
phy_log_level ="warn";
phy_log_verbosity ="high";
mac_log_level ="warn";
mac_log_verbosity ="high";
rlc_log_level ="warn";
rlc_log_verbosity ="high";
pdcp_log_level ="warn";
pdcp_log_verbosity ="high";
rrc_log_level ="warn";
rrc_log_verbosity ="high";
};

View File

@@ -529,14 +529,14 @@ class Dashboard:
mr_notes = editable_mr.notes.list(all=True)
body = '[Consolidated Test Results](https://oaitestdashboard.s3.eu-west-1.amazonaws.com/MR'+mr+'/index.html)\\\n'
body += 'Tested CommitID: ' + commit
body += 'Tested CommitID: ' + commit + '\\\n'
for i in range(0,n_tests):
jobname = args[4*i]
buildurl = args[4*i+1]
buildid = args[4*i+2]
status = args[4*i+3]
body += '\\\n' + jobname + ': **'+status+'** ([' + buildid + '](' + buildurl + '))'
body += jobname+': **'+status+'** ([' + buildid + '](' + buildurl + '))\\\n'
#create new note
mr_note = editable_mr.notes.create({

View File

@@ -32,7 +32,7 @@
<testCase id="000001">
<class>Build_eNB</class>
<desc>Build gNB</desc>
<Build_eNB_args>-w USRP -c --gNB --ninja --noavx512</Build_eNB_args>
<Build_eNB_args>-w USRP -c --gNB --ninja</Build_eNB_args>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
<forced_workspace_cleanup>True</forced_workspace_cleanup>

View File

@@ -50,7 +50,7 @@
<testCase id="000002">
<class>Build_eNB</class>
<desc>Build gNB</desc>
<Build_eNB_args>-w USRP -c --gNB --ninja --noavx512</Build_eNB_args>
<Build_eNB_args>-w USRP -c --gNB --ninja</Build_eNB_args>
<eNB_instance>1</eNB_instance>
<eNB_serverId>1</eNB_serverId>
<backgroundBuild>True</backgroundBuild>

View File

@@ -34,7 +34,7 @@
<mode>TesteNB</mode>
<class>Build_eNB</class>
<desc>Build gNB (USRP)</desc>
<Build_eNB_args>--gNB -w USRP --ninja --cmake-opt -DBoost_INCLUDE_DIR=/usr/include/boost169 --noavx512</Build_eNB_args>
<Build_eNB_args>--gNB -w USRP --ninja --cmake-opt -DBoost_INCLUDE_DIR=/usr/include/boost169</Build_eNB_args>
<forced_workspace_cleanup>True</forced_workspace_cleanup>
</testCase>

View File

@@ -32,7 +32,7 @@
<testCase id="000001">
<class>Build_PhySim</class>
<desc>Build for physical simulator</desc>
<physim_build_args>--phy_simulators --ninja --noavx512</physim_build_args>
<physim_build_args>--phy_simulators --ninja</physim_build_args>
<forced_workspace_cleanup>FALSE</forced_workspace_cleanup>
</testCase>

View File

@@ -203,23 +203,17 @@ if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
else (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
if(EXISTS "/proc/cpuinfo")
file(STRINGS "/proc/cpuinfo" CPUINFO REGEX flags LIMIT_COUNT 1)
message("NOAVX512 is ${NOAVX512}")
if (CPUINFO MATCHES "avx512bw" AND "${NOAVX512}" STREQUAL "False")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512 " )
if (CPUINFO MATCHES "avx2")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mavx2")
set(COMPILATION_AVX2 "True")
else()
if (CPUINFO MATCHES "avx2")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mavx2")
set(COMPILATION_AVX2 "True")
else()
set(COMPILATION_AVX2 "False")
endif()
if (CPUINFO MATCHES "sse4_1")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1 -mpclmul")
endif()
if (CPUINFO MATCHES "ssse3")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mssse3")
endif()
set(COMPILATION_AVX2 "False")
endif()
if (CPUINFO MATCHES "sse4_1")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -msse4.1 -mpclmul")
endif()
if (CPUINFO MATCHES "ssse3")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -mssse3")
endif()
else()
Message("/proc/cpuinfo does not exit. We will use manual CPU flags")
@@ -230,11 +224,11 @@ set(C_FLAGS_PROCESSOR " ${C_FLAGS_PROCESSOR} ${CFLAGS_PROCESSOR_USER}")
Message("C_FLAGS_PROCESSOR is ${C_FLAGS_PROCESSOR}")
#if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
# if ( (NOT( C_FLAGS_PROCESSOR MATCHES "ssse3")) OR (NOT( C_FLAGS_PROCESSOR MATCHES "msse4.1")) )
# Message(FATAL_ERROR "For x86 Architecture, you must have following flags: -mssse3 -msse4.1. The current detected flags are: ${C_FLAGS_PROCESSOR}. You can pass the flags manually in build script, for example: ./build_oai --cflags_processor \"-mssse3 -msse4.1 -mavx2\" ")
# endif()
#endif()
if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
if ( (NOT( C_FLAGS_PROCESSOR MATCHES "ssse3")) OR (NOT( C_FLAGS_PROCESSOR MATCHES "msse4.1")) )
Message(FATAL_ERROR "For x86 Architecture, you must have following flags: -mssse3 -msse4.1. The current detected flags are: ${C_FLAGS_PROCESSOR}. You can pass the flags manually in build script, for example: ./build_oai --cflags_processor \"-mssse3 -msse4.1 -mavx2\" ")
endif()
endif()
#
# add autotools definitions that were maybe used!
@@ -253,22 +247,6 @@ add_boolean_option(SANITIZE_ADDRESS False "enable the address sanitizer (ASan)")
if (SANITIZE_ADDRESS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common")
# There seems to be some incompatibility with pthread_create and the RT scheduler, which
# results in pthread_create hanging.
#
# When we switch from Ubuntu 16.04 to 18.04, we found that running with the address sanitizer,
# the pthread_create function calls were not working. The inital thought was that we were
# trying to create a thread that was not-blocking and would eventually crash the machine during
# the run. After more debugging, we found that we would never even start the thread. We narrowed
# down the first two instances of pthread_create in the gNB and NR UE to be sctp_eNB_task and
# one_thread, respectively. We found that adding sleeps, and various other pauses to the threads
# had not effect. From there, we found that if we add an abort(); prior to the thread loop, we
# do not execute that. This indicated to us that the problem is not likely to be a non-blocking
# thread, but perhaps and issue with pthread_create itself. From there we begain to research the
# issue on the web. See: https://github.com/google/sanitizers/issues/1125
#
# Google searching indicates this appears to be a problem since at least 2018. This could be something
# wrong in the pthread library, or something subtly wrong in this CMakeLists.txt. Use Ubuntu 20.04 instead.
endif ()
add_definitions("-DASN_DISABLE_OER_SUPPORT")
@@ -340,7 +318,6 @@ add_boolean_option(DEBUG_MAC_INTERFACE False "print MAC-RLC PDU exchange to stdo
add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace
add_boolean_option(PRINT_STATS False "This adds the possibility to see the status")
add_boolean_option(T_TRACER True "Activate the T tracer, a debugging/monitoring framework" )
add_boolean_option(LATSEQ False "Active Latency Sequence tools")
add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs")
add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace")
add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace")
@@ -1203,7 +1180,6 @@ add_library(UTIL
${OPENAIR2_DIR}/UTIL/LISTS/list2.c
${OPENAIR_DIR}/common/utils/LOG/log.c
${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.c
${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c
${OPENAIR2_DIR}/UTIL/MATH/oml.c
${OPENAIR2_DIR}/UTIL/OPT/probe.c
${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
@@ -1408,11 +1384,8 @@ set(PHY_NR_CODINGIF
)
add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} )
target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} )
target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} )
target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS)
add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} )
target_link_libraries(ldpc_cl OpenCL)
add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL)
@@ -1424,7 +1397,6 @@ if (CUDA_FOUND)
endif (CUDA_FOUND)
add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} )
target_link_libraries(ldpc PRIVATE ldpc_gen_HEADERS)
add_library(coding MODULE ${PHY_TURBOSRC} )
@@ -1435,9 +1407,13 @@ add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c )
set(PHY_SRC_COMMON
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
# ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/slss.c
# ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/sldch.c
# ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/slsch.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pbch.c #Source files that had to be added after merge with sidelink
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_modulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_coding.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pcfich.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/get_pmi.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/group_hopping.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/phich_common.c
@@ -1450,6 +1426,10 @@ set(PHY_SRC_COMMON
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/srs_modulation.c
${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c #Source files that had to be added after merge with sidelink
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c
${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_cell_spec.c
${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_uespec.c
${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold.c
@@ -1545,6 +1525,9 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/prach_ue.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/pmch_ue.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/pch_ue.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/slpss.c #Transfer sidelink source files to LTE_TRANSPORT_UE
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/slsss.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/slbch.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/slss.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/sldch.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/slsch.c
@@ -1553,6 +1536,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/ulsch_coding.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/rar_tools_ue.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/initial_sync.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/initial_syncSL.c
${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c
${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_mbsfn.c
${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz_ue.c
@@ -1723,7 +1707,6 @@ set(PHY_MEX_UE
${OPENAIR1_DIR}/PHY/TOOLS/signal_energy.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c
${OPENAIR_DIR}/common/utils/LOG/log.c
${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c
${OPENAIR_DIR}/common/utils/T/T.c
${OPENAIR_DIR}/common/utils/T/local_tracer.c
)
@@ -1955,7 +1938,6 @@ set (MAC_SRC_UE
set (MAC_NR_SRC_UE
${NR_UE_PHY_INTERFACE_DIR}/NR_IF_Module.c
${NR_UE_PHY_INTERFACE_DIR}/NR_Packet_Drop.c
${NR_UE_MAC_DIR}/config_ue.c
${NR_UE_MAC_DIR}/mac_vars.c
${NR_UE_MAC_DIR}/main_ue_nr.c
@@ -3184,4 +3166,3 @@ ADD_CUSTOM_TARGET(oarf
)
include (${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_CMakeLists.txt)
include(${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt)

View File

@@ -1062,8 +1062,7 @@
(Test3: PBCH-only, 217 PRB),
(Test4: PBCH and synchronization, 217 RPB),
(Test5: PBCH-only, 273 PRB),
(Test6: PBCH and synchronization, 273 PRB),
(Test7: PBCH and synchronization, 106PBR, SSB SC OFFSET 6)</desc>
(Test6: PBCH and synchronization, 273 PRB)</desc>
<pre_compile_prog></pre_compile_prog>
<compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
<compile_prog_args> --phy_simulators -c </compile_prog_args>
@@ -1075,9 +1074,8 @@
-s-11 -S-8 -n10 -R217
-s-11 -S-8 -n10 -o8000 -I -R217
-s-11 -S-8 -n10 -R273
-s-11 -S-8 -n10 -o8000 -I -R273
-s-11 -S-8 -n10 -R106 -O6</main_exec_args>
<tags>nr_pbchsim.test1 nr_pbchsim.test2 nr_pbchsim.test3 nr_pbchsim.test4 nr_pbchsim.test5 nr_pbchsim.test6 nr_pbchsim.test7</tags>
-s-11 -S-8 -n10 -o8000 -I -R273</main_exec_args>
<tags>nr_pbchsim.test1 nr_pbchsim.test2 nr_pbchsim.test3 nr_pbchsim.test4 nr_pbchsim.test5 nr_pbchsim.test6</tags>
<search_expr_true>PBCH test OK</search_expr_true>
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>
@@ -1107,8 +1105,7 @@
(Test20: Mapping type B, 4 DMRS Symbols),
(Test21: 4x4 MIMO, 1 Layer),
(Test22: 4x4 MIMO, 2 Layers),
(Test23: 25 PRBs, 15 kHz SCS)
(Test24: MCS 0, low SNR performance)</desc>
(Test23: 25 PRBs, 15 kHz SCS)</desc>
<pre_compile_prog></pre_compile_prog>
<compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
<compile_prog_args> --phy_simulators -c </compile_prog_args>
@@ -1137,9 +1134,8 @@
-n100 -s2 -U 2 1 3
-n10 -s20 -U 3 0 0 2 -gR -x1 -y4 -z4
-n10 -s20 -U 3 0 0 2 -gR -x2 -y4 -z4
-n100 -m0 -e0 -R25 -b25 -i 2 1 0
-n100 -e0 -t95 -S-1.0 -i 2 1 0</main_exec_args>
<tags>nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 nr_dlsim.test11 nr_dlsim.test12 nr_dlsim.test13 nr_dlsim.test14 nr_dlsim.test15 nr_dlsim.test16 nr_dlsim.test17 nr_dlsim.test18 nr_dlsim.test19 nr_dlsim.test20 nr_dlsim.test21 nr_dlsim.test22 nr_dlsim.test23 nr_dlsim.test24</tags>
-n100 -m0 -e0 -R25 -b25 -i 2 1 0</main_exec_args>
<tags>nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 nr_dlsim.test11 nr_dlsim.test12 nr_dlsim.test13 nr_dlsim.test14 nr_dlsim.test15 nr_dlsim.test16 nr_dlsim.test17 nr_dlsim.test18 nr_dlsim.test19 nr_dlsim.test20 nr_dlsim.test21 nr_dlsim.test22 nr_dlsim.test23</tags>
<search_expr_true>PDSCH test OK</search_expr_true>
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>
@@ -1318,8 +1314,7 @@
(Test18: 25 PRBs, 15 kHz SCS),
(Test19: 3GPP G-FR1-A4-13 2 RX Antennas Requirements Test),
(Test20: 3GPP G-FR1-A4-13 4 RX Antennas Requirements Test),
(Test21: 3GPP G-FR1-A4-13 8 RX Antennas Requirements Test),
(Test22: MCS 0, low SNR performance)</desc>
(Test21: 3GPP G-FR1-A4-13 8 RX Antennas Requirements Test)</desc>
<pre_compile_prog></pre_compile_prog>
<compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
<compile_prog_args> --phy_simulators -c </compile_prog_args>
@@ -1346,9 +1341,9 @@
-n100 -u0 -m0 -R25 -r25 -i 2 1 0
-m16 -r106 -s8.8 -S9.4 -z2 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0
-m16 -r106 -s5.4 -S6 -z4 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0
-m16 -r106 -s3.4 -S3.8 -z8 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0
-n100 -m0 -S -0.6 -i 2 1 0</main_exec_args>
<tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 nr_ulsim.test18 nr_ulsim.test19 nr_ulsim.test20 nr_ulsim.test21 nr_ulsim.test22</tags>
-m16 -r106 -s3.4 -S3.8 -z8 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0</main_exec_args>
<tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 nr_ulsim.test18 nr_ulsim.test19 nr_ulsim.test20 nr_ulsim.test21</tags>
<search_expr_true>PUSCH test OK</search_expr_true>
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>

View File

@@ -55,7 +55,6 @@ BUILD_COVERITY_SCAN=0
DISABLE_HARDWARE_DEPENDENCY="False"
CMAKE_BUILD_TYPE="RelWithDebInfo"
CMAKE_CMD="$CMAKE"
NOAVX512="False"
BUILD_ECLIPSE=0
NR="False"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope"
@@ -165,8 +164,6 @@ Options:
Build optional shared library, <libraries> can be one or several of $OPTIONAL_LIBRARIES or \"all\"
--usrp-recplay
Build for I/Q record-playback modes
--noavx512
Build without AVX512 if it is present on CPU
-k | --skip-shared-libraries
Skip build for shared libraries to reduce compilation time when building frequently for debugging purposes
--ninja
@@ -395,10 +392,6 @@ function main() {
CMAKE_CMD="$CMAKE_CMD -DT_TRACER=False"
echo_info "Disabling the T tracer"
shift 1;;
--enable-latseq)
CMAKE_CMD="$CMAKE_CMD -DLATSEQ=True"
echo info "Enabling Latency Sequence measures"
shift 1;;
--disable-hardware-dependency)
echo_info "Disabling hardware dependency for compiling software"
DISABLE_HARDWARE_DEPENDENCY="True"
@@ -443,10 +436,6 @@ function main() {
fi
fi
shift 2;;
--noavx512)
NOAVX512="True"
echo_info "Disabling AVX512"
shift 1;;
-k | --skip-shared-libraries)
SKIP_SHARED_LIB_FLAG="True"
echo_info "Skipping build of shared libraries, rfsimulator and transport protocol libraries"
@@ -456,7 +445,6 @@ function main() {
MAKE_CMD=ninja
shift;;
--sanitize-address | -fsanitize=address)
grep -sq "Ubuntu 18.04" /etc/os-release && echo_error "Bug in OS with this option, see CMakeLists.txt"
CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True"
shift;;
--ittiSIM)
@@ -636,7 +624,6 @@ function main() {
cd $DIR/$BUILD_DIR/build
if [[ ${#CMAKE_C_FLAGS[@]} > 0 ]]; then CMAKE_CMD="$CMAKE_CMD -DCMAKE_C_FLAGS=\"${CMAKE_C_FLAGS[*]}\""; fi
if [[ ${#CMAKE_CXX_FLAGS[@]} > 0 ]]; then CMAKE_CMD="$CMAKE_CMD -DCMAKE_CXX_FLAGS=\"${CMAKE_CXX_FLAGS[*]}\""; fi
CMAKE_CMD="$CMAKE_CMD -DNOAVX512=\"${NOAVX512[*]}\""
echo_info "running $CMAKE_CMD"
eval $CMAKE_CMD ../..

View File

@@ -109,7 +109,6 @@ check_supported_distribution() {
"ubuntu18.04") return 0 ;;
"ubuntu16.04") return 0 ;;
"fedora35") return 0 ;;
"fedora36") return 0 ;;
"rhel7") return 0 ;;
"rhel7.6") return 0 ;;
"rhel7.7") return 0 ;;
@@ -217,7 +216,6 @@ compilations() {
if [ "$MAKE_CMD" != "" ]; then
$MAKE_CMD $2
else
if [ "$VERBOSE_COMPILE" == "1" ]; then
$COV_SCAN_PREFIX make -j`nproc` $2 VERBOSE=$VERBOSE_COMPILE
else
@@ -625,6 +623,7 @@ check_install_additional_tools (){
android-tools-adb \
wvdial \
sshpass \
nscd \
bc \
ntp"
elif [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then
@@ -649,6 +648,7 @@ check_install_additional_tools (){
wvdial \
numpy \
sshpass \
nscd \
python2-paramiko \
python-pyroute2 \
python-netifaces \
@@ -676,6 +676,7 @@ check_install_additional_tools (){
wvdial \
python-numpy \
sshpass \
nscd \
python-paramiko \
python-pyroute2 \
python-netifaces \

View File

@@ -1,264 +0,0 @@
# LATency SEQuence analysis extension for OpenAirInterface
A tool for internal latency analysis in Base Station.
Code licenced under BSD-3. See more on https://github.com/Orange-OpenSource/LatSeq
Author : Flavien Ronteix--Jacquet (Orange Innovation), Alexandre Ferrieux (Orange Innovation)
Email : flavien.ronteixjacquet@orange.com, alexandre.ferrieux@orange.com
## Installation
- Put LatSeq extension source code in OAI code (https://gitlab.eurecom.fr/oai/openairinterface5g). We recommend to put it in the path common/utils/LATSEQ.
- In cmake_targets/CMakeLists.txt put `add_boolean_option(LATSEQ True "Active Latency Sequence tools")`. Also add Latseq to compiled source `set(UTIL_SRC... ${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c`
- Put test/ in targets/TEST/LATSEQ/
- Verify installation of LatSeq with `make` in targets/TEST/LATSEQ
## Usage
0) Add init_latseq(appname) and close_latseq() in main Base Station thread at the start and end.
1) Add a new LatSeq measure point in the code with
#include "common/utils/LATSEQ/latseq.h"
#if LATSEQ
LATSEQ_P("D pdcp--rlc", "pdcp%d.rlc%d", 0, 1);
#endif
where first argument is the direction, the second the observed segment and the third argument is a string of data_identifier
1) Compile OAI code with cmake option LATSEQ at True
2) Run scanario for Uplink and Downlink
3) Process lseq traces to yield data do statistics with LatSeq tools
More in docs/Latseq.pdf
## LatSeq measurement module
For now, latseq is designed to be the more independant as possible : Means that it does not use oai LOG system (not register by logInit()) and the flag "LATSEQ" disable all lines related to latseq in the code (using #ifdef). In a second time, it could be conceivable to integrate more deeply latseq into oai code.
latseq_t, global structure for latseq embodied the latseq logging info. log_buffer is a circular buffer with 2 head index, i_write_head and i_read_head. this buffer of latseq_element_t is designed to bo mutex-less.
LATSEQ_P macro calls log_measure(). The idea is to have a low-footprint at logging explains why log_measure() should do a minimal amount of operations.
latseq_log_to_file() is the function run in the logger thread. It writes log_elements in the log file.
LATSEQ_P with direction of D (Downlink) or U (Uplink) observed the passage of a data.
LATSEQ_P with direction of I (Information) observed a scalar property at a point of code. e.g. buffer occupancy.
**We assume that**:
- All the point and latseq module run on the same machine (to don't have to synchronize clock of different machines)
- Clock give by asm rdtsc is same for all the CPU cores (constant_tsc enabled)
## TOOLS
Get scripts on https://github.com/Orange-OpenSource/LatSeq/tools
- rdtsctots : convert rdtsc timestamp to unix timestamp value
- latseq_logs : convert lseq log file into useful json file for statistics and visualization
- filter_Is.awk : filter contextual informations
- lseqj2any : generate waterfall to format gp or svg
- latseq_checker : verify constitency of Latseq points before compiling
- latseq_filter : filter output of latseq_logs
- latseq_stats : perform statistic
### latseq_checker
Checker to verify that points LATSEQ_P points are consistent.
Verify the number of argument, the emptiness, format...
ex. ./latseq_checker.sh /home/oai/
### rdtsctots
convert rdtsc value to unix timestamp value
ex. `./rdtsctots.py trace_raw.lseq > trace.lseq`
### latseq_logs
Proceeds LatSeq logs.
A *.lseq is required.
By default, builds the latseq_log object.
- Reads lseq file given in raw_input
- Cleans raw_input to inputs.
- Builds points structure and paths possible.
- Saves object related to the *.lseq files to a *.plk (pickle)
**Arguments**:
- "-h" : help
- "-C" : cleans pickle file associated to the log file and rebuild
- "-l" : required lseq file of fingerprints
- "-i" : request cleaned input measurements in the case of command line script
- "-r" returns the paths present in the log file as json.
```
{
"D": [
["ip", "pdcp.in",...],
...
],
"U": ...
}
``̀
- "-p" returns points structure as json.
Becareful, if journeys has not been rebuilt, then you do not have "duration" attibute which is used for statistics.
```
{
"layer1.point": {
"next": [layer2.point2,...],
"count": 5,
"dir": [0],
"duration": {
"journeys uid": 0.0115,
...
}
}
}
{
...
}
```
- "-j" returns journeys structure as json.
- Rebuilds journeys with rebuild_packets_journey method
- Builds out_journeys
```
{
"uid": 52,
"dir": 0,
"glob": {
"rnti": "54614",...
},
"set": [[1542, 1592409314.253678, "rlc.rx.am--pdcp.rx"],[...],...], # set of pointer to input entry
"set_ids": {
"drb": "1",...
},
"path": 0, # path according to direction and paths obtainable by -p
"completed": true,
"ts_in": 123.456,
"ts_out": 789.012
}
{
...
}
```
- "-m" returns metadata of information as list
```
20200423_143226.191801 rlc.am.txbuf occ1:drb1
20200423_143226.191802 rlc.am.txbuf occ2:drb1
...
20200423_143226.192000 rlc.um.txbuf occ15:drb2
```
- "-o" returns a latseq journey file line by line. redirects output to a file to have a *.lseqj for waterfall generation
```
#funcId ip pdcp.in pdcp.tx rlc.tx.um rlc.seg.um mac.mux mac.txreq phy.out.proc phy.in.proc mac.demux rlc.rx.um rlc.unseg.um pdcp.rx
20200423_143226.191801 D (len64) ip--pdcp.in.gtp uid0.rnti54614.drb1.gsn12
20200423_143226.191802 D (len64) pdcp.in--pdcp.tx uid0.rnti54614.drb1.gsn12.psn10
20200423_143226.191803 D (len66) pdcp.tx--rlc.tx.um uid0.rnti54614.drb1.psn10.lcid3.rsdu0
```
Requested json are printed in stdout line by line
Errors, Warnings, Informations are printed in stderr
Example of usage:
./latseq_logs.py -l ~/latseq.23042020.lseq 2>/dev/null
./latseq_logs.py -j -l ~/latseq.23042020.lseq 2>/dev/null
./latseq_logs.py -p -l ~/latseq.23042020.lseq 2>/dev/null
./latseq_logs.py -o -l ~/latseq.23042020.lseq > 23042020.lseqj 2>/dev/null
### latseq_filter
Applies a filter to a json stream.
It uses jq filters.
Help website to design jq filter : https://jqplay.org/
Takes a file with a filter or a filter as string in argument.
Example of usage:
./latseq_filter.sh journeys_downlinks_gsn.lfilter
cat journeys_downlinks_gsn.lfilter
> select(.["dir"] == 0 and .["set_ids"]["gsn"] == "18")
### latseq_stats
Performs statistics from json. Report json or print in stdout.
By default, reads on stdin. "-l" *.lseq will try to open a *.json associated.
By default, returns a json report on stdout.
Arguments:
- "-f" enables to choose format "json", "csv",...
- "-P" prints statistics formated by the latseq_stats module.
- "-sj" returns statistics on journeys
`̀``
{
"D": {
"size": 34,
"min": 0.19598,
"max": 1.187086,
"mean": 0.788976,
"stdev": 0.153623,
"quantiles": [0.694859, 0.699043, 0.834942, 0.838041, 0.955701]
}
`̀``
- "-sjpp" returns the shares of delay introduced by each point for each journeys by path.
```
{
"U02": { # Uplinks, path 0, point 2
"size": 4,
"min": 0,
"max": 0.7273,
"mean": 0.36239999999999994,
"stdev": 0.2915949673776967,
"quantiles": [
0.025005000000000003,
0.125025,
0.36114999999999997,
0.598525,
0.7015449999999999
]
}
}
```
- "-sp" returns statistics on points
```
{
"pdcp.rx": {
"dir": "U",
"size": 4,
"min": 0.01,
"max": 0.02,
"mean": 0.015,
"stdev": 0.005,
"quantiles": [0.012,...] # 5%, 25%, 50%, 75%, 95%
},
...
}
`̀``
- "-djd" returns data journeys' duration
`̀``
{
"00": { # first decimal indicates uplink/downlink followed by the journey unique id
"ts": 1587645146.191801,
"durations": 0.19598 # in ms
},
...
}
`̀``
Example of usage of the full toolchain for LatSeq Analysis Module
./latseq_logs.py -l ~/latseq.simple.lseq -j 2>/dev/null | ./latseq_filter.sh journeys_downlinks_gsn.lfilt | ./latseq_stats.py -sj --print
### lseqj2any
generate waterfall
cat uplink_burst.30102020_203233.lseqj | lseqj2any gp > uplink_burst.gp
## TEST_LATSEQ
in targets/TEST/LATSEQ test_latseq test different part of latseq module
- "h" : help menu
- "i" : test init and close latseq
- "a" : test init, capture 2 fingerprints and close
- "t" : same test as "a" but with 2 concurrent threads
- "m" : test measurement time to capture 1000000 fingerprints
- "n" : test measurement time to capture 1000 fingerprints with 1,2,3,5,10 data identifiers
- "w" : test writer speed for a simplified data collector

View File

@@ -1,284 +0,0 @@
/*
* Software Name : LatSeq
* Version: 1.0
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 Orange Labs
* SPDX-License-Identifier: BSD-3-Clause
*
* This software is distributed under the BSD 3-clause,
* the text of which is available at https://opensource.org/licenses/BSD-3-Clause
* or see the "license.txt" file for more details.
*
* Author: Flavien Ronteix--Jacquet
* Software description: LatSeq measurement part core
*/
#define _GNU_SOURCE // required for pthread_setname_np()
#include "latseq.h"
/*--- GLOBALS and EXTERNS ----------------------------------------------------*/
latseq_t g_latseq;
__thread latseq_thread_data_t tls_latseq = {
.th_latseq_id = 0
}; // need to be a thread local storage variable.
pthread_t logger_thread;
pthread_t fflusher_thread;
//double cpuf; //cpu frequency in MHz -> usec. Should be initialized in main.c
extern volatile int oai_exit; //oai is ended. Close latseq
/*--- UTILS FUNCTIONS --------------------------------------------------------*/
uint64_t get_cpu_freq_cycles(void)
{
uint64_t ts = l_rdtsc();
sleep(1);
return (l_rdtsc() - ts);
}
/*--- MAIN THREAD FUNCTIONS --------------------------------------------------*/
int init_latseq(const char * appname, uint64_t cpufreq)
{
// init members
g_latseq.is_running = 0;
//synchronise time and rdtsc
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
g_latseq.time_zero = (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec;
g_latseq.rdtsc_zero = l_rdtsc(); //check at compile time that constant_tsc is enabled in /proc/cpuinfo
if (cpufreq == 0) {
g_latseq.cpu_freq = get_cpu_freq_cycles();
} else {
g_latseq.cpu_freq = cpufreq;
}
// Open traces
char time_string[16];
strftime(time_string, sizeof (time_string), "%d%m%Y_%H%M%S", localtime(&ts.tv_sec));
g_latseq.filelog_name = (char *)malloc(LATSEQ_MAX_STR_SIZE);
sprintf(g_latseq.filelog_name, "%s.%s.lseq", appname, time_string);
//open logfile
g_latseq.outstream = fopen(g_latseq.filelog_name, "w");
if (g_latseq.outstream == NULL) {
g_latseq.is_running = 0;
printf("[LATSEQ] Error at opening log file\n");
return -1;
}
//write header
char hdr[] = "# LatSeq packet fingerprints\n# By Alexandre Ferrieux and Flavien Ronteix Jacquet\n# timestamp\tU/D\tsrc--dest\tlen:ctxtId:localId\n";
size_t ret = fwrite(hdr, sizeof(char), sizeof(hdr) - 1, g_latseq.outstream);
if (ret < 0) {
printf("[LATSEQ] Error at opening log file\n");
g_latseq.is_running = 0;
return -1;
}
fprintf(g_latseq.outstream, "%ld S rdtsc--gettimeofday %ld.%09ld\n", g_latseq.rdtsc_zero, ts.tv_sec, ts.tv_nsec);
fflush(g_latseq.outstream);
// init registry
g_latseq.local_log_buffers.read_ith_thread = 0;
g_latseq.local_log_buffers.nb_th = 0;
memset(&g_latseq.local_log_buffers.i_read_heads, 0, MAX_NB_THREAD * sizeof(unsigned int));
// init stat
g_latseq.stats.entry_counter = 0;
g_latseq.stats.bytes_counter = 0;
// init latseq_thread_t
tls_latseq.th_latseq_id = 0;
// init logger thread
g_latseq.is_running = 1;
return init_logger_latseq();
}
int init_logger_latseq(void)
{
// init thread to write buffer to file
if(pthread_create(&logger_thread, NULL, (void *) &latseq_log_to_file, NULL) > 0) {
printf("[LATSEQ] Error at starting data collector\n");
g_latseq.is_running = 0;
return -1;
}
// init thread to flush into file
pthread_create(&fflusher_thread, NULL, (void *) &fflush_latseq_periodically, NULL);
return g_latseq.is_running;
}
void latseq_print_stats(void)
{
printf("[LATSEQ] === stats ===\n");
printf("[LATSEQ] number of entry in log : %d\n", g_latseq.stats.entry_counter);
//printf("[LATSEQ] heads positions : %d (Write) : %d (Read)\n", g_latseq.i_write_head, g_latseq.i_read_head);
}
int close_latseq(void)
{
g_latseq.is_running = 0;
//Wait logger finish to write data
pthread_join(logger_thread, NULL);
//At this point, data_ids and points should be freed by the logger thread
free((char*) g_latseq.filelog_name);
if (fclose(g_latseq.outstream)){
fprintf(stderr, "[LATSEQ] error on closing %s\n", g_latseq.filelog_name);
exit(EXIT_FAILURE);
}
return 1;
}
/*--- INSTRUMENTED THREAD FUNCTIONS ------------------------------------------*/
int init_thread_for_latseq(void)
{
//Init tls_latseq for local thread
tls_latseq.i_write_head = 0; //local thread tls_latseq
//memset(tls_latseq.log_buffer, 0, sizeof(tls_latseq.log_buffer));
//Register thread in the registry
latseq_registry_t * reg = &g_latseq.local_log_buffers;
//Check if space left in registry
if (reg->nb_th >= MAX_NB_THREAD) {
g_latseq.is_running = 0;
fprintf(g_latseq.outstream, "Max instrumented thread MAX_NB_THREAD reached\n");
return -1;
}
reg->tls[reg->nb_th] = &tls_latseq;
reg->i_read_heads[reg->nb_th] = 0;
//Give id to the thread
reg->nb_th++;
tls_latseq.th_latseq_id = reg->nb_th;
return 0;
//TODO : No destroy function ? What happens when thread is stopped and data had not been written in the log file ?
}
/*--- DATA COLLECTOR THREAD FUNCTIONS ----------------------------------------*/
static int write_latseq_entry(void)
{
//reference to latseq_thread_data
latseq_thread_data_t * th = g_latseq.local_log_buffers.tls[g_latseq.local_log_buffers.read_ith_thread];
//read_head for this thread_data
unsigned int * i_read_head = &g_latseq.local_log_buffers.i_read_heads[g_latseq.local_log_buffers.read_ith_thread];
//reference to element to write
latseq_element_t * e = &th->log_buffer[(*i_read_head)%RING_BUFFER_SIZE];
char * tmps;
//Convert latseq_element to a string
tmps = calloc(LATSEQ_MAX_STR_SIZE, sizeof(char));
//Write the data identifier, e.g. do the vsprintf() here and not at measure()
//We put the first NB_DATA_IDENTIFIERS elements of array, even there are no NB_DATA_IDENTIFIERS element to write. sprintf will get the firsts...
sprintf(
tmps,
e->format,
e->data_id[0],
e->data_id[1],
e->data_id[2],
e->data_id[3],
e->data_id[4],
e->data_id[5],
e->data_id[6],
e->data_id[7],
e->data_id[8],
e->data_id[9]);
// Write into file
int ret = fprintf(g_latseq.outstream, "%ld %s %s\n",
e->ts,
e->point,
tmps);
if (ret < 0) {
g_latseq.is_running = 0;
fclose(g_latseq.outstream);
fprintf(stderr, "[LATSEQ] output log file cannot be written\n");
exit(EXIT_FAILURE);
}
#ifdef LATSEQ_DEBUG
fprintf(g_latseq.outstream, "# debug %ld.%06ld : log an entry (len %d) for %s\n", etv.tv_sec, etv.tv_usec, ret, e->point);
fprintf(g_latseq.outstream, "# info %ld.%06ld : buffer occupancy (%d / %d) for thread which embedded %s\n",etv.tv_sec, etv.tv_usec, OCCUPANCY((*(&th->i_write_head)%RING_BUFFER_SIZE), ((*i_read_head)%RING_BUFFER_SIZE)), RING_BUFFER_SIZE, e->point);
#endif
free(tmps);
// cleanup buffer element
e->ts = 0;
memset(e->data_id, 0, (sizeof(uint32_t) * e->len_id));
e->len_id = 0;
//Update read_head for the current read_ith_thread
//Update g_latseq.local_log_buffers.i_read_heads[g_latseq.local_log_buffers.read_ith_thread] head position
(*i_read_head)++;
return ret;
}
void latseq_log_to_file(void)
{
// pthread config
pthread_t thId = pthread_self();
//set name
pthread_setname_np(thId, "latseq_log_to_file");
//set priority
int prio_for_policy = 10;
pthread_setschedprio(thId, prio_for_policy);
latseq_registry_t * reg = &g_latseq.local_log_buffers;
int items_to_read = 0;
while (!oai_exit) { // run until oai is stopped
if (!g_latseq.is_running) { break; } //running flag is at 0, not running
//If no thread registered, continue and wait
if (reg->nb_th == 0) { usleep(1000); continue; }
//Select a thread to read with read_ith_thread.
// Using RR for now, WRR in near future according to occupancy
if (reg->read_ith_thread + 1 >= reg->nb_th) {
reg->read_ith_thread = 0;
} else {
reg->read_ith_thread++;
}
//If max occupancy reached for a local buffer
if (reg->tls[reg->read_ith_thread]->i_write_head < reg->i_read_heads[reg->read_ith_thread]) {
fprintf(g_latseq.outstream, "# Error\tring buffer of thread (%d) reach max occupancy of %d\n", reg->read_ith_thread, RING_BUFFER_SIZE);
}
items_to_read = CHUNK_SIZE_ITEMS;
// Write by chunk
while (reg->tls[reg->read_ith_thread]->i_write_head > reg->i_read_heads[reg->read_ith_thread] && items_to_read > 0 ) {
//printf("[debug] th %d : (%d)w (%d)r : (%d)items_to_read\n", reg->read_ith_thread, reg->tls[reg->read_ith_thread]->i_write_head, reg->i_read_heads[reg->read_ith_thread], items_to_read);
items_to_read--;
//Write pointed entry into log file
g_latseq.stats.bytes_counter += (uint32_t)write_latseq_entry();
g_latseq.stats.entry_counter++;
}
usleep(1);
} // while(!oai_exit)
//Write all remaining data
for (uint8_t i = 0; i < reg->nb_th; i++) {
reg->read_ith_thread = i;
while (reg->tls[reg->read_ith_thread]->i_write_head > reg->i_read_heads[reg->read_ith_thread])
{
g_latseq.stats.bytes_counter += (uint32_t)write_latseq_entry();
g_latseq.stats.entry_counter++;
}
}
//close_latseq(); // function to close latseq properly
//exit thread
pthread_exit(NULL);
}
void fflush_latseq_periodically(void)
{
struct timespec ts;
while(1){
sleep(1);
fflush(g_latseq.outstream);
clock_gettime(CLOCK_REALTIME, &ts);
fprintf(g_latseq.outstream, "%ld S rdtsc--gettimeofday %ld.%09ld\n", l_rdtsc(), ts.tv_sec, ts.tv_nsec);
}
pthread_exit(NULL);
}

View File

@@ -1,409 +0,0 @@
/*
* Software Name : LatSeq
* Version: 1.0
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 Orange Labs
* SPDX-License-Identifier: BSD-3-Clause
*
* This software is distributed under the BSD 3-clause,
* the text of which is available at https://opensource.org/licenses/BSD-3-Clause
* or see the "license.txt" file for more details.
*
* Author: Flavien Ronteix--Jacquet
* Software description: LatSeq measurement part core
*/
#ifndef __LATSEQ_H__
#define __LATSEQ_H__
/*--- INCLUDES ---------------------------------------------------------------*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdarg.h>
#include <time.h>
#include <stdint.h>
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <pthread.h>
#include <utils.h>
/*--- DEFINE -----------------------------------------------------------------*/
#define RING_BUFFER_SIZE 1024 // Number of fingerprints in Ring Buffer
#define NB_DATA_IDENTIFIERS 10 // to update according to distinct data identifier used in point
#define LATSEQ_MAX_STR_SIZE 128 // Length for filelog_name AND latseq fingerprint string size
#define CHUNK_SIZE_ITEMS 16 // Size of chunk of ring buffer to read at data collector. 1 correspoding to full RR, RING_BUFFER_SIZE read all buffer by passage
#define MAX_NB_THREAD 32 // Maximum number of instrumented threads expected
/*--- MACRO ------------------------------------------------------------------*/
#define LATSEQ_P3(p, f, i1) do {log_measure1(p, f, (uint32_t)i1); } while(0)
#define LATSEQ_P4(p, f, i1, i2) do {log_measure2(p, f, (uint32_t)i1, (uint32_t)i2); } while(0)
#define LATSEQ_P5(p, f, i1, i2, i3) do {log_measure3(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3); } while(0)
#define LATSEQ_P6(p, f, i1, i2, i3, i4) do {log_measure4(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4);} while(0)
#define LATSEQ_P7(p, f, i1, i2, i3, i4, i5) do {log_measure5(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5); } while(0)
#define LATSEQ_P8(p, f, i1, i2, i3, i4, i5, i6) do {log_measure6(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6); } while(0)
#define LATSEQ_P9(p, f, i1, i2, i3, i4, i5, i6, i7) do {log_measure7(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7); } while(0)
#define LATSEQ_P10(p, f, i1, i2, i3, i4, i5, i6, i7, i8) do {log_measure8(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8); } while(0)
#define LATSEQ_P11(p, f, i1, i2, i3, i4, i5, i6, i7, i8, i9) do {log_measure9(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8, (uint32_t)i9); } while(0)
#define LATSEQ_P12(p, f, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) do {log_measure10(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8, (uint32_t)i9, (uint32_t)i10); } while(0)
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,NAME,...) NAME
#define LATSEQ_P(...) GET_MACRO(__VA_ARGS__, LATSEQ_P12, LATSEQ_P11, LATSEQ_P10, LATSEQ_P9, LATSEQ_P8, LATSEQ_P7, LATSEQ_P6, LATSEQ_P5, LATSEQ_P4, LATSEQ_P3)(__VA_ARGS__)
#define OCCUPANCY(w, r) (w - r)
/*--- STRUCT -----------------------------------------------------------------*/
// A latseq element of the buffer
typedef struct latseq_element_t {
uint64_t ts; // timestamp of the measure
const char * point;
const char * format;
ushort len_id; // Number data identifiers
uint32_t data_id[NB_DATA_IDENTIFIERS]; // values for the data identifier. What is the best type ?
} latseq_element_t;
// Statistics structures for latseq
typedef struct latseq_stats_t {
uint32_t entry_counter;
uint32_t bytes_counter;
} latseq_stats_t;
//thread specific data struct
typedef struct latseq_thread_data_t {
uint8_t th_latseq_id; //Identifier of pthread for registry
latseq_element_t log_buffer[RING_BUFFER_SIZE]; //log buffer, structure mutex-less
unsigned int i_write_head; // position of writer in the log_buffer (main thread)
} latseq_thread_data_t;
//Registry of pointers to thread-specific struct latseq_data_thread
typedef struct latseq_registry_t {
uint8_t read_ith_thread;
uint8_t nb_th;
latseq_thread_data_t * tls[MAX_NB_THREAD];
unsigned int i_read_heads[MAX_NB_THREAD]; // position of reader in the ith log buffer (logger thread)
} latseq_registry_t;
// Global structure of LatSeq module
typedef struct latseq_t {
int is_running; //1 is running, 0 not running
char * filelog_name;
FILE * outstream; //Output descriptor
uint64_t time_zero; // time zero
uint64_t rdtsc_zero; //rdtsc zero
uint64_t cpu_freq; //cpu frequency
latseq_registry_t local_log_buffers; //Register of thread-specific buffers
latseq_stats_t stats; // stats of latseq instance
} latseq_t;
/*--- EXTERNS ----------------------------------------------------------------*/
extern latseq_t g_latseq; // global structure
extern __thread latseq_thread_data_t tls_latseq;
/*--- FUNCTIONS --------------------------------------------------------------*/
/** \fn int init_latseq(const char * appname);
* \brief init latency sequences module.
* \param appname app's name. The output file is appname.date_hour.lseq
* \param cpufreq. cpu frequency in cycles.
* \return -1 if error 1 otherwise
*/
int init_latseq(const char * appname, uint64_t cpufreq);
/** \fn init_logger_to_mem(void);
* \brief init thread logger
* \return -1 if error 1 otherwise
*/
int init_logger_latseq(void);
/** \fn init_thread_for_latseq(void);
* \brief init tls_latseq for local oai thread
* \return -1 if error, 0 otherwise
*/
int init_thread_for_latseq(void);
/** \fn l_rdtsc(void);
* \brief rdtsc wrapper
* \return time
*/
static __inline__ uint64_t l_rdtsc(void) {
uint32_t a, d;
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
return (((uint64_t)d)<<32) | ((uint64_t)a);
}
/** \fn get_cpu_freq_cycles(void);
* \brief Compute CPU clock in a 1 second experiment
* \return CPU clock in cycles
*/
uint64_t get_cpu_freq_cycles(void);
/*--- MEASUREMENTS -----------------------------------------------------------*/
/** \fn void log_measure(const char * point, const char *identifier);
* \brief function to log a new measure into buffer.
* From 1 to NB_DATA_IDENTIFIERS
* \param point name of the measurement point
* \param id identifier for the data pointed
* \todo measure latency introduced by this function
*/
static __inline__ void log_measure1(const char * point, const char *fmt, uint32_t i1)
{
//check if the oai thread is already registered
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
//get reference on new element
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 1;
e->data_id[0] = i1;
//Update head position
tls_latseq.i_write_head++;
}
static __inline__ void log_measure2(const char * point, const char *fmt, uint32_t i1, uint32_t i2)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 2;
e->data_id[0] = i1;
e->data_id[1] = i2;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure3(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 3;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure4(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 4;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure5(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 5;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure6(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 6;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
e->data_id[5] = i6;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure7(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 7;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
e->data_id[5] = i6;
e->data_id[6] = i7;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure8(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 8;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
e->data_id[5] = i6;
e->data_id[6] = i7;
e->data_id[7] = i8;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure9(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8, uint32_t i9)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 9;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
e->data_id[5] = i6;
e->data_id[6] = i7;
e->data_id[7] = i8;
e->data_id[8] = i9;
tls_latseq.i_write_head++;
}
static __inline__ void log_measure10(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8, uint32_t i9, uint32_t i10)
{
if (tls_latseq.th_latseq_id == 0) {
//is not initialized yet
if (init_thread_for_latseq()) {
return;
}
}
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
e->ts = l_rdtsc();
e->point = point;
e->format = fmt;
e->len_id = 10;
e->data_id[0] = i1;
e->data_id[1] = i2;
e->data_id[2] = i3;
e->data_id[3] = i4;
e->data_id[4] = i5;
e->data_id[5] = i6;
e->data_id[6] = i7;
e->data_id[7] = i8;
e->data_id[8] = i9;
e->data_id[9] = i10;
tls_latseq.i_write_head++;
}
/** \fn static int write_latseq_entry(void);
* \brief private function to write an entry in the log file
*/
//static int write_latseq_entry(void);
/** \fn void log_to_file(void);
* \brief function to save buffer of logs into a file
*/
void latseq_log_to_file(void);
/** \fn void fflush_latseq_periodically(void);
* \brief flush periodically into fprintf
*/
void fflush_latseq_periodically(void);
/** \fn void latseq_print_stats(void);
* \brief print some stats about latseq
*/
void latseq_print_stats(void);
/** \fn int close_latseq(void);
* \brief finish latseq measurement if a latseq is running
* \return 0 if error 1 otherwise
*/
int close_latseq(void);
/*----------------------------------------------------------------------------*/
#endif

View File

@@ -37,7 +37,6 @@ typedef enum hashtable_return_code_e {
HASH_TABLE_KEY_ALREADY_EXISTS = 3,
HASH_TABLE_BAD_PARAMETER_HASHTABLE = 4,
HASH_TABLE_SYSTEM_ERROR = 5,
HASH_TABLE_NONE = 6,
HASH_TABLE_CODE_MAX
} hashtable_rc_t;

View File

@@ -21,6 +21,8 @@ gNBs =
////////// Physical parameters:
ssb_SubcarrierOffset = 31; //0;
pdsch_AntennaPorts = 1;
servingCellConfigCommon = (
{

View File

@@ -35,4 +35,4 @@ COPY . .
RUN /bin/sh oaienv && \
cd cmake_targets && \
mkdir -p log && \
./build_oai --eNB --gNB --RU --UE --nrUE --ninja --build-lib all -w USRP --verbose-ci --noavx512
./build_oai --eNB --gNB --RU --UE --nrUE --ninja --build-lib all -w USRP --verbose-ci

View File

@@ -35,4 +35,4 @@ COPY . .
RUN /bin/sh oaienv && \
cd cmake_targets && \
mkdir -p log && \
./build_oai --eNB --gNB --RU --UE --nrUE --ninja --build-lib all -w USRP --verbose-ci --noavx512
./build_oai --eNB --gNB --RU --UE --nrUE --ninja --build-lib all -w USRP --verbose-ci

View File

@@ -38,7 +38,7 @@ RUN yum install -y libasan
RUN /bin/sh oaienv && \
cd cmake_targets && \
mkdir -p log && \
./build_oai --phy_simulators --ninja --verbose-ci --sanitize-address --noavx512
./build_oai --phy_simulators --ninja --verbose-ci --sanitize-address
#start from scratch for target executable
FROM registry.access.redhat.com/ubi8/ubi:latest as oai-physim

View File

@@ -64,10 +64,6 @@ static int DEFENBS[] = {0};
#include <openair2/LAYER2/MAC/mac_vars.h>
#include <openair2/RRC/LTE/rrc_vars.h>
#if LATSEQ
#include "common/utils/LATSEQ/latseq.h"
#endif
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
@@ -681,7 +677,7 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
exit_fun("Exiting IQ record/playback");
#else
//exit_fun( "problem receiving samples" );
LOG_E(PHY, "problem receiving samples\n");
LOG_E(PHY, "problem receiving samples");
#endif
}
@@ -693,11 +689,6 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
old_ts=timestamp_rx;
setAllfromTS(timestamp_rx, proc);
#if LATSEQ
LATSEQ_P("U phy.in.ant--phy.in.proc","len%d::fm%d.subfm%d", rxs, proc->frame_rx, proc->subframe_rx);
#endif
}
void ocp_tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
@@ -743,11 +734,6 @@ void ocp_tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
sf_extension = (sf_extension)&0xfffffffc;
#endif
#if LATSEQ
LATSEQ_P("D phy.out.proc--phy.out.ant","len%d::fm%d.subfm%d",siglen, proc->frame_tx, proc->subframe_tx);
#endif
for (i=0; i<ru->nb_tx; i++)
txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];
@@ -1168,9 +1154,7 @@ int main ( int argc, char **argv ) {
set_softmodem_sighandler();
cpuf=get_cpu_freq_GHz();
set_taus_seed (0);
#if LATSEQ
init_latseq("/tmp/main_ocp", (uint64_t)(cpuf*1000000000LL));
#endif
if (opp_enabled ==1)
reset_opp_meas();
@@ -1354,9 +1338,6 @@ int main ( int argc, char **argv ) {
oai_exit=1;
LOG_I(ENB_APP,"oai_exit=%d\n",oai_exit);
// stop threads
#if LATSEQ
close_latseq(); //close before end of threads
#endif
if (RC.nb_inst == 0 || !NODE_IS_CU(node_type)) {
if(IS_SOFTMODEM_DOSCOPE)

View File

@@ -61,9 +61,6 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#if LATSEQ
"common/utils/LATSEQ/latseq.h"
#endif
#include "intertask_interface.h"
@@ -654,12 +651,7 @@ int main( int argc, char **argv ) {
}
cpuf=get_cpu_freq_GHz();
#if LATSEQ
init_latseq("/tmp/nr_softmodem", (uint64_t)(cpuf*1000000000LL));
#endif
itti_init(TASK_MAX, tasks_info);
// initialize mscgen log after ITTI
init_opt();
if(PDCP_USE_NETLINK && !IS_SOFTMODEM_NOS1) {
@@ -831,9 +823,6 @@ int main( int argc, char **argv ) {
}
#endif*/
#if LATSEQ
close_latseq(); //close befire head of threads
#endif
printf("stopping MODEM threads\n");
// cleanup
stop_gNB(NB_gNB_INST);

View File

@@ -209,7 +209,6 @@ extern int usrp_tx_thread;
#define SOFTMODEM_NONBIOT_BIT (1<<2)
#define SOFTMODEM_RFSIM_BIT (1<<10)
#define SOFTMODEM_SIML1_BIT (1<<12)
#define SOFTMODEM_DLSIM_BIT (1<<13)
#define SOFTMODEM_DOSCOPE_BIT (1<<15)
#define SOFTMODEM_RECPLAY_BIT (1<<16)
#define SOFTMODEM_TELNETCLT_BIT (1<<17)
@@ -226,7 +225,6 @@ extern int usrp_tx_thread;
#define IS_SOFTMODEM_NONBIOT ( get_softmodem_optmask() & SOFTMODEM_NONBIOT_BIT)
#define IS_SOFTMODEM_RFSIM ( get_softmodem_optmask() & SOFTMODEM_RFSIM_BIT)
#define IS_SOFTMODEM_SIML1 ( get_softmodem_optmask() & SOFTMODEM_SIML1_BIT)
#define IS_SOFTMODEM_DLSIM ( get_softmodem_optmask() & SOFTMODEM_DLSIM_BIT)
#define IS_SOFTMODEM_DOSCOPE ( get_softmodem_optmask() & SOFTMODEM_DOSCOPE_BIT)
#define IS_SOFTMODEM_IQPLAYER ( get_softmodem_optmask() & SOFTMODEM_RECPLAY_BIT)
#define IS_SOFTMODEM_TELNETCLT_BIT ( get_softmodem_optmask() & SOFTMODEM_TELNETCLT_BIT)

View File

@@ -3,6 +3,7 @@
typedef struct threads_s {
int main;
int iq;
int sync;
int one;
int two;

View File

@@ -1,64 +0,0 @@
SNR BLER BER UNCODED_BER ENCODER_MEAN ENCODER_STD ENCODER_MAX DECODER_TIME_MEAN DECODER_TIME_STD DECODER_TIME_MAX DECODER_ITER_MEAN DECODER_ITER_STD DECODER_ITER_MAX
-2.000000 1.000000 0.346185 0.258473 44.551218 31.688925 357.883903 217.655668 12.810778 326.852166 5.000000 0.000000 5
-1.900000 1.000000 0.345395 0.256275 40.787109 4.190954 65.926488 215.687102 4.300128 230.585721 5.000000 0.000000 5
-1.800000 1.000000 0.343100 0.253634 40.748628 3.912915 56.669470 215.314020 4.139156 227.806468 5.000000 0.000000 5
-1.700000 1.000000 0.341806 0.250634 40.550845 3.347808 56.032851 216.839001 5.959734 244.483352 5.000000 0.000000 5
-1.600000 1.000000 0.339245 0.248129 40.457158 3.735092 56.853508 215.747244 4.995522 242.867659 5.000000 0.000000 5
-1.500000 1.000000 0.337230 0.245763 41.178595 4.297429 56.265874 215.785600 4.151781 227.795995 5.000000 0.000000 5
-1.400000 1.000000 0.335131 0.243311 39.915221 2.739586 55.454917 216.866764 6.547848 251.528327 5.000000 0.000000 5
-1.300000 1.000000 0.333085 0.240664 40.119215 3.044973 55.978253 216.208443 4.459816 228.810686 5.000000 0.000000 5
-1.200000 1.000000 0.330664 0.238769 40.507713 2.998241 55.701876 215.868796 3.778455 226.049304 5.000000 0.000000 5
-1.100000 1.000000 0.329130 0.235812 41.038895 4.522472 56.760814 215.654663 4.746822 236.021980 5.000000 0.000000 5
-1.000000 1.000000 0.325980 0.233534 41.067622 4.626711 57.444142 215.260535 3.481966 225.512853 5.000000 0.000000 5
-0.900000 1.000000 0.323823 0.230863 40.683316 3.689159 56.208182 215.560917 5.180017 243.603452 5.000000 0.000000 5
-0.800000 1.000000 0.321004 0.228222 41.643513 4.717568 58.502452 215.630891 4.283475 238.574145 5.000000 0.000000 5
-0.700000 1.000000 0.317983 0.225520 41.214547 3.941824 56.054211 215.910346 4.375081 227.444626 5.000000 0.000000 5
-0.600000 1.000000 0.316243 0.222903 40.834442 4.370416 56.765508 215.153296 3.617927 226.280086 5.000000 0.000000 5
-0.500000 1.000000 0.312886 0.220473 40.178174 4.185502 64.657291 219.647151 4.454154 236.473446 5.000000 0.000000 5
-0.400000 1.000000 0.309757 0.217536 40.240385 3.172484 55.751563 217.761119 3.900779 228.757195 5.000000 0.000000 5
-0.300000 1.000000 0.305464 0.215229 40.852271 3.761739 56.158869 217.830497 4.087453 230.237764 5.000000 0.000000 5
-0.200000 1.000000 0.302919 0.212364 40.531166 3.688281 56.426841 217.657657 5.498697 253.516146 5.000000 0.000000 5
-0.100000 1.000000 0.298246 0.209310 41.058364 4.140510 59.959571 217.519279 4.087389 228.768313 5.000000 0.000000 5
0.000000 1.000000 0.294110 0.207107 40.436486 3.604369 55.788895 217.853044 4.012624 236.118036 5.000000 0.000000 5
0.100000 1.000000 0.288139 0.204033 40.603738 4.045866 57.560760 217.046816 4.583841 244.429411 5.000000 0.000000 5
0.200000 1.000000 0.285604 0.201954 40.494607 3.886199 59.431970 217.322824 4.080988 233.317513 5.000000 0.000000 5
0.300000 1.000000 0.278478 0.198929 40.311327 3.452837 56.124657 217.319394 4.434358 232.534720 5.000000 0.000000 5
0.400000 1.000000 0.270992 0.196299 40.649243 3.415612 56.204178 218.079445 4.990947 245.055337 5.000000 0.000000 5
0.500000 1.000000 0.263944 0.193661 40.464299 3.622703 56.602842 218.555364 3.936432 229.481159 5.000000 0.000000 5
0.600000 1.000000 0.256340 0.191194 40.200314 2.474984 53.432412 216.547260 3.695211 227.198078 5.000000 0.000000 5
0.700000 1.000000 0.251578 0.188606 40.111945 3.029821 54.900896 216.581752 4.247622 237.358365 5.000000 0.000000 5
0.800000 1.000000 0.234558 0.184742 39.533282 1.182169 42.753097 215.462335 2.960246 226.716604 5.000000 0.000000 5
0.900000 1.000000 0.225915 0.182691 39.851294 1.108193 42.180342 216.404194 4.450720 228.482353 5.000000 0.000000 5
1.000000 1.000000 0.216180 0.179994 40.721936 3.302539 56.032206 217.082196 4.599188 227.979232 5.000000 0.000000 5
1.100000 1.000000 0.203481 0.177332 41.006217 3.798207 56.014901 216.204345 4.292145 227.297386 5.000000 0.000000 5
1.200000 1.000000 0.188297 0.174121 40.739289 3.269948 56.653507 216.585873 6.250858 251.207034 5.000000 0.000000 5
1.300000 1.000000 0.172624 0.171622 41.215540 4.783342 55.692883 215.885639 3.629370 226.473280 5.000000 0.000000 5
1.400000 1.000000 0.156483 0.169110 40.289903 3.749338 56.290861 215.663761 4.176366 225.824735 5.000000 0.000000 5
1.500000 1.000000 0.136293 0.165692 42.208932 6.070189 69.182665 216.390504 4.816283 235.417446 5.000000 0.000000 5
1.600000 1.000000 0.125127 0.163325 40.890581 3.941185 56.491504 215.752348 4.426511 226.425984 5.000000 0.000000 5
1.700000 1.000000 0.104593 0.159971 41.263557 4.128935 57.062514 217.284932 5.311288 249.647163 5.000000 0.000000 5
1.800000 1.000000 0.091397 0.157460 40.273078 3.062810 55.546913 217.252505 6.331426 251.175692 5.000000 0.000000 5
1.900000 1.000000 0.078256 0.154628 40.407489 3.419342 56.316166 216.967648 4.712664 245.093313 5.000000 0.000000 5
2.000000 1.000000 0.065221 0.152571 40.660365 4.317854 57.537407 216.198346 4.991856 245.173269 5.000000 0.000000 5
2.100000 1.000000 0.053694 0.148885 40.355654 4.062614 60.051963 215.797667 4.447252 236.221454 5.000000 0.000000 5
2.200000 1.000000 0.042182 0.146229 40.613562 4.124655 56.201536 216.117304 4.060825 227.115987 5.000000 0.000000 5
2.300000 1.000000 0.034334 0.143612 40.465884 3.541452 55.067611 215.575953 4.891719 244.546802 5.000000 0.000000 5
2.400000 1.000000 0.026641 0.140869 41.074690 4.697458 61.619188 216.069185 4.700827 233.830937 5.000000 0.000000 5
2.500000 1.000000 0.019976 0.138112 40.766971 4.274128 58.871741 215.761570 5.633731 249.753931 5.000000 0.000000 5
2.600000 1.000000 0.012826 0.135122 40.559343 2.952804 54.017706 215.835161 4.039993 226.822103 5.000000 0.000000 5
2.700000 1.000000 0.010550 0.132915 40.985193 3.330639 55.013950 215.975836 4.240744 227.040703 5.000000 0.000000 5
2.800000 1.000000 0.007327 0.130133 39.778804 3.002485 56.610555 216.462786 7.082268 265.051418 5.000000 0.000000 5
2.900000 1.000000 0.004038 0.126763 40.327795 3.934211 55.515352 215.982666 4.626198 230.696124 5.000000 0.000000 5
3.000000 1.000000 0.003087 0.124336 40.337807 3.537021 55.101627 215.468662 4.177203 230.789145 5.000000 0.000000 5
3.100000 1.000000 0.001576 0.121689 39.812195 3.116738 55.422687 215.797778 4.091192 225.897780 5.000000 0.000000 5
3.200000 0.980000 0.001000 0.118928 39.853764 2.871322 56.405555 215.562722 4.187466 232.598421 5.000000 0.000000 5
3.300000 0.960000 0.000623 0.116065 40.440328 3.580650 56.738889 216.165848 4.735158 240.329999 5.000000 0.000000 5
3.400000 0.850000 0.000303 0.113505 40.974107 4.291544 56.280236 215.889562 4.448049 237.556780 5.000000 0.000000 5
3.500000 0.690000 0.000152 0.111010 41.508631 4.251791 56.198873 216.740295 4.889693 242.922934 5.000000 0.000000 5
3.600000 0.530000 0.000102 0.108493 40.065231 3.643794 57.120823 216.887338 5.242621 250.003843 5.000000 0.000000 5
3.700000 0.320000 0.000043 0.105612 40.462159 4.162383 56.782173 216.465615 3.846314 227.022697 5.000000 0.000000 5
3.800000 0.210000 0.000032 0.103084 42.192455 6.207380 64.648964 217.030913 4.482820 228.095918 5.000000 0.000000 5
3.900000 0.110000 0.000013 0.100391 40.640286 3.715782 55.922914 217.726055 4.553212 236.362804 5.000000 0.000000 5
4.000000 0.050000 0.000006 0.097518 40.437760 2.838308 54.764308 218.230040 4.309275 237.932625 5.000000 0.000000 5
4.100000 0.020000 0.000002 0.095436 41.347934 4.608500 64.182062 217.408836 4.385757 228.219627 5.000000 0.000000 5
4.200000 0.000000 0.000000 0.092396 40.782371 3.621708 55.984245 217.579878 4.102149 228.145363 5.000000 0.000000 5

View File

@@ -352,7 +352,7 @@ uint32_t generate_dummy_w(uint32_t D, uint8_t *w,uint8_t F) {
uint32_t generate_dummy_w_cc(uint32_t D, uint8_t *w) {
uint32_t RCC = (D>>5), ND;
uint32_t col,Kpi,index;
uint32_t row,col,Kpi,index;
int32_t k;
#ifdef RM_DEBUG_CC
uint32_t nulled=0;
@@ -377,11 +377,11 @@ uint32_t generate_dummy_w_cc(uint32_t D, uint8_t *w) {
printf("Col %d\n",col);
#endif
index = bitrev_cc[col];
if (index<ND) {
w[k] = LTE_NULL;
w[Kpi+k] = LTE_NULL;
w[(Kpi<<1)+k] = LTE_NULL;
for (row=0;row<RCC;row++){
if (index<ND) {
w[k] = LTE_NULL;
w[Kpi+k] = LTE_NULL;
w[(Kpi<<1)+k] = LTE_NULL;
#ifdef RM_DEBUG_CC
nulled+=3;
#endif
@@ -417,7 +417,9 @@ uint32_t generate_dummy_w_cc(uint32_t D, uint8_t *w) {
#ifdef RM_DEBUG_CC
printf("k %d w (%d,%d,%d), index-ND %d index+32-ND %d\n",k,w[k],w[Kpi+k],w[(Kpi<<1)+k],index-ND,index+32-ND);
#endif
k+=RCC;
index+=32;
k++;
}
}
#ifdef RM_DEBUG_CC

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,960 @@
%
% Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
% contributor license agreements. See the NOTICE file distributed with
% this work for additional information regarding copyright ownership.
% The OpenAirInterface Software Alliance licenses this file to You under
% the OAI Public License, Version 1.1 (the "License"); you may not use this file
% except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.openairinterface.org/?page_id=698
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
%-------------------------------------------------------------------------------
% For more information about the OpenAirInterface (OAI) Software Alliance:
% contact@openairinterface.org
%
\documentclass{article}
\usepackage[a4paper, total={6in, 8in}]{geometry}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{booktabs}
\usepackage{url}
\usepackage{tcolorbox}
\usepackage{tikz}
\usetikzlibrary{arrows,decorations,shapes,backgrounds,patterns}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\definecolor{green}{RGB}{32,127,43}
\usetikzlibrary{calc}
\usepackage{listings}
\lstdefinestyle{customc}{
belowcaptionskip=1\baselineskip,
breaklines=true,
frame=L,
xleftmargin=\parindent,
language=C,
showstringspaces=false,
basicstyle=\footnotesize\ttfamily,
keywordstyle=\bfseries\color{green!40!black},
commentstyle=\itshape\color{purple!40!black},
identifierstyle=\color{blue},
stringstyle=\color{orange},
}
\lstset{escapechar=@,style=customc}
\title{NR LDPC Decoder}
\author{Sebastian Wagner (TCL)}
\date{\today}
\def\0{\mathbf{0}}
\def\b{\mathbf{b}}
\def\Bbb{\mathbb{B}}
\def\Bcal{\mathcal{B}}
\def\c{\mathbf{c}}
\def\C{\mathbf{C}}
\def\Cbb{\mathbb{C}}
\def\Ccal{\mathcal{C}}
\def\eqdef{\triangleq}
\def\g{\mathbf{g}}
\def\G{\mathbf{G}}
\def\Gcal{\mathcal{G}}
\def\h{\mathbf{h}}
\def\H{\mathbf{H}}
\def\Hbg{\mathbf{H}_\mathrm{BG}}
\def\Hbgo{\mathbf{H}_\mathrm{BG1}}
\def\Hbgt{\mathbf{H}_\mathrm{BG2}}
\def\I{\mathbf{I}}
\def\Kb{{K_b}}
\def\m{\mathbf{m}}
\def\Mb{{M_b}}
\def\Nb{{N_b}}
\def\Nbb{\mathbb{N}}
\def\n{\mathbf{n}}
\def\nr{{n_{\rm r}}}
\def\nt{{n_{\rm t}}}
\def\s{\mathbf{s}}
\def\SNR{\mathsf{SNR}}
\def\y{\mathbf{y}}
\def\z{\mathbf{z}}
\def\Z{\mathbf{Z}}
\def\Zc{{Z_c}}
\def\herm{\mathsf{H}}
\def\trans{\mathsf{T}}
\def\EE{\mathsf{E}}
\newcommand{\sgn}{\operatorname{sgn}}
\begin{document}
\maketitle
\begin{tikzpicture}[remember picture,overlay]
\node[anchor=north west,inner sep=0pt] at (current page.north west)
{\includegraphics[scale=0.5]{logo.png}};
\end{tikzpicture}
\begin{center}Currently Supported:\end{center}
\tcbox[center]{
\begin{tabular}{lll}
\toprule
\textbf{BG} & \textbf{Lifting Size Z} & \textbf{Code Rate R} \\
\midrule
1 & all & 1/3, 2/3, 8/9 \\
2 & all & 1/5, 1/3, 2/3 \\
\bottomrule
\end{tabular}
}
\paragraph{Version 1.0:}
\begin{itemize}
\item Initial version
\end{itemize}
\paragraph{Version 2.0:}
\begin{itemize}
\item Enhancements in message passing:
\begin{itemize}
\item LUTs replaced by smaller BG-specific parameters
\item Inefficient load/store replaced by circular memcpy
\end{itemize}
\item Bug fixes:
\begin{itemize}
\item Fixed bug in function \texttt{llr2CnProcBuf}
\item Corrected input LLR dynamic range in BLER simulations
\end{itemize}
\item Results:
\begin{itemize}
\item Size of LUTs reduced significantly (60MB to 200KB)
\item Siginifcantly enhances execution time (factor 3.5)
\item Improved BLER performance (all simulation results have been updated)
\end{itemize}
\end{itemize}
\newpage
\tableofcontents
\newpage
\section{Introduction}
\label{sec:introduction}
Low Density Parity Check (LDPC) codes have been developed by Gallager in 1963 \cite{gallager1962low}. They are linear error correcting codes that are capacity-achieving for large block length and are completely described by their Parity Check Matrix (PCM) $\H^{M\times N}$. The PCM $\H$ defines $M$ constraints on the codeword $\c$ of length $N$ such that
\begin{equation}
\label{eq:29}
\H\c = \0.
\end{equation}
The number of information bits $B$ that can be encoded with $\H$ is given by $B=N-M$. Hence the code rate $R$ of $\H$ reads
\begin{equation}
\label{eq:37}
R = \frac{B}{N} = 1-\frac{M}{N}.
\end{equation}
\subsection{LDPC in NR}
\label{sec:ldpc-nr}
NR uses quasi-cyclic (QC) Protograph LDPC codes, i.e. a smaller graph, called Base Graph (BG), is defined and utilized to construct the larger PCM. This has the advantage that the large PCM does not have to be stored in memory and allows for a more efficient implementation while maintaining good decoding properties.
Two BGs $\Hbg\in\Nbb^{\Mb\times \Nb}$ are defined in NR:
\begin{enumerate}
\item $\Hbgo\in\Nbb^{46\times 68}$
\item $\Hbgt\in\Nbb^{42\times 52}$
\end{enumerate}
where $\Nbb$ is the set of integers. For instance the first 3 rows and 13 columns of BG2 are given by
\setcounter{MaxMatrixCols}{30}
\begin{equation*}
\label{eq:33}
\Hbgt =
\begin{bmatrix}
9 & 117 & 204 & 26 & \emptyset & \emptyset & 189 & \emptyset & \emptyset & 205 & 0 & 0 & \emptyset & \emptyset \\
127 & \emptyset & \emptyset & 166 & 253 & 125 & 226 & 156 & 224 & 252 & \emptyset & 0 & 0 & \emptyset \\
81 & 114 & \emptyset & 44 & 52 & \emptyset & \emptyset & \emptyset & 240 & \emptyset & 1 & \emptyset & 0 & 0
\end{bmatrix}.
\end{equation*}
To obtain the PCM $\H$ from the BG $\Hbg$, each element $\Hbg(i,j)$ in the BG is replaced by a lifting matrix of size $\Zc\times \Zc$ according to
\begin{equation}
\label{eq:35}
\Hbg(i,j) =
\begin{cases}
\0 & \textrm{if}~ \Hbg(i,j)=\emptyset \\
\I_{P_{ij}} & \textrm{otherwise}
\end{cases}
\end{equation}
where $\I_{P_{ij}}$ is the identity matrix circularly shifted to the right by $P_{ij} = \Hbg(i,j)\mod \Zc$. Hence, the resulting PCM $\H$ will be of size $\Mb\Zc\times\Nb\Zc$.
The lifting size $\Zc$ depends on the number of bits to encode. To limit the complexity, a discrete set $\mathcal{Z}$ of possible values of $\Zc$ has been defined in \cite{3gpp2017_38212} and the optimal value $\Zc$ is calculated according to
\begin{equation}
\label{eq:36}
\Zc = \min_{\Z\in\mathcal{Z}}\left[Z\geq\frac{B}{\Nb}\right].
\end{equation}
The base rate of the two BGs is $1/3$ and $1/5$ for BG1 and BG2, respectively. That is, BG1 encodes $K=22\Zc$ bits and BG2 encodes $K=10\Zc$ bits. Note that the first 2 columns of BG 1 and 2 are always punctured, that is after encoding, the first $2\Zc$ bits are discarded and not transmitted.
For instance, consider $B=500$ information bits to encode using BG2, \eqref{eq:36} yields $\Zc=64$ hence $K=640$. Since $K>B$, $K-B=140$ filler bits are appended to the information bits. The PCM $\Hbgt$ is of size $2688\times 3328$ and the $640$ bits $\b$ are encoded according to \eqref{eq:29} at a rate $R \approx 0.192$. To achieve the higher base rate of $0.2$, the first $128$ are punctured, i.e. instead of transmitting all $3328$ bits, only $3200$ are transmitted resulting in the desired rate $R=640/3200=0.2$.
\subsection{LDPC Decoding}
\label{sec:ldpc-decoding}
The decoding of codeword $\c$ can be achieved via the classical message passing algorithm. This algorithm can be illustrated best using the Tanner graph of the PCM. The rows of the PCM are called check nodes (CN) since they represent the parity check equations. The parity check equation of each of these check nodes involves various bits in the codeword. Similarly, every column of the PCM corresponds to a bit and each bit is involved in several parity check equations. In the Tanner graph representation, the bits are called bit nodes (BN). Let's go back to the previous example of BG2 and assume $\Zc=2$, hence the first 3 rows and 13 columns of BG2 $\Hbgt$ read
\begin{equation*}
\label{eq:36}
\Hbgt =
\begin{bmatrix}
1 & 1 & 0 & 0 & \emptyset & \emptyset & 1 & \emptyset & \emptyset & 1 & 0 & 0 & \emptyset & \emptyset \\
1 & \emptyset & \emptyset & 0 & 1 & 1 & 0 & 0 & 0 & 0 & \emptyset & 0 & 0 & \emptyset \\
1 & 0 & \emptyset & 0 & 0 & \emptyset & \emptyset & \emptyset & 0 & \emptyset & 1 & \emptyset & 0 & 0
\end{bmatrix}.
\end{equation*}
Replacing the elements according to \eqref{eq:35}, we obtain the first 6 rows and 26 columns of the PCM as
\begin{equation*}
\label{eq:39}
\H =
\begin{bmatrix}
0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\
1 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0\\
0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0\\
1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0\\
0 & 1 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0\\
1 & 0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 1
\end{bmatrix}.
\end{equation*}
The Tanner graph of the first 8 BNs is shown in Figure \ref{fig:tannergraph}.
\begin{figure}[ht]
\label{fig:tannergraph}
\centering
\def\ww{0.3cm}
\def\hh{0.3cm}
\tikzstyle{cnode}=[fill=white,rectangle,draw=black,thick,inner sep=2pt, minimum height=\hh,minimum width=\ww, rounded corners=1pt,text width=\ww]
\tikzstyle{vnode}=[fill=white,circle,draw=black,thick,inner sep=2pt, minimum height=\hh,minimum width=\ww, rounded corners=1pt,text width=\ww]
\tikzstyle{connector}=[<->,>=latex',semithick]
\begin{tikzpicture}
\tikzstyle{every node}=[node distance=1.5cm,text centered]
% Check nodes
\node[cnode, label=above:$v_0$] (v0) {};
\node[cnode, label=above:$v_1$, right of=v0] (v1) {};
\node[cnode, label=above:$v_2$, right of=v1] (v2) {};
% Variable nodes
\node[vnode, label=below:$c_3$, below of=v1, node distance=1.5cm] (c3) {};
\node[vnode, label=below:$c_2$, left of=c3, node distance=1.5cm] (c2) {};
\node[vnode, label=below:$c_1$, left of=c2, node distance=1.5cm] (c1) {};
\node[vnode, label=below:$c_0$, left of=c1, node distance=1.5cm] (c0) {};
\node[vnode, label=below:$c_4$, right of=c3, node distance=1.5cm] (c4) {};
\node[vnode, label=below:$c_5$, right of=c4, node distance=1.5cm] (c5) {};
\node[vnode, label=below:$c_6$, right of=c5, node distance=1.5cm] (c6) {};
% Draw edges
\draw (c0) edge[connector] (v1);
\draw (c1) edge[connector] (v0);
\draw (c1) edge[connector] (v2);
\draw (c2) edge[connector] (v1);
\draw (c3) edge[connector] (v0);
\draw (c4) edge[connector] (v0);
\draw (c4) edge[connector] (v2);
\draw (c5) edge[connector] (v1);
\draw (c6) edge[connector] (v0);
\draw (c6) edge[connector] (v2);
\end{tikzpicture}
\caption{Tanner graph for first 7 bits nodes and 3 check nodes from \eqref{eq:39}.}
\end{figure}
The message passing algorithm is an iterative algorithm where probabilities of the bits (being either 0 or 1) are exchanged between the BNs and CNs. After sufficient iterations, the probabilities will have either converged to either 0 or 1 and the parity check equations will be satisfied, at this point, the codeword has been decoded correctly.
\newpage
\section{LDPC Decoder Implementation}
\label{sec:ldpc-implementation}
The implementation on a general purpose processor (GPP) has to take advantage of potential instruction extension of the processor architecture. We focus on the Intel x86 instruction set architecture (ISA) and its advanced vector extension (AVX). In particular, we utilize AVX2 with its 256-bit single instruction multiple data (SIMD) format. In order to utilize AVX2 to speed up the processing at the CNs and BNs, the corresponding data has to be ordered/aligned in a specific way. The processing flow of the LDPC decoder is depicted in \ref{fig:ldpc_decoder_flow}.
\begin{figure}[ht]
\label{fig:ldpc_decoder_flow}
\centering
\def\ww{0.3cm}
\def\hh{0.3cm}
\tikzstyle{func}=[,draw=none]
\tikzstyle{connector}=[->,>=latex',semithick]
\begin{tikzpicture}
\tikzstyle{every node}=[node distance=2.5cm,text centered]
% Check nodes
% First iteration
\node[func] (llr2llrProcBuf) {\texttt{llr2llrProcBuf}};
\node[func, above of=llr2llrProcBuf] (llr2CnProcBuf) {\texttt{llr2CnProcBuf}};
\node[func, above right of=llr2CnProcBuf] (cnProc1) {\texttt{cnProc}};
\node[func, below right of=cnProc1] (cn2bnProcBuf1) {\texttt{cn2bnProcBuf}};
\node[func, below of=cn2bnProcBuf1] (bnProcPc1) {\texttt{bnProcPc}};
% Iterations
\node[func, right of=cnProc1, node distance=7cm] (cnProc) {\texttt{cnProc}};
\node[func, below right of=cnProc] (cn2bnProcBuf) {\texttt{cn2bnProcBuf}};
\node[func, below of=cn2bnProcBuf] (bnProcPc) {\texttt{bnProcPc}};
\node[func, below left of=cnProc] (bn2cnProcBuf) {\texttt{bn2cnProcBuf}};
\node[func, below of=bn2cnProcBuf] (bnProc) {\texttt{bnProc}};
% Post processing
\node[func, below of=bnProcPc] (llrRes2llrOut) {\texttt{llrRes2llrOut}};
\node[func, below of=llrRes2llrOut, node distance=1cm] (llr2bit) {\texttt{llr2bit}};
% Draw edges
\draw (llr2llrProcBuf) edge[connector] (llr2CnProcBuf);
\draw (llr2CnProcBuf) edge[connector] (cnProc1);
\draw (cnProc1) edge[connector] (cn2bnProcBuf1);
\draw (cn2bnProcBuf1) edge[connector] (bnProcPc1);
\draw (bnProcPc) edge[connector] (bnProc);
\draw (bnProc) edge[connector] (bn2cnProcBuf);
\draw (bn2cnProcBuf) edge[connector] node[above left] {\texttt{cnProcPc}} (cnProc);
\draw (cnProc) edge[connector] (cn2bnProcBuf);
\draw (cn2bnProcBuf) edge[connector] (bnProcPc);
\draw (bnProcPc1) edge[connector] (bnProc);
\draw (bnProcPc) edge[connector] node[left] {iterations done} (llrRes2llrOut);
\draw (llrRes2llrOut) edge[connector] (llr2bit);
% Boxes
\node[inner sep=0pt,above right of=cn2bnProcBuf1, node distance = 2.5cm] (ref) {};
\draw[fill=black,opacity=.2, rounded corners] (llr2llrProcBuf.south west) rectangle ($(ref) + (-.5cm,.5cm)$);
\draw[fill=black,opacity=.2, rounded corners] ($(ref) + (.5cm,.5cm)$) rectangle ($(bnProcPc.south east) + (.4cm,0)$);
\node[func, above of=cnProc1, node distance=.8cm] (iter1) {\textbf{First Iteration}};
\node[func, above of=cnProc , node distance=.8cm] (iterX) {\textbf{Subsequent Iterations}};
\end{tikzpicture}
\caption{LDPC Decoder processing flow.}
\end{figure}
The functions involved are described in more detail in Table \ref{tab:sum_func}.
\begin{table}[ht]
\centering
\begin{tabular}{ll}
\toprule
\textbf{Function} & \textbf{Description} \\
\midrule
\texttt{llr2llrProcBuf} & Copies input LLRs to LLR processing buffer \\
\texttt{llr2CnProcBuf} & Copies input LLRs to CN processing buffer \\
\texttt{cnProc} & Performs CN signal processing \\
\texttt{cnProcPc} & Performs parity check \\
\texttt{cn2bnProcBuf} & Copies the CN results to the BN processing buffer \\
\texttt{bnProcPc} & Performs BN processing for parity check and/or hard-decision \\
\texttt{bnProc} & Utilizes the results of \texttt{bnProcPc} to compute LLRs for CN processing \\
\texttt{bn2cnProcBuf} & Copies the BN results to the CN processing buffer \\
\texttt{llrRes2llrOut} & Copies the results of \texttt{bnProcPc} to output LLRs \\
\texttt{llr2bit} & Performs hard-decision on the output LLRs \\
\bottomrule
\end{tabular}
\caption{Summary of the LDPC decoder functions.}
\label{tab:sum_func}
\end{table}
The input LLRs are assumed to be 8-bit and aligned on 32 bytes. CN processing is carried out in 8-bit whereas BN processing is done in 16 bit. Subsequently, the processing tasks at the CNs and BNs are explained in more detail.
\newpage
\subsection{Check Node Processing}
\label{sec:check-node-proc}
Denote $q_{ij}$ the value from BN $j$ to CN $i$ and let $\Bcal_i$ be the set of connected BNs to the $i$th CN. Then, using the min-sum approximation, CN $i$ has to carry out the following operation for each connected BN.
\begin{equation}
\label{eq:40}
r_{ji} = \prod_{j'\in\Bcal_i\setminus j}\sgn q_{ij'}\min_{j'\in\Bcal_i\setminus j} |q_{ij'}|
\end{equation}
where $r_{ji}$ is the value returned to BN $j$ from CN $i$. There are $\Mb = \{46,42\}$ CNs in BG 1 and BG 2, respectively. Each of these CNs is connected to only a small number of BNs. The number of connected BNs to CN $i$ is $|\Bcal_i|$. In BG1 and BG2, $|\Bcal_i|=\{3,4,5,6,7,8,9,10,19\}$ and $|\Bcal_i|=\{3,4,5,6,8,10\}$, respectively. The following tables show the number of CNs $M_{|\Bcal_i|}$ that are connected to the same number of BNs.
\begin{table}[ht]
\centering
\begin{tabular}{llllllllll}
\toprule
$|\Bcal_i|$ & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 19 \\
\midrule
$M_{|\Bcal_i|}^\mathrm{BG1}$ & 1 & 5 &18 & 8 & 5 & 2 & 2 & 1 & 4 \\
$M_{|\Bcal_i|}^\mathrm{BG2}$ & 6 & 20 & 9 & 3 & 0 & 2 & 0 & 2 & 0 \\
\bottomrule
\end{tabular}
\caption{Ceck node groups for BG1 and BG2.}
\label{tab:checkNodeGroups}
\end{table}
It can be observed that each CN is at least connected to 3 BNs and there are 9 groups and 5 groups in BG1 and BG2, respectively. Denote the set of CN groups as $\Gcal$ and $M_k$ the number of CNs in group $k\in\Gcal$, e.g. for BG2 $M_4=20\Zc$. Each CN group will be processed separately. The CN processing buffer $p_C^k$ of group $k$ is defined as
\begin{equation}
\label{eq:44}
p_C^k = \{\underbrace{q_{11}q_{21}\dots q_{M_k 1}}_{\text 1. BN},\underbrace{q_{12}q_{22}\dots q_{M_k 2}}_{\text 2. BN},\dots,\underbrace{q_{12}q_{22}\dots q_{M_k k}}_{\text last BN}\}
\end{equation}
Hence, $|p_C^k| = kM_k$, e.g, $\Zc=128$, $|p_C^4| = 4\cdot 20\cdot 128 = 10240$.
\begin{lstlisting}[frame=single,caption={Example of CN processing for group 3 from \texttt{cnProc}.},label=code_cnproc] % Start your code-block
const uint8_t lut_idxCnProcG3[3][2] = {{72,144}, {0,144}, {0,72}};
// =====================================================================
// Process group with 3 BNs
// Number of groups of 32 CNs for parallel processing
M = (lut_numCnInCnGroups[0]*Z)>>5;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[0]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 3
p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[0]];
p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[0]];
// Loop over every BN
for (j=0; j<3; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
sgn = _mm256_sign_epi8(*p_ones, ymm0);
min = _mm256_abs_epi8(ymm0);
// 32 CNs of second BN
ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][1] + i];
min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
sgn = _mm256_sign_epi8(sgn, ymm0);
// Store result
min = _mm256_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
p_cnProcBufResBit++;
}
}
}
\end{lstlisting}
Once all results of the check node processing $r_{ji}$ have been calculated, they are copied to the bit node processing buffer.
\subsection{Bit Node Processing}
\label{sec:bit-node-processing}
Denote $r_{ji}$ the value from CN $i$ to BN $j$ and let $\Ccal_j$ be the set of connected CNs to the $j$th BN. Each BN $j$ has to carry out the following operation for every connected CN $i\in\Ccal_j$.
\begin{equation}
\label{eq:46}
q_{ij} = \Lambda_j + \sum_{i'\in\Ccal_j\setminus i}r_{ji'}
\end{equation}
There are $\Nb = \{68,52\}$ BNs in BG 1 and BG 2, respectively. Each of these BNs is connected to only a small number of CNs. The number of connected CNs to BN $j$ is $|\Ccal_j|$. In BG1 and BG2, $|\Ccal_j|=\{1,4,7,8,9,10,11,12,28,30\}$ and $|\Ccal_j|=\{1,5,6,7,8,9,10,12,13,14,16,22,23\}$, respectively. The following tables show the number of BNs $K_{|\Ccal_j|}$ that are connected to the same number of CNs.
\begin{table}[ht]
\centering
\begin{tabular}{lllllllllllllllllll}
\toprule
$|\Ccal_j|$ & 1&4&5&6&7&8&9&10&11&12&13 & 14 & 15 & 16 & 22 & 23 &28&30 \\
\midrule
$K_{|\Ccal_j|}^\mathrm{BG1}$ & 42 & 1 & 1 & 2 & 4 & 3 & 1 & 4 & 3 & 4 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\
$K_{|\Ccal_j|}^\mathrm{BG2}$ & 38 & 0 & 2 & 1 & 1 & 1 & 2 & 1 & 0 & 1 & 1 & 1 & 0 & 1 & 1 & 1 & 0 & 0\\
\bottomrule
\end{tabular}
\caption{Bit node groups for BG1 and BG2 for base rates 1/3 and 1/5, respectively.}
\label{tab:bitNodeGroups}
\end{table}
The BNs that are connected to a single CN do not need to be considered in the BN processing since \eqref{eq:46} yields $q_{ij} = \Lambda_j$. It can be observed that the grouping is less compact, i.e. there are many groups with only a small number of elements.
Denote the set of BN groups as $\Bcal$ and $K_k$ the number of BNs in group $k\in\Bcal$, e.g. for BG2 $K_5=2\Zc$. Each BN group will be processed separately. The BN processing buffer $p_B^k$ of group $k$ is defined as
\begin{equation}
\label{eq:47}
p_B^k = \{\underbrace{r_{11}r_{21}\dots r_{K_k 1}}_{\text 1. CN},\underbrace{r_{12}r_{22}\dots r_{K_k 2}}_{\text 2. CN},\dots,\underbrace{r_{12}r_{22}\dots r_{K_k k}}_{\text last CN}\}
\end{equation}
Hence, $|p_B^k| = kK_k$, e.g, $\Zc=128$, $|p_B^5| = 5\cdot 2\cdot 128 = 1024$.
Depending on the code rate, some parity bits are not being transmitted. For instance, for BG2 with code rate $R = 1/3$ the last $20\Zc$ bits are discarded. Therefore, the last 20 columns or the last $20\Zc$ parity check equation are not required for decoding. This means that the BN groups shown in table \ref{tab:bitNodeGroups} are depending on the rate.
\begin{lstlisting}[frame=single,caption={Example of BN processing for group 3 from \texttt{bnProcPc}.},label=code_bnproc] % Start your code-block
// If elements in group move to next address
idxBnGroup++;
// Number of groups of 32 BNs for parallel processing
M = (lut_numBnInBnGroups[2]*Z)>>5;
// Set the offset to each CN within a group in terms of 16 Byte
cnOffsetInGroup = (lut_numBnInBnGroups[2]*NR_LDPC_ZMAX)>>4;
// Set pointers to start of group 3
p_bnProcBuf = (__m128i*) &bnProcBuf [lut_startAddrBnGroups [idxBnGroup]];
p_llrProcBuf = (__m128i*) &llrProcBuf [lut_startAddrBnGroupsLlr[idxBnGroup]];
p_llrRes = (__m256i*) &llrRes [lut_startAddrBnGroupsLlr[idxBnGroup]];
// Loop over BNs
for (i=0,j=0; i<M; i++,j+=2)
{
// First 16 LLRs of first CN
ymmRes0 = _mm256_cvtepi8_epi16(p_bnProcBuf[j]);
ymmRes1 = _mm256_cvtepi8_epi16(p_bnProcBuf[j+1]);
// Loop over CNs
for (k=1; k<3; k++)
{
ymm0 = _mm256_cvtepi8_epi16(p_bnProcBuf[k*cnOffsetInGroup + j]);
ymmRes0 = _mm256_adds_epi16(ymmRes0, ymm0);
ymm1 = _mm256_cvtepi8_epi16(p_bnProcBuf[k*cnOffsetInGroup + j+1]);
ymmRes1 = _mm256_adds_epi16(ymmRes1, ymm1);
}
// Add LLR from receiver input
ymm0 = _mm256_cvtepi8_epi16(p_llrProcBuf[j]);
ymmRes0 = _mm256_adds_epi16(ymmRes0, ymm0);
ymm1 = _mm256_cvtepi8_epi16(p_llrProcBuf[j+1]);
ymmRes1 = _mm256_adds_epi16(ymmRes1, ymm1);
// Pack results back to epi8
ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1);
// ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]]
// p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]]
*p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8);
// Next result
p_llrRes++;
}
}
\end{lstlisting}
The sum of the LLRs is carried out in 16 bit for accuracy and is then saturated to 8 bit for CN processing. Saturation after each addition results in significant loss of sensitivity for low code rates.
\subsection{Mapping to the Processing Buffers}
\label{sec:mapp-cn-proc}
For efficient processing with the AVX instructions, the data is required to be aligned in a certain manner. That is the reason why processing buffers have been introduced. The drawback is that the results of the processing need to copied every time to the processing buffer of the next task. However, the speed up in computation with AVX more than makes up for the time wasted in copying data. The copying is implemented as a circular memcpy because every edge in the BG is a circular shift of a $Z\times Z$ identity matrix. Hence, a circular mempcy consists of two regular memcpys each copying a part of the $Z$ values depending on the circular shift in the BG definition. The circular shifts are stored in \texttt{nrLDPC\_lut.h} in arrays \texttt{circShift\_BGX\_ZX\_CNGX}. In the specification there are only 8 sets of cirular shifts defined. However, the applied circular shift depends on $Z$, i.e. modulo $Z$. To avoid inefficient modulo operations in loops, we store the the circular shift values for every $Z$. Moreover, for convinience the arrays are already arranged depending on the CN group (CNG).
\newpage
\section{Performance Results}
\label{sec:performance-results}
In this section, the performance in terms of BLER and decoding latency of the current LDPC decoder implementation is verified.
\subsection{BLER Performance}
\label{sec:bler-performance}
In all simulations, we assume AWGN, QPSK modulation and 8-bit input LLRs, i.e. $-127$ until $+127$. The DLSCH coding procedure in 38.212 is used to encode/decode the TB and an error is declared if the TB CRC check failed. Results are averaged over at least $10\,000$ channel realizations.
The first set of simulations in Figure \ref{fig:bler-bg2-15} compares the current LDPC decoder implementation to the reference implementation developed by Kien. This reference implementation is called \textit{LDPC Ref} and uses the min-sum algorithm with 2 layers and 16 bit for processing. Our current optimized decoder implementation is referred to as \textit{LDPC OAI}. Moreover, reference results provided by Huawei are also shown.
\begin{figure}[ht]
\centering
\begin{tikzpicture}
\tikzstyle{every pin}=[fill=white,draw=black]
\pgfplotsset{every axis legend/.append style={
cells={anchor=west}, at={(1.05,1)}, anchor=north west}}
% \pgfplotsset{every axis plot/.append style={smooth}}
\pgfplotsset{every axis/.append style={line width=0.5pt}}
\pgfplotsset{every axis/.append style={mark options=solid, mark size=2.5pt}}
\begin{semilogyaxis}[title={}, xlabel={$\SNR$ [dB]}, ylabel={BLER},
grid={both}, xmin=-4, xmax=2, xtick={-4,-3.5,...,2}, ymin=0,
ymax=1,ytickten={-5,-4,-3,-2,-1,0},legend columns=1]
% HUAWEI merged BG2 2017-06-15
\addplot[black, solid] plot coordinates { (-3.91839,0.01) (-3.5567,0.0001) };
% 5 iterations
% LDPC Ref
\addplot[red, solid, mark=o] plot coordinates {(-1.250000,0.781300) (-1.000000,0.421000) (-0.750000,0.140400) (-0.500000,0.028900) (-0.250000,0.003300) (0.000000,0.000300) (0.250000,0.000000) (0.500000,0.000000)};
% LDPC OAI
\addplot[blue, solid, mark=square] plot coordinates {(-1.000000,0.693730) (-0.750000,0.370190) (-0.500000,0.137260) (-0.250000,0.038850) (0.000000,0.009740) (0.250000,0.002510) (0.500000,0.000730) (0.750000,0.000180) };
% Matlab layered min-sum with scaling factor 1
\addplot[green, solid, mark=triangle] plot coordinates {(-1.750000,0.709000) (-1.500000,0.360600) (-1.250000,0.105500) (-1.000000,0.015700) (-0.750000,0.001300) (-0.500000,0.000100) (-0.250000,0.000000) (0.000000,0.000000) };
% Matlab layered min-sum with scaling factor 0.8
%\addplot[green, solid, mark=triangle] plot coordinates {(-2.750000,0.982300) (-2.500000,0.882200) (-2.250000,0.573100) (-2.000000,0.214100) (-1.750000,0.041300) (-1.500000,0.003800) (-1.250000,0.000000) (-1.000000,0.000000) };
% 10 iterations
% Kien's 2-layer 16bit code
\addplot[red, solid, mark=o] plot coordinates { (-2.750000,0.915500) (-2.500000,0.576000) (-2.250000,0.165000) (-2.000000,0.017100) (-1.750000,0.000600) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)};
% LDPC OAI
\addplot[blue, solid, mark=square] plot coordinates { (-2.750000,0.997200) (-2.500000,0.955000) (-2.250000,0.710900) (-2.000000,0.270400) (-1.750000,0.042400) (-1.500000,0.002200) (-1.250000,0.000000) (-1.000000,0.000000)};
% Matlab layered min-sum with scaling factor 1
\addplot[green, solid, mark=triangle] plot coordinates {(-2.750000,0.942900) (-2.500000,0.723200) (-2.250000,0.362300) (-2.000000,0.098400) (-1.750000,0.014500) (-1.500000,0.001100) (-1.250000,0.000000) (-1.000000,0.000000) };
% Matlab layered min-sum with scaling factor 0.8
%\addplot[green, solid, mark=triangle] plot coordinates {(-3.750000,0.994300) (-3.500000,0.927200) (-3.250000,0.651100) (-3.000000,0.252000) (-2.750000,0.042500) (-2.500000,0.002700) (-2.250000,0.000000) (-2.000000,0.000000) (-1.750000,0.000000) (-1.500000,0.000000) };
% 20 iterations
% Kien's 2-layer 16bit code
\addplot[red, solid, mark=o] plot coordinates { (-2.750000,0.330300) (-2.500000,0.067800) (-2.250000,0.006000) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)};
% LDPC OAI
\addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.337900) (-2.500000,0.058300) (-2.250000,0.004000) (-2.000000,0.000200) (-1.750000,0.000000) (-1.500000,0.000000) };
% Matlab layered min-sum with scaling factor 1
%\addplot[green, solid, mark=triangle] plot coordinates {(-2.750000,0.843200) (-2.500000,0.524600) (-2.250000,0.198100) (-2.000000,0.037300) (-1.750000,0.003200) (-1.500000,0.000000) };
% Matlab layered min-sum with scaling factor 0.8
%\addplot[green, solid, mark=triangle] plot coordinates {(-3.750000,0.872300) (-3.500000,0.544600) (-3.250000,0.186400) (-3.000000,0.027500) (-2.750000,0.001900) (-2.500000,0.000000) };
% Parity check 50 iterations
%\addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.214600) (-2.500000,0.029200) (-2.250000,0.001500) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000000) };
\draw (axis cs:-3.3,0.1) node[fill=white,draw=black] (pint0) {20 iter};
\draw (axis cs:-2.3,0.01) node[draw,black,thick,ellipse,minimum height=0.3cm] (ell0) {}; \draw[black,thick] (pint0) -- (ell0);
\draw (axis cs:-1.2,0.0001) node[fill=white,draw=black] (pint1) {10 iter};
\draw (axis cs:-1.6,0.002) node[draw,black,thick,ellipse,minimum width=0.8cm] (ell1) {}; \draw[black,thick] (pint1) -- (ell1);
\draw (axis cs:1.3,0.2) node[fill=white,draw=black] (pint2) {5 iter};
\draw (axis cs:-0.4,0.01) node[draw,black,thick,ellipse,minimum width=2cm] (ell2) {}; \draw[black,thick] (pint2) -- (ell2);
\legend{ {Huawei 2017-06-15}\\
{LDPC Ref}\\
{LDPC OAI}\\
{MATLAB NMS SF=1}\\};
\end{semilogyaxis}
\end{tikzpicture}
\caption{BLER vs. SNR, BG2, Rate=1/5, \{5,10,20\} Iterations, B=1280.}
\label{fig:bler-bg2-15}
\end{figure}
From Figure \ref{fig:bler-bg2-15} it can be observed that the reference decoder outperforms the current implementation significantly for low to medium number of iterations. The reason is the implementation of 2 layers in the reference decoder, which results in faster convergence for punctured codes and hence requires less iterations to achieve a given BLER target. Note that there is a large performance loss of about 4 dB at BLER $10^{-2}$ between the Huawei reference and the current optimized decoder implementation with 5 iterations.
Moreover, there is a gap of about 1.5 dB between the results provided by Huawei and the current decoder with 20 iterations. The reason is the min-sum approximation algorithm used in both the reference decoder and the current implementation. The gap can be closed by using a tighter approximation like the min-sum with normalization or the lambda-min approach. Moreover, the gap closes for higher code rates which can be observed from Figure \ref{fig:bler-bg2-r23}. The gap is only about 0.6 dB for 50 iterations.
The Matlab results denoted \texttt{MATLAB NMS} are obtained with the function \texttt{nrLDPCDecode} provided by the MATLAB 5G Toolbox R2019b. The following options are provided to the function: \texttt{'Termination','max','Algorithm','Normalized min-sum','ScalingFactor',1}. Furthermore, the 8-bit input LLRs are adapted to fit the dynamic range of \texttt{nrLDPCDecode} which is shown in Listing \ref{ldpc_matlab}.
\begin{lstlisting}[frame=single,caption={Input adaptation for MATLAB LDPC Decoder},label=ldpc_matlab]
maxLLR = max(abs(softbits));
rxLLRs = round((softbits/maxLLR)*127);
// adjust range to fit tanh use in decoder code
softbits = rxLLRs/3.4;
\end{lstlisting}
A scaling factor (SF) of 1 has been chosen to compare the results more easily with the \textit{LDPC OAI} since the resulting check node processing is the same. However, the Matlab normelized min-sum algorithm uses layered processing and floating point operations. Thus, for the same number of iterations, the performance is significantly better than \textit{LDPC OAI}, especially for small a number of iterations.
\begin{figure}[ht]
\centering
\begin{tikzpicture}
\tikzstyle{every pin}=[fill=white,draw=black]
\pgfplotsset{every axis legend/.append style={
cells={anchor=west}, at={(1.05,1)}, anchor=north west}}
% \pgfplotsset{every axis plot/.append style={smooth}}
\pgfplotsset{every axis/.append style={line width=0.5pt}}
\pgfplotsset{every axis/.append style={mark options=solid, mark size=2.5pt}}
\begin{semilogyaxis}[title={}, xlabel={$\SNR$ [dB]}, ylabel={BLER},
grid={both}, xmin=3, xmax=6.5, xtick={3,3.5,...,6.5}, ymin=0,
ymax=1,ytickten={-5,-4,-3,-2,-1,0},legend columns=1]
% Kien's 2-layer 16bit code
%\addplot[red, solid] plot coordinates { (-2.750000,0.915500) (-2.500000,0.576000) (-2.250000,0.165000) (-2.000000,0.017100) (-1.750000,0.000600) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)};
% Huawei
\addplot[black, solid] plot coordinates { (3.28392,0.01) (3.73319,0.0001) };
% LDPC opt with 16bit BN processing
%\addplot[blue, solid, mark=square] plot coordinates {(4.000000,0.487500) (4.250000,0.163400) (4.500000,0.029800) (4.750000,0.002700) (5.000000,0.000100)};
\addplot[blue, solid, mark=square] plot coordinates {(5.000000,0.439600) (5.250000,0.185800) (5.500000,0.062100) (5.750000,0.015000) (6.000000,0.003900)};
%\addplot[blue, dashed, mark=triangle] plot coordinates {(4.000000,0.487500) (4.250000,0.163700) (4.500000,0.030000) (4.750000,0.002900) (5.000000,0.000100)};
%\addplot[blue, dashed, mark=square] plot coordinates {(3.000000,0.911600) (3.250000,0.614100) (3.500000,0.230100) (3.750000,0.036900) (4.000000,0.001100) (4.250000,0.000000) (4.500000,0.000000)};
\addplot[blue, dashed, mark=square] plot coordinates {(3.000000,0.900400) (3.250000,0.600000) (3.500000,0.216400) (3.750000,0.036000) (4.000000,0.002600) (4.250000,0.000000) };
\legend{ {Huawei 2017-06-15}\\
{LDPC OAI 5 iter}\\
{LDPC OAI 50 iter}\\};
\end{semilogyaxis}
\end{tikzpicture}
\caption{BLER vs. SNR, BG2, Rate=2/3, \{5,50\} Iterations, B=1280.}
\label{fig:bler-bg2-r23}
\end{figure}
In Figure \ref{fig:bler-bg2-15-2} we compare the performance of different algorithms using at most 50 iterations with early stopping if the parity check passes. The Matlab layered believe propagation (LBP) is used with unquantized input LLRs and performs the best since no approximation is done in the processing. Both NMS and offset min-sum (OMS) use a scaling factor and offset, respectively, that has been empirically found to perform best in this simulation setting. Theirs performance is very close to the BLP and OMS is slightly better than NMS. The performance of \textit{LDPC OAI} is more than 1 dB worse mainly because of the looser approximation. Moreover, the NMS algorithm with SF=1 performs worst probably because the SF is not optimized for the input LLRs. From the results in Figure \ref{fig:bler-bg2-15-2} we can conclude that the performance of the \textit{LDPC OAI} can be significantly improved by adopting an offset min-sum approximation improving the performance to within 0.3dB of the Huawei reference curve.
\begin{figure}[ht]
\centering
\begin{tikzpicture}
\tikzstyle{every pin}=[fill=white,draw=black]
\pgfplotsset{every axis legend/.append style={
cells={anchor=west}, at={(1.05,1)}, anchor=north west}}
% \pgfplotsset{every axis plot/.append style={smooth}}
\pgfplotsset{every axis/.append style={line width=0.5pt}}
\pgfplotsset{every axis/.append style={mark options=solid, mark size=2.5pt}}
\begin{semilogyaxis}[title={}, xlabel={$\SNR$ [dB]}, ylabel={BLER},
grid={both}, xmin=-4, xmax=-1, xtick={-4,-3.5,...,-1}, ymin=0,
ymax=1,ytickten={-5,-4,-3,-2,-1,0},legend columns=1]
% HUAWEI merged BG2 2017-06-15
\addplot[black, solid] plot coordinates { (-3.91839,0.01) (-3.5567,0.0001) };
% Parity check 50 iterations
\addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.214600) (-2.500000,0.029200) (-2.250000,0.001500) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000000) };
% Matlab layered believe propagation
\addplot[red, solid, mark=diamond] plot coordinates {(-4.500000,0.854200) (-4.250000,0.495800) (-4.000000,0.147700) (-3.750000,0.016100) (-3.500000,0.000800) (-3.250000,0.000200) (-3.000000,0.000000) };
% Matlab layered min-sum with scaling factor 1
\addplot[green, dashed, mark=triangle] plot coordinates {(-2.750000,0.830100) (-2.500000,0.497700) (-2.250000,0.165800) (-2.000000,0.024000) (-1.750000,0.001900) (-1.500000,0.000000) };
% Matlab layered min-sum with scaling factor 0.8
%\addplot[green, solid, mark=triangle] plot coordinates {(-3.750000,0.734800) (-3.500000,0.353800) (-3.250000,0.084300) (-3.000000,0.008000) (-2.750000,0.000400) };
\addplot[green, solid, mark=triangle] plot coordinates {(-4.500000,0.964400) (-4.250000,0.748200) (-4.000000,0.333600) (-3.750000,0.057700) (-3.500000,0.004400) (-3.250000,0.000400) };
% Matlab layered offset min-sum with offset 0.025
\addplot[brown, solid, mark=asterisk] plot coordinates {(-4.250000,0.688800) (-4.000000,0.253800) (-3.750000,0.035600) (-3.500000,0.002000) (-3.250000,0.000000) (-3.000000,0.000000) };
\legend{ {Huawei 2017-06-15}\\
{LDPC OAI}\\
{MATLAB LBP}\\
{MATLAB NMS SF=1}\\
{MATLAB NMS SF=0.65}\\
{MATLAB OMS OS=0.025}\\};
\end{semilogyaxis}
\end{tikzpicture}
\caption{BLER vs. SNR, BG2, Rate=1/5, max iterations = 50, B=1280.}
\label{fig:bler-bg2-15-2}
\end{figure}
Figure \ref{fig:bler-bg1-r89} shows the performance of BG1 with largest block size of $B=8448$ and highest code rate $R=8/9$. From Figure \ref{fig:bler-bg1-r89} it can be observed that the performance gap is only about 0.3 dB if 50 iterations are used. However, for 5 iterations there is still a significant performance loss of about 2.3 dB at BLER $10^{-2}$.
\begin{figure}[ht]
\centering
\begin{tikzpicture}
\tikzstyle{every pin}=[fill=white,draw=black]
\pgfplotsset{every axis legend/.append style={
cells={anchor=west}, at={(1.05,1)}, anchor=north west}}
% \pgfplotsset{every axis plot/.append style={smooth}}
\pgfplotsset{every axis/.append style={line width=0.5pt}}
\pgfplotsset{every axis/.append style={mark options=solid, mark size=2.5pt}}
\begin{semilogyaxis}[title={}, xlabel={$\SNR$ [dB]}, ylabel={BLER},
grid={both}, xmin=6, xmax=9, xtick={6,6.5,...,9}, ymin=0,
ymax=1,ytickten={-5,-4,-3,-2,-1,0},legend columns=1]
% Huawei
\addplot[black, solid] plot coordinates { (6.118717,0.01) (6.291449,0.0001) };
% LDPC opt 5 iter
%\addplot[blue, solid, mark=square] plot coordinates {(8.500000,0.350000) (8.750000,0.155100) (9.000000,0.062400) (9.250000,0.023000) (9.500000,0.008700) (9.750000,0.003500) (10.000000,0.000900) (10.250000,0.000300) };
\addplot[blue, solid, mark=square] plot coordinates {(7.500000,0.858900) (7.750000,0.449500) (8.000000,0.129700) (8.250000,0.025500) (8.500000,0.002300) (8.750000,0.000300) (9.000000,0.000000) };
% LDPC opt 50 iter
%\addplot[blue, dashed, mark=square] plot coordinates {(6.000000,0.705333) (6.100000,0.353367) (6.200000,0.102100) (6.300000,0.015133) (6.400000,0.000967) (6.500000,0.000000)};
\addplot[blue, dashed, mark=square] plot coordinates {(6.000000,0.970000) (6.100000,0.830800) (6.200000,0.527300) (6.300000,0.216900) (6.400000,0.045500) (6.500000,0.005600) (6.600000,0.000300) (6.700000,0.000000) (6.800000,0.000000) };
\legend{ {Huawei}\\
{LDPC OAI 5 iter}\\
{LDPC OAI 50 iter}\\};
\end{semilogyaxis}
\end{tikzpicture}
\caption{BLER vs. SNR, BG1, Rate=8/9 \{5,50\} Iterations, B=8448.}
\label{fig:bler-bg1-r89}
\end{figure}
\newpage
\subsection{Decoding Latency}
\label{sec:decoding-time}
This section provides results in terms of decoding latency. That is, the time it takes the decoder to to finish decoding for a given number of iterations. To measure the run time of the decoder we use the OAI tool \texttt{time\_meas.h}. The clock frequency is about 2.9 GHZ, decoder is run on a single core and the results are averaged over $10\,000$ blocks.
The results in Table \ref{tab:lat-bg2-r15} show the impact of the number of iterations on the decoding latency. It can be observed that the latency roughly doubles if the number of iterations are doubled.
\begin{table}[ht]
\centering
\begin{tabular}{lrrr}
\toprule
\textbf{Function} & \textbf{Time [$\mu s$] (5 it)} & \textbf{Time [$\mu s$] (10 it)} & \textbf{Time [$\mu s$] (20 it)}\\
\midrule
% \texttt{llr2llrProcBuf} & 1.1 & 1.1 & 1.1 \\
% \texttt{llr2CnProcBuf} & 12.4 & 12.0 & 12.0 \\
% \texttt{cnProc} & 11.7 & 22.1 & 43.5 \\
% \texttt{bnProcPc} & 6.6 & 12.1 & 23.8 \\
% \texttt{bnProc} & 4.2 & 8.1 & 16.2 \\
% \texttt{cn2bnProcBuf} & 61.3 & 118.3 & 234.9 \\
% \texttt{bn2cnProcBuf} & 38.1 & 82.5 & 172.3 \\
% \texttt{llrRes2llrOut} & 3.5 & 3.4 & 3.4 \\
% \texttt{llr2bit} & 0.2 & 0.1 & 0.1 \\
\texttt{llr2llrProcBuf} & 0.5 & 0.5 & 0.5 \\
\texttt{llr2CnProcBuf} & 5.0 & 4.8 & 4.9 \\
\texttt{cnProc} & 12.4 & 23.0 & 42.7 \\
\texttt{bnProcPc} & 8.4 & 14.8 & 27.0 \\
\texttt{bnProc} & 5.5 & 10.1 & 19.0 \\
\texttt{cn2bnProcBuf} & 14.9 & 24.4 & 44.0 \\
\texttt{bn2cnProcBuf} & 10.5 & 17.8 & 31.8 \\
\texttt{llrRes2llrOut} & 0.3 & 0.3 & 0.3 \\
\texttt{llr2bit} & 0.2 & 0.2 & 0.2 \\
\midrule
% \textbf{Total} & \textbf{139.4} & \textbf{260.3} & \textbf{508.4} \\
\textbf{Total} & \textbf{58.5} & \textbf{97.1} & \textbf{172.6} \\
\bottomrule
\end{tabular}
\caption{BG2, Z=128, R=1/5, B=1280, LDPC OAI}
\label{tab:lat-bg2-r15}
\end{table}
Table \ref{tab:lat-bg2-i5} shows the impact of the code rate on the latency for a given block size and 5 iterations. It can be observed that the performance gain from code rate 1/3 to 2/3 is about a factor 2.
\begin{table}[ht]
\centering
\begin{tabular}{lrrr}
\toprule
\textbf{Function} & \textbf{Time [$\mu s$] (R=1/5)} & \textbf{Time [$\mu s$] (R=1/3)} & \textbf{Time [$\mu s$] (R=2/3)}\\
\midrule
% \texttt{llr2llrProcBuf} & 3.2 & 2.9 & 2.6 \\
% \texttt{llr2CnProcBuf} & 36.5 & 25.4 & 14.8 \\
% \texttt{cnProc} & 33.6 & 25.2 & 13.3 \\
% \texttt{bnProcPc} & 17.6 & 10.2 & 4.5 \\
% \texttt{bnProc} & 8.5 & 5.4 & 2.5 \\
% \texttt{cn2bnProcBuf} & 175.3 & 110.6 & 50.7 \\
% \texttt{bn2cnProcBuf} & 106.6 & 71.2 & 36.1 \\
% \texttt{llrRes2llrOut} & 10.2 & 6.3 & 3.3 \\
% \texttt{llr2bit} & 0.4 & 0.2 & 0.1 \\
\texttt{llr2llrProcBuf} & 1.5 & 0.9 & 0.5 \\
\texttt{llr2CnProcBuf} & 6.0 & 4.1 & 2.2 \\
\texttt{cnProc} & 32.2 & 23.7 & 14.4 \\
\texttt{bnProcPc} & 21.2 & 12.1 & 5.5 \\
\texttt{bnProc} & 9.8 & 5.9 & 2.9 \\
\texttt{cn2bnProcBuf} & 23.3 & 13.9 & 6.8 \\
\texttt{bn2cnProcBuf} & 14.8 & 9.7 & 5.0 \\
\texttt{llrRes2llrOut} & 0.6 & 0.4 & 0.3 \\
\texttt{llr2bit} & 0.7 & 0.4 & 0.2 \\
\midrule
% \textbf{Total} & \textbf{392.4} & \textbf{258.0} & \textbf{128.2} \\
\textbf{Total} & \textbf{111.0} & \textbf{71.8} & \textbf{38.5} \\
\bottomrule
\end{tabular}
\caption{BG2, Z=384, B=3840, LDPC OAI, 5 iterations}
\label{tab:lat-bg2-i5}
\end{table}
Table \ref{tab:lat-bg1-i5} shows the results for BG1, larges block size and different code rates. The latency difference betwee code rate 1/3 and code rate 2/3 is less than half because upper left corner of the PCM is more dense than the rest of the PCM.
\begin{table}[ht]
\centering
\begin{tabular}{lrrr}
\toprule
\textbf{Function} & \textbf{Time [$\mu s$] (R=1/3)} & \textbf{Time [$\mu s$] (R=2/3)} & \textbf{Time [$\mu s$] (R=8/9)}\\
\midrule
% \texttt{llr2llrProcBuf} & 5.5 & 4.9 & 4.6 \\
% \texttt{llr2CnProcBuf} & 60.6 & 34.1 & 24.4 \\
% \texttt{cnProc} & 102.0 & 74.1 & 56.0 \\
% \texttt{bnProcPc} & 26.0 & 11.0 & 6.4 \\
% \texttt{bnProc} & 15.7 & 7.4 & 4.5 \\
% \texttt{cn2bnProcBuf} & 291.0 & 140.8 & 83.1 \\
% \texttt{bn2cnProcBuf} & 193.6 & 100.5 & 63.0 \\
% \texttt{llrRes2llrOut} & 13.3 & 6.9 & 5.2 \\
% \texttt{llr2bit} & 0.4 & 0.2 & 0.2 \\
\texttt{llr2llrProcBuf} & 2.1 & 1.2 & 0.9 \\
\texttt{llr2CnProcBuf} & 10.6 & 5.4 & 2.9 \\
\texttt{cnProc} & 89.8 & 66.3 & 50.0 \\
\texttt{bnProcPc} & 28.1 & 12.4 & 7.1 \\
\texttt{bnProc} & 17.1 & 8.1 & 4.8 \\
\texttt{cn2bnProcBuf} & 38.7 & 17.1 & 9.3 \\
\texttt{bn2cnProcBuf} & 25.6 & 12.7 & 7.2 \\
\texttt{llrRes2llrOut} & 0.8 & 0.4 & 0.3 \\
\texttt{llr2bit} & 0.9 & 0.4 & 0.3 \\
\midrule
% \textbf{Total} & \textbf{708.9} & \textbf{380.6} & \textbf{248.1}\\
\textbf{Total} & \textbf{214.6} & \textbf{124.6} & \textbf{83.6}\\
\bottomrule
\end{tabular}
\caption{BG1, Z=384, B=8448, LDPC OAI, 5 iterations}
\label{tab:lat-bg1-i5}
\end{table}
From the above results it can be observed that the data transfer between CNs and BNs takes up a significant amount of the run time. However, the performance gain due to AVX instructions in both CN and BN processing is significantly larger than the penalty incurred by the data transfers.
\section{Parity Check and Early Stopping Criteria}
It is often unnecessary to carry out the maximum number of iterations. After each iteration a parity check (PC) \eqref{eq:29} can be computed and if a valid code word is found the decoder can stop. This functionality has been implemented and the additional overhead is reasonable. The PC is carried out in the CN processing buffer and the calculation complexity itself is negligible. However, for the processing it is necessary to move the BN results to the CN buffer which takes time, the overall overhead is at most $10\%$ compared to an algorithm without early stopping criteria with the same number of iterations. The PC has to be activated via the define \texttt{NR\_LDPC\_ENABLE\_PARITY\_CHECK}.
\section{Conclusion}
\label{sec:conclusion}
The results in the previous sections show that the current optimized LDPC implementation full-fills the requirements in terms of decoding latency for low to medium number of iterations at the expense of a loss in BLER performance. To improve BLER performance, it is recommended to implement a layered algorithm and a min-sum algorithm with normalization. Further improvements upon the current implementation are detailed in the next section.
\newpage
\section{Future Work}
\label{sec:future-work}
The improvements upon the current LDPC decoder implementation can be divided into two categories:
\begin{enumerate}
\item Improved BLER performance
\item Reduced decoding latency
\end{enumerate}
\subsection{Improved BLER Performance}
\label{sec:impr-bler-perf}
The BLER performance can be improved by using a tighter approximation than the min-sum approximation. For instance, the min-sum algorithm can be improved by adding a correction factor in the CN processing . The min-sum approximation in \eqref{eq:40} is modified as
\begin{equation}
\label{eq:50}
r_{ji} = \prod_{j'\in\Bcal_i\setminus j}\sgn q_{ij'}\min_{j'\in\Bcal_i\setminus j} |q_{ij'}| + w(q_{ij'})
\end{equation}
The correction term $w(q_{ij'})$ is defined as
\begin{equation}
\label{eq:51}
w(q_{ij'}) =
\begin{cases}
c & \textrm{if}~ \\
-c & \textrm{if}~ \\
0 & \textrm{otherwise}
\end{cases}
\end{equation}
where the constant $c$ is of order $0.5$ typically.
\subsection{Reduced Decoding Latency}
\label{sec:reduc-decod-latency}
The following improvements will reduce the decoding latency:
\begin{itemize}
\item Adapt to AVX512
\item Optimization of CN processing
\item Implement 2/3-layers for faster convergence
\end{itemize}
\paragraph{AVX512:}
The computations in the CN and BN processing can be further accelerated by using AVX512 instructions. This improvement will speed-up the CN and BN processing by a approximately a factor of 2.
\paragraph{Optimization of CN Processing:}
It can be investigated if CN processing can be improved by computing two minima regardless of the number of BNs. Susequently, the (absolute) value fed back to the BN is one of those minima.
\paragraph{Layered processing:}
The LDPC code in NR always punctures the first 2 columns of the base graph. Hence, the decoder inserts LLRs with value 0 at their place and needs to retrieve those bits during the decoding process. Instead of computing all the parity equations and then passing the results to the BN processing, it is beneficial to first compute parity equations where at most one punctured BN is connected to that CN. If two punctured BNs are connected than according to \eqref{eq:40}, the result will be again 0. Thus in a first sub-iteration those parity equation are computed and the results are send to BN processing which calculates the results using only those rows in the PCM. In the second sub-iteration the remaining check equation are used.
The convergence of this layered approach is much fast since the bit can be retrieved more quickly while the decoding complexity remains the same. Therefore, for a fixed number of iterations the layered algorithm will have a significantly better performance.
\newpage
\bibliographystyle{IEEEtran}
\bibliography{./references}
\end{document}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:

View File

@@ -0,0 +1,105 @@
%
% Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
% contributor license agreements. See the NOTICE file distributed with
% this work for additional information regarding copyright ownership.
% The OpenAirInterface Software Alliance licenses this file to You under
% the OAI Public License, Version 1.1 (the "License"); you may not use this file
% except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.openairinterface.org/?page_id=698
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
%-------------------------------------------------------------------------------
% For more information about the OpenAirInterface (OAI) Software Alliance:
% contact@openairinterface.org
%
@online{3gpp5gTimeline,
author = {3GPP},
title = {{3GPP 5G Timeline}},
year = 2016,
urldate = {2017-06-14},
url = {http://www.3gpp.org/images/articleimages/5g_timeline.jpg}
}
@techreport{3gppTR38913,
author = "{Technical Specification Group Radio Access Network}",
title = "{Study on Scenarios and Requirements for Next Generation Access Technologies}",
institution = "{3GPP TR 38.913 V14.2.0}",
month = mar,
year = 2017,
};
@techreport{iturM2038,
author = "{ITU-R}",
title = "{IMT Vision -- Framework and overall objectives of the future development of IMT for 2020 and beyond}",
institution = "{Radiocommunication Sector of ITU}",
month = sep,
year = 2015,
};
@techreport{3gpp2014seb,
author = "{Samsung, Nokia Networks}",
title = "{New SID Proposal: Study on Elevation Beamforming/Full-Dimension (FD) MIMO for LTE}",
institution = "3GPP",
month = sep,
year = 2014,
};
@techreport{3gpp2015fdm,
author = "{Technical Specification Group Radio Access Network}",
title = "{Study on elevation beamforming / Full-Dimension (FD) Multiple Input Multiple Output (MIMO) for LTE}",
institution = "3GPP TR 36.897 V13.0.0",
month = jun,
year = 2015,
};
@techreport{3gpp2008tsg,
author = "{Technical Specification Group Radio Access Network;
Evolved Universal Terrestrial Radio Access (E-UTRA)}",
title = "{Further advancements for E-UTRA physical layer aspects (Release 9)}",
institution = "{3GPP TR 36.814 V9.0.0}",
month = mar,
year = 2010,
};
@techreport{3gpp2011uer,
author = "{Technical Specification Group Radio Access Network;
Evolved Universal Terrestrial Radio Access (E-UTRA)}",
title = "{User Equipment (UE) Radio Transmission and Reception}",
institution = "{3GPP TR 36.101 V10.3.0}",
month = jun,
year = 2011,
};
@techreport{3gpp2009_36211,
author = "{3rd Generation Partnership Project}",
title = "{Physical Channels and Modulation (Release 8)}",
institution = "{3GPP TS 36.211 V8.6.0}",
month = mar,
year = 2009,
};
@techreport{3gpp2017_38212,
author = "{3rd Generation Partnership Project}",
title = "{Multiplexing and channel coding (Release 15)}",
institution = "{3GPP TS 38.212 V15.0.1}",
month = mar,
year = 2018,
};
@article{gallager1962low,
title={Low-density parity-check codes},
author={Gallager, Robert},
journal={IRE Transactions on information theory},
volume={8},
number={1},
pages={21--28},
year={1962},
publisher={IEEE}
}

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,7 @@
#ifndef __NR_LDPC_BNPROC__H__
#define __NR_LDPC_BNPROC__H__
#include <immintrin.h>
/**
\brief Performs first part of BN processing on the BN processing buffer and stores the results in the LLR results buffer.
At every BN, the sum of the returned LLRs from the connected CNs and the LLR of the receiver input is computed.

View File

@@ -1,4 +1,3 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -29,8 +28,8 @@
* \warning
*/
#ifndef __NR_LDPC_DECODER_CNPROC__H__
#define __NR_LDPC_DECODER_CNPROC__H__
#ifndef __NR_LDPC_CNPROC__H__
#define __NR_LDPC_CNPROC__H__
/**
\brief Performs CN processing for BG2 on the CN processing buffer and stores the results in the CN processing results buffer.
@@ -38,13 +37,6 @@
\param p_procBuf Pointer to processing buffers
\param Z Lifting size
*/
#ifdef __AVX512BW__
#include "nrLDPC_cnProc_avx512.h"
#else
static inline void nrLDPC_cnProc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z)
{
const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups;
@@ -100,14 +92,14 @@ static inline void nrLDPC_cnProc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
ymm0 = pj0[i];
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
ymm0 = pj0[i];
sgn = _mm256_sign_epi8(*p_ones, ymm0);
min = _mm256_abs_epi8(ymm0);
// 32 CNs of second BN
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][1] + i];
ymm0 = pj1[i];
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][1] + i];
ymm0 = pj1[i];
min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
sgn = _mm256_sign_epi8(sgn, ymm0);
@@ -115,7 +107,7 @@ static inline void nrLDPC_cnProc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int
min = _mm256_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
//*p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
//p_cnProcBufResBit++;
p_cnProcBufResBit[i]=_mm256_sign_epi8(min, sgn);
p_cnProcBufResBit[i]=_mm256_sign_epi8(min, sgn);
}
}
}
@@ -372,15 +364,6 @@ static inline void nrLDPC_cnProc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int
}
/**
\brief Performs CN processing for BG1 on the CN processing buffer and stores the results in the CN processing results buffer.
\param p_lut Pointer to decoder LUTs
\param Z Lifting size
*/
/**
\brief Performs CN processing for BG1 on the CN processing buffer and stores the results in the CN processing results buffer.
\param p_lut Pointer to decoder LUTs
@@ -448,7 +431,6 @@ static inline void nrLDPC_cnProc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int
min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
sgn = _mm256_sign_epi8(sgn, ymm0);
// Store result
min = _mm256_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
@@ -877,7 +859,6 @@ static inline void nrLDPC_cnProc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int
}
#endif
/**
\brief Performs parity check for BG1 on the CN processing buffer. Stops as soon as error is detected.
\param p_lut Pointer to decoder LUTs
@@ -1941,6 +1922,3 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu
}
#endif

View File

@@ -1,865 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*!\file nrLDPC_cnProc_avx512.h
* \brief Defines the functions for check node processing
* \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
* \date 30-09-2021
* \version 1.0
* \note
* \warning
*/
#ifndef __NR_LDPC_CNPROC__H__
#define __NR_LDPC_CNPROC__H__
#define conditional_negate(a,b,z) _mm512_mask_sub_epi8(a,_mm512_movepi8_mask(b),z,a)
static inline void nrLDPC_cnProc_BG2_AVX512(t_nrLDPC_lut* p_lut, int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z)
{
const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
__m512i* p_cnProcBuf;
__m512i* p_cnProcBufRes;
// Number of CNs in Groups
uint32_t M;
uint32_t i;
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 32 Byte
uint32_t bitOffsetInGroup;
__m512i zmm0, min, sgn, zeros;
zeros = _mm512_setzero_si512();
// maxLLR = _mm512_set1_epi8((char)127);
__m512i* p_cnProcBufResBit;
const __m512i* p_ones = (__m512i*) ones512_epi8;
const __m512i* p_maxLLR = (__m512i*) maxLLR512_epi8;
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup
const uint8_t lut_idxCnProcG3[3][2] = {{72,144}, {0,144}, {0,72}};
// =====================================================================
// Process group with 3 BNs
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[0]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[0]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 3
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[0]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[0]];
// Loop over every BN
for (j=0; j<3; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
__m512i *pj0 = &p_cnProcBuf[(lut_idxCnProcG3[j][0]/2)];
__m512i *pj1 = &p_cnProcBuf[(lut_idxCnProcG3[j][1]/2)];
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
zmm0 = pj0[i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// 32 CNs of second BN
// zmm0 = p_cnProcBuf[(lut_idxCnProcG3[j][1]/2) + i];
zmm0 = pj1[i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
//p_cnProcBufResBit[i]=_mm512_sign_epi8(min, sgn);
}
}
}
// =====================================================================
// Process group with 4 BNs
// Offset is 20*384/32 = 240
const uint16_t lut_idxCnProcG4[4][3] = {{240,480,720}, {0,480,720}, {0,240,720}, {0,240,480}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[1]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[1]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 4
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[1]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<4; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG4[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<3; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG4[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 5 BNs
// Offset is 9*384/32 = 108
const uint16_t lut_idxCnProcG5[5][4] = {{108,216,324,432}, {0,216,324,432},
{0,108,324,432}, {0,108,216,432}, {0,108,216,324}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[2]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[2]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 5
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[2]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[2]];
// Loop over every BN
for (j=0; j<5; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG5[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<4; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG5[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 6 BNs
// Offset is 3*384/32 = 36
const uint16_t lut_idxCnProcG6[6][5] = {{36,72,108,144,180}, {0,72,108,144,180},
{0,36,108,144,180}, {0,36,72,144,180},
{0,36,72,108,180}, {0,36,72,108,144}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[3]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[3]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 6
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[3]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[3]];
// Loop over every BN
for (j=0; j<6; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG6[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<5; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG6[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 8 BNs
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[4]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[4]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 8
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[4]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[4]];
// Loop over every BN
for (j=0; j<8; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG8[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<7; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG8[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 10 BNs
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG10[10][9] = {{24,48,72,96,120,144,168,192,216}, {0,48,72,96,120,144,168,192,216},
{0,24,72,96,120,144,168,192,216}, {0,24,48,96,120,144,168,192,216},
{0,24,48,72,120,144,168,192,216}, {0,24,48,72,96,144,168,192,216},
{0,24,48,72,96,120,168,192,216}, {0,24,48,72,96,120,144,192,216},
{0,24,48,72,96,120,144,168,216}, {0,24,48,72,96,120,144,168,192}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[5]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[5]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 10
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[5]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[5]];
// Loop over every BN
for (j=0; j<10; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG10[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<9; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG10[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
}
static inline void nrLDPC_cnProc_BG1_AVX512(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_procBuf, uint16_t Z)
{
const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups;
int8_t* cnProcBuf = p_procBuf->cnProcBuf;
int8_t* cnProcBufRes = p_procBuf->cnProcBufRes;
__m512i* p_cnProcBuf;
__m512i* p_cnProcBufRes;
// Number of CNs in Groups
uint32_t M;
uint32_t i;
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 32 Byte
uint32_t bitOffsetInGroup;
__m512i zmm0, min, sgn, zeros;
zeros = _mm512_setzero_si512();
// maxLLR = _mm512_set1_epi8((char)127);
__m512i* p_cnProcBufResBit;
const __m512i* p_ones = (__m512i*) ones512_epi8;
const __m512i* p_maxLLR = (__m512i*) maxLLR512_epi8;
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup (1*384/32)
const uint8_t lut_idxCnProcG3[3][2] = {{12,24}, {0,24}, {0,12}};
// =====================================================================
// Process group with 3 BNs
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[0]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[0]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 3
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[0]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[0]];
// Loop over every BN
for (j=0; j<3; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG3[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// 32 CNs of second BN
zmm0 = p_cnProcBuf[(lut_idxCnProcG3[j][1]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 4 BNs
// Offset is 5*384/32 = 60
const uint8_t lut_idxCnProcG4[4][3] = {{60,120,180}, {0,120,180}, {0,60,180}, {0,60,120}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[1]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[1]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 4
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[1]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<4; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG4[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<3; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG4[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 5 BNs
// Offset is 18*384/32 = 216
const uint16_t lut_idxCnProcG5[5][4] = {{216,432,648,864}, {0,432,648,864},
{0,216,648,864}, {0,216,432,864}, {0,216,432,648}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[2]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[2]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 5
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[2]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[2]];
// Loop over every BN
for (j=0; j<5; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG5[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<4; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG5[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 6 BNs
// Offset is 8*384/32 = 96
const uint16_t lut_idxCnProcG6[6][5] = {{96,192,288,384,480}, {0,192,288,384,480},
{0,96,288,384,480}, {0,96,192,384,480},
{0,96,192,288,480}, {0,96,192,288,384}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[3]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[3]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 6
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[3]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[3]];
// Loop over every BN
for (j=0; j<6; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG6[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<5; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG6[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 7 BNs
// Offset is 5*384/32 = 60
const uint16_t lut_idxCnProcG7[7][6] = {{60,120,180,240,300,360}, {0,120,180,240,300,360},
{0,60,180,240,300,360}, {0,60,120,240,300,360},
{0,60,120,180,300,360}, {0,60,120,180,240,360},
{0,60,120,180,240,300}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[4]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[4]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 7
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[4]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[4]];
// Loop over every BN
for (j=0; j<7; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG7[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<6; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG7[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 8 BNs
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[5]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[5]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 8
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[5]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[5]];
// Loop over every BN
for (j=0; j<8; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG8[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<7; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG8[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 9 BNs
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG9[9][8] = {{24,48,72,96,120,144,168,192}, {0,48,72,96,120,144,168,192},
{0,24,72,96,120,144,168,192}, {0,24,48,96,120,144,168,192},
{0,24,48,72,120,144,168,192}, {0,24,48,72,96,144,168,192},
{0,24,48,72,96,120,168,192}, {0,24,48,72,96,120,144,192},
{0,24,48,72,96,120,144,168}};
if (lut_numCnInCnGroups[6] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[6]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[6]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 9
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[6]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[6]];
// Loop over every BN
for (j=0; j<9; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG9[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<8; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG9[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 10 BNs
// Offset is 1*384/32 = 12
const uint8_t lut_idxCnProcG10[10][9] = {{12,24,36,48,60,72,84,96,108}, {0,24,36,48,60,72,84,96,108},
{0,12,36,48,60,72,84,96,108}, {0,12,24,48,60,72,84,96,108},
{0,12,24,36,60,72,84,96,108}, {0,12,24,36,48,72,84,96,108},
{0,12,24,36,48,60,84,96,108}, {0,12,24,36,48,60,72,96,108},
{0,12,24,36,48,60,72,84,108}, {0,12,24,36,48,60,72,84,96}};
if (lut_numCnInCnGroups[7] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[7]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[7]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 10
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[7]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[7]];
// Loop over every BN
for (j=0; j<10; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG10[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<9; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG10[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
// =====================================================================
// Process group with 19 BNs
// Offset is 4*384/32 = 12
const uint16_t lut_idxCnProcG19[19][18] = {{48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816}};
if (lut_numCnInCnGroups[8] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
M = (lut_numCnInCnGroups[8]*Z + 63)>>6;
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[8]*NR_LDPC_ZMAX)>>6;
// Set pointers to start of group 19
p_cnProcBuf = (__m512i*) &cnProcBuf [lut_startAddrCnGroups[8]];
p_cnProcBufRes = (__m512i*) &cnProcBufRes[lut_startAddrCnGroups[8]];
// Loop over every BN
for (j=0; j<19; j++)
{
// Set of results pointer to correct BN address
p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
for (i=0; i<M; i++)
{
// Abs and sign of 32 CNs (first BN)
zmm0 = p_cnProcBuf[(lut_idxCnProcG19[j][0]/2) + i];
sgn = _mm512_xor_si512(*p_ones, zmm0);
min = _mm512_abs_epi8(zmm0);
// Loop over BNs
for (k=1; k<18; k++)
{
zmm0 = p_cnProcBuf[(lut_idxCnProcG19[j][k]/2) + i];
min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
sgn = _mm512_xor_si512(sgn, zmm0);
}
// Store result
min = _mm512_min_epu8(min, *p_maxLLR); // 128 in epi8 is -127
*p_cnProcBufResBit = conditional_negate(min, sgn,zeros);
p_cnProcBufResBit++;
}
}
}
}
#endif

View File

@@ -1,5 +1,3 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -22,8 +20,14 @@
*/
/*!\file nrLDPC_decoder.c
* \brief Defines thenrLDPC decoder
*/
* \brief Defines the LDPC decoder
* \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
* \date 30-09-2019
* \version 2.0
* \note
* \warning
*/
#include <stdint.h>
#include <immintrin.h>
@@ -33,83 +37,6 @@
#include "nrLDPC_mPass.h"
#include "nrLDPC_cnProc.h"
#include "nrLDPC_bnProc.h"
#define UNROLL_CN_PROC 1
#define UNROLL_BN_PROC 1
#define UNROLL_BN_PROC_PC 1
#define UNROLL_BN2CN_PROC 1
/*----------------------------------------------------------------------
| cn processing files -->AVX512
/----------------------------------------------------------------------*/
//BG1-------------------------------------------------------------------
#ifdef __AVX512BW__
#include "cnProc_avx512/nrLDPC_cnProc_BG1_R13_AVX512.h"
#include "cnProc_avx512/nrLDPC_cnProc_BG1_R23_AVX512.h"
#include "cnProc_avx512/nrLDPC_cnProc_BG1_R89_AVX512.h"
//BG2-------------------------------------------------------------------
#include "cnProc_avx512/nrLDPC_cnProc_BG2_R15_AVX512.h"
#include "cnProc_avx512/nrLDPC_cnProc_BG2_R13_AVX512.h"
#include "cnProc_avx512/nrLDPC_cnProc_BG2_R23_AVX512.h"
#else
/*----------------------------------------------------------------------
| cn Processing files -->AVX2
/----------------------------------------------------------------------*/
//BG1------------------------------------------------------------------
#include "cnProc/nrLDPC_cnProc_BG1_R13_AVX2.h"
#include "cnProc/nrLDPC_cnProc_BG1_R23_AVX2.h"
#include "cnProc/nrLDPC_cnProc_BG1_R89_AVX2.h"
//BG2 --------------------------------------------------------------------
#include "cnProc/nrLDPC_cnProc_BG2_R15_AVX2.h"
#include "cnProc/nrLDPC_cnProc_BG2_R13_AVX2.h"
#include "cnProc/nrLDPC_cnProc_BG2_R23_AVX2.h"
#endif
/*----------------------------------------------------------------------
| bn Processing files -->AVX2
/----------------------------------------------------------------------*/
//bnProcPc-------------------------------------------------------------
//BG1------------------------------------------------------------------
#include "bnProcPc/nrLDPC_bnProcPc_BG1_R13_AVX2.h"
#include "bnProcPc/nrLDPC_bnProcPc_BG1_R23_AVX2.h"
#include "bnProcPc/nrLDPC_bnProcPc_BG1_R89_AVX2.h"
//BG2 --------------------------------------------------------------------
#include "bnProcPc/nrLDPC_bnProcPc_BG2_R15_AVX2.h"
#include "bnProcPc/nrLDPC_bnProcPc_BG2_R13_AVX2.h"
#include "bnProcPc/nrLDPC_bnProcPc_BG2_R23_AVX2.h"
//bnProc----------------------------------------------------------------
#ifdef __AVX512BW__
//BG1-------------------------------------------------------------------
#include "bnProc_avx512/nrLDPC_bnProc_BG1_R13_AVX512.h"
#include "bnProc_avx512/nrLDPC_bnProc_BG1_R23_AVX512.h"
#include "bnProc_avx512/nrLDPC_bnProc_BG1_R89_AVX512.h"
//BG2 --------------------------------------------------------------------
#include "bnProc_avx512/nrLDPC_bnProc_BG2_R15_AVX512.h"
#include "bnProc_avx512/nrLDPC_bnProc_BG2_R13_AVX512.h"
#include "bnProc_avx512/nrLDPC_bnProc_BG2_R23_AVX512.h"
#else
#include "bnProc/nrLDPC_bnProc_BG1_R13_AVX2.h"
#include "bnProc/nrLDPC_bnProc_BG1_R23_AVX2.h"
#include "bnProc/nrLDPC_bnProc_BG1_R89_AVX2.h"
//BG2 --------------------------------------------------------------------
#include "bnProc/nrLDPC_bnProc_BG2_R15_AVX2.h"
#include "bnProc/nrLDPC_bnProc_BG2_R13_AVX2.h"
#include "bnProc/nrLDPC_bnProc_BG2_R23_AVX2.h"
#endif
#define NR_LDPC_ENABLE_PARITY_CHECK
//#define NR_LDPC_PROFILER_DETAIL
@@ -139,31 +66,28 @@ int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_
}
/**
\brief PerformsnrLDPC decoding of one code block
\brief Performs LDPC decoding of one code block
\param p_llr Input LLRs
\param p_out Output vector
\param numLLR Number of LLRs
\param p_lut Pointer to decoder LUTs
\param p_decParamsnrLDPC decoder parameters
\param p_profilernrLDPC profiler statistics
\param p_decParams LDPC decoder parameters
\param p_profiler LDPC profiler statistics
*/
static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_t numLLR, t_nrLDPC_lut* p_lut, t_nrLDPC_dec_params* p_decParams, t_nrLDPC_time_stats* p_profiler)
{
uint16_t Z = p_decParams->Z;
uint8_t BG = p_decParams->BG;
uint8_t R = p_decParams->R; //Decoding rate: Format 15,13,... for code rates 1/5, 1/3,... */
uint8_t numMaxIter = p_decParams->numMaxIter;
e_nrLDPC_outMode outMode = p_decParams->outMode;
// int8_t* cnProcBuf= cnProcBuf;
// int8_t* cnProcBufRes= cnProcBufRes;
int8_t cnProcBuf[NR_LDPC_SIZE_CN_PROC_BUF] __attribute__ ((aligned(64))) = {0};
int8_t cnProcBufRes[NR_LDPC_SIZE_CN_PROC_BUF] __attribute__ ((aligned(64))) = {0};
int8_t bnProcBuf[NR_LDPC_SIZE_BN_PROC_BUF] __attribute__ ((aligned(64))) = {0};
int8_t bnProcBufRes[NR_LDPC_SIZE_BN_PROC_BUF] __attribute__ ((aligned(64))) = {0};
int8_t llrRes[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(64))) = {0};
int8_t llrProcBuf[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(64))) = {0};
int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(64))) = {0};
int8_t cnProcBuf[NR_LDPC_SIZE_CN_PROC_BUF] __attribute__ ((aligned(32))) = {0};
int8_t cnProcBufRes[NR_LDPC_SIZE_CN_PROC_BUF] __attribute__ ((aligned(32))) = {0};
int8_t bnProcBuf[NR_LDPC_SIZE_BN_PROC_BUF] __attribute__ ((aligned(32))) = {0};
int8_t bnProcBufRes[NR_LDPC_SIZE_BN_PROC_BUF] __attribute__ ((aligned(32))) = {0};
int8_t llrRes[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))) = {0};
int8_t llrProcBuf[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))) = {0};
int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))) = {0};
// Minimum number of iterations is 1
// 0 iterations means hard-decision on input LLRs
uint32_t i = 1;
@@ -199,8 +123,14 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->llr2CnProcBuf);
#endif
if (BG == 1) nrLDPC_llr2CnProcBuf_BG1(p_lut, p_llr, cnProcBuf, Z);
else nrLDPC_llr2CnProcBuf_BG2(p_lut, p_llr, cnProcBuf, Z);
if (BG == 1)
{
nrLDPC_llr2CnProcBuf_BG1(p_lut, p_llr, cnProcBuf, Z);
}
else
{
nrLDPC_llr2CnProcBuf_BG2(p_lut, p_llr, cnProcBuf, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->llr2CnProcBuf);
#endif
@@ -216,79 +146,13 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->cnProc);
#endif
if (BG==1) {
#ifndef UNROLL_CN_PROC
if (BG == 1)
{
nrLDPC_cnProc_BG1(p_lut, cnProcBuf, cnProcBufRes, Z);
#else
switch (R)
{
case 13:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R13_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R13_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R23_AVX512(cnProcBuf,cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R23_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 89:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R89_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R89_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
}
#endif
} else {
#ifndef UNROLL_CN_PROC
}
else
{
nrLDPC_cnProc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
#else
switch (R) {
case 15:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R15_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R15_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 13:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R13_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R13_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R23_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R23_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
}
#endif
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->cnProc);
@@ -302,8 +166,14 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->cn2bnProcBuf);
#endif
if (BG == 1) nrLDPC_cn2bnProcBuf_BG1(p_lut, cnProcBufRes, bnProcBuf, Z);
else nrLDPC_cn2bnProcBuf_BG2(p_lut, cnProcBufRes, bnProcBuf, Z);
if (BG == 1)
{
nrLDPC_cn2bnProcBuf_BG1(p_lut, cnProcBufRes, bnProcBuf, Z);
}
else
{
nrLDPC_cn2bnProcBuf_BG2(p_lut, cnProcBufRes, bnProcBuf, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->cn2bnProcBuf);
#endif
@@ -317,51 +187,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bnProcPc);
#endif
#ifndef UNROLL_BN_PROC_PC
nrLDPC_bnProcPc(p_lut, bnProcBuf, bnProcBufRes, llrProcBuf, llrRes, Z);
#else
if (BG==1) {
switch (R) {
case 13:
{
nrLDPC_bnProcPc_BG1_R13_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
case 23:
{
nrLDPC_bnProcPc_BG1_R23_AVX2(bnProcBuf,bnProcBufRes, llrRes, llrProcBuf, Z);
break;
}
case 89:
{
nrLDPC_bnProcPc_BG1_R89_AVX2(bnProcBuf,bnProcBufRes, llrRes, llrProcBuf, Z);
break;
}
}
} else {
switch (R) {
case 15:
{
nrLDPC_bnProcPc_BG2_R15_AVX2(bnProcBuf,bnProcBufRes, llrRes, llrProcBuf, Z);
break;
}
case 13:
{
nrLDPC_bnProcPc_BG2_R13_AVX2(bnProcBuf,bnProcBufRes,llrRes,llrProcBuf, Z);
break;
}
case 23:
{
nrLDPC_bnProcPc_BG2_R23_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
}
}
#endif
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bnProcPc);
#endif
@@ -374,78 +200,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bnProc);
#endif
if (BG==1) {
#ifndef UNROLL_BN_PROC
nrLDPC_bnProc(p_lut, bnProcBuf, bnProcBufRes, llrRes, Z);
#else
switch (R) {
case 13:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R13_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R13_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R23_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R23_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 89:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R89_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R89_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
}
#endif
} else {
#ifndef UNROLL_BN2CN_PROC
nrLDPC_bn2cnProcBuf_BG2(p_lut, bnProcBufRes, cnProcBuf, Z);
#else
switch (R) {
case 15:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R15_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R15_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 13:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R13_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R13_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R23_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R23_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
}
#endif
}
nrLDPC_bnProc(p_lut, bnProcBuf, bnProcBufRes, llrRes, Z);
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bnProc);
#endif
@@ -459,8 +214,14 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bn2cnProcBuf);
#endif
if (BG == 1) nrLDPC_bn2cnProcBuf_BG1(p_lut, bnProcBufRes, cnProcBuf, Z);
else nrLDPC_bn2cnProcBuf_BG2(p_lut, bnProcBufRes, cnProcBuf, Z);
if (BG == 1)
{
nrLDPC_bn2cnProcBuf_BG1(p_lut, bnProcBufRes, cnProcBuf, Z);
}
else
{
nrLDPC_bn2cnProcBuf_BG2(p_lut, bnProcBufRes, cnProcBuf, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bn2cnProcBuf);
#endif
@@ -475,7 +236,8 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
// First iteration finished
while ( (i < numMaxIter) && (pcRes != 0) ) {
while ( (i < numMaxIter) && (pcRes != 0) )
{
// Increase iteration counter
i++;
@@ -483,74 +245,13 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->cnProc);
#endif
if (BG==1) {
#ifndef UNROLL_CN_PROC
nrLDPC_cnProc_BG1(p_lut, cnProcBuf, cnProcBufRes, Z);
#else
switch (R) {
case 13:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R13_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R13_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R23_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R23_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 89:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG1_R89_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG1_R89_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
}
#endif
} else {
#ifndef UNROLL_CN_PROC
nrLDPC_cnProc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
#else
switch (R) {
case 15:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R15_AVX512(cnProcBuf,cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R15_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 13:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R13_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R13_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_cnProc_BG2_R23_AVX512(cnProcBuf, cnProcBufRes, Z);
#else
nrLDPC_cnProc_BG2_R23_AVX2(cnProcBuf, cnProcBufRes, Z);
#endif
break;
}
}
#endif
if (BG == 1)
{
nrLDPC_cnProc_BG1(p_lut, cnProcBuf, cnProcBufRes, Z);
}
else
{
nrLDPC_cnProc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->cnProc);
@@ -564,8 +265,14 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->cn2bnProcBuf);
#endif
if (BG == 1) nrLDPC_cn2bnProcBuf_BG1(p_lut, cnProcBufRes, bnProcBuf, Z);
else nrLDPC_cn2bnProcBuf_BG2(p_lut, cnProcBufRes, bnProcBuf, Z);
if (BG == 1)
{
nrLDPC_cn2bnProcBuf_BG1(p_lut, cnProcBufRes, bnProcBuf, Z);
}
else
{
nrLDPC_cn2bnProcBuf_BG2(p_lut, cnProcBufRes, bnProcBuf, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->cn2bnProcBuf);
#endif
@@ -578,49 +285,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bnProcPc);
#endif
#ifndef UNROLL_BN_PROC_PC
nrLDPC_bnProcPc(p_lut, bnProcBuf, bnProcBufRes, llrProcBuf, llrRes, Z);
#else
if (BG==1) {
switch (R) {
case 13:
{
nrLDPC_bnProcPc_BG1_R13_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
case 23:
{
nrLDPC_bnProcPc_BG1_R23_AVX2(bnProcBuf,bnProcBufRes, llrRes, llrProcBuf, Z);
break;
}
case 89:
{
nrLDPC_bnProcPc_BG1_R89_AVX2(bnProcBuf,bnProcBufRes, llrRes, llrProcBuf, Z);
break;
}
}
} else {
switch (R)
{
case 15:
{
nrLDPC_bnProcPc_BG2_R15_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
case 13:
{
nrLDPC_bnProcPc_BG2_R13_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
case 23:
{
nrLDPC_bnProcPc_BG2_R23_AVX2(bnProcBuf,bnProcBufRes,llrRes, llrProcBuf, Z);
break;
}
}
}
#endif
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bnProcPc);
#endif
@@ -632,75 +297,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bnProc);
#endif
#ifndef UNROLL_BN_PROC
nrLDPC_bnProc(p_lut, bnProcBuf, bnProcBufRes, llrRes, Z);
#else
if (BG==1) {
switch (R) {
case 13:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R13_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R13_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R23_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R23_AVX2(bnProcBuf,bnProcBufRes,llrRes, Z);
#endif
break;
}
case 89:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG1_R89_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG1_R89_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
}
} else {
switch (R)
{
case 15:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R15_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R15_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 13:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R13_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R13_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
case 23:
{
#ifdef __AVX512BW__
nrLDPC_bnProc_BG2_R23_AVX512(bnProcBuf, bnProcBufRes,llrRes, Z);
#else
nrLDPC_bnProc_BG2_R23_AVX2(bnProcBuf, bnProcBufRes,llrRes, Z);
#endif
break;
}
}
}
#endif
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bnProc);
#endif
@@ -713,8 +310,14 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->bn2cnProcBuf);
#endif
if (BG == 1) nrLDPC_bn2cnProcBuf_BG1(p_lut, bnProcBufRes, cnProcBuf, Z);
else nrLDPC_bn2cnProcBuf_BG2(p_lut, bnProcBufRes, cnProcBuf, Z);
if (BG == 1)
{
nrLDPC_bn2cnProcBuf_BG1(p_lut, bnProcBufRes, cnProcBuf, Z);
}
else
{
nrLDPC_bn2cnProcBuf_BG2(p_lut, bnProcBufRes, cnProcBuf, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->bn2cnProcBuf);
#endif
@@ -723,44 +326,60 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, uint32_
nrLDPC_debug_writeBuffer2File(nrLDPC_buffers_CN_PROC, cnProcBuf);
#endif
// Parity Check
// Parity Check
#ifdef NR_LDPC_ENABLE_PARITY_CHECK
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->cnProcPc);
start_meas(&p_profiler->cnProcPc);
#endif
if (BG == 1) pcRes = nrLDPC_cnProcPc_BG1(p_lut, cnProcBuf, cnProcBufRes, Z);
else pcRes = nrLDPC_cnProcPc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
if (BG == 1)
{
pcRes = nrLDPC_cnProcPc_BG1(p_lut, cnProcBuf, cnProcBufRes, Z);
}
else
{
pcRes = nrLDPC_cnProcPc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->cnProcPc);
stop_meas(&p_profiler->cnProcPc);
#endif
#endif
} // end while
}
// If maximum number of iterations reached an PC still fails increase number of iterations
// Thus, i > numMaxIter indicates that PC has failed
#ifdef NR_LDPC_ENABLE_PARITY_CHECK
if (pcRes != 0)
{
i++;
}
#endif
// Last iteration
if (pcRes != 0) i++;
// Assign results from processing buffer to output
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->llrRes2llrOut);
start_meas(&p_profiler->llrRes2llrOut);
#endif
nrLDPC_llrRes2llrOut(p_lut, p_llrOut, llrRes, Z, BG);
nrLDPC_llrRes2llrOut(p_lut, p_llrOut, llrRes, Z, BG);
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->llrRes2llrOut);
stop_meas(&p_profiler->llrRes2llrOut);
#endif
// Hard-decision
#ifdef NR_LDPC_PROFILER_DETAIL
start_meas(&p_profiler->llr2bit);
start_meas(&p_profiler->llr2bit);
#endif
if (outMode == nrLDPC_outMode_BIT) nrLDPC_llr2bitPacked(p_out, p_llrOut, numLLR);
else //if (outMode == nrLDPC_outMode_BITINT8)
nrLDPC_llr2bit(p_out, p_llrOut, numLLR);
if (outMode == nrLDPC_outMode_BIT)
{
nrLDPC_llr2bitPacked(p_out, p_llrOut, numLLR);
}
else if (outMode == nrLDPC_outMode_BITINT8)
{
nrLDPC_llr2bit(p_out, p_llrOut, numLLR);
}
#ifdef NR_LDPC_PROFILER_DETAIL
stop_meas(&p_profiler->llr2bit);
#endif
return i;
}

View File

@@ -1,83 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*!\file nrLDPC_init_mem.h
* \brief Defines the function to initialize the LDPC decoder and sets correct LUTs.
* \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
* \date 07-12-2018
* \version 1.0
* \note
* \warning
*/
#ifndef __NR_LDPC_INIT_MEM__H__
#define __NR_LDPC_INIT_MEM__H__
#include <stdlib.h>
#include "nrLDPC_types.h"
/**
\brief Allocates 32 byte aligned memory and initializes to zero
\param size Input size in bytes
\return Pointer to memory
*/
static inline void* malloc32_clear(size_t size)
{
void* ptr = (void*) memalign(64, size+64);
memset(ptr, 0, size);
return ptr;
}
/**
\brief Allocates and initializes the internal decoder processing buffers
\param p_decParams Pointer to decoder parameters
\param p_lut Pointer to decoder LUTs
\return Number of LLR values
*/
static inline t_nrLDPC_procBuf* nrLDPC_init_mem(void)
{
t_nrLDPC_procBuf* p_procBuf = (t_nrLDPC_procBuf*) malloc32_clear(sizeof(t_nrLDPC_procBuf));
if (p_procBuf)
{
p_procBuf->cnProcBuf = (int8_t*) malloc32_clear(NR_LDPC_SIZE_CN_PROC_BUF*sizeof(int8_t));
p_procBuf->cnProcBufRes = (int8_t*) malloc32_clear(NR_LDPC_SIZE_CN_PROC_BUF*sizeof(int8_t));
p_procBuf->bnProcBuf = (int8_t*) malloc32_clear(NR_LDPC_SIZE_BN_PROC_BUF*sizeof(int8_t));
p_procBuf->bnProcBufRes = (int8_t*) malloc32_clear(NR_LDPC_SIZE_BN_PROC_BUF*sizeof(int8_t));
p_procBuf->llrRes = (int8_t*) malloc32_clear(NR_LDPC_MAX_NUM_LLR *sizeof(int8_t));
p_procBuf->llrProcBuf = (int8_t*) malloc32_clear(NR_LDPC_MAX_NUM_LLR *sizeof(int8_t));
}
return(p_procBuf);
}
static inline void nrLDPC_free_mem(t_nrLDPC_procBuf* p_procBuf)
{
free(p_procBuf->cnProcBuf);
free(p_procBuf->cnProcBufRes);
free(p_procBuf->bnProcBuf);
free(p_procBuf->bnProcBufRes);
free(p_procBuf->llrRes);
free(p_procBuf->llrProcBuf);
free(p_procBuf);
}
#endif

View File

@@ -21,16 +21,21 @@
/*!\file nrLDPC_mPass.h
* \brief Defines the functions for message passing
*
*/
* \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
* \date 30-09-2019
* \version 2.0
* \note
* \warning
*/
#ifndef __NR_LDPC_MPASS__H__
#define __NR_LDPC_MPASS__H__
#include <string.h>
#include "nrLDPCdecoder_defs.h"
//#include <omp.h>
/**
\brief Circular memcpy1
\brief Circular memcpy
|<- rem->|<- circular shift ->|
(src) str2 = |--------xxxxxxxxxxxxxxxxxxxxx|
\_______________
@@ -41,7 +46,6 @@
\param Z Lifting size
\param cshift Circular shift
*/
static inline void *nrLDPC_inv_circ_memcpy(int8_t *str1, const int8_t *str2, uint16_t Z, uint16_t cshift)
{
uint16_t rem = Z - cshift;
@@ -165,8 +169,6 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, in
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[0]*NR_LDPC_ZMAX;
for (j=0; j<3; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[0] + j*bitOffsetInGroup];
@@ -198,10 +200,8 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, in
// =====================================================================
// CN group with 5 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[2]*NR_LDPC_ZMAX;
for (j=0; j<5; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[2] + j*bitOffsetInGroup];
@@ -234,10 +234,8 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, in
// =====================================================================
// CN group with 7 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[4]*NR_LDPC_ZMAX;
for (j=0; j<7; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[4] + j*bitOffsetInGroup];
@@ -255,7 +253,6 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, in
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[5]*NR_LDPC_ZMAX;
for (j=0; j<8; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[5] + j*bitOffsetInGroup];
@@ -305,7 +302,6 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, in
// =====================================================================
// CN group with 19 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[8]*NR_LDPC_ZMAX;
for (j=0; j<19; j++)
@@ -1011,18 +1007,18 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
// CN group with 4 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[1]*NR_LDPC_ZMAX;
for (j=0; j<3; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[1] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[1]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG4[j][i] + lut_bnPosBnProcBuf_CNG4[j][i]*Z;
nrLDPC_circ_memcpy(p_cnProcBuf, &bnProcBufRes[idxBn], Z, lut_circShift_CNG4[j][i]);
p_cnProcBuf += Z;
}
}
}
// =====================================================================
// CN group with 5 BNs
@@ -1031,7 +1027,6 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
for (j=0; j<4; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[2] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[2]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG5[j][i] + lut_bnPosBnProcBuf_CNG5[j][i]*Z;
@@ -1044,11 +1039,10 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
// CN group with 6 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[3]*NR_LDPC_ZMAX;
for (j=0; j<5; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[3] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[3]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG6[j][i] + lut_bnPosBnProcBuf_CNG6[j][i]*Z;
@@ -1061,12 +1055,11 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
// CN group with 7 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[4]*NR_LDPC_ZMAX;
for (j=0; j<6; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[4] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[4]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG7[j][i] + lut_bnPosBnProcBuf_CNG7[j][i]*Z;
@@ -1099,7 +1092,6 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
for (j=0; j<8; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[6] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[6]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG9[j][i] + lut_bnPosBnProcBuf_CNG9[j][i]*Z;
@@ -1112,11 +1104,10 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
// CN group with 10 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[7]*NR_LDPC_ZMAX;
for (j=0; j<9; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[7] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[7]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG10[j][i] + lut_bnPosBnProcBuf_CNG10[j][i]*Z;
@@ -1129,11 +1120,10 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* bnProcBu
// CN group with 19 BNs
bitOffsetInGroup = lut_numCnInCnGroups_BG1_R13[8]*NR_LDPC_ZMAX;
for (j=0; j<19; j++)
{
p_cnProcBuf = &cnProcBuf[lut_startAddrCnGroups[8] + j*bitOffsetInGroup];
for (i=0; i<lut_numCnInCnGroups[8]; i++)
{
idxBn = lut_startAddrBnProcBuf_CNG19[j][i] + lut_bnPosBnProcBuf_CNG19[j][i]*Z;
@@ -1182,7 +1172,3 @@ static inline void nrLDPC_llrRes2llrOut(t_nrLDPC_lut* p_lut, int8_t* llrOut, int
}
#endif

View File

@@ -1,19 +0,0 @@
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_bnProc ldpc/generator_bnProc)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_bnProc_avx512 ldpc/generator_bnProc_avx512)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_cnProc ldpc/generator_cnProc)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_cnProc_avx512 ldpc/generator_cnProc_avx512)
# custom target to build all generators
add_custom_target(ldpc_generators)
add_dependencies(ldpc_generators
bnProc_gen_avx2
bnProc_gen_avx512
cnProc_gen_avx2
cnProc_gen_avx512)
add_library(ldpc_gen_HEADERS INTERFACE)
target_link_libraries(ldpc_gen_HEADERS INTERFACE
bnProc_gen_avx2_HEADERS
bnProc_gen_avx512_HEADERS
cnProc_gen_avx2_HEADERS
cnProc_gen_avx512_HEADERS)

View File

@@ -1,36 +0,0 @@
add_executable(bnProc_gen_avx2
bnProc_gen_BG1_avx2.c
bnProc_gen_BG2_avx2.c
bnProcPc_gen_BG1_avx2.c
bnProcPc_gen_BG2_avx2.c
main.c)
target_compile_options(bnProc_gen_avx2 PRIVATE -W -Wall -mavx2)
#set(bnProc_headers
# bnProc/nrLDPC_bnProc_BG1_R13_AVX2.h
# bnProc/nrLDPC_bnProc_BG1_R23_AVX2.h
# bnProc/nrLDPC_bnProc_BG1_R89_AVX2.h
# bnProc/rLDPC_bnProc_BG2_R13_AVX2.h
# bnProc/rLDPC_bnProc_BG2_R15_AVX2.h
# bnProc/rLDPC_bnProc_BG2_R23_AVX2.h)
#
#set(bnProcPc_headers
# bnProcPc/rLDPC_bnProcPc_BG1_R13_AVX2.h
# bnProcPc/rLDPC_bnProcPc_BG1_R23_AVX2.h
# bnProcPc/rLDPC_bnProcPc_BG1_R89_AVX2.h
# bnProcPc/rLDPC_bnProcPc_BG2_R13_AVX2.h
# bnProcPc/rLDPC_bnProcPc_BG2_R15_AVX2.h
# bnProcPc/rLDPC_bnProcPc_BG2_R23_AVX2.h)
add_custom_command(TARGET bnProc_gen_avx2 POST_BUILD
#OUTPUT ${bnProc_headers} ${bnProcPc_headers}
COMMAND ${CMAKE_COMMAND} -E make_directory bnProc
COMMAND ${CMAKE_COMMAND} -E make_directory bnProcPc
COMMAND bnProc_gen_avx2 .
DEPENDS bnProc_gen_avx2
COMMENT "Generating LDPC bnProc header files for AVX2"
)
add_library(bnProc_gen_avx2_HEADERS INTERFACE)
target_include_directories(bnProc_gen_avx2_HEADERS INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(bnProc_gen_avx2_HEADERS bnProc_gen_avx2)

View File

@@ -1,55 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#define NB_R 3
void nrLDPC_bnProc_BG1_generator_AVX2(const char*, int);
void nrLDPC_bnProc_BG2_generator_AVX2(const char*, int);
void nrLDPC_bnProcPc_BG1_generator_AVX2(const char*, int);
void nrLDPC_bnProcPc_BG2_generator_AVX2(const char*, int);
const char *__asan_default_options()
{
/* don't do leak checking in nr_ulsim, creates problems in the CI */
return "detect_leaks=0";
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <output-dir>\n", argv[0]);
return 1;
}
const char *dir = argv[1];
int R[NB_R]={0,1,2};
for(int i=0; i<NB_R;i++){
nrLDPC_bnProc_BG1_generator_AVX2(dir, R[i]);
nrLDPC_bnProc_BG2_generator_AVX2(dir, R[i]);
nrLDPC_bnProcPc_BG1_generator_AVX2(dir, R[i]);
nrLDPC_bnProcPc_BG2_generator_AVX2(dir, R[i]);
}
return(0);
}

View File

@@ -1,36 +0,0 @@
add_executable(bnProc_gen_avx512
bnProc_gen_BG1_avx512.c
bnProc_gen_BG2_avx512.c
bnProcPc_gen_BG1_avx512.c
bnProcPc_gen_BG2_avx512.c
main.c)
target_compile_options(bnProc_gen_avx512 PRIVATE -W -Wall -mavx2)
#set(bnProc_avx512_headers
# bnProc_avx512/rLDPC_bnProc_BG1_R13_AVX512.h
# bnProc_avx512/rLDPC_bnProc_BG1_R23_AVX512.h
# bnProc_avx512/rLDPC_bnProc_BG1_R89_AVX512.h
# bnProc_avx512/rLDPC_bnProc_BG2_R13_AVX512.h
# bnProc_avx512/rLDPC_bnProc_BG2_R15_AVX512.h
# bnProc_avx512/rLDPC_bnProc_BG2_R23_AVX512.h)
#
#set(bnProcPc_avx512_headers
# bnProcPc_avx512/rLDPC_bnProcPc_BG1_R13_AVX512.h
# bnProcPc_avx512/rLDPC_bnProcPc_BG1_R23_AVX512.h
# bnProcPc_avx512/rLDPC_bnProcPc_BG1_R89_AVX512.h
# bnProcPc_avx512/rLDPC_bnProcPc_BG2_R13_AVX512.h
# bnProcPc_avx512/rLDPC_bnProcPc_BG2_R15_AVX512.h
# bnProcPc_avx512/rLDPC_bnProcPc_BG2_R23_AVX512.h)
add_custom_command(TARGET bnProc_gen_avx512 POST_BUILD
#OUTPUT ${bnProc_avx512_headers} ${bnProcPc_avx512_headers}
COMMAND ${CMAKE_COMMAND} -E make_directory bnProc_avx512
COMMAND ${CMAKE_COMMAND} -E make_directory bnProcPc_avx512
COMMAND bnProc_gen_avx512 .
DEPENDS bnProc_gen_avx512
COMMENT "Generating LDPC bnProc header files for AVX512"
)
add_library(bnProc_gen_avx512_HEADERS INTERFACE)
target_include_directories(bnProc_gen_avx512_HEADERS INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(bnProc_gen_avx512_HEADERS bnProc_gen_avx512)

View File

@@ -1,56 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define NB_R 3
void nrLDPC_bnProc_BG1_generator_AVX512(const char *, int);
void nrLDPC_bnProc_BG2_generator_AVX512(const char *, int);
void nrLDPC_bnProcPc_BG1_generator_AVX512(const char *, int);
void nrLDPC_bnProcPc_BG2_generator_AVX512(const char *, int);
const char *__asan_default_options()
{
/* don't do leak checking in nr_ulsim, creates problems in the CI */
return "detect_leaks=0";
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <output-dir>\n", argv[0]);
return 1;
}
const char *dir = argv[1];
int R[NB_R]={0,1,2};
for(int i=0; i<NB_R;i++){
nrLDPC_bnProc_BG1_generator_AVX512(dir, R[i]);
nrLDPC_bnProc_BG2_generator_AVX512(dir, R[i]);
nrLDPC_bnProcPc_BG1_generator_AVX512(dir, R[i]);
nrLDPC_bnProcPc_BG2_generator_AVX512(dir, R[i]);
}
return(0);
}

View File

@@ -1,25 +0,0 @@
add_executable(cnProc_gen_avx2
cnProc_gen_BG1_avx2.c
cnProc_gen_BG2_avx2.c
main.c)
target_compile_options(cnProc_gen_avx2 PRIVATE -W -Wall -mavx2)
#set(cnProc_headers
# cnProc/rLDPC_cnProc_BG1_R13_AVX2.h
# cnProc/rLDPC_cnProc_BG1_R23_AVX2.h
# cnProc/rLDPC_cnProc_BG1_R89_AVX2.h
# cnProc/rLDPC_cnProc_BG2_R13_AVX2.h
# cnProc/rLDPC_cnProc_BG2_R15_AVX2.h
# cnProc/rLDPC_cnProc_BG2_R23_AVX2.h)
add_custom_command(TARGET cnProc_gen_avx2 POST_BUILD
#OUTPUT ${cnProc_headers}
COMMAND ${CMAKE_COMMAND} -E make_directory cnProc
COMMAND cnProc_gen_avx2 .
DEPENDS cnProc_gen_avx2
COMMENT "Generating LDPC cnProc header files for AVX2"
)
add_library(cnProc_gen_avx2_HEADERS INTERFACE)
target_include_directories(cnProc_gen_avx2_HEADERS INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(cnProc_gen_avx2_HEADERS cnProc_gen_avx2)

View File

@@ -1,693 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "../../nrLDPCdecoder_defs.h"
void nrLDPC_cnProc_BG1_generator_AVX2(const char* dir, int R)
{
const char *ratestr[3]={"13","23","89"};
if (R<0 || R>2) {printf("Illegal R %d\n",R); abort();}
// system("mkdir -p ../ldpc_gen_files");
char fname[FILENAME_MAX+1];
snprintf(fname, sizeof(fname), "%s/cnProc/nrLDPC_cnProc_BG1_R%s_AVX2.h", dir, ratestr[R]);
FILE *fd=fopen(fname,"w");
if (fd == NULL) {
printf("Cannot create file %s\n", fname);
abort();
}
fprintf(fd,"#include <stdint.h>\n");
fprintf(fd,"#include <immintrin.h>\n");
fprintf(fd,"static inline void nrLDPC_cnProc_BG1_R%s_AVX2(int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z) {\n",ratestr[R]);
const uint8_t* lut_numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = lut_startAddrCnGroups_BG1;
if (R==0) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R13;
else if (R==1) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R23;
else if (R==2) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R89;
else { printf("aborting, illegal R %d\n",R); fclose(fd);abort();}
//__m256i* p_cnProcBuf;
//__m256i* p_cnProcBufRes;
// Number of CNs in Groups
//uint32_t M;
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 32 Byte
uint32_t bitOffsetInGroup;
//__m256i ymm0, min, sgn;
//__m256i* p_cnProcBufResBit;
// const __m256i* p_ones = (__m256i*) ones256_epi8;
// const __m256i* p_maxLLR = (__m256i*) maxLLR256_epi8;
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup (1*384/32)
// const uint8_t lut_idxCnProcG3[3][2] = {{12,24}, {0,24}, {0,12}};
// =====================================================================
// Process group with 3 BNs
fprintf(fd,"//Process group with 3 BNs\n");
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup (1*384/32)
const uint8_t lut_idxCnProcG3[3][2] = {{12,24}, {0,24}, {0,12}};
fprintf(fd," __m256i ymm0, min, sgn,ones,maxLLR;\n");
fprintf(fd," ones = _mm256_set1_epi8((char)1);\n");
fprintf(fd," maxLLR = _mm256_set1_epi8((char)127);\n");
fprintf(fd," uint32_t M;\n");
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[0] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[0]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 3
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[0]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[0]];
// Loop over every BN
for (j=0; j<3; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>5)+lut_idxCnProcG3[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// 32 CNs of second BN
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][1] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>5)+lut_idxCnProcG3[j][1]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[0]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 4 BNs
fprintf(fd,"//Process group with 4 BNs\n");
// Offset is 5*384/32 = 60
const uint8_t lut_idxCnProcG4[4][3] = {{60,120,180}, {0,120,180}, {0,60,180}, {0,60,120}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[1] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[1]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 4
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<4; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>5)+lut_idxCnProcG4[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<3; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>5)+lut_idxCnProcG4[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[1]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 5 BNs
fprintf(fd,"//Process group with 5 BNs\n");
// Offset is 18*384/32 = 216
const uint16_t lut_idxCnProcG5[5][4] = {{216,432,648,864}, {0,432,648,864},
{0,216,648,864}, {0,216,432,864}, {0,216,432,648}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[2] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[2]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 4
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<5; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>5)+lut_idxCnProcG5[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<4; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>5)+lut_idxCnProcG5[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[2]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 6 BNs
fprintf(fd,"//Process group with 6 BNs\n");
// Offset is 8*384/32 = 96
const uint16_t lut_idxCnProcG6[6][5] = {{96,192,288,384,480}, {0,192,288,384,480},
{0,96,288,384,480}, {0,96,192,384,480},
{0,96,192,288,480}, {0,96,192,288,384}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[3] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[3]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 4
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<6; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>5)+lut_idxCnProcG6[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<5; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>5)+lut_idxCnProcG6[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[3]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 7 BNs
fprintf(fd,"//Process group with 7 BNs\n");
// Offset is 5*384/32 = 60
const uint16_t lut_idxCnProcG7[7][6] = {{60,120,180,240,300,360}, {0,120,180,240,300,360},
{0,60,180,240,300,360}, {0,60,120,240,300,360},
{0,60,120,180,300,360}, {0,60,120,180,240,360},
{0,60,120,180,240,300}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[4] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[4]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 4
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<7; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>5)+lut_idxCnProcG7[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<6; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>5)+lut_idxCnProcG7[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[4]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 8 BNs
fprintf(fd,"//Process group with 8 BNs\n");
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[5] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[5]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 4
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<8; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>5)+lut_idxCnProcG8[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<7; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>5)+lut_idxCnProcG8[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[5]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 9 BNs
fprintf(fd,"//Process group with 9 BNs\n");
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG9[9][8] = {{24,48,72,96,120,144,168,192}, {0,48,72,96,120,144,168,192},
{0,24,72,96,120,144,168,192}, {0,24,48,96,120,144,168,192},
{0,24,48,72,120,144,168,192}, {0,24,48,72,96,144,168,192},
{0,24,48,72,96,120,168,192}, {0,24,48,72,96,120,144,192},
{0,24,48,72,96,120,144,168}};
if (lut_numCnInCnGroups[6] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[6] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[6]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 9
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<9; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[6]>>5)+lut_idxCnProcG9[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<8; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[6]>>5)+lut_idxCnProcG9[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[6]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 10 BNs
fprintf(fd,"//Process group with 10 BNs\n");
// Offset is 1*384/32 = 12
const uint8_t lut_idxCnProcG10[10][9] = {{12,24,36,48,60,72,84,96,108}, {0,24,36,48,60,72,84,96,108},
{0,12,36,48,60,72,84,96,108}, {0,12,24,48,60,72,84,96,108},
{0,12,24,36,60,72,84,96,108}, {0,12,24,36,48,72,84,96,108},
{0,12,24,36,48,60,84,96,108}, {0,12,24,36,48,60,72,96,108},
{0,12,24,36,48,60,72,84,108}, {0,12,24,36,48,60,72,84,96}};
if (lut_numCnInCnGroups[7] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, " M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[7] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[7]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 10
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<10; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[7]>>5)+lut_idxCnProcG10[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<9; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[7]>>5)+lut_idxCnProcG10[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[7]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 19 BNs
fprintf(fd,"//Process group with 19 BNs\n");
// Offset is 4*384/32 = 12
const uint16_t lut_idxCnProcG19[19][18] = {{48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816}};
if (lut_numCnInCnGroups[8] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, " M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[8] );
// Set the offset to each bit within a group in terms of 32 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[8]*NR_LDPC_ZMAX)>>5;
// Set pointers to start of group 19
//p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[1]];
//p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[1]];
// Loop over every BN
for (j=0; j<19; j++)
{
// Set of results pointer to correct BN address
//p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup);
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[8]>>5)+lut_idxCnProcG19[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<18; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[8]>>5)+lut_idxCnProcG19[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[8]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
fprintf(fd,"}\n");
fclose(fd);
}//end of the function nrLDPC_cnProc_BG1

View File

@@ -1,436 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "../../nrLDPCdecoder_defs.h"
#include "../../nrLDPC_types.h"
#include "../../nrLDPC_bnProc.h"
void nrLDPC_cnProc_BG2_generator_AVX2(const char* dir, int R)
{
const char *ratestr[3]={"15","13","23"};
if (R<0 || R>2) {printf("Illegal R %d\n",R); abort();}
// system("mkdir -p ldpc_gen_files/avx2");
char fname[FILENAME_MAX+1];
snprintf(fname, sizeof(fname), "%s/cnProc/nrLDPC_cnProc_BG2_R%s_AVX2.h", dir, ratestr[R]);
FILE *fd=fopen(fname,"w");
if (fd == NULL) {
printf("Cannot create file %s\n", fname);
abort();
}
fprintf(fd,"#include <stdint.h>\n");
fprintf(fd,"#include <immintrin.h>\n");
fprintf(fd,"static inline void nrLDPC_cnProc_BG2_R%s_AVX2(int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z) {\n",ratestr[R]);
const uint8_t* lut_numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = lut_startAddrCnGroups_BG2;
if (R==0) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R15;
else if (R==1) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R13;
else if (R==2) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R23;
else { printf("aborting, illegal R %d\n",R); fclose(fd);abort();}
// Number of CNs in Groups
//uint32_t M;
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 32 byte
uint32_t bitOffsetInGroup;
// Offsets are in units of bitOffsetInGroup (1*384/32)
// const uint8_t lut_idxCnProcG3[3][2] = {{12,24}, {0,24}, {0,12}};
// =====================================================================
// Process group with 3 BNs
fprintf(fd,"//Process group with 3 BNs\n");
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup
const uint8_t lut_idxCnProcG3[3][2] = {{72,144}, {0,144}, {0,72}};
fprintf(fd," __m256i ymm0, min, sgn,ones,maxLLR;\n");
fprintf(fd," ones = _mm256_set1_epi8((char)1);\n");
fprintf(fd," maxLLR = _mm256_set1_epi8((char)127);\n");
fprintf(fd," uint32_t M;\n");
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[0] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[0]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<3; j++)
{
fprintf(fd," for (int i=0;i<M;i+=2) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>5)+lut_idxCnProcG3[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// 32 CNs of second BN
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][1] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>5)+lut_idxCnProcG3[j][1]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[0]>>5)+(j*bitOffsetInGroup));
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>5)+lut_idxCnProcG3[j][0]+1);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 4 BNs
fprintf(fd,"//Process group with 4 BNs\n");
// Offset is 20*384/32 = 240
const uint16_t lut_idxCnProcG4[4][3] = {{240,480,720}, {0,480,720}, {0,240,720}, {0,240,480}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[1] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[1]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<4; j++)
{
// Loop over CNs
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>5)+lut_idxCnProcG4[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<3; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>5)+lut_idxCnProcG4[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[1]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 5 BNs
fprintf(fd,"//Process group with 5 BNs\n");
// Offset is 9*384/32 = 108
const uint16_t lut_idxCnProcG5[5][4] = {{108,216,324,432}, {0,216,324,432},
{0,108,324,432}, {0,108,216,432}, {0,108,216,324}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd," M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[2] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[2]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<5; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>5)+lut_idxCnProcG5[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<4; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>5)+lut_idxCnProcG5[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[2]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 6 BNs
fprintf(fd,"//Process group with 6 BNs\n");
// Offset is 3*384/32 = 36
const uint16_t lut_idxCnProcG6[6][5] = {{36,72,108,144,180}, {0,72,108,144,180},
{0,36,108,144,180}, {0,36,72,144,180},
{0,36,72,108,180}, {0,36,72,108,144}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[3] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[3]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<6; j++)
{
// Loop over CNs
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>5)+lut_idxCnProcG6[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<5; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>5)+lut_idxCnProcG6[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[3]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 8 BNs
fprintf(fd,"//Process group with 8 BNs\n");
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[4] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[4]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<8; j++)
{
// Loop over CNs
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>5)+lut_idxCnProcG8[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<7; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>5)+lut_idxCnProcG8[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[4]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 10 BNs
fprintf(fd,"//Process group with 10 BNs\n");
const uint8_t lut_idxCnProcG10[10][9] = {{24,48,72,96,120,144,168,192,216}, {0,48,72,96,120,144,168,192,216},
{0,24,72,96,120,144,168,192,216}, {0,24,48,96,120,144,168,192,216},
{0,24,48,72,120,144,168,192,216}, {0,24,48,72,96,144,168,192,216},
{0,24,48,72,96,120,168,192,216}, {0,24,48,72,96,120,144,192,216},
{0,24,48,72,96,120,144,168,216}, {0,24,48,72,96,120,144,168,192}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 32 CNs for parallel processing
// Ceil for values not divisible by 32
fprintf(fd, "M = (%d*Z + 31)>>5;\n",lut_numCnInCnGroups[5] );
// Set the offset to each bit within a group in terms of 32 byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[5]*NR_LDPC_ZMAX)>>5;
// Loop over every BN
for (j=0; j<10; j++)
{
// Loop over CNs
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 32 CNs (first BN)
// ymm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>5)+lut_idxCnProcG10[j][0]);
// sgn = _mm256_sign_epi8(ones, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(ones, ymm0);\n");
// min = _mm256_abs_epi8(ymm0);
fprintf(fd," min = _mm256_abs_epi8(ymm0);\n");
// Loop over BNs
for (k=1; k<9; k++)
{
fprintf(fd," ymm0 = ((__m256i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>5)+lut_idxCnProcG10[j][k]);
// min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));
fprintf(fd," min = _mm256_min_epu8(min, _mm256_abs_epi8(ymm0));\n");
// sgn = _mm256_sign_epi8(sgn, ymm0);
fprintf(fd," sgn = _mm256_sign_epi8(sgn, ymm0);\n");
}
// Store result
// min = _mm256_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm256_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm256_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m256i*)cnProcBufRes)[%d+i] = _mm256_sign_epi8(min, sgn);\n",(lut_startAddrCnGroups[5]>>5)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
fprintf(fd,"}\n");
fclose(fd);
}//end of the function nrLDPC_cnProc_BG2

View File

@@ -1,50 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#define NB_R 3
void nrLDPC_cnProc_BG1_generator_AVX2(const char*, int);
void nrLDPC_cnProc_BG2_generator_AVX2(const char*, int);
const char *__asan_default_options()
{
/* don't do leak checking in nr_ulsim, creates problems in the CI */
return "detect_leaks=0";
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <output-dir>\n", argv[0]);
return 1;
}
const char *dir = argv[1];
int R[NB_R]={0,1,2};
for(int i=0; i<NB_R;i++) {
nrLDPC_cnProc_BG1_generator_AVX2(dir, R[i]);
nrLDPC_cnProc_BG2_generator_AVX2(dir, R[i]);
}
return(0);
}

View File

@@ -1,25 +0,0 @@
add_executable(cnProc_gen_avx512
cnProc_gen_BG1_avx512.c
cnProc_gen_BG2_avx512.c
main.c)
target_compile_options(cnProc_gen_avx512 PRIVATE -W -Wall -mavx2)
#set(cnProc_avx512_headers
# cnProc_avx512/nrLDPC_cnProc_BG1_R13_AVX512.h
# cnProc_avx512/nrLDPC_cnProc_BG1_R23_AVX512.h
# cnProc_avx512/nrLDPC_cnProc_BG1_R89_AVX512.h
# cnProc_avx512/nrLDPC_cnProc_BG2_R13_AVX512.h
# cnProc_avx512/nrLDPC_cnProc_BG2_R15_AVX512.h
# cnProc_avx512/nrLDPC_cnProc_BG2_R23_AVX512.h)
add_custom_command(TARGET cnProc_gen_avx512 POST_BUILD
#OUTPUT ${cnProc_avx512_headers}
COMMAND ${CMAKE_COMMAND} -E make_directory cnProc_avx512
COMMAND cnProc_gen_avx512 .
DEPENDS cnProc_gen_avx512
COMMENT "Generating LDPC cnProc header files for AVX512"
)
add_library(cnProc_gen_avx512_HEADERS INTERFACE)
target_include_directories(cnProc_gen_avx512_HEADERS INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(cnProc_gen_avx512_HEADERS cnProc_gen_avx512)

View File

@@ -1,597 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "../../nrLDPCdecoder_defs.h"
void nrLDPC_cnProc_BG1_generator_AVX512(const char *dir, int R)
{
const char *ratestr[3]={"13","23","89"};
if (R<0 || R>2) {printf("Illegal R %d\n",R); abort();}
// system("mkdir -p ../ldpc_gen_files");
char fname[FILENAME_MAX+1];
snprintf(fname, sizeof(fname), "%s/cnProc_avx512/nrLDPC_cnProc_BG1_R%s_AVX512.h", dir, ratestr[R]);
FILE *fd=fopen(fname,"w");
if (fd == NULL) {
printf("Cannot create file %s\n", fname);
abort();
}
// fprintf(fd,"#include <stdint.h>\n");
// fprintf(fd,"#include <immintrin.h>\n");
fprintf(fd, "#define conditional_negate(a,b,z) _mm512_mask_sub_epi8(a,_mm512_movepi8_mask(b),z,a)\n");
fprintf(fd,"static inline void nrLDPC_cnProc_BG1_R%s_AVX512(int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z) {\n",ratestr[R]);
const uint8_t* lut_numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = lut_startAddrCnGroups_BG1;
if (R==0) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R13;
else if (R==1) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R23;
else if (R==2) lut_numCnInCnGroups = lut_numCnInCnGroups_BG1_R89;
else { printf("aborting, illegal R %d\n",R); fclose(fd);abort();}
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 64 Byte
uint32_t bitOffsetInGroup;
fprintf(fd," uint32_t M, i;\n");
fprintf(fd," __m512i zmm0, min, sgn,zeros,maxLLR, ones;\n");
fprintf(fd," zeros = _mm512_setzero_si512();\n");
fprintf(fd," maxLLR = _mm512_set1_epi8((char)127);\n");
fprintf(fd," ones = _mm512_set1_epi8((char)1);\n");
// =====================================================================
// Process group with 3 BNs
fprintf(fd,"//Process group with 3 BNs\n");
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup (1*384/32)12
// Offsets are in units of bitOffsetInGroup (1*384/32)12
const uint8_t lut_idxCnProcG3[3][2] = {{12,24}, {0,24}, {0,12}};
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
//M = (lut_numCnInCnGroups[0]*Z + 63)>>6;
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[0] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[0]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<3; j++)
{
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>6)+lut_idxCnProcG3[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// for (k=1; k<2; k++)
//{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>6)+lut_idxCnProcG3[j][1]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
// }
// Store result
// min = _mm512_min_epu8(min, *maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm512_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[0]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 4 BNs
fprintf(fd,"//Process group with 4 BNs\n");
// Offset is 5*384/32 = 30
const uint8_t lut_idxCnProcG4[4][3] = {{60,120,180}, {0,120,180}, {0,60,180}, {0,60,120}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
//M = (lut_numCnInCnGroups[1]*Z + 63)>>6;
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[1] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[1]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<4; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>6)+lut_idxCnProcG4[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<3; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>6)+lut_idxCnProcG4[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm512_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[1]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 5 BNs
fprintf(fd,"//Process group with 5 BNs\n");
// Offset is 18*384/32 = 216
const uint16_t lut_idxCnProcG5[5][4] = {{216,432,648,864}, {0,432,648,864},
{0,216,648,864}, {0,216,432,864}, {0,216,432,648}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
//M = (lut_numCnInCnGroups[2]*Z + 63)>>6;
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[2] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[2]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<5; j++)
{
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>6)+lut_idxCnProcG5[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<4; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>6)+lut_idxCnProcG5[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[2]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 6 BNs
fprintf(fd,"//Process group with 6 BNs\n");
// Offset is 8*384/32 = 48
const uint16_t lut_idxCnProcG6[6][5] = {{96,192,288,384,480}, {0,192,288,384,480},
{0,96,288,384,480}, {0,96,192,384,480},
{0,96,192,288,480}, {0,96,192,288,384}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
//M = (lut_numCnInCnGroups[3]*Z + 63)>>6;
fprintf(fd, "M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[3] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[3]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<6; j++)
{
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>6)+lut_idxCnProcG6[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<5; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>6)+lut_idxCnProcG6[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[3]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 7 BNs
fprintf(fd,"//Process group with 7 BNs\n");
// Offset is 5*384/32 = 30
const uint16_t lut_idxCnProcG7[7][6] = {{60,120,180,240,300,360}, {0,120,180,240,300,360},
{0,60,180,240,300,360}, {0,60,120,240,300,360},
{0,60,120,180,300,360}, {0,60,120,180,240,360},
{0,60,120,180,240,300}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
// M = (lut_numCnInCnGroups[4]*Z + 63)>>6;
fprintf(fd, "M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[4] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[4]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<7; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0= ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>6)+lut_idxCnProcG7[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<6; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>6)+lut_idxCnProcG7[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[4]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 8 BNs
fprintf(fd,"//Process group with 8 BNs\n");
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
// M = (lut_numCnInCnGroups[5]*Z + 63)>>6;
fprintf(fd, "M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[5] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[5]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<8; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>6)+lut_idxCnProcG8[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<7; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>6)+lut_idxCnProcG8[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[5]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 9 BNs
fprintf(fd,"//Process group with 9 BNs\n");
// Offset is 2*384/32 = 12
const uint8_t lut_idxCnProcG9[9][8] = {{24,48,72,96,120,144,168,192}, {0,48,72,96,120,144,168,192},
{0,24,72,96,120,144,168,192}, {0,24,48,96,120,144,168,192},
{0,24,48,72,120,144,168,192}, {0,24,48,72,96,144,168,192},
{0,24,48,72,96,120,168,192}, {0,24,48,72,96,120,144,192},
{0,24,48,72,96,120,144,168}};
if (lut_numCnInCnGroups[6] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
// M = (lut_numCnInCnGroups[5]*Z + 63)>>6;
fprintf(fd, "M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[6] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[6]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<9; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[6]>>6)+lut_idxCnProcG9[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<8; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[6]>>6)+lut_idxCnProcG9[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[6]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 10 BNs
fprintf(fd,"//Process group with 10 BNs\n");
// Offset is 1*384/32 = 6
const uint8_t lut_idxCnProcG10[10][9] = {{12,24,36,48,60,72,84,96,108}, {0,24,36,48,60,72,84,96,108},
{0,12,36,48,60,72,84,96,108}, {0,12,24,48,60,72,84,96,108},
{0,12,24,36,60,72,84,96,108}, {0,12,24,36,48,72,84,96,108},
{0,12,24,36,48,60,84,96,108}, {0,12,24,36,48,60,72,96,108},
{0,12,24,36,48,60,72,84,108}, {0,12,24,36,48,60,72,84,96}};
if (lut_numCnInCnGroups[7] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
//M = (lut_numCnInCnGroups[7]*Z + 63)>>6;
fprintf(fd, " M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[7] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[7]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<10; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[7]>>6)+lut_idxCnProcG10[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<9; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[7]>>6)+lut_idxCnProcG10[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min,sgn,zeros);\n",(lut_startAddrCnGroups[7]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 19 BNs
fprintf(fd,"//Process group with 19 BNs\n");
// Offset is 4*384/32 = 24
const uint16_t lut_idxCnProcG19[19][18] = {{48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,192,240,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,240,288,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,288,336,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,336,384,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,384,432,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,432,480,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,480,528,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,528,576,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,576,624,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,624,672,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,672,720,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,720,768,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,768,816,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,816,864}, {0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,864},
{0,48,96,144,192,240,288,336,384,432,480,528,576,624,672,720,768,816}};
if (lut_numCnInCnGroups[8] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
// M = (lut_numCnInCnGroups[8]*Z + 63)>>6;
fprintf(fd, " M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[8] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG1_R13[8]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<19; j++)
{
// Loop over CNs
// for (i=0; i<M; i++,iprime++)
// {
fprintf(fd," for (i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[8]>>6)+lut_idxCnProcG19[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<18; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[8]>>6)+lut_idxCnProcG19[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[8]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
fprintf(fd,"}\n");
fclose(fd);
}//end of the function nrLDPC_cnProc_BG1

View File

@@ -1,414 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "../../nrLDPCdecoder_defs.h"
void nrLDPC_cnProc_BG2_generator_AVX512(const char *dir, int R)
{
const char *ratestr[3]={"15","13","23"};
if (R<0 || R>2) {printf("Illegal R %d\n",R); abort();}
// system("mkdir -p ../ldpc_gen_files");
char fname[FILENAME_MAX+1];
snprintf(fname, sizeof(fname), "%s/cnProc_avx512/nrLDPC_cnProc_BG2_R%s_AVX512.h", dir, ratestr[R]);
FILE *fd=fopen(fname,"w");
if (fd == NULL) {
printf("Cannot create file %s\n", fname);
abort();
}
//fprintf(fd,"#include <stdint.h>\n");
// fprintf(fd,"#include <immintrin.h>\n");
fprintf(fd, "#define conditional_negate(a,b,z) _mm512_mask_sub_epi8(a,_mm512_movepi8_mask(b),z,a)\n");
fprintf(fd,"static inline void nrLDPC_cnProc_BG2_R%s_AVX512(int8_t* cnProcBuf, int8_t* cnProcBufRes, uint16_t Z) {\n",ratestr[R]);
const uint8_t* lut_numCnInCnGroups;
const uint32_t* lut_startAddrCnGroups = lut_startAddrCnGroups_BG2;
if (R==0) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R15;
else if (R==1) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R13;
else if (R==2) lut_numCnInCnGroups = lut_numCnInCnGroups_BG2_R23;
else { printf("aborting, illegal R %d\n",R); fclose(fd);abort();}
// Number of CNs in Groups
//uint32_t M;
uint32_t j;
uint32_t k;
// Offset to each bit within a group in terms of 64 Byte
uint32_t bitOffsetInGroup;
fprintf(fd," uint32_t M;\n");
fprintf(fd," __m512i zmm0, min, sgn,zeros,ones,maxLLR;\n");
fprintf(fd," zeros = _mm512_setzero_si512();\n");
fprintf(fd," maxLLR = _mm512_set1_epi8((char)127);\n");
fprintf(fd," ones = _mm512_set1_epi8((char)1);\n");
// =====================================================================
// Process group with 3 BNs
fprintf(fd,"//Process group with 3 BNs\n");
// LUT with offsets for bits that need to be processed
// 1. bit proc requires LLRs of 2. and 3. bit, 2.bits of 1. and 3. etc.
// Offsets are in units of bitOffsetInGroup
const uint8_t lut_idxCnProcG3[3][2] = {{72,144}, {0,144}, {0,72}};
if (lut_numCnInCnGroups[0] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[0] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[0]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<3; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>6)+lut_idxCnProcG3[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// for (k=1; k<2; k++)
//{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[0]>>6)+lut_idxCnProcG3[j][1]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(*p_ones, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
// }
// Store result
// min = _mm512_min_epu8(min, *maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm512_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[0]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 4 BNs
fprintf(fd,"//Process group with 4 BNs\n");
// Offset is 20*384/32 = 240
const uint16_t lut_idxCnProcG4[4][3] = {{240,480,720}, {0,480,720}, {0,240,720}, {0,240,480}};
if (lut_numCnInCnGroups[1] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[1] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[1]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<4; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>6)+lut_idxCnProcG4[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<3; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[1]>>6)+lut_idxCnProcG4[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(sgn, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
// *p_cnProcBufResBit = _mm512_sign_epi8(min, sgn);
// p_cnProcBufResBit++;
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[1]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 5 BNs
fprintf(fd,"//Process group with 5 BNs\n");
// Offset is 9*384/32 = 108
const uint16_t lut_idxCnProcG5[5][4] = {{108,216,324,432}, {0,216,324,432},
{0,108,324,432}, {0,108,216,432}, {0,108,216,324}};
if (lut_numCnInCnGroups[2] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[2] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[2]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<5; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>6)+lut_idxCnProcG5[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<4; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[2]>>6)+lut_idxCnProcG5[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(sgn, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[2]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 6 BNs
fprintf(fd,"//Process group with 6 BNs\n");
// Offset is 3*384/32 = 36
const uint16_t lut_idxCnProcG6[6][5] = {{36,72,108,144,180}, {0,72,108,144,180},
{0,36,108,144,180}, {0,36,72,144,180},
{0,36,72,108,180}, {0,36,72,108,144}};
if (lut_numCnInCnGroups[3] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[3] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[3]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<6; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>6)+lut_idxCnProcG6[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<5; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[3]>>6)+lut_idxCnProcG6[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(sgn, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[3]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 8 BNs
fprintf(fd,"//Process group with 8 BNs\n");
// Offset is 2*384/32 = 24
const uint8_t lut_idxCnProcG8[8][7] = {{24,48,72,96,120,144,168}, {0,48,72,96,120,144,168},
{0,24,72,96,120,144,168}, {0,24,48,96,120,144,168},
{0,24,48,72,120,144,168}, {0,24,48,72,96,144,168},
{0,24,48,72,96,120,168}, {0,24,48,72,96,120,144}};
if (lut_numCnInCnGroups[4] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[4] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[4]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<8; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>6)+lut_idxCnProcG8[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<7; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[4]>>6)+lut_idxCnProcG8[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(sgn, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min, sgn,zeros);\n",(lut_startAddrCnGroups[4]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
// =====================================================================
// Process group with 10 BNs
fprintf(fd,"//Process group with 10 BNs\n");
const uint8_t lut_idxCnProcG10[10][9] = {{24,48,72,96,120,144,168,192,216}, {0,48,72,96,120,144,168,192,216},
{0,24,72,96,120,144,168,192,216}, {0,24,48,96,120,144,168,192,216},
{0,24,48,72,120,144,168,192,216}, {0,24,48,72,96,144,168,192,216},
{0,24,48,72,96,120,168,192,216}, {0,24,48,72,96,120,144,192,216},
{0,24,48,72,96,120,144,168,216}, {0,24,48,72,96,120,144,168,192}};
if (lut_numCnInCnGroups[5] > 0)
{
// Number of groups of 64 CNs for parallel processing
// Ceil for values not divisible by 64
fprintf(fd," M = (%d*Z + 63)>>6;\n",lut_numCnInCnGroups[5] );
// Set the offset to each bit within a group in terms of 64 Byte
bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[5]*NR_LDPC_ZMAX)>>6;
// Loop over every BN
for (j=0; j<10; j++)
{
fprintf(fd," for (int i=0;i<M;i++) {\n");
// Abs and sign of 64 CNs (first BN)
// zmm0 = p_cnProcBuf[lut_idxCnProcG3[j][0] + i];
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>6)+lut_idxCnProcG10[j][0]/2);
fprintf(fd," sgn = _mm512_xor_si512(ones, zmm0);\n");
fprintf(fd," min = _mm512_abs_epi8(zmm0);\n");
// Loop over BNs
for (k=1; k<9; k++)
{
fprintf(fd," zmm0 = ((__m512i*)cnProcBuf)[%d+i];\n",(lut_startAddrCnGroups[5]>>6)+lut_idxCnProcG10[j][k]/2);
// min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));
fprintf(fd," min = _mm512_min_epu8(min, _mm512_abs_epi8(zmm0));\n");
// sgn = _mm512_sign_epi8(sgn, zmm0);
fprintf(fd," sgn = _mm512_xor_si512(sgn, zmm0);\n");
}
// Store result
// min = _mm512_min_epu8(min, maxLLR); // 128 in epi8 is -127
fprintf(fd," min = _mm512_min_epu8(min, maxLLR);\n");
fprintf(fd," ((__m512i*)cnProcBufRes)[%d+i] = conditional_negate(min,sgn,zeros);\n",(lut_startAddrCnGroups[5]>>6)+(j*bitOffsetInGroup));
fprintf(fd," }\n");
}
}
fprintf(fd,"}\n");
fclose(fd);
}//end of the function nrLDPC_cnProc_BG2

View File

@@ -1,50 +0,0 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdint.h>
#define NB_R 3
void nrLDPC_cnProc_BG1_generator_AVX512(const char *, int);
void nrLDPC_cnProc_BG2_generator_AVX512(const char *, int);
const char *__asan_default_options()
{
/* don't do leak checking in nr_ulsim, creates problems in the CI */
return "detect_leaks=0";
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <output-dir>\n", argv[0]);
return 1;
}
const char *dir = argv[1];
int R[NB_R]={0,1,2};
for(int i=0; i<NB_R;i++){
nrLDPC_cnProc_BG1_generator_AVX512(dir, R[i]);
nrLDPC_cnProc_BG2_generator_AVX512(dir, R[i]);
}
return(0);
}

View File

@@ -1,11 +0,0 @@
#!/bin/bash
echo "to build the LDPC decoder headers: go to the build directory, and type"
echo "make/ninja ldpc_generators"
echo
echo "assuming your build directory is ran_build/build, I trigger building for"
echo "you now. The generated headers will be in ran_build/build/ldpc/generator_*/"
echo
cd $OPENAIR_HOME/cmake_targets/ran_build/build
make ldpc_generators || ninja ldpc_generators

View File

@@ -30,9 +30,8 @@
#ifndef __NR_LDPC_TYPES__H__
#define __NR_LDPC_TYPES__H__
#ifndef CODEGEN
#include "time_meas.h"
#endif
#include "nrLDPCdecoder_defs.h"
// ==============================================================================
// TYPES
@@ -78,7 +77,6 @@ typedef struct nrLDPC_dec_params {
/**
Structure containing LDPC decoder processing time statistics.
*/
#ifndef CODEGEN
typedef struct nrLDPC_time_stats {
time_stats_t llr2llrProcBuf; /**< Statistics for function llr2llrProcBuf */
time_stats_t llr2CnProcBuf; /**< Statistics for function llr2CnProcBuf */
@@ -92,7 +90,7 @@ typedef struct nrLDPC_time_stats {
time_stats_t llr2bit; /**< Statistics for function llr2bit */
time_stats_t total; /**< Statistics for total processing time */
} t_nrLDPC_time_stats;
#endif
/**
Structure containing the processing buffers
*/

View File

@@ -198,14 +198,4 @@ static const int8_t zeros256_epi8[32] __attribute__ ((aligned(32))) = {0,0,0,0,0
/** Vector of 32 '127' in int8 for application with AVX2 */
static const int8_t maxLLR256_epi8[32] __attribute__ ((aligned(32))) = {127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127};
/** Vector of 64 '1' in int8 for application with AVX512 */
static const int8_t ones512_epi8[64] __attribute__ ((aligned(64))) = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
/** Vector of 64 '0' in int8 for application with AVX512 */
static const int8_t zeros512_epi8[64] __attribute__ ((aligned(64))) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/** Vector of 64 '127' in int8 for application with AVX512 */
static const int8_t maxLLR512_epi8[64] __attribute__ ((aligned(64))) = {127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127};
#endif

View File

@@ -48,7 +48,7 @@ static int8_t m1_table[64*16*16*16] __attribute__ ((aligned(16)));
// Set up Viterbi tables for SSE2 implementation
void phy_generate_viterbi_tables_lte( void )
void phy_generate_viterbi_tables_lte()
{
int8_t w[8],in0,in1,in2;

View File

@@ -73,6 +73,7 @@ void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) {
init_unscrambling_lut();
init_scrambling_lut();
//set_taus_seed(1328);
init_sss();
}
void free_lte_top(void) {

View File

@@ -33,6 +33,7 @@
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
#include "PHY/LTE_TRANSPORT/transport_common_proto.h"
#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "nfapi/oai_integration/vendor_ext.h"
void init_7_5KHz(void);
@@ -606,6 +607,17 @@ void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH *const pdsch, const LTE_DL_FRAME_PARMS
}
}
int phy_config_SL(int Mod_id,SLDCH_t *sldch_rx,SLSCH_t *slsch_rx) {
PHY_VARS_UE *ue=PHY_vars_UE_g[Mod_id][0];
memcpy((void*)&ue->sldch_rx,(void*)sldch_rx,sizeof(SLDCH_t));
memcpy((void*)&ue->slsch_rx,(void*)slsch_rx,sizeof(SLSCH_t));
ue->slsch_active = 1;
return(0);
}
int init_lte_ue_signal(PHY_VARS_UE *ue,
int nb_connected_eNB,
uint8_t abstraction_flag) {
@@ -628,10 +640,9 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
crcTableInit();
load_dftslib();
init_frame_parms(&ue->frame_parms,1);
init_7_5KHz();
lte_sync_time_init(&ue->frame_parms);
init_lte_top(&ue->frame_parms);
init_sss();
init_7_5KHz();
init_ul_hopping(&ue->frame_parms);
// many memory allocation sizes are hard coded
AssertFatal( fp->nb_antennas_rx <= 2, "hard coded allocation for ue_common_vars->dl_ch_estimates[eNB_id]" );
@@ -666,15 +677,24 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
}
// init RX buffers
common_vars->rxdata = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
common_vars->common_vars_rx_data_per_thread[0].rxdataF = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
common_vars->common_vars_rx_data_per_thread[1].rxdataF = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
for (i=0; i<fp->nb_antennas_rx; i++) {
common_vars->rxdata[i] = (int32_t *) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) );
int nb_rx = (ue->sidelink_active == 1 && ue->SLonly == 0) ? 2*fp->nb_antennas_rx : fp->nb_antennas_rx;
common_vars->rxdata = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
common_vars->common_vars_rx_data_per_thread[0].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
common_vars->common_vars_rx_data_per_thread[1].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
if (ue->sidelink_active == 1) common_vars->rxdata_syncSL = (int16_t**)malloc16( fp->nb_antennas_rx*sizeof(int16_t*) );
for (i=0; i<nb_rx; i++) {
common_vars->rxdata[i] = (int32_t*) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) );
LOG_I(PHY,"common_vars->rxdata[%d] %p\n",i,common_vars->rxdata[i]);
common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
}
for (i=0; i<fp->nb_antennas_rx; i++) {
common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
if (ue->sidelink_active == 1) common_vars->rxdata_syncSL[i] = (int16_t*)malloc16_clear(((40*fp->samples_per_tti)+2048)*2*sizeof(int16_t));
}
// Channel estimates
@@ -713,6 +733,8 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
prach_vars[eNB_id] = (LTE_UE_PRACH *)malloc16_clear(sizeof(LTE_UE_PRACH));
pbch_vars[eNB_id] = (LTE_UE_PBCH *)malloc16_clear(sizeof(LTE_UE_PBCH));
ue->pscch_vars_tx = (LTE_UE_PSCCH_TX *)malloc16_clear(sizeof(LTE_UE_PSCCH_TX));
ue->pscch_vars_rx = (LTE_UE_PSCCH_RX *)malloc16_clear(sizeof(LTE_UE_PSCCH_RX));
for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
phy_init_lte_ue__PDSCH( (*pdsch_vars_th)[th_id][eNB_id], fp );
phy_init_lte_ue__PDSCH( (*pdsch_vars_MCH_th)[th_id][eNB_id], fp );
@@ -919,6 +941,74 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
ue->decode_MIB = 1;
ue->decode_SIB = 1;
init_prach_tables(839);
ue->pusch_slcch = (LTE_eNB_PUSCH*)malloc(sizeof(LTE_eNB_PUSCH));
ue->pusch_slcch->rxdataF_ext = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slcch->drs_ch_estimates = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slcch->rxdataF_comp = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slcch->ul_ch_mag = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slsch = (LTE_eNB_PUSCH*)malloc(sizeof(LTE_eNB_PUSCH));
ue->pusch_slsch->rxdataF_ext = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slsch->drs_ch_estimates = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slsch->rxdataF_comp = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slsch->ul_ch_mag = (int32_t **)malloc(2*sizeof(int32_t*));
for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
ue->pusch_sldch[th_id] = (LTE_eNB_PUSCH*)malloc(sizeof(LTE_eNB_PUSCH));
ue->pusch_sldch[th_id]->rxdataF_ext = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_sldch[th_id]->drs_ch_estimates = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_sldch[th_id]->rxdataF_comp = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_sldch[th_id]->ul_ch_mag = (int32_t **)malloc(2*sizeof(int32_t*));
ue->sl_rxdata_7_5kHz[th_id] = (int16_t **)malloc(2*sizeof(int32_t*));
ue->sl_rxdataF[th_id] = (int16_t **)malloc(2*sizeof(int32_t*));
for (int aa=0;aa<ue->frame_parms.nb_antennas_rx;aa++) {
ue->sl_rxdataF[th_id][aa] = (int16_t*)malloc16_clear(ue->frame_parms.ofdm_symbol_size*14*sizeof(int32_t));
ue->sl_rxdata_7_5kHz[th_id][aa] = (int16_t*)malloc16_clear(ue->frame_parms.samples_per_tti*sizeof(int32_t));
ue->pusch_sldch[th_id]->rxdataF_ext[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_sldch[th_id]->drs_ch_estimates[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_sldch[th_id]->rxdataF_comp[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_sldch[th_id]->ul_ch_mag[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
}
ue->sldch_dlsch_llr[th_id] = (int16_t *)malloc(2*2*12*1200*sizeof(int16_t*));
ue->sldch_ulsch_llr[th_id] = (int16_t *)malloc(2*2*12*1200*sizeof(int16_t*));
}
ue->pusch_slbch = (LTE_eNB_PUSCH*)malloc(sizeof(LTE_eNB_PUSCH));
ue->pusch_slbch->rxdataF_ext = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slbch->drs_ch_estimates = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slbch->rxdataF_comp = (int32_t **)malloc(2*sizeof(int32_t*));
ue->pusch_slbch->ul_ch_mag = (int32_t **)malloc(2*sizeof(int32_t*));
for (int aa=0;aa<ue->frame_parms.nb_antennas_rx;aa++) {
ue->pusch_slcch->rxdataF_ext[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slcch->drs_ch_estimates[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slcch->rxdataF_comp[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slcch->ul_ch_mag[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slsch->rxdataF_ext[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slsch->drs_ch_estimates[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slsch->rxdataF_comp[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slsch->ul_ch_mag[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slbch->rxdataF_ext[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slbch->drs_ch_estimates[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slbch->rxdataF_comp[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
ue->pusch_slbch->ul_ch_mag[aa] = (int32_t*)malloc16_clear(ue->frame_parms.N_RB_DL*12*14*sizeof(int32_t));
}
ue->slsch_dlsch_llr = (int16_t *)malloc(2*6*12*1200*sizeof(int16_t*));
ue->slsch_ulsch_llr = (int16_t *)malloc(2*6*12*1200*sizeof(int16_t*));
return 0;
}
@@ -939,6 +1029,311 @@ void init_lte_ue_transport(PHY_VARS_UE *ue,int abstraction_flag) {
ue->transmission_mode[i] = ue->frame_parms.nb_antenna_ports_eNB==1 ? 1 : 2;
}
for (int i=0;i<MAX_SLDCH;i++) ue->dlsch_rx_sldch[i] = new_ue_dlsch(1,4,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag);
ue->dlsch_sldch = new_eNB_dlsch(1,1,NSOFT,ue->frame_parms.N_RB_DL, abstraction_flag,&ue->frame_parms);
ue->ulsch_sldch = new_ue_ulsch(ue->frame_parms.N_RB_DL, abstraction_flag);
//***/ Substituted the next line with the double for loop as harq_ids is a 2-dimension array now
//for (i=0;i<10;i++) ue->dlsch_sldch->harq_ids[i] = 0;
//LTE_eNB_DLSCH_t *dlsch_sldch_tmp = &ue->dlsch_sldch;
for (i=0; i<20; i++)
ue->dlsch_sldch->harq_ids[i/10][i%10] = 0;
ue->dlsch_rx_slsch = new_ue_dlsch(1,4,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag);
ue->dlsch_slsch = new_eNB_dlsch(1,1,NSOFT,ue->frame_parms.N_RB_DL, abstraction_flag,&ue->frame_parms);
ue->ulsch_slsch = new_ue_ulsch(ue->frame_parms.N_RB_DL, abstraction_flag);
//Panos: Substituted the next line with the double for loop as harq_ids is a 2-dimension array now
//for (i=0;i<10;i++) ue->dlsch_slsch->harq_ids[i] = 0;
//LTE_eNB_DLSCH_t *dlsch_slsch_tmp = &ue->dlsch_slsch;
for (i=0; i<20; i++)
ue->dlsch_slsch->harq_ids[i/10][i%10] = 0;
ue->slsch_txcnt = 0;
ue->slsch_errors = 0;
for (int i=0;i<4;i++) ue->slsch_rxcnt[i] = 0;
ue->frame_parms.pucch_config_common.deltaPUCCH_Shift = 1;
ue->dlsch_MCH[0] = new_ue_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,MAX_TURBO_ITERATIONS_MBSFN,ue->frame_parms.N_RB_DL,0);
}
void free_ue_resources(PHY_VARS_UE *ue) {
LTE_DL_FRAME_PARMS *fp = &ue->frame_parms;
LTE_UE_COMMON* const common_vars = &ue->common_vars;
LTE_UE_PDSCH** const pdsch_vars_SI = ue->pdsch_vars_SI;
LTE_UE_PDSCH** const pdsch_vars_ra = ue->pdsch_vars_ra;
LTE_UE_PDSCH** const pdsch_vars_p = ue->pdsch_vars_p;
LTE_UE_PDSCH** const pdsch_vars_mch = ue->pdsch_vars_MCH;
LTE_UE_PDSCH* (*pdsch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX+1] = &ue->pdsch_vars;
LTE_UE_PDCCH* (*pdcch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX] = &ue->pdcch_vars;
LTE_UE_PBCH** const pbch_vars = ue->pbch_vars;
LTE_UE_PRACH** const prach_vars = ue->prach_vars;
for (int i=0; i<fp->nb_antennas_tx; i++) {
free(common_vars->txdata[i]);
free(common_vars->txdataF[i]);
}
free(common_vars->txdata);
free(common_vars->txdataF);
// init RX buffers
for (int i=0; i<fp->nb_antennas_rx; i++) {
free(common_vars->rxdata[i]);
free(common_vars->common_vars_rx_data_per_thread[0].rxdataF[i]);
free(common_vars->common_vars_rx_data_per_thread[1].rxdataF[i]);
if (ue->sidelink_active == 1) free(common_vars->rxdata_syncSL[i]);
}
free(common_vars->rxdata);
free(common_vars->common_vars_rx_data_per_thread[0].rxdataF);
free(common_vars->common_vars_rx_data_per_thread[1].rxdataF);
if (ue->sidelink_active==1) free(common_vars->rxdata_syncSL);
int eNB_id;
// Channel estimates
for (eNB_id=0; eNB_id<7; eNB_id++) {
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free(common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id]);
free(common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id]);
}
for (int i=0; i<fp->nb_antennas_rx; i++)
for (int j=0; j<4; j++) {
int idx = (j<<1) + i;
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free(common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id][idx]);
free(common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id][idx]);
}
}
}
// DLSCH
for (eNB_id=0; eNB_id<ue->n_connected_eNB; eNB_id++) {
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]);
}
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]);
}
free(pdsch_vars_SI[eNB_id]);
free(pdsch_vars_ra[eNB_id]);
free(pdsch_vars_p[eNB_id]);
free(pdsch_vars_mch[eNB_id]);
free(prach_vars[eNB_id]);
free(pbch_vars[eNB_id]);
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
free(ue->pscch_vars_tx);
free(ue->pscch_vars_rx);
#endif
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->llr_shifts);
free((*pdsch_vars_th)[th_id][eNB_id]->llr_shifts_p);
free((*pdsch_vars_th)[th_id][eNB_id]->llr[1]);
free((*pdsch_vars_th)[th_id][eNB_id]->llr128_2ndstream);
free((*pdsch_vars_th)[th_id][eNB_id]->rho);
}
for (int i=0; i<fp->nb_antennas_rx; i++){
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->rho[i]);
}
}
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho2_ext);
}
for (int i=0; i<fp->nb_antennas_rx; i++)
for (int j=0; j<4; j++) {
const int idx = (j<<1)+i;
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho2_ext[idx]);
}
}
//const size_t num = 7*2*fp->N_RB_DL*12+4;
for (int k=0;k<8;k++) { //harq_pid
for (int l=0;l<8;l++) { //round
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->rxdataF_comp1[k][l]);
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l]);
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l]);
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l]);
}
for (int i=0; i<fp->nb_antennas_rx; i++)
for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++)
const int idx = (j<<1)+i;
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l][idx]);
free((*pdsch_vars_th)[th_id][eNB_id]->rxdataF_comp1[k][l][idx]);
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l][idx]);
free((*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l][idx]);
}
}
}
}
// 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->llr);
free((*pdcch_vars_th)[th_id][eNB_id]->llr16);
free((*pdcch_vars_th)[th_id][eNB_id]->wbar);
free((*pdcch_vars_th)[th_id][eNB_id]->e_rx);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext);
free((*pdcch_vars_th)[th_id][eNB_id]->rho);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext);
}
for (int i=0; i<fp->nb_antennas_rx; i++) {
//ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) );
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->rho[i]);
}
for (int j=0; j<4; j++) { //fp->nb_antennas_tx; j++)
int idx = (j<<1)+i;
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx]);
}
}
}
// 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->llr);
free((*pdcch_vars_th)[th_id][eNB_id]->llr16);
free((*pdcch_vars_th)[th_id][eNB_id]->wbar);
free((*pdcch_vars_th)[th_id][eNB_id]->e_rx);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext);
free((*pdcch_vars_th)[th_id][eNB_id]->rho);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext);
}
for (int i=0; i<fp->nb_antennas_rx; i++) {
//ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) );
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->rho[i]);
}
for (int j=0; j<4; j++) { //fp->nb_antennas_tx; j++)
int idx = (j<<1)+i;
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx]);
free((*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx]);
}
}
}
// PBCH
free(pbch_vars[eNB_id]->rxdataF_ext);
free(pbch_vars[eNB_id]->rxdataF_comp);
free(pbch_vars[eNB_id]->dl_ch_estimates_ext);
free(pbch_vars[eNB_id]->llr);
free(prach_vars[eNB_id]->prachF);
free(prach_vars[eNB_id]->prach);
for (int i=0; i<fp->nb_antennas_rx; i++) {
free(pbch_vars[eNB_id]->rxdataF_ext[i]);
for (int j=0; j<4; j++) {//fp->nb_antennas_tx;j++) {
int idx = (j<<1)+i;
free(pbch_vars[eNB_id]->rxdataF_comp[idx]);
free(pbch_vars[eNB_id]->dl_ch_estimates_ext[idx]);
}
}
free(pbch_vars[eNB_id]->decoded_output);
}
// initialization for the last instance of pdsch_vars (used for MU-MIMO)
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]);
}
free(pdsch_vars_SI[eNB_id]);
free(pdsch_vars_ra[eNB_id]);
free(pdsch_vars_p[eNB_id]);
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free((*pdsch_vars_th)[th_id][eNB_id]->llr[1]);
}
free(ue->sinr_CQI_dB);
if (ue->sidelink_active == 1) {
for (int aa=0;aa<ue->frame_parms.nb_antennas_rx;aa++) {
free(ue->sl_rxdataF[aa]);
free(ue->sl_rxdata_7_5kHz[aa]);
free(ue->pusch_slcch->rxdataF_ext[aa]);
free(ue->pusch_slcch->drs_ch_estimates[aa]);
free(ue->pusch_slcch->rxdataF_comp[aa]);
free(ue->pusch_slcch->ul_ch_mag[aa]);
free(ue->pusch_slsch->rxdataF_ext[aa]);
free(ue->pusch_slsch->drs_ch_estimates[aa]);
free(ue->pusch_slsch->rxdataF_comp[aa]);
free(ue->pusch_slsch->ul_ch_mag[aa]);
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free(ue->sl_rxdataF[th_id][aa]);
free(ue->sl_rxdata_7_5kHz[th_id][aa]);
free(ue->pusch_sldch[th_id]->rxdataF_ext[aa]);
free(ue->pusch_sldch[th_id]->drs_ch_estimates[aa]);
free(ue->pusch_sldch[th_id]->rxdataF_comp[aa]);
free(ue->pusch_sldch[th_id]->ul_ch_mag[aa]);
}
}
}
if (ue->sidelink_active == 1) {
free(ue->sl_rxdataF);
free(ue->sl_rxdata_7_5kHz);
free(ue->pusch_slcch->rxdataF_ext);
free(ue->pusch_slcch->drs_ch_estimates);
free(ue->pusch_slcch->rxdataF_comp);
free(ue->pusch_slcch->ul_ch_mag);
free(ue->pusch_slsch->rxdataF_ext);
free(ue->pusch_slsch->drs_ch_estimates);
free(ue->pusch_slsch->rxdataF_comp);
free(ue->pusch_slsch->ul_ch_mag);
for (int th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
free(ue->pusch_sldch[th_id]->rxdataF_ext);
free(ue->pusch_sldch[th_id]->drs_ch_estimates);
free(ue->pusch_sldch[th_id]->rxdataF_comp);
free(ue->pusch_sldch[th_id]->ul_ch_mag);
free(ue->sldch_dlsch_llr[th_id]);
free(ue->sldch_ulsch_llr[th_id]);
}
free(ue->slsch_dlsch_llr);
free(ue->slsch_ulsch_llr);
}
}

View File

@@ -56,7 +56,10 @@ void lte_param_init(PHY_VARS_eNB **eNBp,
uint8_t pa,
uint8_t threequarter_fs,
uint8_t osf,
uint32_t perfect_ce) {
uint32_t perfect_ce,
uint8_t sidelink_active,
uint8_t SLonly) {
LTE_DL_FRAME_PARMS *frame_parms;
int i;
PHY_VARS_eNB *eNB;
@@ -119,6 +122,8 @@ void lte_param_init(PHY_VARS_eNB **eNBp,
for (i=0; i<3; i++)
lte_gold(frame_parms,UE->lte_gold_table[i],Nid_cell+i);
UE->sidelink_active = sidelink_active;
UE->SLonly = SLonly;
printf("Calling init_lte_ue_signal\n");
init_lte_ue_signal(UE,1,0);

View File

@@ -60,7 +60,7 @@ int nr_phy_init_RU(RU_t *ru) {
for (i=0; i<ru->nb_tx; i++) {
// Allocate 10 subframes of I/Q TX signal data (time) if not
ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t));
ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension +fp->samples_per_frame) *sizeof(int32_t));
LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",i,ru->common.txdata[i],
(ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t),ru->sf_extension);
ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension];

View File

@@ -344,6 +344,15 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *phy_vars_eNB);
*/
int phy_init_secsys_eNB(PHY_VARS_eNB *phy_vars_eNb);
/*!
\fn void phy_config_SL(int Mod_id,SLDCH_t *sldch_rx,SLSCH_t *slsch_rx)
\brief Configure PHY Sidelink parameters .
@param Mod_id
@param sldch_rx Sidelink discovery channel configuration
@param slsch_rx Sidelink Control/Shared channel configuration
*/
int phy_config_SL(int Mod_id,SLDCH_t *sldch_rx,SLSCH_t *slsch_rx);
void free_lte_top(void);
void init_lte_top(LTE_DL_FRAME_PARMS *lte_frame_parms);
@@ -366,7 +375,9 @@ void lte_param_init(PHY_VARS_eNB **eNBp,
uint8_t pa,
uint8_t threequarter_fs,
uint8_t osf,
uint32_t perfect_ce);
uint32_t perfect_ce,
uint8_t sidelink_active,
uint8_t SLonly);
void phy_config_dedicated_scell_ue(uint8_t Mod_id,

View File

@@ -20,11 +20,11 @@
*/
#include "PHY/defs_eNB.h"
#include "PHY/phy_extern.h"
#include "PHY/sse_intrin.h"
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
// This is 4096/(1:4096) in __m128i format
__m128i inv_ch[4096];/* = {512,512,512,512,512,512,512,512,
// This is 512/(1:256) in __m128i format
int16_t inv_ch[256*8] = {512,512,512,512,512,512,512,512,
256,256,256,256,256,256,256,256,
170,170,170,170,170,170,170,170,
128,128,128,128,128,128,128,128,
@@ -280,11 +280,7 @@ __m128i inv_ch[4096];/* = {512,512,512,512,512,512,512,512,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
};*/
void init_fde() {
for (int i=1;i<4096;i++) inv_ch[i] = _mm_set1_epi16(4096/i);
}
};
void freq_equalization(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
@@ -300,12 +296,12 @@ void freq_equalization(LTE_DL_FRAME_PARMS *frame_parms,
__m128i *ul_ch_mag128,*ul_ch_magb128,*rxdataF_comp128;
rxdataF_comp128 = (__m128i *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (__m128i *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (__m128i *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (Qm == 6) ? (__m128i *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12] : NULL;
#elif defined(__arm__)
int16x8_t *ul_ch_mag128,*ul_ch_magb128,*rxdataF_comp128;
rxdataF_comp128 = (int16x8_t*)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (int16x8_t*)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (int16x8_t*)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (Qm == 6) ? (int16x8_t*)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12] : NULL;
#endif
AssertFatal(symbol<frame_parms->symbols_per_tti,"symbol %d >= %d\n",
@@ -317,25 +313,25 @@ void freq_equalization(LTE_DL_FRAME_PARMS *frame_parms,
amp=(*((int16_t*)&ul_ch_mag128[re]));
if (amp>4095)
amp=4095;
if (amp>255)
amp=255;
//printf("freq_eq: symbol %d re %d => mag %d,amp %d,inv %d, prod %d (%d,%d)\n",symbol,re,*((int16_t*)(&ul_ch_mag128[re])),amp,_mm_extract_epi16(inv_ch[amp],0),(*((int16_t*)(&ul_ch_mag128[re]))*_mm_extract_epi16(inv_ch[amp],0))>>3,*(int16_t*)&(rxdataF_comp128[re]),*(1+(int16_t*)&(rxdataF_comp128[re])));
// printf("freq_eq: symbol %d re %d => %d,%d,%d, (%d) (%d,%d) => ",symbol,re,*((int16_t*)(&ul_ch_mag128[re])),amp,inv_ch[8*amp],*((int16_t*)(&ul_ch_mag128[re]))*inv_ch[8*amp],*(int16_t*)&(rxdataF_comp128[re]),*(1+(int16_t*)&(rxdataF_comp128[re])));
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128[re] = _mm_srai_epi16(_mm_mullo_epi16(rxdataF_comp128[re],inv_ch[amp]),3);
rxdataF_comp128[re] = _mm_mullo_epi16(rxdataF_comp128[re],*((__m128i *)&inv_ch[8*amp]));
if (Qm==4)
ul_ch_mag128[re] = _mm_set1_epi16(324); // this is 512*2/sqrt(10)
else {
else if (Qm==6) {
ul_ch_mag128[re] = _mm_set1_epi16(316); // this is 512*4/sqrt(42)
ul_ch_magb128[re] = _mm_set1_epi16(158); // this is 512*2/sqrt(42)
}
#elif defined(__arm__)
rxdataF_comp128[re] = vmulq_s16(rxdataF_comp128[re],inv_ch[amp]);
rxdataF_comp128[re] = vmulq_s16(rxdataF_comp128[re],*((int16x8_t *)&inv_ch[8*amp]));
if (Qm==4)
ul_ch_mag128[re] = vdupq_n_s16(324); // this is 512*2/sqrt(10)
else {
else if (Qm==6){
ul_ch_mag128[re] = vdupq_n_s16(316); // this is 512*4/sqrt(42)
ul_ch_magb128[re] = vdupq_n_s16(158); // this is 512*2/sqrt(42)
}

View File

@@ -21,6 +21,7 @@
#include "PHY/types.h"
#include "PHY/defs_eNB.h"
#include "PHY/phy_extern.h"
#include "common/utils/LOG/vcd_signal_dumper.h"

View File

@@ -64,6 +64,10 @@ int lte_sync_time(int **rxdata,
LTE_DL_FRAME_PARMS *frame_parms,
int *eNB_id);
int lte_sync_timeSL(PHY_VARS_UE *ue,
int *ind,
int64_t *lev,
int64_t *avg);
/*!
\brief This function performs the coarse frequency and PSS synchronization.
The algorithm uses a frequency-domain correlation. It scans over 20 MHz/10ms signal chunks using each of the 3 PSS finding the most likely (strongest) carriers and their frequency offset (+-2.5 kHz).
@@ -230,6 +234,8 @@ int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t l,
uint8_t Ns);
int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **ul_ch_estimates,
int32_t **ul_ch_estimates_time,

View File

@@ -30,175 +30,392 @@
#include "PHY/defs_UE.h"
#include "PHY/phy_extern_ue.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "PHY/MODULATION/modulation_extern.h"
#include "LAYER2/MAC/mac.h"
#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface.h"
// Note: this is for prototype of generate_drs_pusch (OTA synchronization of RRUs)
#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
static c16_t *primary_synch0_time __attribute__((aligned(32)));
static c16_t *primary_synch1_time __attribute__((aligned(32)));
static c16_t *primary_synch2_time __attribute__((aligned(32)));
static struct complex16 *primary_synch0_time __attribute__((aligned(32)));
static struct complex16 *primary_synch1_time __attribute__((aligned(32)));
static struct complex16 *primary_synch2_time __attribute__((aligned(32)));
static void doIdft(int size, short *in, short *out) {
switch (size) {
static void doIdft(int size, short *in, short *out)
{
switch (size)
{
case 6:
idft(IDFT_128,in,out,1);
idft(IDFT_128, in, out, 1);
break;
case 25:
idft(IDFT_512,in,out,1);
idft(IDFT_512, in, out, 1);
break;
case 50:
idft(IDFT_1024,in,out,1);
idft(IDFT_1024, in, out, 1);
break;
case 75:
idft(IDFT_1536,in,out,1);
idft(IDFT_1536, in, out, 1);
break;
case 100:
idft(IDFT_2048,in,out,1);
idft(IDFT_2048, in, out, 1);
break;
default:
LOG_E(PHY,"Unsupported N_RB_DL %d\n",size);
abort();
LOG_E(PHY, "Unsupported N_RB_DL %d\n", size);
abort();
break;
}
}
}
static void copyPrimary( c16_t *out, struct complex16 *in, int ofdmSize) {
int k=ofdmSize-36;
for (int i=0; i<72; i++) {
out[k].r = in[i].r>>1; //we need to shift input to avoid overflow in fft
out[k].i = in[i].i>>1;
static void copyPrimary(struct complex16 *out, struct complex16 *in, int ofdmSize)
{
int k = ofdmSize - 36;
for (int i = 0; i < 72; i++)
{
out[k].r = in[i].r >> 1; //we need to shift input to avoid overflow in fft
out[k].i = in[i].i >> 1;
k++;
if (k >= ofdmSize) {
k++; // skip DC carrier
k-=ofdmSize;
if (k >= ofdmSize)
{
k++; // skip DC carrier
k -= ofdmSize;
}
}
}
int lte_sync_time_init(LTE_DL_FRAME_PARMS *frame_parms)
{ // LTE_UE_COMMON *common_vars
int i, k;
int32_t sync_tmpSL[2048 * 2] __attribute__((aligned(32)));
int16_t syncF_tmpSL[2048 * 2] __attribute__((aligned(32)));
struct complex16 syncF_tmp[2048] __attribute__((aligned(32))) = {{0}};
int sz = frame_parms->ofdm_symbol_size * sizeof(*primary_synch0_time);
AssertFatal(NULL != (primary_synch0_time = (struct complex16 *)malloc16(sz)), "");
bzero(primary_synch0_time, sz);
AssertFatal(NULL != (primary_synch1_time = (struct complex16 *)malloc16(sz)), "");
bzero(primary_synch1_time, sz);
AssertFatal(NULL != (primary_synch2_time = (struct complex16 *)malloc16(sz)), "");
bzero(primary_synch2_time, sz);
// generate oversampled sync_time sequences
copyPrimary(syncF_tmp, (struct complex16 *)primary_synch0, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp, (short *)primary_synch0_time);
copyPrimary(syncF_tmp, (struct complex16 *)primary_synch1, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp, (short *)primary_synch1_time);
copyPrimary(syncF_tmp, (struct complex16 *)primary_synch2, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp, (short *)primary_synch2_time);
if (LOG_DUMPFLAG(DEBUG_LTEESTIM))
{
LOG_M("primary_sync0.m", "psync0", primary_synch0_time, frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("primary_sync1.m", "psync1", primary_synch1_time, frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("primary_sync2.m", "psync2", primary_synch2_time, frame_parms->ofdm_symbol_size, 1, 1);
}
int lte_sync_time_init(LTE_DL_FRAME_PARMS *frame_parms ) { // LTE_UE_COMMON *common_vars
c16_t syncF_tmp[2048]__attribute__((aligned(32)))= {{0}};
int sz=frame_parms->ofdm_symbol_size*sizeof(*primary_synch0_time);
AssertFatal( NULL != (primary_synch0_time = (c16_t *)malloc16(sz)),"");
bzero(primary_synch0_time,sz);
AssertFatal( NULL != (primary_synch1_time = (c16_t *)malloc16(sz)),"");
bzero(primary_synch1_time,sz);
AssertFatal( NULL != (primary_synch2_time = (c16_t *)malloc16(sz)),"");
bzero(primary_synch2_time,sz);
// generate oversampled sync_time sequences
copyPrimary( syncF_tmp, (c16_t *) primary_synch0, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch0_time);
copyPrimary( syncF_tmp, (c16_t *) primary_synch1, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch1_time);
copyPrimary( syncF_tmp, (c16_t *) primary_synch2, frame_parms->ofdm_symbol_size);
doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch2_time);
//THE REST IS FOR SIDELINK
primary_synch0SL_time = (int16_t *)malloc16((frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * sizeof(int16_t) * 2);
if (primary_synch0SL_time)
{
bzero(primary_synch0SL_time, (frame_parms->ofdm_symbol_size) * sizeof(int16_t) * 2);
#ifdef DEBUG_PHY
LOG_D(PHY, "[openair][LTE_PHY][SYNC] primary_synch0SL_time allocated at %p\n", primary_synch0SL_time);
#endif
}
else
AssertFatal(1 == 0, "primary_synch0SL_time not allocated\n");
if ( LOG_DUMPFLAG(DEBUG_LTEESTIM)){
LOG_M("primary_sync0.m","psync0",primary_synch0_time,frame_parms->ofdm_symbol_size,1,1);
LOG_M("primary_sync1.m","psync1",primary_synch1_time,frame_parms->ofdm_symbol_size,1,1);
LOG_M("primary_sync2.m","psync2",primary_synch2_time,frame_parms->ofdm_symbol_size,1,1);
primary_synch0SL_time_rx = (int16_t *)malloc16(2 * (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * sizeof(int16_t) * 2);
if (primary_synch0SL_time_rx)
{
bzero(primary_synch0SL_time_rx, (frame_parms->ofdm_symbol_size) * sizeof(int16_t) * 2);
#ifdef DEBUG_PHY
LOG_D(PHY, "[openair][LTE_PHY][SYNC] primary_synch0SL_time_rx allocated at %p\n", primary_synch0SL_time);
#endif
}
else
AssertFatal(1 == 0, "primary_synch0SL_time_rx not allocated\n");
primary_synch1SL_time = (int16_t *)malloc16(((frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples)) * sizeof(int16_t) * 2);
if (primary_synch1SL_time)
{
bzero(primary_synch1SL_time, (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * sizeof(int16_t) * 2);
#ifdef DEBUG_PHY
LOG_D(PHY, "[openair][LTE_PHY][SYNC] primary_synch1SL_time allocated at %p\n", primary_synch1SL_time);
#endif
}
else
AssertFatal(1 == 0, "primary_synch1SL_time not allocated\n");
primary_synch1SL_time_rx = (int16_t *)malloc16(2 * (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * sizeof(int16_t) * 2);
if (primary_synch1SL_time_rx)
{
bzero(primary_synch1SL_time_rx, 2 * (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * sizeof(int16_t) * 2);
#ifdef DEBUG_PHY
LOG_D(PHY, "[openair][LTE_PHY][SYNC] primary_synch1SL_time_rx allocated at %p\n", primary_synch1SL_time);
#endif
}
else
AssertFatal(1 == 0, "primary_synch1SL_time_rx not allocated\n");
memset((void *)syncF_tmpSL, 0, 2048 * sizeof(int32_t));
k = frame_parms->ofdm_symbol_size - 36;
for (i = 0; i < 72; i++){
syncF_tmpSL[2 * k] = primary_synch0SL[2 * i] >> 2; //we need to shift input to avoid overflow in fft
syncF_tmpSL[2 * k + 1] = primary_synch0SL[2 * i + 1] >> 2;
k++;
if (k >= frame_parms->ofdm_symbol_size){
k -= frame_parms->ofdm_symbol_size;
}
}
int16_t *kHz7_5ptr;
switch (frame_parms->N_RB_DL)
{
case 6:
idft(IDFT_128, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
kHz7_5ptr = (frame_parms->Ncp==0) ? ((int16_t*)s6n_kHz_7_5)+(2*138): ((int16_t*)s6e_kHz_7_5)+(2*160);
break;
case 25:
idft(IDFT_512, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
kHz7_5ptr = (frame_parms->Ncp==0) ? ((int16_t*)s25n_kHz_7_5)+(2*552) : ((int16_t*)s25e_kHz_7_5)+(2*640);
break;
case 50:
idft(IDFT_1024, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
kHz7_5ptr = (frame_parms->Ncp==0) ? ((int16_t*)s50n_kHz_7_5)+(2*1104) : ((int16_t*)s50e_kHz_7_5)+(2*1280);
break;
case 75:
idft(IDFT_1536, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
kHz7_5ptr = (frame_parms->Ncp==0) ? ((int16_t*)s75n_kHz_7_5)+(2*1656): ((int16_t*)s75e_kHz_7_5)+(2*1920);
break;
case 100:
idft(IDFT_2048, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
kHz7_5ptr = (frame_parms->Ncp==0) ? ((int16_t*)s100n_kHz_7_5)+(2*2208) : ((int16_t*)s100e_kHz_7_5)+(2*2560);
break;
default:
LOG_E(PHY, "Unsupported N_RB_DL %d\n", frame_parms->N_RB_DL);
kHz7_5ptr = NULL;
break;
}
int imod;
for (i=0; i<(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2; i++) {
imod = i%(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
if (i<(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples))
((int32_t*)primary_synch0SL_time)[i] = sync_tmpSL[(i+(frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples))%frame_parms->ofdm_symbol_size];
primary_synch0SL_time_rx[i<<1] = (int16_t)(((int32_t)primary_synch0SL_time[imod<<1]*kHz7_5ptr[i<<1])>>15) - (int16_t)(((int32_t)primary_synch0SL_time[1+(imod<<1)]*kHz7_5ptr[1+(i<<1)])>>15);
primary_synch0SL_time_rx[1+(i<<1)] = (int16_t)(((int32_t)primary_synch0SL_time[imod<<1]*kHz7_5ptr[1+(i<<1)])>>15) + (int16_t)(((int32_t)primary_synch0SL_time[1+(imod<<1)]*kHz7_5ptr[i<<1])>>15);
}
memset((void *)syncF_tmpSL, 0, 2048 * sizeof(int32_t));
k = frame_parms->ofdm_symbol_size - 36;
for (i = 0; i < 72; i++)
{
syncF_tmpSL[2 * k] = primary_synch1SL[2 * i] >> 2; //we need to shift input to avoid overflow in fft
syncF_tmpSL[2 * k + 1] = primary_synch1SL[2 * i + 1] >> 2;
k++;
if (k >= frame_parms->ofdm_symbol_size)
{
k -= frame_parms->ofdm_symbol_size;
}
}
switch (frame_parms->N_RB_DL)
{
case 6:
idft(IDFT_128, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
break;
case 25:
idft(IDFT_512, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
break;
case 50:
idft(IDFT_1024, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
break;
case 75:
idft(IDFT_1536, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
break;
case 100:
idft(IDFT_2048, (int16_t *)syncF_tmpSL, /// complex input
(int16_t *)sync_tmpSL, /// complex output
1);
break;
default:
LOG_E(PHY, "Unsupported N_RB_DL %d\n", frame_parms->N_RB_DL);
break;
}
for (i=0;i<(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);i++)
((int32_t*)primary_synch1SL_time)[i] = sync_tmpSL[(i+(frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples))%frame_parms->ofdm_symbol_size];
for (i=0; i<(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2; i++) {
imod = i%(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
primary_synch1SL_time_rx[i<<1] = (int16_t)(((int32_t)primary_synch1SL_time[imod<<1]*kHz7_5ptr[i<<1])>>15) +
(int16_t)(((int32_t)primary_synch1SL_time[1+(imod<<1)]*kHz7_5ptr[1+(i<<1)])>>15);
primary_synch1SL_time_rx[1+(i<<1)] = -(int16_t)(((int32_t)primary_synch1SL_time[imod<<1]*kHz7_5ptr[1+(i<<1)])>>15) +
(int16_t)(((int32_t)primary_synch1SL_time[1+(imod<<1)]*kHz7_5ptr[i<<1])>>15);
}
return (1);
}
void lte_sync_time_free(void) {
if (primary_synch0_time) {
LOG_D(PHY,"Freeing primary_sync0_time ...\n");
void lte_sync_time_free(void)
{
if (primary_synch0_time)
{
LOG_D(PHY, "Freeing primary_sync0_time ...\n");
free(primary_synch0_time);
}
if (primary_synch1_time) {
LOG_D(PHY,"Freeing primary_sync1_time ...\n");
if (primary_synch1_time)
{
LOG_D(PHY, "Freeing primary_sync1_time ...\n");
free(primary_synch1_time);
}
if (primary_synch2_time) {
LOG_D(PHY,"Freeing primary_sync2_time ...\n");
if (primary_synch2_time)
{
LOG_D(PHY, "Freeing primary_sync2_time ...\n");
free(primary_synch2_time);
}
if (primary_synch0SL_time)
{
LOG_D(PHY, "Freeing primary_sync0SL_time ...\n");
free(primary_synch0SL_time);
}
if (primary_synch1SL_time)
{
LOG_D(PHY, "Freeing primary_sync1SL_time ...\n");
free(primary_synch1SL_time);
}
primary_synch0_time = NULL;
primary_synch1_time = NULL;
primary_synch2_time = NULL;
}
static inline int abs32(int x) {
return (((int)((short*)&x)[0])*((int)((short*)&x)[0]) + ((int)((short*)&x)[1])*((int)((short*)&x)[1]));
static inline int abs32(int x)
{
return (((int)((short *)&x)[0]) * ((int)((short *)&x)[0]) + ((int)((short *)&x)[1]) * ((int)((short *)&x)[1]));
}
static inline double absF(struct complexd x) {
return x.r*x.r+x.i*x.i;
static inline double absF(struct complexd x)
{
return x.r * x.r + x.i * x.i;
}
#define complexNull(c) bzero((void*) &(c), sizeof(c))
#define complexNull(c) bzero((void *)&(c), sizeof(c))
#define SHIFT 17
int lte_sync_time(int **rxdata, ///rx data in time domain
LTE_DL_FRAME_PARMS *frame_parms,
int *eNB_id) {
int *eNB_id)
{
// perform a time domain correlation using the oversampled sync sequence
unsigned int n, ar, s, peak_pos, peak_val, sync_source;
int result,result2;
struct complexd sync_out[3]= {{0}}, sync_out2[3]= {{0}};
int length = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti>>1;
int result, result2;
struct complexd sync_out[3] = {{0}}, sync_out2[3] = {{0}};
int length = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME * frame_parms->samples_per_tti >> 1;
peak_val = 0;
peak_pos = 0;
sync_source = 0;
for (n=0; n<length; n+=4) {
for (s=0; s<3; s++) {
for (n = 0; n < length; n += 4)
{
for (s = 0; s < 3; s++)
{
complexNull(sync_out[s]);
complexNull(sync_out2[s]);
}
// if (n<(length-frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples)) {
if (n<(length-frame_parms->ofdm_symbol_size)) {
if (n < (length - frame_parms->ofdm_symbol_size))
{
//calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
result = dot_product((short *)primary_synch0_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch0_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[0].r += ((short *) &result)[0];
sync_out[0].i += ((short *) &result)[1];
sync_out2[0].r += ((short *) &result2)[0];
sync_out2[0].i += ((short *) &result2)[1];
for (ar = 0; ar < frame_parms->nb_antennas_rx; ar++)
{
result = dot_product((short *)primary_synch0_time, (short *)&(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch0_time, (short *)&(rxdata[ar][n + length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[0].r += ((short *)&result)[0];
sync_out[0].i += ((short *)&result)[1];
sync_out2[0].r += ((short *)&result2)[0];
sync_out2[0].i += ((short *)&result2)[1];
}
for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
result = dot_product((short *)primary_synch1_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch1_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[1].r += ((short *) &result)[0];
sync_out[1].i += ((short *) &result)[1];
sync_out2[1].r += ((short *) &result2)[0];
sync_out2[1].i += ((short *) &result2)[1];
for (ar = 0; ar < frame_parms->nb_antennas_rx; ar++)
{
result = dot_product((short *)primary_synch1_time, (short *)&(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch1_time, (short *)&(rxdata[ar][n + length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[1].r += ((short *)&result)[0];
sync_out[1].i += ((short *)&result)[1];
sync_out2[1].r += ((short *)&result2)[0];
sync_out2[1].i += ((short *)&result2)[1];
}
for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
result = dot_product((short *)primary_synch2_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch2_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[2].r += ((short *) &result)[0];
sync_out[2].i += ((short *) &result)[1];
sync_out2[2].r += ((short *) &result2)[0];
sync_out2[2].i += ((short *) &result2)[1];
for (ar = 0; ar < frame_parms->nb_antennas_rx; ar++)
{
result = dot_product((short *)primary_synch2_time, (short *)&(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
result2 = dot_product((short *)primary_synch2_time, (short *)&(rxdata[ar][n + length]), frame_parms->ofdm_symbol_size, SHIFT);
sync_out[2].r += ((short *)&result)[0];
sync_out[2].i += ((short *)&result)[1];
sync_out2[2].r += ((short *)&result2)[0];
sync_out2[2].i += ((short *)&result2)[1];
}
}
// calculate the absolute value of sync_corr[n]
for (s=0; s<3; s++) {
for (s = 0; s < 3; s++)
{
double tmp = absF(sync_out[s]) + absF(sync_out2[s]);
if (tmp>peak_val) {
if (tmp > peak_val)
{
peak_val = tmp;
peak_pos = n;
sync_source = s;
@@ -211,22 +428,133 @@ int lte_sync_time(int **rxdata, ///rx data in time domain
}
*eNB_id = sync_source;
LOG_I(PHY,"[UE] lte_sync_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n",sync_source,peak_pos,peak_val/2,dB_fixed(peak_val/2)/2);
return(peak_pos);
LOG_I(PHY, "[UE] lte_sync_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n", sync_source, peak_pos, peak_val / 2, dB_fixed(peak_val / 2) / 2);
return (peak_pos);
}
int lte_sync_timeSL(PHY_VARS_UE *ue,
int *ind,
int64_t *lev,
int64_t *avg)
{
int ru_sync_time_init(RU_t *ru) { // LTE_UE_COMMON *common_vars
LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
// perform a time domain correlation using the oversampled sync sequence
int length = 4*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti;
// circular copy of beginning to end of rxdata buffer. Note: buffer should be big enough upon calling this function
for (int ar=0;ar<frame_parms->nb_antennas_rx;ar++) memcpy((void*)&ue->common_vars.rxdata_syncSL[ar][2*length],
(void*)&ue->common_vars.rxdata_syncSL[ar][0],
frame_parms->ofdm_symbol_size);
int64_t tmp0,tmp1;
int64_t magtmp0,magtmp1,maxlev0=0,maxlev1=0;
int maxpos0=0,maxpos1=0;
int64_t avg0=0,avg1=0;
int64_t result;
int32_t **rxdata = (int32_t**)ue->common_vars.rxdata_syncSL; ///rx data in time domain
RU_t ru_tmp;
int16_t **rxdata_7_5kHz = (int16_t**)ue->sl_rxdata_7_5kHz;
printf("**rxdata %lld, **rxdata_7_5kHz %lld\n", **rxdata,**rxdata_7_5kHz);
memset((void*)&ru_tmp,0,sizeof(RU_t));
memcpy((void*)&ru_tmp.frame_parms,(void*)&ue->frame_parms,sizeof(LTE_DL_FRAME_PARMS));
ru_tmp.N_TA_offset=0;
ru_tmp.common.rxdata = rxdata;
ru_tmp.common.rxdata_7_5kHz = (int32_t**)rxdata_7_5kHz;
ru_tmp.nb_rx = frame_parms->nb_antennas_rx;
int maxval=0;
for (int i=0;i<2*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);i++) {
maxval = max(maxval,primary_synch0SL_time_rx[i]);
maxval = max(maxval,-primary_synch0SL_time_rx[i]);
maxval = max(maxval,primary_synch1SL_time_rx[i]);
maxval = max(maxval,-primary_synch1SL_time_rx[i]);
}
int shift = log2_approx(maxval);//*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2);
printf("Synchtime SL : shifting by %d bits\n",shift);
for (int n=0; n<length; n+=4)
{
tmp0 = 0;
tmp1 = 0;
int32_t tmp0_re=((int32_t*)&tmp0)[0], tmp0_im=((int32_t*)&tmp0)[1];
int32_t tmp1_re=((int32_t*)&tmp1)[0], tmp1_im=((int32_t*)&tmp1)[1];
//calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
for (int ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
result = dot_product(primary_synch0SL_time_rx,
(int16_t*) &(rxdata[ar][n]),
(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2,
shift);
tmp0_re += ((int32_t*) &result)[0];
tmp0_im += ((int32_t*) &result)[1];
result = dot_product(primary_synch1SL_time_rx,
(int16_t*) &(rxdata[ar][n]),
(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2,
shift);
tmp1_re += ((int32_t*) &result)[0];
tmp1_im += ((int32_t*) &result)[1];
}
// tmpi holds <synchi,rx0>+<synci,rx1>+...+<synchi,rx_{nbrx-1}>
magtmp0 = (int64_t)tmp0_re*tmp0_re + (int64_t)tmp0_im*tmp0_im;
magtmp1 = (int64_t)tmp1_re*tmp1_re + (int64_t)tmp1_im*tmp1_im;
//printf("0: n %d (%d,%d) => %lld\n",n,tmp0_re,tmp0_im,magtmp0);
//printf("1: n %d (%d,%d) => %lld\n",n,tmp1_re,tmp1_im,magtmp1);
// this does max |tmpi(n)|^2 + |tmpi(n-L)|^2 and argmax |tmpi(n)|^2 + |tmpi(n-L)|^2
if (magtmp0>maxlev0) { maxlev0 = magtmp0; maxpos0 = n; }
if (magtmp1>maxlev1) { maxlev1 = magtmp1; maxpos1 = n; }
avg0 += magtmp0;
avg1 += magtmp1;
}
printf("result after dot product:%lld\n",result);
avg0/=(length/4);
avg1/=(length/4);
// PSS in symbol 1
int pssoffset = frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples0;
printf("maxpos = (%d,%d), pssoffset = %d, maxlev= (%lld,%lld) avglev (%lld,%lld)\n",maxpos0,maxpos1,pssoffset,
(long long int)maxlev0,(long long int)maxlev1,(long long int)avg0,(long long int)avg1);
if (maxlev0 > maxlev1) {
if ((int64_t)maxlev0 > (5*avg0)) {*lev = maxlev0; *ind=0; *avg=avg0; return((length+maxpos0-pssoffset)%length);};
}
else {
if ((int64_t)maxlev1 > (5*avg1)) {*lev = maxlev1; *ind=1; *avg=avg1; return((length+maxpos1-pssoffset)%length);};
}
return(-1);
}
int ru_sync_time_init(RU_t *ru)
{ // LTE_UE_COMMON *common_vars
/*
int16_t dmrs[2048];
int16_t *dmrsp[2] = {dmrs,NULL};
*/
int32_t dmrs[ru->frame_parms->ofdm_symbol_size*14] __attribute__((aligned(32)));
int32_t dmrs[ru->frame_parms->ofdm_symbol_size * 14] __attribute__((aligned(32)));
//int32_t *dmrsp[2] = {&dmrs[(3-ru->frame_parms->Ncp)*ru->frame_parms->ofdm_symbol_size],NULL};
int32_t *dmrsp[2] = {&dmrs[0],NULL};
int32_t *dmrsp[2] = {&dmrs[0], NULL};
generate_ul_ref_sigs();
ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms->ofdm_symbol_size*2*sizeof(int16_t));
ru->dmrs_corr = (uint64_t *)malloc16_clear(ru->frame_parms->samples_per_tti*10*sizeof(uint64_t));
ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms->ofdm_symbol_size * 2 * sizeof(int16_t));
ru->dmrs_corr = (uint64_t *)malloc16_clear(ru->frame_parms->samples_per_tti * 10 * sizeof(uint64_t));
generate_drs_pusch(NULL,
NULL,
ru->frame_parms,
@@ -238,48 +566,49 @@ int ru_sync_time_init(RU_t *ru) { // LTE_UE_COMMON *common_vars
ru->frame_parms->N_RB_DL,
0);
switch (ru->frame_parms->N_RB_DL) {
case 6:
idft(IDFT_128,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
switch (ru->frame_parms->N_RB_DL)
{
case 6:
idft(IDFT_128, (int16_t *)(&dmrsp[0][3 * ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 25:
idft(IDFT_512,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 25:
idft(IDFT_512, (int16_t *)(&dmrsp[0][3 * ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 50:
idft(IDFT_1024,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 50:
idft(IDFT_1024, (int16_t *)(&dmrsp[0][3 * ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 75:
idft(IDFT_1536,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync,
1); /// complex output
break;
case 75:
idft(IDFT_1536, (int16_t *)(&dmrsp[0][3 * ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync,
1); /// complex output
break;
case 100:
idft(IDFT_2048,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
case 100:
idft(IDFT_2048, (int16_t *)(&dmrsp[0][3 * ru->frame_parms->ofdm_symbol_size]),
ru->dmrssync, /// complex output
1);
break;
default:
AssertFatal(1==0,"Unsupported N_RB_DL %d\n",ru->frame_parms->N_RB_DL);
break;
default:
AssertFatal(1 == 0, "Unsupported N_RB_DL %d\n", ru->frame_parms->N_RB_DL);
break;
}
return(0);
return (0);
}
void ru_sync_time_free(RU_t *ru) {
AssertFatal(ru->dmrssync!=NULL,"ru->dmrssync is NULL\n");
void ru_sync_time_free(RU_t *ru)
{
AssertFatal(ru->dmrssync != NULL, "ru->dmrssync is NULL\n");
free(ru->dmrssync);
if (ru->dmrs_corr)
@@ -292,49 +621,55 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain
LTE_DL_FRAME_PARMS *frame_parms,
uint32_t length,
uint32_t *peak_val_out,
uint32_t *sync_corr_eNB) {
uint32_t *sync_corr_eNB)
{
// perform a time domain correlation using the oversampled sync sequence
unsigned int n, ar, peak_val, peak_pos;
uint64_t mean_val;
int result;
short *primary_synch_time;
int eNB_id = frame_parms->Nid_cell%3;
int eNB_id = frame_parms->Nid_cell % 3;
// LOG_E(PHY,"[SYNC TIME] Calling sync_time_eNB(%p,%p,%d,%d)\n",rxdata,frame_parms,eNB_id,length);
if (sync_corr_eNB == NULL) {
LOG_E(PHY,"[SYNC TIME] sync_corr_eNB not yet allocated! Exiting.\n");
return(-1);
if (sync_corr_eNB == NULL)
{
LOG_E(PHY, "[SYNC TIME] sync_corr_eNB not yet allocated! Exiting.\n");
return (-1);
}
switch (eNB_id) {
case 0:
primary_synch_time = (short *)primary_synch0_time;
break;
switch (eNB_id)
{
case 0:
primary_synch_time = (short *)primary_synch0_time;
break;
case 1:
primary_synch_time = (short *)primary_synch1_time;
break;
case 1:
primary_synch_time = (short *)primary_synch1_time;
break;
case 2:
primary_synch_time = (short *)primary_synch2_time;
break;
case 2:
primary_synch_time = (short *)primary_synch2_time;
break;
default:
LOG_E(PHY,"[SYNC TIME] Illegal eNB_id!\n");
return (-1);
default:
LOG_E(PHY, "[SYNC TIME] Illegal eNB_id!\n");
return (-1);
}
peak_val = 0;
peak_pos = 0;
mean_val = 0;
for (n=0; n<length; n+=4) {
for (n = 0; n < length; n += 4)
{
sync_corr_eNB[n] = 0;
if (n<(length-frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples)) {
if (n < (length - frame_parms->ofdm_symbol_size - frame_parms->nb_prefix_samples))
{
//calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
result = dot_product((short *)primary_synch_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
for (ar = 0; ar < frame_parms->nb_antennas_rx; ar++)
{
result = dot_product((short *)primary_synch_time, (short *)&(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
//((short*)sync_corr)[2*n] += ((short*) &result)[0];
//((short*)sync_corr)[2*n+1] += ((short*) &result)[1];
sync_corr_eNB[n] += abs32(result);
@@ -349,81 +684,90 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain
*/
mean_val += sync_corr_eNB[n];
if (sync_corr_eNB[n]>peak_val) {
if (sync_corr_eNB[n] > peak_val)
{
peak_val = sync_corr_eNB[n];
peak_pos = n;
}
}
mean_val/=length;
mean_val /= length;
*peak_val_out = peak_val;
if (peak_val <= (40*(uint32_t)mean_val)) {
LOG_I(PHY,"[SYNC TIME] No peak found (%u,%u,%"PRIu64",%"PRIu64")\n",peak_pos,peak_val,mean_val,40*mean_val);
return(-1);
} else {
LOG_I(PHY,"[SYNC TIME] Peak found at pos %u, val = %u, mean_val = %"PRIu64"\n",peak_pos,peak_val,mean_val);
return(peak_pos);
if (peak_val <= (40 * (uint32_t)mean_val))
{
LOG_I(PHY, "[SYNC TIME] No peak found (%u,%u,%" PRIu64 ",%" PRIu64 ")\n", peak_pos, peak_val, mean_val, 40 * mean_val);
return (-1);
}
else
{
LOG_I(PHY, "[SYNC TIME] Peak found at pos %u, val = %u, mean_val = %" PRIu64 "\n", peak_pos, peak_val, mean_val);
return (peak_pos);
}
}
static inline int64_t abs64(int64_t x) {
return (((int64_t)((int32_t *)&x)[0])*((int64_t)((int32_t *)&x)[0]) + ((int64_t)
((int32_t *)&x)[1])*((int64_t)((int32_t *)&x)[1]));
static inline int64_t abs64(int64_t x)
{
return (((int64_t)((int32_t *)&x)[0]) * ((int64_t)((int32_t *)&x)[0]) + ((int64_t)((int32_t *)&x)[1]) * ((int64_t)((int32_t *)&x)[1]));
}
int ru_sync_time(RU_t *ru,
int64_t *lev,
int64_t *avg) {
int64_t *avg)
{
LTE_DL_FRAME_PARMS *frame_parms = ru->frame_parms;
RU_CALIBRATION *calibration = &ru->calibration;
// perform a time domain correlation using the oversampled sync sequence
int length = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti;
int length = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME * frame_parms->samples_per_tti;
// circular copy of beginning to end of rxdata buffer. Note: buffer should be big enough upon calling this function
for (int ar=0; ar<ru->nb_rx; ar++)
memcpy((void *)&ru->common.rxdata[ar][2*length],
for (int ar = 0; ar < ru->nb_rx; ar++)
memcpy((void *)&ru->common.rxdata[ar][2 * length],
(void *)&ru->common.rxdata[ar][0],
frame_parms->ofdm_symbol_size);
int32_t maxlev0=0;
int maxpos0=0;
int64_t avg0=0;
int32_t maxlev0 = 0;
int maxpos0 = 0;
int64_t avg0 = 0;
int64_t result;
int64_t dmrs_corr;
int maxval=0;
int maxval = 0;
for (int i=0; i<2*(frame_parms->ofdm_symbol_size); i++) {
maxval = max(maxval,ru->dmrssync[i]);
maxval = max(maxval,-ru->dmrssync[i]);
for (int i = 0; i < 2 * (frame_parms->ofdm_symbol_size); i++)
{
maxval = max(maxval, ru->dmrssync[i]);
maxval = max(maxval, -ru->dmrssync[i]);
}
if (ru->state == RU_CHECK_SYNC) {
for (int i=0; i<2*(frame_parms->ofdm_symbol_size); i++) {
maxval = max(maxval,calibration->drs_ch_estimates_time[0][i]);
maxval = max(maxval,-calibration->drs_ch_estimates_time[0][i]);
if (ru->state == RU_CHECK_SYNC)
{
for (int i = 0; i < 2 * (frame_parms->ofdm_symbol_size); i++)
{
maxval = max(maxval, calibration->drs_ch_estimates_time[0][i]);
maxval = max(maxval, -calibration->drs_ch_estimates_time[0][i]);
}
}
int shift = log2_approx(maxval);
for (int n=0; n<length; n+=4) {
for (int n = 0; n < length; n += 4)
{
dmrs_corr = 0;
//calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
for (int ar=0; ar<ru->nb_rx; ar++) {
result = dot_product64(ru->dmrssync,
(int16_t *) &ru->common.rxdata[ar][n],
frame_parms->ofdm_symbol_size,
shift);
for (int ar = 0; ar < ru->nb_rx; ar++)
{
result = dot_product64(ru->dmrssync,
(int16_t *)&ru->common.rxdata[ar][n],
frame_parms->ofdm_symbol_size,
shift);
if (ru->state == RU_CHECK_SYNC) {
result = dot_product64((int16_t *) &calibration->drs_ch_estimates_time[ar],
(int16_t *) &ru->common.rxdata[ar][n],
frame_parms->ofdm_symbol_size,
shift);
if (ru->state == RU_CHECK_SYNC)
{
result = dot_product64((int16_t *)&calibration->drs_ch_estimates_time[ar],
(int16_t *)&ru->common.rxdata[ar][n],
frame_parms->ofdm_symbol_size,
shift);
}
dmrs_corr += abs64(result);
@@ -434,7 +778,8 @@ int ru_sync_time(RU_t *ru,
// tmpi holds <synchi,rx0>+<synci,rx1>+...+<synchi,rx_{nbrx-1}>
if (dmrs_corr>maxlev0) {
if (dmrs_corr > maxlev0)
{
maxlev0 = dmrs_corr;
maxpos0 = n;
}
@@ -442,14 +787,15 @@ int ru_sync_time(RU_t *ru,
avg0 += dmrs_corr;
}
avg0/=(length/4);
int dmrsoffset = frame_parms->samples_per_tti + (3*frame_parms->ofdm_symbol_size)+(3*frame_parms->nb_prefix_samples) + frame_parms->nb_prefix_samples0;
avg0 /= (length / 4);
int dmrsoffset = frame_parms->samples_per_tti + (3 * frame_parms->ofdm_symbol_size) + (3 * frame_parms->nb_prefix_samples) + frame_parms->nb_prefix_samples0;
if ((int64_t)maxlev0 > (10*avg0)) {
if ((int64_t)maxlev0 > (10 * avg0))
{
*lev = maxlev0;
*avg=avg0;
return((length+maxpos0-dmrsoffset)%length);
*avg = avg0;
return ((length + maxpos0 - dmrsoffset) % length);
}
return(-1);
return (-1);
}

View File

@@ -380,6 +380,9 @@ int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms,
return(0);
}
int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms,
int32_t **ul_ch_estimates,
int32_t **ul_ch_estimates_time,
@@ -423,7 +426,7 @@ int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms,
/*
*/
Msc_idx_ptr = (uint16_t *) bsearch(&Msc_RS, dftsizes, 33, sizeof(uint16_t), compareints);
Msc_idx_ptr = (uint16_t *) bsearch(&Msc_RS, dftsizes, 34, sizeof(uint16_t), compareints);
if (Msc_idx_ptr)
Msc_RS_idx = Msc_idx_ptr - dftsizes;

View File

@@ -23,6 +23,14 @@ primary_synch2_mod = zeros(1,72*2);
primary_synch2_mod(1:2:end) = floor(32767*real(primary_synch2));
primary_synch2_mod(2:2:end) = floor(32767*imag(primary_synch2));
primary_synch0SL_mod = zeros(1,72*2);
primary_synch0SL_mod(1:2:end) = floor(32767*real(primary_synch0_SL));
primary_synch0SL_mod(2:2:end) = floor(32767*imag(primary_synch0_SL));
primary_synch1SL_mod = zeros(1,72*2);
primary_synch1SL_mod(1:2:end) = floor(32767*real(primary_synch1_SL));
primary_synch1SL_mod(2:2:end) = floor(32767*imag(primary_synch1_SL));
primary_synch0_mod2 = zeros(1,128);
primary_synch0_mod2((128-35):128)=primary_synch0(1:36);
primary_synch0_mod2(2:37)=primary_synch0(37:end);
@@ -59,6 +67,27 @@ fprintf(fd,'%d,',primary_synch2_tab(1:end-1));
fprintf(fd,'%d};\n',primary_synch2_tab(end));
fclose(fd);
primary_synch0_SL = [zeros(1,5) exp(-1j*pi*26*(0:30).*(1:31)/63) exp(-1j*pi*26*(32:62).*(33:63)/63) zeros(1,5)];
primary_synch1_SL = [zeros(1,5) exp(-1j*pi*37*(0:30).*(1:31)/63) exp(-1j*pi*37*(32:62).*(33:63)/63) zeros(1,5)];
primary_synch0SL_mod = zeros(1,72*2);
primary_synch0SL_mod(1:2:end) = floor(32767*real(primary_synch0_SL));
primary_synch0SL_mod(2:2:end) = floor(32767*imag(primary_synch0_SL));
primary_synch1SL_mod = zeros(1,72*2);
primary_synch1SL_mod(1:2:end) = floor(32767*real(primary_synch1_SL));
primary_synch1SL_mod(2:2:end) = floor(32767*imag(primary_synch1_SL));
fd = fopen('primary_synch_SL.h','w');
fprintf(fd,'short primary_synch0SL[144] = {');
fprintf(fd,'%d,',primary_synch0SL_mod(1:end-1));
fprintf(fd,'%d};\n',primary_synch0SL_mod(end));
fprintf(fd,'short primary_synch1SL[144] = {');
fprintf(fd,'%d,',primary_synch1SL_mod(1:end-1));
fprintf(fd,'%d};\n',primary_synch1SL_mod(end));
fclose(fd);
% for LEON we need to invert the endianess
fd = fopen('primary_synch_leon.h','w');
primary_synch0_tab = reshape(primary_synch0_tab,4,[]);

View File

@@ -0,0 +1,2 @@
short primary_synch0SL[144] = {0,0,0,0,0,0,0,0,0,0,32767,0,-27960,-17086,2448,-32676,-32402,-4884,22879,-23457,11971,-30502,-16384,28377,-30791,11206,20429,25618,-29523,14217,-10436,31060,2448,-32676,11971,-30502,-30791,11206,-16384,-28378,-32402,4883,22879,-23457,20429,-25619,-29523,14217,-27960,-17086,-16384,28377,-16384,-28378,-27960,-17086,27073,18458,11971,30501,22879,-23457,20429,25618,32767,-1,-30791,11206,-32402,4883,27073,18458,27073,18458,-32402,4883,-30791,11206,32767,0,20429,25618,22879,-23457,11971,30501,27073,18458,-27960,-17086,-16384,-28378,-16384,28377,-27960,-17086,-29523,14217,20429,-25619,22879,-23457,-32402,4883,-16384,-28378,-30791,11206,11971,-30502,2448,-32676,-10436,31060,-29523,14217,20429,25618,-30791,11206,-16384,28377,11971,-30502,22879,-23457,-32402,-4884,2448,-32676,-27960,-17086,32767,-1,0,0,0,0,0,0,0,0,0,0};
short primary_synch1SL[144] = {0,0,0,0,0,0,0,0,0,0,32767,0,-27960,17085,2448,32675,-32402,4883,22879,23456,11971,30501,-16384,-28378,-30791,-11207,20429,-25619,-29523,-14218,-10436,-31061,2448,32675,11971,30501,-30791,-11207,-16384,28377,-32402,-4884,22879,23456,20429,25618,-29523,-14218,-27960,17085,-16384,-28378,-16384,28377,-27960,17085,27073,-18459,11971,-30502,22879,23456,20429,-25619,32767,0,-30791,-11207,-32402,-4884,27073,-18459,27073,-18459,-32402,-4884,-30791,-11207,32767,0,20429,-25619,22879,23456,11971,-30502,27073,-18459,-27960,17085,-16384,28377,-16384,-28378,-27960,17085,-29523,-14218,20429,25618,22879,23456,-32402,-4884,-16384,28377,-30791,-11207,11971,30501,2448,32675,-10436,-31061,-29523,-14218,20429,-25619,-30791,-11207,-16384,-28378,11971,30501,22879,23456,-32402,4883,2448,32675,-27960,17085,32767,-1,0,0,0,0,0,0,0,0,0,0};

View File

@@ -40,14 +40,11 @@
#include "SCHED/sched_eNB.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "common/utils/LOG/log.h"
#if LATSEQ
#include "common/utils/LATSEQ/latseq.h"
#endif
#include "targets/RT/USER/lte-softmodem.h"
#include <syscall.h>
#include <common/utils/threadPool/thread-pool.h>
//#define DEBUG_DLSCH_CODING
#define DEBUG_DLSCH_CODING 1
//#define DEBUG_DLSCH_FREE 1
/*
@@ -376,16 +373,8 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
// printf("CRC %x (A %d)\n",crc,A);
hadlsch->B = A+24;
// hadlsch->b = a;
// LATSEQ
/*
#if LATSEQ
LATSEQ_P_TEST("D mac.txreq--mac.harq","rnti%d:harq%d.fm%d.subfm%d",dlsch->rnti, harq_pid, frame, subframe);
#endif
*/
// END_LATSEQ
memcpy(hadlsch->b,a,(A/8)+4);
if (lte_segmentation(hadlsch->b,
hadlsch->c,
hadlsch->B,
@@ -540,5 +529,109 @@ int dlsch_encoding_fembms_pmch(PHY_VARS_eNB *eNB,
return(0);
}
//Used only for sidelink
int dlsch_encoding0(LTE_DL_FRAME_PARMS *frame_parms,
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) {
unsigned char harq_pid = dlsch->harq_ids[frame%2][subframe];
if((harq_pid < 0) || (harq_pid >= dlsch->Mdlharq)) {
LOG_E(PHY,"dlsch_encoding illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
return(-1);
}
LTE_DL_eNB_HARQ_t *hadlsch=dlsch->harq_processes[harq_pid];
uint8_t beamforming_mode=0;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN);
if(hadlsch->mimo_mode == TM7)
beamforming_mode = 7;
else if(hadlsch->mimo_mode == TM8)
beamforming_mode = 8;
else if(hadlsch->mimo_mode == TM9_10)
beamforming_mode = 9;
unsigned int G;
unsigned short nb_rb = hadlsch->nb_rb;
unsigned char mod_order;
mod_order = hadlsch->Qm;
if (num_pdcch_symbols > 0) G= get_G(frame_parms,hadlsch->nb_rb,
hadlsch->rb_alloc,
hadlsch->Qm, // mod order
hadlsch->Nl,
num_pdcch_symbols,
frame,subframe,beamforming_mode);
else G = nb_rb * ((frame_parms->Ncp == 0)?12:10) * 12 * mod_order; // SLSCH Coding
// if (hadlsch->Ndi == 1) { // this is a new packet
if (hadlsch->round == 0) { // this is a new packet
// Add 24-bit crc (polynomial A) to payload
unsigned int A=hadlsch->TBS; //6228;
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];
// printf("CRC %x (A %d)\n",crc,A);
hadlsch->B = A+24;
// hadlsch->b = a;
memcpy(hadlsch->b,a,(A/8)+4);
if (lte_segmentation(hadlsch->b,
hadlsch->c,
hadlsch->B,
&hadlsch->C,
&hadlsch->Cplus,
&hadlsch->Cminus,
&hadlsch->Kplus,
&hadlsch->Kminus,
&hadlsch->F)<0)
return(-1);
}
for (int r=0, r_offset=0; r<hadlsch->C; r++) {
union turboReqUnion id= {.s={dlsch->rnti,frame,subframe,r,0}};
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboEncode_t), id.p, NULL, TPencode);
turboEncode_t * rdata=(turboEncode_t *) NotifiedFifoData(req);
rdata->input=hadlsch->c[r];
rdata->Kr_bytes= ( r<hadlsch->Cminus ? hadlsch->Kminus : hadlsch->Kplus) >>3;
rdata->filler=(r==0) ? hadlsch->F : 0;
rdata->r=r;
rdata->harq_pid=harq_pid;
rdata->dlsch=dlsch;
rdata->rm_stats=rm_stats;
rdata->te_stats=te_stats;
rdata->i_stats=i_stats;
rdata->round=hadlsch->round;
rdata->r_offset=r_offset;
rdata->G=G;
TPencode(rdata);
delNotifiedFIFO_elt(req);
int Qm=hadlsch->Qm;
int C=hadlsch->C;
int Nl=hadlsch->Nl;
int Gp = G/Nl/Qm;
int GpmodC = Gp%C;
if (r < (C-(GpmodC)))
r_offset += Nl*Qm * (Gp/C);
else
r_offset += Nl*Qm * ((GpmodC==0?0:1) + (Gp/C));
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_OUT);
return(0);
}

View File

@@ -140,6 +140,8 @@ int allocate_pbch_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms,
return(0);
}
void pbch_scrambling_fembms(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t *pbch_e,
uint32_t length)
@@ -165,6 +167,31 @@ void pbch_scrambling_fembms(LTE_DL_FRAME_PARMS *frame_parms,
}
}
void pbch_scrambling(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t *pbch_e,
uint32_t length,
int SLflag)
{
int i;
uint8_t reset;
uint32_t x1, x2, s=0;
reset = 1;
// x1 is set in lte_gold_generic
x2 = SLflag==0 ? frame_parms->Nid_cell : frame_parms->Nid_SL; //this is c_init in 36.211 Sec 6.6.1
// msg("pbch_scrambling: Nid_cell = %d\n",x2);
for (i=0; i<length; i++) {
if ((i&0x1f)==0) {
s = lte_gold_generic(&x1, &x2, reset);
// printf("lte_gold[%d]=%x\n",i,s);
reset = 0;
}
pbch_e[i] = (pbch_e[i]&1) ^ ((s>>(i&0x1f))&1);
}
}
int generate_pbch_fembms(LTE_eNB_PBCH *eNB_pbch,
int32_t **txdataF,
int amp,
@@ -418,7 +445,7 @@ int generate_pbch_fembms(LTE_eNB_PBCH *eNB_pbch,
return(0);
}
/* Old one without SLflag
void pbch_scrambling(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t *pbch_e,
uint32_t length)
@@ -443,6 +470,7 @@ void pbch_scrambling(LTE_DL_FRAME_PARMS *frame_parms,
}
}
*/
//uint8_t pbch_d[96+(3*(16+PBCH_A))], pbch_w[3*3*(16+PBCH_A)],pbch_e[1920]; //one bit per byte
int generate_pbch(LTE_eNB_PBCH *eNB_pbch,
@@ -602,7 +630,8 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch,
pbch_scrambling(frame_parms,
eNB_pbch->pbch_e,
pbch_E);
pbch_E,
0);
#ifdef DEBUG_PBCH
if (frame_mod4==0) {
LOG_M("pbch_e_s.m","pbch_e_s",

View File

@@ -160,20 +160,40 @@ typedef struct {
} PRACH_TDD_PREAMBLE_MAP;
typedef struct {
uint32_t SL_OffsetIndicator;
uint16_t slss_id;
uint8_t *slmib;
uint8_t slmib_length;
uint8_t slmib[5];
} SLSS_t;
typedef enum {
disc_type1=0,
disc_type2B=1
} SLD_t;
typedef struct {
// SL Configuration
/// Number of SL resource blocks (1-100)
uint32_t N_SL_RB;
/// prb-start (0-99)
uint32_t prb_Start;
/// prb-End (0-99)
uint32_t prb_End;
/// Number of SL resource blocks (1-100) for SCI
uint32_t N_SL_RB_SC;
/// prb-start (0-99) for SCI
uint32_t prb_Start_SC;
/// prb-End (0-99) for SCI
uint32_t prb_End_SC;
/// Number of SL resource blocks (1-100) for SCI
uint32_t N_SL_RB_data;
/// prb-start (0-99) for SCI
uint32_t prb_Start_data;
/// prb-End (0-99) for SCI
uint32_t prb_End_data;
/// SL-OffsetIndicator (0-10239)
uint32_t SL_OffsetIndicator;
/// SL-OffsetIndicator data (0-10239)
uint32_t SL_OffsetIndicator_data;
/// SC-SC_Period
uint32_t SL_SC_Period;
/// SC bitmap length (subframes)
uint32_t SubframeBitmapSL_length;
/// PSCCH subframe bitmap, first 64-bits (up to 40 bits for Rel 12)
uint64_t bitmap1;
/// PSCCH subframe bitmap, 2nd 64-bits (up to 100 bits for Rel 14)
@@ -210,6 +230,10 @@ typedef struct {
uint32_t cinit;
/// redundancy version
uint32_t rvidx;
/// n_prime_VRB parameters (36.213 14.1.1.2.1), RB_start
uint32_t RB_start;
/// n_prime_VRB parameters (36.213 14.1.1.2.1), L_CRBs
uint32_t L_CRBs;
/// n_prime_VRB (36.213 14.1.1.2.1)
uint32_t n_prime_VRB;
/// M_RB_PSSCH_RP (36.213 14.1.3
@@ -222,9 +246,48 @@ typedef struct {
int payload_length;
/// pointer to payload
uint8_t *payload;
/// index of current subframe modulo 10 in subframe pool
uint8_t ljmod10;
} SLSCH_t;
typedef struct {
// SL Discovery Configuration
/// Discovery Type
SLD_t type;
/// Number of SL resource blocks (1-100)
uint32_t N_SL_RB;
/// prb-start (0-99)
uint32_t prb_Start;
/// prb-End (0-99)
uint32_t prb_End;
/// SL-OffsetIndicator (0-10239)
uint32_t offsetIndicator;
/// SL-Discovery Period
uint32_t discPeriod;
/// Number of Repetitions (N_R)
uint32_t numRepetitions;
/// Number of retransmissions (numRetx-r12)
uint32_t numRetx;
/// PSDCH subframe bitmap (up to 100 bits, first 64)6
uint64_t bitmap1;
/// PSDCH subframe bitmap (up to 100 bits, second 36)
uint64_t bitmap2;
/// Bitmap length (N_B) (valid values (4,8,12,16,30,40,42) Rel12, (16,20,100) Rel14
uint32_t bitmap_length;
/// N1_PSDCH (a-r12)
uint32_t N1;
/// N1_PSDCH (b-r12)
uint32_t N2;
/// N1_PSDCH (c-r12)
uint32_t N3;
/// a10 (discPRB-Index)
uint32_t a10;
/// b10 (discSF-Index)
uint32_t b10;
/// transmission index (j)
uint32_t j;
// Discovery resource
uint32_t n_psdch;
/// payload length
int payload_length;
uint8_t payload[100];

Some files were not shown because too many files have changed in this diff Show More