Merge remote-tracking branch 'origin/NR_fix_tpmi_ctnd' into integration_2025_w34 (!3591)

separate computation of size and value for DCI precoding information

This removes stuff that is only relevant for the gNB from the common
functions and moves it to the gNB scheduler functions (related to UL
precoding). In principle no functional change.
This commit is contained in:
Robert Schmidt
2025-08-20 13:11:47 +02:00
3 changed files with 359 additions and 278 deletions
+43 -249
View File
@@ -1972,49 +1972,6 @@ static const int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l[12][8] = {
{0, 3072, -1, -1, 3, 1539, -1, -1}, // 14 // (DMRS l' position)
};
// TS 38.212
static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24,
25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55};
static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59};
static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61};
static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25};
static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32};
static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33};
static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35};
static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22};
static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29};
static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15};
static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6};
static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8};
static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3};
static const uint16_t table_7_3_1_1_2_28[3][15] = {
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
static const uint16_t table_7_3_1_1_2_29[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0},
};
static const uint16_t table_7_3_1_1_2_30[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},
};
static const uint16_t table_7_3_1_1_2_31[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
};
static const uint16_t table_7_3_1_1_2_32[3][15] = {
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
// the following tables contain 10 times the value reported in 214 (in line with SCF specification and to avoid fractional values)
//Table 5.1.3.1-1 of 38.214
static const uint16_t Table_51311[32][2] = {{2, 1200}, {2, 1570}, {2, 1930}, {2, 2510}, {2, 3080}, {2, 3790}, {2, 4490}, {2, 5260},
@@ -2503,61 +2460,61 @@ static int binomial(int n, int k)
return c;
}
int srs_codebook_nb_res(NR_SRS_Config_t *srs_config)
{
int count = 0;
for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook)
count++;
}
return count;
}
int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config)
{
int count = 0;
for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook)
count++;
}
return count;
}
int srs_binomial_sum(int count, int Lmax)
{
int lmin = 0;
int lsum = 0;
lmin = count < Lmax ? count : Lmax;
for (int k = 1; k <= lmin; k++)
lsum += binomial(count, k);
return lsum;
}
// #define DEBUG_SRS_RESOURCE_IND
uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
nr_srs_feedback_t *srs_feedback,
uint32_t *val)
static uint8_t compute_srs_resource_indicator_size(long *maxMIMO_Layers, NR_PUSCH_Config_t *pusch_Config, NR_SRS_Config_t *srs_config)
{
uint8_t nbits = 0;
// SRI occupies a number of bits which is dependent upon the uplink transmission scheme, and it is used to determine
// the antenna ports and uplink transmission beam to use for PUSCH transmission. In the case of codebook based
// transmission, the SRI is used to select between SRS Resources belonging to different antenna panels
// (kind of directional antenna). There can be up to 2 SRS Resources (2 antenna panels). In the case of non-codebook
// based transmission, the SRI is used to select one or more SRS Resources from a set of N_SRS resources. The number
// of SRS Resources selected corresponds to the number of layers (rank) to be transmitted.
if (val) {
*val = 0;
}
if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) {
if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) {
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_codebook\n");
#endif
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to
// Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook,
// where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer
// parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook.
int count = 0;
for (int i=0; i<srs_config->srs_ResourceSetToAddModList->list.count; i++) {
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) {
count++;
}
}
if (count>0) {
int count = srs_codebook_nb_res(srs_config);
if (count > 0)
nbits = ceil(log2(count));
if (val && srs_feedback && count > 1) {
*val = table_7_3_1_1_2_32[count-2][srs_feedback->sri];
}
}
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count);
LOG_I(NR_MAC, "count = %i\n", count);
#endif
} else {
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_nonCodebook\n");
#endif
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k))))
// bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where
// N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter
@@ -2572,68 +2529,29 @@ uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
if (maxMIMO_Layers != NULL)
Lmax = *maxMIMO_Layers;
else
AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
int lmin = 0;
int lsum = 0;
int count = 0;
for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) {
count++;
}
}
lmin = count < Lmax ? count : Lmax;
for (int k=1;k<=lmin;k++) {
lsum += binomial(count,k);
}
if (lsum>0) {
AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
int count = srs_non_codebook_nb_res(srs_config);
int lsum = srs_binomial_sum(count, Lmax);
if (lsum > 0)
nbits = ceil(log2(lsum));
if (val && srs_feedback && nbits > 0) {
switch(Lmax) {
case 1:
*val = table_7_3_1_1_2_28[count-2][srs_feedback->sri];
break;
case 2:
*val = table_7_3_1_1_2_29[count-2][srs_feedback->sri];
break;
case 3:
*val = table_7_3_1_1_2_30[count-2][srs_feedback->sri];
break;
case 4:
*val = table_7_3_1_1_2_31[count-2][srs_feedback->sri];
break;
default:
LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax);
}
}
}
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count);
LOG_I(NR_MAC, "count = %i\n", count);
LOG_I(NR_MAC, "Lmax = %i\n", Lmax);
LOG_I(NR_MAC, "lsum = %i\n", lsum);
#endif
}
}
return nbits;
}
uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
dci_field_t srs_resource_indicator,
nr_srs_feedback_t *srs_feedback,
const uint8_t *nrOfLayers,
int *tpmi,
uint32_t *val)
static uint8_t compute_precoding_info_size(NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
dci_field_t srs_resource_indicator)
{
// It is only applicable to codebook based transmission. This field occupies 0 bits for non-codebook based
// transmission. It also occupies 0 bits for codebook based transmission using a single antenna port.
uint8_t nbits = 0;
if (val) {
*val = 0;
}
uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator);
if (!pusch_Config
@@ -2645,7 +2563,6 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
long max_rank = *pusch_Config->maxRank;
long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
long *codebookSubset = pusch_Config->codebookSubset;
int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1;
if (pusch_antenna_ports == 2) {
@@ -2658,23 +2575,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
// of higher layer parameter codebookSubset;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
nbits = 2;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi);
*val = ul_tpmi;
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 1;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi);
*val = ul_tpmi;
}
} else {
nbits = 3;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi);
*val = ul_tpmi;
}
}
}
} else {
@@ -2685,27 +2590,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
// fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
nbits = 2;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) || (*nrOfLayers==2 && ul_tpmi == 0),
"TPMI %d is invalid!\n", ul_tpmi);
*val = *nrOfLayers==1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2;
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 2;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) || (*nrOfLayers==2 && ul_tpmi == 0),
"TPMI %d is invalid!\n", ul_tpmi);
*val = *nrOfLayers==1 ? ul_tpmi : 2;
}
} else {
nbits = 4;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) || (*nrOfLayers==2 && ul_tpmi <= 2),
"TPMI %d is invalid!\n", ul_tpmi);
*val = *nrOfLayers==1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] :
table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi];
}
}
}
}
@@ -2722,37 +2611,16 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 3;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi);
}
} else {
nbits = 4;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi);
}
}
if (val && srs_feedback) {
*val = table_7_3_1_1_2_3A[ul_tpmi];
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 2;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi);
}
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
nbits = 4;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi);
}
} else {
nbits = 5;
if (val && srs_feedback) {
AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi);
}
}
if (val && srs_feedback) {
*val = ul_tpmi;
}
}
} else {
@@ -2769,99 +2637,26 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
if (max_rank == 2) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi==13)) || (*nrOfLayers==2 && ul_tpmi <= 6),
"TPMI %d is invalid!\n", ul_tpmi);
}
} else {
nbits = 5;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13),
"TPMI %d is invalid!\n", ul_tpmi);
}
}
if (val && srs_feedback) {
*val = *nrOfLayers==1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi];
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi == 13)) || (*nrOfLayers==2 && ul_tpmi <= 6) ||
(*nrOfLayers==3 && ul_tpmi <= 1) || (*nrOfLayers==4 && ul_tpmi == 0),
"TPMI %d is invalid!\n", ul_tpmi);
}
} else {
nbits = 6;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13) ||
(*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2),
"TPMI %d is invalid!\n", ul_tpmi);
}
}
if (val && srs_feedback) {
switch (*nrOfLayers) {
case 1:
*val = table_7_3_1_1_2_2B_1layer[ul_tpmi];
break;
case 2:
*val = table_7_3_1_1_2_2B_2layers[ul_tpmi];
break;
case 3:
*val = table_7_3_1_1_2_2B_3layers[ul_tpmi];
break;
case 4:
*val = table_7_3_1_1_2_2B_4layers[ul_tpmi];
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 3) || (*nrOfLayers==2 && ul_tpmi <= 5) ||
(*nrOfLayers==3 && ul_tpmi == 0) || (*nrOfLayers==4 && ul_tpmi == 0),
"TPMI %d is invalid!\n", ul_tpmi);
}
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
nbits = 5;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 11) || (*nrOfLayers==2 && ul_tpmi <= 13) ||
(*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2),
"TPMI %d is invalid!\n", ul_tpmi);
}
} else {
nbits = 6;
if (val && srs_feedback) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 28) || (*nrOfLayers==2 && ul_tpmi <= 22) ||
(*nrOfLayers==3 && ul_tpmi <= 7) || (*nrOfLayers==4 && ul_tpmi <= 5),
"TPMI %d is invalid!\n", ul_tpmi);
}
}
if (val && srs_feedback) {
switch (*nrOfLayers) {
case 1:
*val = table_7_3_1_1_2_2_1layer[ul_tpmi];
break;
case 2:
*val = table_7_3_1_1_2_2_2layers[ul_tpmi];
break;
case 3:
*val = table_7_3_1_1_2_2_3layers[ul_tpmi];
break;
case 4:
*val = table_7_3_1_1_2_2_4layers[ul_tpmi];
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
}
}
}
return nbits;
}
@@ -3100,12 +2895,11 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
}
// SRS resource indicator
dci_pdu->srs_resource_indicator.nbits =
compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config, NULL, NULL);
compute_srs_resource_indicator_size(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config);
size += dci_pdu->srs_resource_indicator.nbits;
LOG_D(NR_MAC, "dci_pdu->srs_resource_indicator.nbits %d\n", dci_pdu->srs_resource_indicator.nbits);
// Precoding info and number of layers
dci_pdu->precoding_information.nbits =
compute_precoding_information(pusch_Config, srs_config, dci_pdu->srs_resource_indicator, NULL, NULL, NULL, NULL);
dci_pdu->precoding_information.nbits = compute_precoding_info_size(pusch_Config, srs_config, dci_pdu->srs_resource_indicator);
size += dci_pdu->precoding_information.nbits;
LOG_D(NR_MAC, "dci_pdu->precoding_informaiton.nbits=%d\n", dci_pdu->precoding_information.nbits);
// Antenna ports
+46 -15
View File
@@ -41,6 +41,49 @@
#define NB_SRS_PERIOD (18)
static const uint16_t srs_period[NB_SRS_PERIOD] = { 0, 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560};
// TS 38.212
static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24,
25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55};
static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59};
static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61};
static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25};
static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32};
static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33};
static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35};
static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22};
static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29};
static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15};
static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6};
static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8};
static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3};
static const uint16_t table_7_3_1_1_2_28[3][15] = {
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
static const uint16_t table_7_3_1_1_2_29[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0},
};
static const uint16_t table_7_3_1_1_2_30[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},
};
static const uint16_t table_7_3_1_1_2_31[3][15] = {
{0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
};
static const uint16_t table_7_3_1_1_2_32[3][15] = {
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
typedef enum {
pusch_dmrs_pos0 = 0,
pusch_dmrs_pos1 = 1,
@@ -81,20 +124,6 @@ void config_frame_structure(int mu,
uint8_t frame_type,
frame_structure_t *fs);
uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
nr_srs_feedback_t *srs_feedback,
uint32_t *val);
uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
dci_field_t srs_resource_indicator,
nr_srs_feedback_t *srs_feedback,
const uint8_t *nrOfLayers,
int *tpmi,
uint32_t *val);
NR_PDSCH_TimeDomainResourceAllocationList_t *get_dl_tdalist(const NR_UE_DL_BWP_t *DL_BWP,
int controlResourceSetId,
int ss_type,
@@ -197,7 +226,9 @@ uint32_t nr_get_code_rate_dl(uint8_t Imcs, uint8_t table_idx);
/** \brief Computes Q based on I_MCS PDSCH and table_idx for uplink. Implements MCS Tables from 38.214. */
uint8_t nr_get_Qm_ul(uint8_t Imcs, uint8_t table_idx);
uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx);
int srs_binomial_sum(int count, int Lmax);
int srs_codebook_nb_res(NR_SRS_Config_t *srs_config);
int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config);
uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset);
void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int *offset);
@@ -895,6 +895,265 @@ dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac,
return dci_payload;
}
static uint32_t compute_srs_resource_indicator(long *maxMIMO_Layers,
NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
nr_srs_feedback_t *srs_feedback)
{
uint32_t val = 0;
if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) {
if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) {
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to
// Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook,
// where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer
// parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook.
int count = srs_codebook_nb_res(srs_config);
if (count > 1)
val = table_7_3_1_1_2_32[count - 2][srs_feedback->sri];
} else {
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k))))
// bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where
// N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter
// srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value nonCodeBook and:
//
// - if UE supports operation with maxMIMO-Layers and the higher layer parameter maxMIMO-Layers of
// PUSCH-ServingCellConfig of the serving cell is configured, Lmax is given by that parameter;
//
// - otherwise, Lmax is given by the maximum number of layers for PUSCH supported by the UE for the serving cell
// for non-codebook based operation.
int Lmax = 0;
if (maxMIMO_Layers != NULL)
Lmax = *maxMIMO_Layers;
else
AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
int count = srs_non_codebook_nb_res(srs_config);
int lsum = srs_binomial_sum(count, Lmax);
if (lsum > 0 && ceil(log2(lsum)) > 0) {
switch(Lmax) {
case 1:
val = table_7_3_1_1_2_28[count-2][srs_feedback->sri];
break;
case 2:
val = table_7_3_1_1_2_29[count-2][srs_feedback->sri];
break;
case 3:
val = table_7_3_1_1_2_30[count-2][srs_feedback->sri];
break;
case 4:
val = table_7_3_1_1_2_31[count-2][srs_feedback->sri];
break;
default:
LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax);
}
}
}
}
return val;
}
static uint32_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
NR_SRS_Config_t *srs_config,
dci_field_t srs_resource_indicator,
nr_srs_feedback_t *srs_feedback,
const uint8_t *nrOfLayers,
int *tpmi)
{
uint32_t val = 0;
uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator);
if (!pusch_Config
|| (pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)
|| pusch_antenna_ports == 1) {
return val;
}
long max_rank = *pusch_Config->maxRank;
long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
long *codebookSubset = pusch_Config->codebookSubset;
int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1;
if (pusch_antenna_ports == 2) {
if (max_rank == 1) {
// - 1 or 3 bits according to Table 7.3.1.1.2-5 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
// is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
// precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset;
// - 2 bits according to Table 7.3.1.1.2-5A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
// fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values
// of higher layer parameter codebookSubset;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi);
val = ul_tpmi;
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi);
val = ul_tpmi;
} else {
AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi);
val = ul_tpmi;
}
}
} else {
// - 2 or 4 bits according to Table 7.3.1.1.2-4 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
// is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
// precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset;
// - 2 bits according to Table 7.3.1.1.2-4A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
// fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2)
|| (*nrOfLayers==2 && ul_tpmi == 0),
"TPMI %d is invalid!\n",
ul_tpmi);
val = *nrOfLayers == 1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2;
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1)
|| (*nrOfLayers==2 && ul_tpmi == 0),
"TPMI %d is invalid!\n",
ul_tpmi);
val = *nrOfLayers == 1 ? ul_tpmi : 2;
} else {
AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5)
|| (*nrOfLayers==2 && ul_tpmi <= 2),
"TPMI %d is invalid!\n",
ul_tpmi);
val = *nrOfLayers == 1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] :
table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi];
}
}
}
} else if (pusch_antenna_ports == 4) {
if (max_rank == 1) {
// - 2, 4, or 5 bits according to Table 7.3.1.1.2-3 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
// is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
// precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset;
// - 3 or 4 bits according to Table 7.3.1.1.2-3A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
// fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values
// of higher layer parameter codebookSubset;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi);
} else {
AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi);
}
val = table_7_3_1_1_2_3A[ul_tpmi];
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi);
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi);
} else {
AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi);
}
val = ul_tpmi;
}
} else {
// - 4, 5, or 6 bits according to Table 7.3.1.1.2-2 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
// is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
// precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset;
// - 4 or 5 bits according to Table 7.3.1.1.2-2A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
// fullpowerMode1, maxRank=2, transform precoder is disabled, and according to the values of higher layer parameter
// codebookSubset;
// - 4 or 6 bits according to Table 7.3.1.1.2-2B for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
// fullpowerMode1, maxRank=3 or 4, transform precoder is disabled, and according to the values of higher layer
// parameter codebookSubset;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (max_rank == 2) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal((*nrOfLayers==1
&& (ul_tpmi <= 3 || ul_tpmi == 13))
|| (*nrOfLayers == 2 && ul_tpmi <= 6),
"TPMI %d is invalid!\n",
ul_tpmi);
} else {
AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15)
|| (*nrOfLayers == 2 && ul_tpmi <= 13),
"TPMI %d is invalid!\n",
ul_tpmi);
}
val = *nrOfLayers == 1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi];
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal((*nrOfLayers == 1
&& (ul_tpmi <= 3 || ul_tpmi == 13))
|| (*nrOfLayers == 2 && ul_tpmi <= 6)
|| (*nrOfLayers == 3 && ul_tpmi <= 1)
|| (*nrOfLayers == 4 && ul_tpmi == 0),
"TPMI %d is invalid!\n",
ul_tpmi);
} else {
AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15)
|| (*nrOfLayers == 2 && ul_tpmi <= 13)
|| (*nrOfLayers == 3 && ul_tpmi <= 2)
|| (*nrOfLayers == 4 && ul_tpmi <= 2),
"TPMI %d is invalid!\n",
ul_tpmi);
}
switch (*nrOfLayers) {
case 1:
val = table_7_3_1_1_2_2B_1layer[ul_tpmi];
break;
case 2:
val = table_7_3_1_1_2_2B_2layers[ul_tpmi];
break;
case 3:
val = table_7_3_1_1_2_2B_3layers[ul_tpmi];
break;
case 4:
val = table_7_3_1_1_2_2B_4layers[ul_tpmi];
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 3)
|| (*nrOfLayers == 2 && ul_tpmi <= 5)
|| (*nrOfLayers == 3 && ul_tpmi == 0)
|| (*nrOfLayers == 4 && ul_tpmi == 0),
"TPMI %d is invalid!\n",
ul_tpmi);
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 11)
|| (*nrOfLayers == 2 && ul_tpmi <= 13)
|| (*nrOfLayers == 3 && ul_tpmi <= 2)
|| (*nrOfLayers == 4 && ul_tpmi <= 2),
"TPMI %d is invalid!\n",
ul_tpmi);
} else {
AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 28)
|| (*nrOfLayers == 2 && ul_tpmi <= 22)
|| (*nrOfLayers == 3 && ul_tpmi <= 7)
|| (*nrOfLayers == 4 && ul_tpmi <= 5),
"TPMI %d is invalid!\n",
ul_tpmi);
}
switch (*nrOfLayers) {
case 1:
val = table_7_3_1_1_2_2_1layer[ul_tpmi];
break;
case 2:
val = table_7_3_1_1_2_2_2layers[ul_tpmi];
break;
case 3:
val = table_7_3_1_1_2_2_3layers[ul_tpmi];
break;
case 4:
val = table_7_3_1_1_2_2_4layers[ul_tpmi];
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
}
}
return val;
}
void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
const nfapi_nr_pusch_pdu_t *pusch_pdu,
dci_pdu_rel15_t *dci_pdu_rel15,
@@ -940,23 +1199,20 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
// bwp indicator as per table 7.3.1.1.2-1 in 38.212
dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? bwp_id : bwp_id - 1;
// SRS resource indicator
if (pusch_Config &&
pusch_Config->txConfig != NULL) {
if (pusch_Config && pusch_Config->txConfig != NULL) {
AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook,
"Non Codebook configuration non supported\n");
compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH,
pusch_Config,
ul_bwp->srs_Config,
srs_feedback,
&dci_pdu_rel15->srs_resource_indicator.val);
dci_pdu_rel15->srs_resource_indicator.val = compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH,
pusch_Config,
ul_bwp->srs_Config,
srs_feedback);
}
compute_precoding_information(pusch_Config,
ul_bwp->srs_Config,
dci_pdu_rel15->srs_resource_indicator,
srs_feedback,
&pusch_pdu->nrOfLayers,
tpmi,
&dci_pdu_rel15->precoding_information.val);
dci_pdu_rel15->precoding_information.val = compute_precoding_information(pusch_Config,
ul_bwp->srs_Config,
dci_pdu_rel15->srs_resource_indicator,
srs_feedback,
&pusch_pdu->nrOfLayers,
tpmi);
// antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4
// Antenna Ports