Compare commits

...

4 Commits

Author SHA1 Message Date
Romain Beurdouche
3959b04335 feat(nrLDPC_coding): Use offload library for DLSCH encoding 2026-02-09 17:28:29 +01:00
Romain Beurdouche
faa49f46c9 feat(nrLDPC_coding): Use offload library for ULSCH decoding 2026-02-09 14:32:25 +00:00
Romain Beurdouche
478428af3b feat(nrLDPC_coding): Implementations claims
Added two new functions for LDPC coding libraries to emit claims upon TBs.
The claims indicate whether the processing of the TB is implemented by
the implementation and whether it is recommended to use this
implementation for the TB.
With multiple LDPC coding libraries loaded, this enables choosing the
most appropriate LDPC coding solution for each TB.
2026-02-09 14:32:11 +00:00
Romain Beurdouche
de55c1883b feat(nrLDPC_coding): Enable loading a second library
A second "offload" LDPC coding library can be loaded in the NR softmodem
TODO: Enable swapping of the default and offload library
2026-02-09 14:31:41 +00:00
10 changed files with 223 additions and 5 deletions

View File

@@ -1329,6 +1329,18 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec
return 0;
}
void nrLDPC_coding_claim_decode(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int8_t *claims)
{
for (int i = 0; i < nrLDPC_slot_decoding_parameters->nb_TBs; i++) {
nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[i];
if (nrLDPC_TB_decoding_parameters->Z >= 128 && nrLDPC_TB_decoding_parameters->BG == 1 && nrLDPC_TB_decoding_parameters->segments[0].R < 89) {
claims[i] = 1;
} else {
claims[i] = 0;
}
}
}
int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters)
{
pthread_mutex_lock(&encode_mutex);
@@ -1367,3 +1379,15 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc
pthread_mutex_unlock(&encode_mutex);
return ret;
}
void nrLDPC_coding_claim_encode(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int8_t *claims)
{
for (int i = 0; i < nrLDPC_slot_encoding_parameters->nb_TBs; i++) {
nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[i];
if (nrLDPC_TB_encoding_parameters->BG == 1 && nrLDPC_TB_encoding_parameters->C > 8 && nrLDPC_TB_encoding_parameters->Z == 384) {
claims[i] = 1;
} else {
claims[i] = 0;
}
}
}

View File

@@ -235,12 +235,32 @@ typedef struct nrLDPC_slot_encoding_parameters_s{
typedef int32_t(nrLDPC_coding_init_t)(void);
typedef int32_t(nrLDPC_coding_shutdown_t)(void);
/**
* \brief slot decoding claim function interface
* through the value returned by this function the LDPC coding library indicates for each Transport Block
* whether it supports decoding the Transport Block and whether it is worth using this implementation
* \param nrLDPC_slot_decoding_parameters pointer to the structure holding the parameters necessary for decoding
* \param claims array of claims upon the Transport blocks of the slot:
* < 0 means not supported, == 0 means supported but not recommended and > 0 means supported and recommended
*/
typedef void(nrLDPC_coding_claim_decode_t)(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int8_t *claims);
/**
* \brief slot decoding function interface
* \param nrLDPC_slot_decoding_parameters pointer to the structure holding the parameters necessary for decoding
*/
typedef int32_t(nrLDPC_coding_decoder_t)(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters);
/**
* \brief slot encoding claim function interface
* through the claims filled returned by this function the LDPC coding library indicates for each Transport Block
* whether it supports encoding the Transport Black and whether it is worth using this implementation
* \param nrLDPC_slot_encoding_parameters pointer to the structure holding the parameters necessary for encoding
* \param claims array of claims upon the Transport blocks of the slot:
* < 0 means not supported, == 0 means supported but not recommended and > 0 means supported and recommended
*/
typedef void(nrLDPC_coding_claim_encode_t)(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int8_t *claims);
/**
* \brief slot encoding function interface
* \param nrLDPC_slot_encoding_parameters pointer to the structure holding the parameters necessary for encoding
@@ -250,11 +270,25 @@ typedef int32_t(nrLDPC_coding_encoder_t)(nrLDPC_slot_encoding_parameters_t *nrLD
typedef struct nrLDPC_coding_interface_s {
nrLDPC_coding_init_t *nrLDPC_coding_init;
nrLDPC_coding_shutdown_t *nrLDPC_coding_shutdown;
nrLDPC_coding_claim_decode_t *nrLDPC_coding_claim_decode;
nrLDPC_coding_decoder_t *nrLDPC_coding_decoder;
nrLDPC_coding_claim_encode_t *nrLDPC_coding_claim_encode;
nrLDPC_coding_encoder_t *nrLDPC_coding_encoder;
} nrLDPC_coding_interface_t;
/**
* \brief LDPC coding library loading function
* \param specifier specifies the configmodule argument to be queried
* the loader loads the library provided with argument --loader.ldpc.<specifier>.shlibversion or --loader.ldpc.<specifier>.shlibpath
* if specifier is NULL then the loader loads the library provided with argument --loader.ldpc.shlibversion or --loader.ldpc.shlibpath
* \param version if not NULL then overrides the library version provided by configmodule
* \param interface pointer to the interface structure
*/
int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *interface);
/**
* \brief LDPC coding library release function
* \param interface pointer to the interface structure
*/
int free_nrLDPC_coding_interface(nrLDPC_coding_interface_t *interface);
#endif

View File

@@ -50,18 +50,22 @@ int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *itf)
/* function description array, to be used when loading the encoding/decoding shared lib */
loader_shlibfunc_t shlib_fdesc[] = {{.fname = "nrLDPC_coding_init"},
{.fname = "nrLDPC_coding_shutdown"},
{.fname = "nrLDPC_coding_claim_decode"},
{.fname = "nrLDPC_coding_decoder"},
{.fname = "nrLDPC_coding_claim_encode"},
{.fname = "nrLDPC_coding_encoder"}};
int ret;
ret = load_module_version_shlib(libname, version, shlib_fdesc, sizeofArray(shlib_fdesc), NULL);
if(ret < 0){
LOG_D(PHY, "NR ULSCH decoding module unavailable");
LOG_D(PHY, "NR channel coding module unavailable");
return ret;
}
itf->nrLDPC_coding_init = (nrLDPC_coding_init_t *)shlib_fdesc[0].fptr;
itf->nrLDPC_coding_shutdown = (nrLDPC_coding_shutdown_t *)shlib_fdesc[1].fptr;
itf->nrLDPC_coding_decoder = (nrLDPC_coding_decoder_t *)shlib_fdesc[2].fptr;
itf->nrLDPC_coding_encoder = (nrLDPC_coding_encoder_t *)shlib_fdesc[3].fptr;
itf->nrLDPC_coding_claim_decode = (nrLDPC_coding_claim_decode_t *)shlib_fdesc[2].fptr;
itf->nrLDPC_coding_decoder = (nrLDPC_coding_decoder_t *)shlib_fdesc[3].fptr;
itf->nrLDPC_coding_claim_encode = (nrLDPC_coding_claim_encode_t *)shlib_fdesc[4].fptr;
itf->nrLDPC_coding_encoder = (nrLDPC_coding_encoder_t *)shlib_fdesc[5].fptr;
AssertFatal(itf->nrLDPC_coding_init() == 0, "error starting LDPC library %s %s\n", libname, version);

View File

@@ -317,3 +317,10 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec
}
return 0;
}
void nrLDPC_coding_claim_decode(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int8_t *claims)
{
for (int i = 0; i < nrLDPC_slot_decoding_parameters->nb_TBs; i++) {
claims[i] = 0;
}
}

View File

@@ -501,3 +501,10 @@ int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encodin
return 0;
}
void nrLDPC_coding_claim_encode(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int8_t *claims)
{
for (int i = 0; i < nrLDPC_slot_encoding_parameters->nb_TBs; i++) {
claims[i] = 0;
}
}

View File

@@ -122,6 +122,13 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, in
return nbDecode;
}
void nrLDPC_coding_claim_decode(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int8_t *claims)
{
for (int i = 0; i < nrLDPC_slot_decoding_parameters->nb_TBs; i++) {
claims[i] = 0;
}
}
/*
int32_t nrLDPC_coding_encoder(void)
{

View File

@@ -22,6 +22,7 @@
#include "executables/softmodem-common.h"
#include "executables/nr-softmodem-common.h"
#include "common/utils/nr/nr_common.h"
#include "common/utils/load_module_shlib.h"
#include "common/ran_context.h"
#include "PHY/defs_gNB.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
@@ -137,6 +138,31 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
int ret_loader = load_nrLDPC_coding_interface(NULL, &gNB->nrLDPC_coding_interface);
AssertFatal(ret_loader == 0, "error loading LDPC library\n");
// load LDPC offload library
// First query configmodule to know if an offload library was provided
char *shlibversion = NULL;
// clang-format off
paramdef_t LoaderParams[] = {
{"shlibversion", NULL, 0, .strptr = &shlibversion, .defstrval = NULL, TYPE_STRING, 0, NULL}
};
// clang-format on
char cfgprefix[sizeof(LOADER_CONFIG_PREFIX) + 30];
sprintf(cfgprefix, LOADER_CONFIG_PREFIX ".ldpc.offload");
int ret_cfgmodule = config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), cfgprefix);
if (ret_cfgmodule <0) {
fprintf(stderr, "[LOADER] %s %d couldn't retrieve config from section %s\n", __FILE__, __LINE__, cfgprefix);
}
if (shlibversion != NULL) {
// an offload library was provided, load it
LOG_D(PHY, "LDPC offload library provided\n");
ret_loader = load_nrLDPC_coding_interface(shlibversion, &gNB->nrLDPC_coding_interface_offload);
gNB->use_offload = (ret_loader == 0);
} else {
// no offload library
LOG_D(PHY, "No LDPC offload library provided\n");
gNB->use_offload = false;
}
gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB;
init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table);
init_delay_table(128, MAX_DELAY_COMP, 128, fp->delay_table128);
@@ -283,6 +309,9 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
free(gNB->pusch_vars);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
if (gNB->use_offload) {
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface_offload);
}
}

View File

@@ -280,7 +280,62 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
.tparity = tparity,
.toutput = toutput,
.TBs = TBs};
gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters);
if (gNB->use_offload) {
// get claims from default implementation
int8_t claims_default[n_dlsch];
memset(claims_default, 0xff, n_dlsch * sizeof(int8_t));
gNB->nrLDPC_coding_interface.nrLDPC_coding_claim_encode(&slot_parameters, claims_default);
// get claims from offload implementation
int8_t claims_offload[n_dlsch];
memset(claims_offload, 0xff, n_dlsch * sizeof(int8_t));
gNB->nrLDPC_coding_interface_offload.nrLDPC_coding_claim_encode(&slot_parameters, claims_offload);
// split and count TBs
nrLDPC_TB_encoding_parameters_t TBs_default[n_dlsch];
uint8_t pdsch_id_default = 0;
nrLDPC_TB_encoding_parameters_t TBs_offload[n_dlsch];
uint8_t pdsch_id_offload = 0;
for (uint8_t pdsch_id = 0; pdsch_id < n_dlsch; pdsch_id++) {
if (claims_offload[pdsch_id] > 0 && claims_offload[pdsch_id] > claims_default[pdsch_id]) {
TBs_offload[pdsch_id_offload] = TBs[pdsch_id];
pdsch_id_offload++;
} else {
TBs_default[pdsch_id_default] = TBs[pdsch_id];
pdsch_id_default++;
}
}
// TODO parallelize
if (pdsch_id_default > 0) {
nrLDPC_slot_encoding_parameters_t slot_parameters_default = {.frame = frame,
.slot = slot,
.nb_TBs = pdsch_id_default,
.threadPool = &gNB->threadPool,
.tinput = tinput,
.tprep = tprep,
.tparity = tparity,
.toutput = toutput,
.TBs = TBs_default};
gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters_default);
}
if (pdsch_id_offload > 0) {
nrLDPC_slot_encoding_parameters_t slot_parameters_offload = {.frame = frame,
.slot = slot,
.nb_TBs = pdsch_id_offload,
.threadPool = &gNB->threadPool,
.tinput = tinput,
.tprep = tprep,
.tparity = tparity,
.toutput = toutput,
.TBs = TBs_offload};
gNB->nrLDPC_coding_interface_offload.nrLDPC_coding_encoder(&slot_parameters_offload);
}
} else {
gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters);
}
for (int i = 0; i < n_dlsch; i++) {
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i];

View File

@@ -281,7 +281,56 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
}
}
int ret_decoder = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
int ret_decoder = 0;
if (phy_vars_gNB->use_offload) {
// get claims from default implementation
int8_t claims_default[nb_pusch];
memset(claims_default, 0xff, nb_pusch * sizeof(int8_t));
phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_claim_decode(&slot_parameters, claims_default);
// get claims from offload implementation
int8_t claims_offload[nb_pusch];
memset(claims_offload, 0xff, nb_pusch * sizeof(int8_t));
phy_vars_gNB->nrLDPC_coding_interface_offload.nrLDPC_coding_claim_decode(&slot_parameters, claims_offload);
// split and count TBs
nrLDPC_TB_decoding_parameters_t TBs_default[nb_pusch];
uint8_t pusch_id_default = 0;
nrLDPC_TB_decoding_parameters_t TBs_offload[nb_pusch];
uint8_t pusch_id_offload = 0;
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
if (claims_offload[pusch_id] > 0 && claims_offload[pusch_id] > claims_default[pusch_id]) {
TBs_offload[pusch_id_offload] = TBs[pusch_id];
pusch_id_offload++;
} else {
TBs_default[pusch_id_default] = TBs[pusch_id];
pusch_id_default++;
}
}
// TODO parallelize
if (pusch_id_default > 0) {
nrLDPC_slot_decoding_parameters_t slot_parameters_default = {.frame = frame,
.slot = nr_tti_rx,
.nb_TBs = pusch_id_default,
.threadPool = &phy_vars_gNB->threadPool,
.TBs = TBs_default};
int ret_default = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters_default);
ret_decoder = ret_default == 0 ? ret_decoder : ret_default;
}
if (pusch_id_offload > 0) {
nrLDPC_slot_decoding_parameters_t slot_parameters_offload = {.frame = frame,
.slot = nr_tti_rx,
.nb_TBs = pusch_id_offload,
.threadPool = &phy_vars_gNB->threadPool,
.TBs = TBs_offload};
int ret_offload = phy_vars_gNB->nrLDPC_coding_interface_offload.nrLDPC_coding_decoder(&slot_parameters_offload);
ret_decoder = ret_offload == 0 ? ret_decoder : ret_offload;
}
} else {
ret_decoder = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
}
// post decode
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {

View File

@@ -421,6 +421,8 @@ typedef struct PHY_VARS_gNB_s {
/// NR LDPC coding related
nrLDPC_coding_interface_t nrLDPC_coding_interface;
nrLDPC_coding_interface_t nrLDPC_coding_interface_offload;
bool use_offload;
int max_ldpc_iterations;
/// indicate the channel estimation technique in time domain