nr,gnb,sched: changed pdsch_allocator interface and extended its respective unit tests

master
Francisco 3 years ago committed by Francisco Paisana
parent dd28f173b0
commit 632f2dbddd

@ -172,6 +172,9 @@ void phy_cfg_nr_default_t::make_pdsch_default(srsran_sch_hl_cfg_nr_t& pdsch)
pdsch.common_time_ra[0].sliv = srsran_ra_type2_to_riv(SRSRAN_NSYMB_PER_SLOT_NR - 1, 1, SRSRAN_NSYMB_PER_SLOT_NR); pdsch.common_time_ra[0].sliv = srsran_ra_type2_to_riv(SRSRAN_NSYMB_PER_SLOT_NR - 1, 1, SRSRAN_NSYMB_PER_SLOT_NR);
pdsch.nof_common_time_ra = 1; pdsch.nof_common_time_ra = 1;
// Set contiguous PRBs as default
pdsch.alloc = srsran_resource_alloc_type1;
// Setup PDSCH DMRS type A position // Setup PDSCH DMRS type A position
pdsch.typeA_pos = srsran_dmrs_sch_typeA_pos_2; pdsch.typeA_pos = srsran_dmrs_sch_typeA_pos_2;
} }

@ -94,15 +94,9 @@ struct bwp_params_t {
bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg_, uint32_t cc, uint32_t bwp_id); bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg_, uint32_t cc, uint32_t bwp_id);
uint32_t coreset_bw(uint32_t cs_id) const { return coresets[cs_id].bw; } prb_interval coreset_prb_range(uint32_t cs_id) const { return coresets[cs_id].prb_limits; }
prb_interval dci_fmt_1_0_prb_lims(uint32_t cs_id) const { return coresets[cs_id].dci_1_0_prb_limits; }
const bwp_rb_bitmap& coreset_prb_limits(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const bwp_rb_bitmap dci_fmt_1_0_excluded_prbs(uint32_t cs_id) const { return coresets[cs_id].usable_common_ss_prb_mask; }
{
if (used_common_prb_masks.contains(ss_id) and dci_fmt == srsran_dci_format_nr_1_0) {
return used_common_prb_masks[ss_id];
}
return cached_empty_prb_mask;
}
const srsran_search_space_t* get_ss(uint32_t ss_id) const const srsran_search_space_t* get_ss(uint32_t ss_id) const
{ {
@ -110,10 +104,11 @@ struct bwp_params_t {
} }
private: private:
bwp_rb_bitmap cached_empty_prb_mask; bwp_rb_bitmap cached_empty_prb_mask;
srsran::optional_vector<bwp_rb_bitmap> used_common_prb_masks;
struct coreset_cached_params { struct coreset_cached_params {
uint32_t bw = 0; prb_interval prb_limits;
prb_interval dci_1_0_prb_limits; /// See TS 38.214, section 5.1.2.2
bwp_rb_bitmap usable_common_ss_prb_mask;
}; };
srsran::optional_vector<coreset_cached_params> coresets; srsran::optional_vector<coreset_cached_params> coresets;
}; };

@ -28,47 +28,96 @@ public:
pdsch_allocator(const bwp_params_t& cfg_, uint32_t sl_index, pdsch_list_t& pdsch_lst); pdsch_allocator(const bwp_params_t& cfg_, uint32_t sl_index, pdsch_list_t& pdsch_lst);
/// Get available RBGs for allocation /// Get available RBGs for allocation
rbg_bitmap occupied_rbgs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const rbg_bitmap occupied_rbgs() const
{ {
return (dl_prbs | bwp_cfg.coreset_prb_limits(ss_id, dci_fmt)).rbgs(); // Note: in case, RBGs are used, dci format is not 1_0
return dl_prbs.rbgs();
} }
/// Get available PRBs for allocation /// Get available PRBs for allocation
prb_bitmap occupied_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const prb_bitmap occupied_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const
{ {
return (dl_prbs | bwp_cfg.coreset_prb_limits(ss_id, dci_fmt)).prbs(); if (dci_fmt == srsran_dci_format_nr_1_0) {
const srsran_search_space_t* ss = bwp_cfg.get_ss(ss_id);
if (ss != nullptr and SRSRAN_SEARCH_SPACE_IS_COMMON(ss->type)) {
return (dl_prbs | bwp_cfg.dci_fmt_1_0_excluded_prbs(ss->coreset_id)).prbs();
}
}
return dl_prbs.prbs();
} }
/// Checks if provided PDSCH arguments produce a valid PDSCH that fits into cell PRBs and does not collide with other /// Verifies if the input arguments are valid for an SI allocation and grant doesnt collide with other grants
/// allocations alloc_result is_si_grant_valid(uint32_t ss_id, const prb_grant& grant) const;
alloc_result is_grant_valid(uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt, /// Verifies if the input arguments are valid for an RAR allocation and grant doesnt collide with other grants
const prb_grant& grant, alloc_result is_rar_grant_valid(const prb_grant& grant) const;
ue_carrier_params_t* ue = nullptr) const;
/// Verifies if the input arguments are valid for an UE allocation and grant doesnt collide with other grants
alloc_result is_ue_grant_valid(const ue_carrier_params_t& ue,
uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant) const;
/** /**
* @brief Tries to allocate PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations * @brief Tries to allocate UE PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations
* @param dci_ctx[in] PDCCH DL DCI context information
* @param ss_id[in] SearchSpaceId used for allocation * @param ss_id[in] SearchSpaceId used for allocation
* @param dci_fmt[in] Chosen DL DCI format
* @param grant[in] PRBs used for the grant * @param grant[in] PRBs used for the grant
* @param pdcch[out] DCI where frequency_assignment and time_assignment get stored. * @param ue[in] UE carrier parameters
* @return pdsch_t object pointer in case of success. alloc_result error code in case of failure * @param dci[out] DCI where frequency_assignment and time_assignment get stored.
* @return pdsch_t* of allocated PDSCH in case of success. alloc_result error code in case of failure
*/ */
pdsch_alloc_result pdsch_alloc_result alloc_ue_pdsch(uint32_t ss_id,
alloc_pdsch(const srsran_dci_ctx_t& dci_ctx, uint32_t ss_id, const prb_grant& grant, srsran_dci_dl_nr_t& dci); srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
const ue_carrier_params_t& ue,
srsran_dci_dl_nr_t& dci);
/// Similar to alloc_ue_pdsch, but it doesn't verify if input parameters are valid
pdsch_t& alloc_ue_pdsch_unchecked(uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
const ue_carrier_params_t& ue,
srsran_dci_dl_nr_t& dci);
/** /**
* @brief Allocates PDSCH grant without verifying for collisions. Useful to avoid redundant is_grant_valid(...) calls * @brief Tries to allocate SI PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations
* @param dci_ctx[in] PDCCH DL DCI context information * @param ss_id[in] SearchSpaceId used for allocation
* @param grant[in] PRBs used for the grant * @param grant[in] PRBs used for the grant
* @param pdcch[out] DCI where frequency and time assignment get stored. * @param dci[out] DCI where frequency_assignment and time_assignment get stored.
* @return pdsch_t* of allocated PDSCH in case of success. alloc_result error code in case of failure
*/
pdsch_alloc_result alloc_si_pdsch(uint32_t ss_id, const prb_grant& grant, srsran_dci_dl_nr_t& dci);
/// Similar to alloc_si_pdsch, but it doesn't verify if input parameters are valid
pdsch_t& alloc_si_pdsch_unchecked(uint32_t ss_id, const prb_grant& grant, srsran_dci_dl_nr_t& dci);
/**
* @brief Tries to allocate RAR PDSCH grant. Ensures that there are no collisions with other previous PDSCH
* allocations
* @param grant[in] PRBs used for the grant
* @param dci[out] DCI where frequency_assignment and time_assignment get stored.
* @return pdsch_t* of allocated PDSCH in case of success. alloc_result error code in case of failure
*/ */
pdsch_t& alloc_pdsch_unchecked(const srsran_dci_ctx_t& dci_ctx, const prb_grant& grant, srsran_dci_dl_nr_t& dci); pdsch_alloc_result alloc_rar_pdsch(const prb_grant& grant, srsran_dci_dl_nr_t& dci);
/// Similar to alloc_rar_pdsch, but it doesn't verify if input parameters are valid
pdsch_t& alloc_rar_pdsch_unchecked(const prb_grant& grant, srsran_dci_dl_nr_t& dci);
/// Cancel last PDSCH allocation
void cancel_last_pdsch(); void cancel_last_pdsch();
/// Clear all PDSCHs
void reset(); void reset();
private: private:
alloc_result is_grant_valid_common(srsran_search_space_type_t ss_type,
srsran_dci_format_nr_t dci_fmt,
uint32_t coreset_id,
const prb_grant& grant) const;
pdsch_t& alloc_pdsch_unchecked(uint32_t coreset_id,
srsran_search_space_type_t ss_type,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
srsran_dci_dl_nr_t& dci);
const bwp_params_t& bwp_cfg; const bwp_params_t& bwp_cfg;
uint32_t slot_idx = 0; uint32_t slot_idx = 0;
@ -96,12 +145,13 @@ public:
/** /**
* @brief Tries to allocate PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations * @brief Tries to allocate PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations
* @param dci_ctx[in] PDCCH DL DCI context information * @param ss_type[in] PDCCH chosen search space type
* @param grant[in] PRBs used for the grant * @param grant[in] PRBs used for the grant
* @param pdcch[out] DCI where frequency_assignment and time_assignment get stored. * @param pdcch[out] DCI where frequency_assignment and time_assignment get stored.
* @return pdsch_t object pointer in case of success. alloc_result error code in case of failure * @return pdsch_t object pointer in case of success. alloc_result error code in case of failure
*/ */
pusch_alloc_result alloc_pusch(const srsran_dci_ctx_t& dci_ctx, const prb_grant& grant, srsran_dci_ul_nr_t& dci); pusch_alloc_result
alloc_pusch(const srsran_search_space_type_t ss_type, const prb_grant& grant, srsran_dci_ul_nr_t& dci);
/** /**
* @brief Allocates PDSCH grant without verifying for collisions. Useful to avoid redundant is_grant_valid(...) calls * @brief Allocates PDSCH grant without verifying for collisions. Useful to avoid redundant is_grant_valid(...) calls

@ -57,8 +57,20 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg
for (const srsran_coreset_t& cs : view_active_coresets(cfg.pdcch)) { for (const srsran_coreset_t& cs : view_active_coresets(cfg.pdcch)) {
coresets.emplace(cs.id); coresets.emplace(cs.id);
auto& cached_coreset = coresets[cs.id]; uint32_t rb_start = srsran_coreset_start_rb(&cs);
cached_coreset.bw = srsran_coreset_get_bw(&cs); coresets[cs.id].prb_limits = prb_interval{rb_start, rb_start + srsran_coreset_get_bw(&cs)};
coresets[cs.id].usable_common_ss_prb_mask = cached_empty_prb_mask;
// TS 38.214, 5.1.2.2 - For DCI format 1_0 and common search space, lowest RB of the CORESET is the RB index = 0
coresets[cs.id].usable_common_ss_prb_mask |= prb_interval(0, rb_start);
coresets[cs.id].dci_1_0_prb_limits = prb_interval{rb_start, cfg.rb_width};
// TS 38.214, 5.1.2.2.2 - when DCI format 1_0, common search space and CORESET#0 is configured for the cell,
// RA type 1 allocs shall be within the CORESET#0 region
if (cfg.pdcch.coreset_present[0]) {
coresets[cs.id].dci_1_0_prb_limits = coresets[cs.id].prb_limits;
coresets[cs.id].usable_common_ss_prb_mask |= prb_interval(coresets[cs.id].prb_limits.stop(), cfg.rb_width);
}
} }
// Derive params of individual slots // Derive params of individual slots
@ -116,16 +128,6 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg
ss_cce_list[sl][agg_idx].resize(n); ss_cce_list[sl][agg_idx].resize(n);
} }
} }
if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss.type)) {
used_common_prb_masks.emplace(ss_id, cached_empty_prb_mask);
uint32_t coreset_start = srsran_coreset_start_rb(&cfg.pdcch.coreset[ss.coreset_id]);
used_common_prb_masks[ss_id] |= prb_interval(0, coreset_start);
if (ss.coreset_id == 0) {
uint32_t coreset0_bw = srsran_coreset_get_bw(&cfg.pdcch.coreset[0]);
used_common_prb_masks[ss_id] |= prb_interval(coreset_start + coreset0_bw, cfg.rb_width);
}
}
} }
} }

@ -123,7 +123,7 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx,
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_slot]; bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_slot];
// Verify there is space in PDSCH // Verify there is space in PDSCH
alloc_result ret = bwp_pdcch_slot.pdschs.is_grant_valid(ss_id, dci_fmt, prbs); alloc_result ret = bwp_pdcch_slot.pdschs.is_si_grant_valid(ss_id, prbs);
if (ret != alloc_result::success) { if (ret != alloc_result::success) {
return ret; return ret;
} }
@ -137,7 +137,7 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx,
pdcch_dl_t& pdcch = *pdcch_result.value(); pdcch_dl_t& pdcch = *pdcch_result.value();
// Allocate PDSCH // Allocate PDSCH
pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch.dci.ctx, prbs, pdcch.dci); pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_si_pdsch_unchecked(ss_id, prbs, pdcch.dci);
// Generate DCI for SIB // Generate DCI for SIB
pdcch.dci_cfg.coreset0_bw = srsran_coreset_get_bw(&cfg.cfg.pdcch.coreset[0]); pdcch.dci_cfg.coreset0_bw = srsran_coreset_get_bw(&cfg.cfg.pdcch.coreset[0]);
@ -177,7 +177,7 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
bwp_slot_grid& bwp_msg3_slot = bwp_grid[msg3_slot]; bwp_slot_grid& bwp_msg3_slot = bwp_grid[msg3_slot];
// Verify there is space in PDSCH // Verify there is space in PDSCH
alloc_result ret = bwp_pdcch_slot.pdschs.is_grant_valid(cfg.cfg.pdcch.ra_search_space.id, dci_fmt, interv); alloc_result ret = bwp_pdcch_slot.pdschs.is_rar_grant_valid(interv);
if (ret != alloc_result::success) { if (ret != alloc_result::success) {
return ret; return ret;
} }
@ -219,7 +219,7 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
pdcch_dl_t& pdcch = *pdcch_result.value(); pdcch_dl_t& pdcch = *pdcch_result.value();
// Allocate PDSCH // Allocate PDSCH
pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch.dci.ctx, interv, pdcch.dci); pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_rar_pdsch_unchecked(interv, pdcch.dci);
// Generate DCI for RAR with given RA-RNTI // Generate DCI for RAR with given RA-RNTI
pdcch.dci_cfg = slot_ues[pending_rachs[0].temp_crnti]->get_dci_cfg(); pdcch.dci_cfg = slot_ues[pending_rachs[0].temp_crnti]->get_dci_cfg();
@ -278,7 +278,7 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, uint32_t ss_id, const
bwp_slot_grid& bwp_uci_slot = bwp_grid[ue.uci_slot]; // UCI : UL control info bwp_slot_grid& bwp_uci_slot = bwp_grid[ue.uci_slot]; // UCI : UL control info
// Verify there is space in PDSCH // Verify there is space in PDSCH
alloc_result ret = bwp_pdcch_slot.pdschs.is_grant_valid(ss_id, dci_fmt, dl_grant); alloc_result ret = bwp_pdcch_slot.pdschs.is_ue_grant_valid(ue.cfg(), ss_id, dci_fmt, dl_grant);
if (ret != alloc_result::success) { if (ret != alloc_result::success) {
return ret; return ret;
} }
@ -309,7 +309,7 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, uint32_t ss_id, const
pdcch_dl_t& pdcch = *pdcch_result.value(); pdcch_dl_t& pdcch = *pdcch_result.value();
// Allocate PDSCH // Allocate PDSCH
pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch.dci.ctx, dl_grant, pdcch.dci); pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_ue_pdsch_unchecked(ss_id, dci_fmt, dl_grant, ue.cfg(), pdcch.dci);
// Allocate HARQ // Allocate HARQ
int mcs = ue->fixed_pdsch_mcs(); int mcs = ue->fixed_pdsch_mcs();
@ -470,9 +470,7 @@ prb_grant find_optimal_dl_grant(bwp_slot_allocator& slot_alloc, const slot_ue& u
{ {
static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; // TODO: Support more DCI formats static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; // TODO: Support more DCI formats
const bwp_slot_grid& sl_grid = slot_alloc.res_grid()[ue.pdsch_slot]; prb_bitmap used_prb_mask = slot_alloc.occupied_dl_prbs(ue.pdsch_slot, ss_id, dci_fmt);
prb_bitmap used_prb_mask = sl_grid.pdschs.occupied_prbs(ss_id, dci_fmt);
prb_interval prb_interv = find_empty_interval_of_length(used_prb_mask, used_prb_mask.size(), 0); prb_interval prb_interv = find_empty_interval_of_length(used_prb_mask, used_prb_mask.size(), 0);

@ -45,7 +45,7 @@ void fill_dci_from_cfg(const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci)
dci.bwp_id = bwp_cfg.bwp_id; dci.bwp_id = bwp_cfg.bwp_id;
dci.cc_id = bwp_cfg.cc; dci.cc_id = bwp_cfg.cc;
dci.tpc = 1; dci.tpc = 1;
dci.coreset0_bw = bwp_cfg.cfg.pdcch.coreset_present[0] ? bwp_cfg.coreset_bw(0) : 0; dci.coreset0_bw = bwp_cfg.cfg.pdcch.coreset_present[0] ? bwp_cfg.coreset_prb_range(0).length() : 0;
} }
void fill_dci_from_cfg(const bwp_params_t& bwp_cfg, srsran_dci_ul_nr_t& dci) void fill_dci_from_cfg(const bwp_params_t& bwp_cfg, srsran_dci_ul_nr_t& dci)

@ -17,7 +17,7 @@ namespace srsenb {
namespace sched_nr_impl { namespace sched_nr_impl {
template <typename... Args> template <typename... Args>
void log_alloc_failure(srslog::log_channel& log_ch, uint32_t ss_id, const char* cause_fmt, Args&&... args) void log_alloc_failure(srslog::log_channel& log_ch, const char* cause_fmt, Args&&... args)
{ {
if (not log_ch.enabled()) { if (not log_ch.enabled()) {
return; return;
@ -25,7 +25,7 @@ void log_alloc_failure(srslog::log_channel& log_ch, uint32_t ss_id, const char*
// Log allocation failure // Log allocation failure
fmt::memory_buffer fmtbuf; fmt::memory_buffer fmtbuf;
fmt::format_to(fmtbuf, "SCHED: Failure to allocate PDSCH in SS#{}. Cause: ", ss_id); fmt::format_to(fmtbuf, "SCHED: Failure to allocate PDSCH. Cause: ");
fmt::format_to(fmtbuf, cause_fmt, std::forward<Args>(args)...); fmt::format_to(fmtbuf, cause_fmt, std::forward<Args>(args)...);
log_ch("%s", srsran::to_c_str(fmtbuf)); log_ch("%s", srsran::to_c_str(fmtbuf));
} }
@ -43,70 +43,168 @@ void pdsch_allocator::reset()
dl_prbs.reset(); dl_prbs.reset();
} }
alloc_result pdsch_allocator::is_grant_valid(uint32_t ss_id, alloc_result pdsch_allocator::is_grant_valid_common(srsran_search_space_type_t ss_type,
srsran_dci_format_nr_t dci_fmt, srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant, uint32_t coreset_id,
ue_carrier_params_t* ue) const const prb_grant& grant) const
{ {
// DL must be active in given slot // DL must be active in given slot
if (not bwp_cfg.slots[slot_idx].is_dl) { if (not bwp_cfg.slots[slot_idx].is_dl) {
log_alloc_failure(bwp_cfg.logger.error, ss_id, "DL is disabled for slot={}", slot_idx); log_alloc_failure(bwp_cfg.logger.error, "DL is disabled for slot={}", slot_idx);
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
// No space in Scheduler PDSCH output list // No space in Scheduler PDSCH output list
if (pdschs.full()) { if (pdschs.full()) {
log_alloc_failure(bwp_cfg.logger.warning, ss_id, "Maximum number of PDSCHs={} reached.", pdschs.size()); log_alloc_failure(bwp_cfg.logger.warning, "Maximum number of PDSCHs={} reached.", pdschs.size());
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
// Verify SearchSpace validity // TS 38.214, 5.1.2.2 - "The UE shall assume that when the scheduling grant is received with DCI format 1_0, then
const srsran_search_space_t* ss = (ue == nullptr) ? bwp_cfg.get_ss(ss_id) : ue->get_ss(ss_id); // downlink resource allocation type 1 is used."
if (ss == nullptr) { if (dci_fmt == srsran_dci_format_nr_1_0 and not grant.is_alloc_type1()) {
// Couldn't find SearchSpace log_alloc_failure(bwp_cfg.logger.warning, "DL Resource Allocation type 1 must be used in case of DCI format 1_0.");
log_alloc_failure(bwp_cfg.logger.error, ss_id, "SearchSpace has not been configured.");
return alloc_result::invalid_grant_params; return alloc_result::invalid_grant_params;
} }
if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss->type)) { // TS 38.214 - 5.1.2.2 - For DCI format 1_0 and Common Search Space, the list of available PRBs is limited by the
// In case of common SearchSpaces, the PRBs must be contiguous // rb_start and bandwidth of the coreset
if (grant.is_alloc_type0()) { if (dci_fmt == srsran_dci_format_nr_1_0 and SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)) {
log_alloc_failure(bwp_cfg.logger.warning, ss_id, "AllocType0 not allowed in common SearchSpace.");
return alloc_result::invalid_grant_params;
}
// Grant PRBs do not collide with CORESET PRB limits (in case of common SearchSpace) // Grant PRBs do not collide with CORESET PRB limits (in case of common SearchSpace)
if (bwp_cfg.coreset_prb_limits(ss_id, dci_fmt).collides(grant)) { if (bwp_cfg.dci_fmt_1_0_excluded_prbs(coreset_id).collides(grant)) {
bwp_cfg.logger.debug("SCHED: Provided RBG mask falls outside common CORESET PRB boundaries."); log_alloc_failure(
bwp_cfg.logger.debug, "Provided PRB grant={:x} falls outside common CORESET PRB boundaries.", grant);
return alloc_result::sch_collision; return alloc_result::sch_collision;
} }
} }
// Grant PRBs do not collide with previous PDSCH allocations // Grant PRBs do not collide with previous PDSCH allocations
if (dl_prbs.collides(grant)) { if (dl_prbs.collides(grant)) {
bwp_cfg.logger.debug("SCHED: Provided RBG mask collides with allocation previously made."); log_alloc_failure(
bwp_cfg.logger.debug, "Provided PRB grant={:x} collides with allocations previously made.", grant);
return alloc_result::sch_collision; return alloc_result::sch_collision;
} }
return alloc_result::success; return alloc_result::success;
} }
srsran::expected<pdsch_t*, alloc_result> pdsch_allocator::alloc_pdsch(const srsran_dci_ctx_t& dci_ctx, alloc_result pdsch_allocator::is_si_grant_valid(uint32_t ss_id, const prb_grant& grant) const
uint32_t ss_id, {
const prb_grant& grant, // Verify SearchSpace validity
srsran_dci_dl_nr_t& dci) const srsran_search_space_t* ss = bwp_cfg.get_ss(ss_id);
if (ss == nullptr) {
// Couldn't find SearchSpace
log_alloc_failure(bwp_cfg.logger.error, "SearchSpace has not been configured.");
return alloc_result::invalid_grant_params;
}
return is_grant_valid_common(ss->type, srsran_dci_format_nr_1_0, ss->coreset_id, grant);
}
alloc_result pdsch_allocator::is_rar_grant_valid(const prb_grant& grant) const
{ {
alloc_result code = is_grant_valid(ss_id, dci_ctx.format, grant); srsran_sanity_check(bwp_cfg.cfg.pdcch.ra_search_space_present,
"Attempting RAR allocation in BWP with no raSearchSpace");
return is_grant_valid_common(bwp_cfg.cfg.pdcch.ra_search_space.type,
srsran_dci_format_nr_1_0,
bwp_cfg.cfg.pdcch.ra_search_space.coreset_id,
grant);
}
alloc_result pdsch_allocator::is_ue_grant_valid(const ue_carrier_params_t& ue,
uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant) const
{
const srsran_search_space_t* ss = ue.get_ss(ss_id);
if (ss == nullptr) {
// Couldn't find SearchSpace
log_alloc_failure(bwp_cfg.logger.error, "rnti=0x%x,SearchSpaceId={} has not been configured.", ue.rnti, ss_id);
return alloc_result::invalid_grant_params;
}
alloc_result alloc_result = is_grant_valid_common(ss->type, dci_fmt, ss->coreset_id, grant);
if (alloc_result != alloc_result::success) {
return alloc_result;
}
// TS 38.214, 5.1.2.2 - "the UE shall use the downlink frequency resource allocation type as defined by the higher
// layer parameter resourceAllocation"
if (ue.phy().pdsch.alloc != srsran_resource_alloc_dynamic) {
if ((ue.phy().pdsch.alloc == srsran_resource_alloc_type0) != grant.is_alloc_type0()) {
log_alloc_failure(bwp_cfg.logger.warning,
"UE rnti=0x{:x} PDSCH RA configuration type {} doesn't match grant type",
ue.rnti,
grant.is_alloc_type0() ? 0 : 1);
return alloc_result::invalid_grant_params;
}
}
return alloc_result::success;
}
pdsch_alloc_result pdsch_allocator::alloc_si_pdsch(uint32_t ss_id, const prb_grant& grant, srsran_dci_dl_nr_t& dci)
{
alloc_result code = is_si_grant_valid(ss_id, grant);
if (code != alloc_result::success) { if (code != alloc_result::success) {
return code; return code;
} }
return {&alloc_si_pdsch_unchecked(ss_id, grant, dci)};
}
pdsch_t& pdsch_allocator::alloc_si_pdsch_unchecked(uint32_t ss_id, const prb_grant& grant, srsran_dci_dl_nr_t& dci)
{
// Verify SearchSpace validity
const srsran_search_space_t* ss = bwp_cfg.get_ss(ss_id);
srsran_sanity_check(ss != nullptr, "SearchSpace has not been configured");
return alloc_pdsch_unchecked(ss->coreset_id, ss->type, srsran_dci_format_nr_1_0, grant, dci);
}
return {&alloc_pdsch_unchecked(dci_ctx, grant, dci)}; pdsch_alloc_result pdsch_allocator::alloc_rar_pdsch(const prb_grant& grant, srsran_dci_dl_nr_t& dci)
{
alloc_result code = is_rar_grant_valid(grant);
if (code != alloc_result::success) {
return code;
}
return {&alloc_rar_pdsch_unchecked(grant, dci)};
}
pdsch_t& pdsch_allocator::alloc_rar_pdsch_unchecked(const prb_grant& grant, srsran_dci_dl_nr_t& dci)
{
// TS 38.213, 8.2 - "In response to a PRACH transmission, a UE attempts to detect a DCI format 1_0"
const static srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0;
return alloc_pdsch_unchecked(
bwp_cfg.cfg.pdcch.ra_search_space.coreset_id, bwp_cfg.cfg.pdcch.ra_search_space.type, dci_fmt, grant, dci);
}
pdsch_alloc_result pdsch_allocator::alloc_ue_pdsch(uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
const ue_carrier_params_t& ue,
srsran_dci_dl_nr_t& dci)
{
alloc_result code = is_ue_grant_valid(ue, ss_id, dci_fmt, grant);
if (code != alloc_result::success) {
return code;
}
return {&alloc_ue_pdsch_unchecked(ss_id, dci_fmt, grant, ue, dci)};
}
pdsch_t& pdsch_allocator::alloc_ue_pdsch_unchecked(uint32_t ss_id,
srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
const ue_carrier_params_t& ue,
srsran_dci_dl_nr_t& dci)
{
const srsran_search_space_t* ss = ue.get_ss(ss_id);
srsran_sanity_check(ss != nullptr, "SearchSpace has not been configured");
return alloc_pdsch_unchecked(ss->coreset_id, ss->type, dci_fmt, grant, dci);
} }
pdsch_t& pdsch_allocator::alloc_pdsch_unchecked(const srsran_dci_ctx_t& dci_ctx, pdsch_t& pdsch_allocator::alloc_pdsch_unchecked(uint32_t coreset_id,
const prb_grant& grant, srsran_search_space_type_t ss_type,
srsran_dci_dl_nr_t& out_dci) srsran_dci_format_nr_t dci_fmt,
const prb_grant& grant,
srsran_dci_dl_nr_t& out_dci)
{ {
// Create new PDSCH entry in output PDSCH list // Create new PDSCH entry in output PDSCH list
pdschs.emplace_back(); pdschs.emplace_back();
@ -121,12 +219,14 @@ pdsch_t& pdsch_allocator::alloc_pdsch_unchecked(const srsran_dci_ctx_t& dci_ctx,
out_dci.freq_domain_assigment = grant.rbgs().to_uint64(); out_dci.freq_domain_assigment = grant.rbgs().to_uint64();
} else { } else {
uint32_t rb_start = grant.prbs().start(), nof_prb = bwp_cfg.nof_prb(); uint32_t rb_start = grant.prbs().start(), nof_prb = bwp_cfg.nof_prb();
if (SRSRAN_SEARCH_SPACE_IS_COMMON(dci_ctx.ss_type)) { if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type)) {
if (dci_ctx.format == srsran_dci_format_nr_1_0) { prb_interval lims = bwp_cfg.coreset_prb_range(coreset_id);
rb_start -= dci_ctx.coreset_start_rb; if (dci_fmt == srsran_dci_format_nr_1_0) {
srsran_sanity_check(rb_start >= lims.start(), "Invalid PRB grant");
rb_start -= lims.start();
} }
if (dci_ctx.coreset_id == 0) { if (coreset_id == 0) {
nof_prb = bwp_cfg.coreset_bw(0); nof_prb = lims.length();
} }
} }
srsran_sanity_check(rb_start + grant.prbs().length() <= nof_prb, "Invalid PRB grant"); srsran_sanity_check(rb_start + grant.prbs().length() <= nof_prb, "Invalid PRB grant");
@ -140,6 +240,7 @@ void pdsch_allocator::cancel_last_pdsch()
{ {
srsran_assert(not pdschs.empty(), "Trying to abort PDSCH allocation that does not exist"); srsran_assert(not pdschs.empty(), "Trying to abort PDSCH allocation that does not exist");
pdschs.pop_back(); pdschs.pop_back();
// TODO: clear bitmap allocated RBs
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -220,9 +321,9 @@ pusch_allocator::is_grant_valid(srsran_search_space_type_t ss_type, const prb_gr
} }
pusch_alloc_result pusch_alloc_result
pusch_allocator::alloc_pusch(const srsran_dci_ctx_t& dci_ctx, const prb_grant& grant, srsran_dci_ul_nr_t& dci) pusch_allocator::alloc_pusch(const srsran_search_space_type_t ss_type, const prb_grant& grant, srsran_dci_ul_nr_t& dci)
{ {
alloc_result code = is_grant_valid(dci_ctx.ss_type, grant); alloc_result code = is_grant_valid(ss_type, grant);
if (code != alloc_result::success) { if (code != alloc_result::success) {
return code; return code;
} }

@ -65,8 +65,7 @@ void test_dci_freq_assignment(const bwp_params_t& bwp_params, prb_interval grant
// Compute BWP PRB limits // Compute BWP PRB limits
prb_interval lims{0, bwp_params.nof_prb()}; prb_interval lims{0, bwp_params.nof_prb()};
if (SRSRAN_SEARCH_SPACE_IS_COMMON(pdcch.dci.ctx.ss_type) and pdcch.dci.ctx.format == srsran_dci_format_nr_1_0) { if (SRSRAN_SEARCH_SPACE_IS_COMMON(pdcch.dci.ctx.ss_type) and pdcch.dci.ctx.format == srsran_dci_format_nr_1_0) {
uint32_t s = pdcch.dci.ctx.coreset_start_rb; lims = bwp_params.dci_fmt_1_0_prb_lims(pdcch.dci.ctx.coreset_id);
lims = prb_interval{s, pdcch.dci.ctx.coreset_id == 0 ? s + bwp_params.coreset_bw(0) : bwp_params.nof_prb()};
} }
// RB indexing should start from the first PRB of CORESET // RB indexing should start from the first PRB of CORESET
@ -99,8 +98,8 @@ void test_si()
pdcch_dl_t pdcch; pdcch_dl_t pdcch;
pdcch.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, ss_id, srsran_rnti_type_si, SRSRAN_SIRNTI); pdcch.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, ss_id, srsran_rnti_type_si, SRSRAN_SIRNTI);
uint32_t min_prb = pdcch.dci.ctx.coreset_start_rb; uint32_t min_prb = bwp_params.dci_fmt_1_0_prb_lims(pdcch.dci.ctx.coreset_id).start();
uint32_t max_prb = min_prb + bwp_params.coreset_bw(0); uint32_t max_prb = bwp_params.dci_fmt_1_0_prb_lims(pdcch.dci.ctx.coreset_id).stop();
std::array<prb_interval, 3> grant_list = { std::array<prb_interval, 3> grant_list = {
prb_interval{2, 4}, prb_interval{min_prb, max_prb}, prb_interval{0, bwp_params.nof_prb()}}; prb_interval{2, 4}, prb_interval{min_prb, max_prb}, prb_interval{0, bwp_params.nof_prb()}};
@ -113,13 +112,13 @@ void test_si()
bool success_expected = grant.start() >= min_prb and grant.stop() <= max_prb; bool success_expected = grant.start() >= min_prb and grant.stop() <= max_prb;
alloc_result check_ret = pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, grant); alloc_result check_ret = pdsch_sched.is_si_grant_valid(ss_id, grant);
prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
TESTASSERT_EQ((int)min_prb, avail_prbs.find_lowest(0, avail_prbs.size(), false)); TESTASSERT_EQ((int)min_prb, avail_prbs.find_lowest(0, avail_prbs.size(), false));
TESTASSERT_EQ((int)max_prb, avail_prbs.find_lowest(min_prb, avail_prbs.size(), true)); TESTASSERT_EQ((int)max_prb, avail_prbs.find_lowest(min_prb, avail_prbs.size(), true));
printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un"); printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un");
alloc_res = pdsch_sched.alloc_pdsch(pdcch.dci.ctx, ss_id, grant, pdcch.dci); alloc_res = pdsch_sched.alloc_si_pdsch(ss_id, grant, pdcch.dci);
if (success_expected) { if (success_expected) {
// SIB1 allocation doesnt go outside CORESET#0 BW // SIB1 allocation doesnt go outside CORESET#0 BW
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
@ -157,8 +156,8 @@ void test_rar()
pdcch_dl_t pdcch; pdcch_dl_t pdcch;
pdcch.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, ss_id, srsran_rnti_type_ra, 0x2); pdcch.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, ss_id, srsran_rnti_type_ra, 0x2);
uint32_t min_prb = pdcch.dci.ctx.coreset_start_rb; uint32_t min_prb = bwp_params.dci_fmt_1_0_prb_lims(pdcch.dci.ctx.coreset_id).start();
uint32_t max_prb = min_prb + bwp_params.coreset_bw(0); uint32_t max_prb = bwp_params.dci_fmt_1_0_prb_lims(pdcch.dci.ctx.coreset_id).stop();
std::array<prb_interval, 3> grant_list = { std::array<prb_interval, 3> grant_list = {
prb_interval{2, 4}, prb_interval{min_prb, max_prb}, prb_interval{0, bwp_params.nof_prb()}}; prb_interval{2, 4}, prb_interval{min_prb, max_prb}, prb_interval{0, bwp_params.nof_prb()}};
@ -171,13 +170,13 @@ void test_rar()
bool success_expected = grant.start() >= min_prb and grant.stop() <= max_prb; bool success_expected = grant.start() >= min_prb and grant.stop() <= max_prb;
alloc_result check_ret = pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, grant); alloc_result check_ret = pdsch_sched.is_rar_grant_valid(grant);
prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
TESTASSERT_EQ((int)min_prb, avail_prbs.find_lowest(0, avail_prbs.size(), false)); TESTASSERT_EQ((int)min_prb, avail_prbs.find_lowest(0, avail_prbs.size(), false));
TESTASSERT_EQ((int)max_prb, avail_prbs.find_lowest(min_prb, avail_prbs.size(), true)); TESTASSERT_EQ((int)max_prb, avail_prbs.find_lowest(min_prb, avail_prbs.size(), true));
printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un"); printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un");
alloc_res = pdsch_sched.alloc_pdsch(pdcch.dci.ctx, ss_id, grant, pdcch.dci); alloc_res = pdsch_sched.alloc_rar_pdsch(grant, pdcch.dci);
if (success_expected) { if (success_expected) {
// SIB1 allocation doesnt go outside CORESET#0 BW // SIB1 allocation doesnt go outside CORESET#0 BW
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
@ -217,8 +216,7 @@ void test_ue_pdsch()
pdcch_common.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 1, srsran_rnti_type_c, 0x4601); pdcch_common.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 1, srsran_rnti_type_c, 0x4601);
pdcch_ue.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 2, srsran_rnti_type_c, 0x4601); pdcch_ue.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 2, srsran_rnti_type_c, 0x4601);
prb_interval lims_common{pdcch_common.dci.ctx.coreset_start_rb, prb_interval lims_common = bwp_params.dci_fmt_1_0_prb_lims(pdcch_common.dci.ctx.coreset_id);
pdcch_common.dci.ctx.coreset_start_rb + bwp_params.coreset_bw(0)};
prb_interval lims_ue{0, bwp_params.nof_prb()}; prb_interval lims_ue{0, bwp_params.nof_prb()};
std::array<std::pair<uint32_t, prb_interval>, 4> grant_list = {std::make_pair(1, prb_interval{2, 4}), std::array<std::pair<uint32_t, prb_interval>, 4> grant_list = {std::make_pair(1, prb_interval{2, 4}),
@ -238,7 +236,7 @@ void test_ue_pdsch()
bool success_expected = grant.start() >= lims.start() and grant.stop() <= lims.stop(); bool success_expected = grant.start() >= lims.start() and grant.stop() <= lims.stop();
alloc_result check_ret = pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, grant); alloc_result check_ret = pdsch_sched.is_ue_grant_valid(ue_cc, ss_id, srsran_dci_format_nr_1_0, grant);
prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap avail_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
int pos = avail_prbs.find_lowest(0, avail_prbs.size(), false); int pos = avail_prbs.find_lowest(0, avail_prbs.size(), false);
TESTASSERT_EQ((int)lims.start(), pos); TESTASSERT_EQ((int)lims.start(), pos);
@ -246,10 +244,10 @@ void test_ue_pdsch()
TESTASSERT_EQ((int)lims.stop(), (pos < 0 ? (int)avail_prbs.size() : pos)); TESTASSERT_EQ((int)lims.stop(), (pos < 0 ? (int)avail_prbs.size() : pos));
printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un"); printf("Attempt %d should be %ssuccessful\n", i, success_expected ? "" : "un");
alloc_res = pdsch_sched.alloc_pdsch(pdcch.dci.ctx, ss_id, grant, pdcch.dci); alloc_res = pdsch_sched.alloc_ue_pdsch(ss_id, srsran_dci_format_nr_1_0, grant, ue_cc, pdcch.dci);
TESTASSERT(success_expected == alloc_res.has_value());
if (success_expected) { if (success_expected) {
// SIB1 allocation doesnt go outside CORESET#0 BW // SIB1 allocation doesnt go outside CORESET#0 BW
TESTASSERT(alloc_res.has_value());
TESTASSERT_EQ(1, pdschs.size()); TESTASSERT_EQ(1, pdschs.size());
TESTASSERT(&pdschs.back() == alloc_res.value()); TESTASSERT(&pdschs.back() == alloc_res.value());
TESTASSERT_EQ(0, pdcch.dci.time_domain_assigment); TESTASSERT_EQ(0, pdcch.dci.time_domain_assigment);
@ -258,7 +256,6 @@ void test_ue_pdsch()
test_dci_freq_assignment(bwp_params, grant, pdcch); test_dci_freq_assignment(bwp_params, grant, pdcch);
} else { } else {
TESTASSERT(alloc_res.is_error());
TESTASSERT(check_ret == alloc_res.error()); TESTASSERT(check_ret == alloc_res.error());
TESTASSERT_EQ(0, pdschs.size()); TESTASSERT_EQ(0, pdschs.size());
TESTASSERT(avail_prbs.any(grant.start(), grant.stop())); TESTASSERT(avail_prbs.any(grant.start(), grant.stop()));
@ -266,6 +263,55 @@ void test_ue_pdsch()
} }
} }
void test_pdsch_fail()
{
srsran::test_delimit_logger delimiter{"Test PDSCH Allocation Failure"};
// Create Cell and UE configs
sched_nr_impl::cell_cfg_t cell_cfg = get_cell_cfg();
sched_nr_impl::ue_cfg_t uecfg = get_ue_cfg(cell_cfg);
sched_nr_interface::sched_args_t sched_args;
bwp_params_t bwp_params{cell_cfg, sched_args, 0, 0};
ue_carrier_params_t ue_cc{0x4601, bwp_params, uecfg};
pdsch_list_t pdschs;
pdsch_alloc_result alloc_res;
pdsch_allocator pdsch_sched(bwp_params, 0, pdschs);
pdcch_dl_t pdcch_common, pdcch_ue, pdcch_rar, pdcch_si, pdcch;
pdcch_si.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 0, srsran_rnti_type_si, SRSRAN_SIRNTI);
pdcch_rar.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 1, srsran_rnti_type_ra, 0x2);
pdcch_common.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 1, srsran_rnti_type_c, 0x4601);
pdcch_ue.dci.ctx = generate_dci_ctx(bwp_params.cfg.pdcch, 2, srsran_rnti_type_c, 0x4601);
// Allocations of type 0 are not compatible with DCI format 1_0
rbg_bitmap rbgs(bwp_params.N_rbg);
rbgs.set(1);
rbgs.set(3);
prb_grant grant_type0 = rbgs;
TESTASSERT_EQ(alloc_result::invalid_grant_params, pdsch_sched.alloc_si_pdsch(0, grant_type0, pdcch_si.dci).error());
TESTASSERT_EQ(alloc_result::invalid_grant_params, pdsch_sched.alloc_rar_pdsch(grant_type0, pdcch_rar.dci).error());
TESTASSERT_EQ(alloc_result::invalid_grant_params,
pdsch_sched.alloc_ue_pdsch(1, srsran_dci_format_nr_1_0, grant_type0, ue_cc, pdcch.dci).error());
TESTASSERT_EQ(alloc_result::invalid_grant_params,
pdsch_sched.alloc_ue_pdsch(2, srsran_dci_format_nr_1_0, grant_type0, ue_cc, pdcch.dci).error());
// Resource Allocation type must be compatible with UE PDSCH configuration
TESTASSERT_EQ(alloc_result::invalid_grant_params,
pdsch_sched.alloc_ue_pdsch(2, srsran_dci_format_nr_1_1, grant_type0, ue_cc, pdcch.dci).error());
// Allocations of DCI format 1_0 should start from CORESET first RB and their BW should be limited by CORESET#0 BW
prb_grant grant_type1 = prb_interval{0, bwp_params.coreset_prb_range(0).stop()};
TESTASSERT(pdsch_sched.alloc_ue_pdsch(1, srsran_dci_format_nr_1_0, grant_type1, ue_cc, pdcch.dci).is_error());
grant_type1 = prb_interval{bwp_params.coreset_prb_range(0).start(), bwp_params.nof_prb()};
TESTASSERT(pdsch_sched.alloc_ue_pdsch(1, srsran_dci_format_nr_1_0, grant_type1, ue_cc, pdcch.dci).is_error());
TESTASSERT(pdsch_sched.alloc_ue_pdsch(2, srsran_dci_format_nr_1_0, grant_type1, ue_cc, pdcch.dci).has_value());
// PRB collisions are detected
TESTASSERT(pdsch_sched.alloc_ue_pdsch(2, srsran_dci_format_nr_1_0, prb_interval{5, 6}, ue_cc, pdcch.dci).is_error());
}
void test_multi_pdsch() void test_multi_pdsch()
{ {
srsran::test_delimit_logger delimiter{"Test Multiple PDSCH Allocations"}; srsran::test_delimit_logger delimiter{"Test Multiple PDSCH Allocations"};
@ -297,13 +343,13 @@ void test_multi_pdsch()
prb_bitmap sib_prbs = ~used_prbs; prb_bitmap sib_prbs = ~used_prbs;
int first_prb = sib_prbs.find_lowest(0, sib_prbs.size(), true); int first_prb = sib_prbs.find_lowest(0, sib_prbs.size(), true);
prb_interval sib_grant{(uint32_t)first_prb, sib1_grant_size}; prb_interval sib_grant{(uint32_t)first_prb, sib1_grant_size};
TESTASSERT_EQ(alloc_result::success, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, sib_grant)); TESTASSERT_EQ(alloc_result::success, pdsch_sched.is_si_grant_valid(ss_id, sib_grant));
alloc_res = pdsch_sched.alloc_pdsch(pdcch->dci.ctx, ss_id, sib_grant, pdcch->dci); alloc_res = pdsch_sched.alloc_si_pdsch(ss_id, sib_grant, pdcch->dci);
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
test_dci_freq_assignment(bwp_params, sib_grant, *pdcch); test_dci_freq_assignment(bwp_params, sib_grant, *pdcch);
prb_bitmap used_prbs_sib1 = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap used_prbs_sib1 = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
TESTASSERT_EQ(used_prbs_sib1.count(), used_prbs.count() + sib_grant.length()); TESTASSERT_EQ(used_prbs_sib1.count(), used_prbs.count() + sib_grant.length());
TESTASSERT_EQ(alloc_result::sch_collision, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, sib_grant)); TESTASSERT_EQ(alloc_result::sch_collision, pdsch_sched.is_si_grant_valid(ss_id, sib_grant));
prb_bitmap last_prb_bitmap(used_prbs.size()); prb_bitmap last_prb_bitmap(used_prbs.size());
last_prb_bitmap.fill(sib_grant.start(), sib_grant.stop()); last_prb_bitmap.fill(sib_grant.start(), sib_grant.stop());
@ -316,13 +362,14 @@ void test_multi_pdsch()
first_prb = ue_prbs.find_lowest(0, ue_prbs.size(), true); first_prb = ue_prbs.find_lowest(0, ue_prbs.size(), true);
uint32_t ue_grant_size = 10; uint32_t ue_grant_size = 10;
prb_interval ue_grant{(uint32_t)first_prb, ue_grant_size}; prb_interval ue_grant{(uint32_t)first_prb, ue_grant_size};
TESTASSERT_EQ(alloc_result::success, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, ue_grant)); TESTASSERT_EQ(alloc_result::success, pdsch_sched.is_ue_grant_valid(ue_cc, ss_id, srsran_dci_format_nr_1_0, ue_grant));
alloc_res = pdsch_sched.alloc_pdsch(pdcch->dci.ctx, ss_id, ue_grant, pdcch->dci); alloc_res = pdsch_sched.alloc_ue_pdsch(ss_id, srsran_dci_format_nr_1_0, ue_grant, ue_cc, pdcch->dci);
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
test_dci_freq_assignment(bwp_params, ue_grant, *pdcch); test_dci_freq_assignment(bwp_params, ue_grant, *pdcch);
prb_bitmap used_prbs_ue = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap used_prbs_ue = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
TESTASSERT_EQ(used_prbs_ue.count(), used_prbs_sib1.count() + ue_grant.length()); TESTASSERT_EQ(used_prbs_ue.count(), used_prbs_sib1.count() + ue_grant.length());
TESTASSERT_EQ(alloc_result::sch_collision, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, ue_grant)); TESTASSERT_EQ(alloc_result::sch_collision,
pdsch_sched.is_ue_grant_valid(ue_cc, ss_id, srsran_dci_format_nr_1_0, ue_grant));
last_prb_bitmap.reset(); last_prb_bitmap.reset();
last_prb_bitmap.fill(ue_grant.start(), ue_grant.stop()); last_prb_bitmap.fill(ue_grant.start(), ue_grant.stop());
@ -334,13 +381,15 @@ void test_multi_pdsch()
used_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); used_prbs = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
prb_interval ue_grant2 = find_empty_interval_of_length(used_prbs, used_prbs_ue.size(), 0); prb_interval ue_grant2 = find_empty_interval_of_length(used_prbs, used_prbs_ue.size(), 0);
TESTASSERT_EQ(bwp_params.nof_prb(), ue_grant2.stop()); TESTASSERT_EQ(bwp_params.nof_prb(), ue_grant2.stop());
TESTASSERT_EQ(alloc_result::success, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, ue_grant2)); TESTASSERT_EQ(alloc_result::success,
alloc_res = pdsch_sched.alloc_pdsch(pdcch->dci.ctx, ss_id, ue_grant2, pdcch->dci); pdsch_sched.is_ue_grant_valid(ue_cc, ss_id, srsran_dci_format_nr_1_0, ue_grant2));
alloc_res = pdsch_sched.alloc_ue_pdsch(ss_id, srsran_dci_format_nr_1_0, ue_grant2, ue_cc, pdcch->dci);
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
test_dci_freq_assignment(bwp_params, ue_grant2, *pdcch); test_dci_freq_assignment(bwp_params, ue_grant2, *pdcch);
prb_bitmap used_prbs_ue2 = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0); prb_bitmap used_prbs_ue2 = pdsch_sched.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
TESTASSERT_EQ(used_prbs_ue2.count(), used_prbs.count() + ue_grant2.length()); TESTASSERT_EQ(used_prbs_ue2.count(), used_prbs.count() + ue_grant2.length());
TESTASSERT_EQ(alloc_result::sch_collision, pdsch_sched.is_grant_valid(ss_id, srsran_dci_format_nr_1_0, ue_grant2)); TESTASSERT_EQ(alloc_result::sch_collision,
pdsch_sched.is_ue_grant_valid(ue_cc, ss_id, srsran_dci_format_nr_1_0, ue_grant2));
last_prb_bitmap.reset(); last_prb_bitmap.reset();
last_prb_bitmap.fill(ue_grant2.start(), ue_grant2.stop()); last_prb_bitmap.fill(ue_grant2.start(), ue_grant2.stop());
@ -382,7 +431,7 @@ void test_multi_pusch()
uint32_t ue_grant_size = 10; uint32_t ue_grant_size = 10;
prb_interval ue_grant = find_empty_interval_of_length(used_prbs, ue_grant_size); prb_interval ue_grant = find_empty_interval_of_length(used_prbs, ue_grant_size);
TESTASSERT_EQ(alloc_result::success, pusch_sched.is_grant_valid(srsran_search_space_type_common_1, ue_grant)); TESTASSERT_EQ(alloc_result::success, pusch_sched.is_grant_valid(srsran_search_space_type_common_1, ue_grant));
alloc_res = pusch_sched.alloc_pusch(pdcch->dci.ctx, ue_grant, pdcch->dci); alloc_res = pusch_sched.alloc_pusch(pdcch->dci.ctx.ss_type, ue_grant, pdcch->dci);
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
prb_bitmap used_prbs_ue1 = pusch_sched.occupied_prbs(); prb_bitmap used_prbs_ue1 = pusch_sched.occupied_prbs();
TESTASSERT_EQ(used_prbs_ue1.count(), used_prbs.count() + ue_grant.length()); TESTASSERT_EQ(used_prbs_ue1.count(), used_prbs.count() + ue_grant.length());
@ -399,7 +448,7 @@ void test_multi_pusch()
used_prbs = pusch_sched.occupied_prbs(); used_prbs = pusch_sched.occupied_prbs();
prb_interval ue2_grant = find_empty_interval_of_length(used_prbs, used_prbs.size()); prb_interval ue2_grant = find_empty_interval_of_length(used_prbs, used_prbs.size());
TESTASSERT_EQ(alloc_result::success, pusch_sched.is_grant_valid(srsran_search_space_type_ue, ue2_grant)); TESTASSERT_EQ(alloc_result::success, pusch_sched.is_grant_valid(srsran_search_space_type_ue, ue2_grant));
alloc_res = pusch_sched.alloc_pusch(pdcch->dci.ctx, ue2_grant, pdcch->dci); alloc_res = pusch_sched.alloc_pusch(pdcch->dci.ctx.ss_type, ue2_grant, pdcch->dci);
TESTASSERT(alloc_res.has_value()); TESTASSERT(alloc_res.has_value());
prb_bitmap used_prbs_ue2 = pusch_sched.occupied_prbs(); prb_bitmap used_prbs_ue2 = pusch_sched.occupied_prbs();
TESTASSERT_EQ(used_prbs_ue2.count(), used_prbs.count() + ue2_grant.length()); TESTASSERT_EQ(used_prbs_ue2.count(), used_prbs.count() + ue2_grant.length());
@ -427,6 +476,7 @@ int main()
srsenb::test_si(); srsenb::test_si();
srsenb::test_rar(); srsenb::test_rar();
srsenb::test_ue_pdsch(); srsenb::test_ue_pdsch();
srsenb::test_pdsch_fail();
srsenb::test_multi_pdsch(); srsenb::test_multi_pdsch();
srsenb::test_multi_pusch(); srsenb::test_multi_pusch();
} }
Loading…
Cancel
Save