Merge pull request #585 from YosysHQ/gatecat/remove-ivbfc
Remove isValidBelForCell
This commit is contained in:
commit
a77ceec5cf
@ -1169,7 +1169,6 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual BelBucketId getBelBucketByName(IdString name) const = 0;
|
virtual BelBucketId getBelBucketByName(IdString name) const = 0;
|
||||||
virtual BelBucketId getBelBucketForBel(BelId bel) const = 0;
|
virtual BelBucketId getBelBucketForBel(BelId bel) const = 0;
|
||||||
virtual BelBucketId getBelBucketForCellType(IdString cell_type) const = 0;
|
virtual BelBucketId getBelBucketForCellType(IdString cell_type) const = 0;
|
||||||
virtual bool isValidBelForCell(CellInfo *cell, BelId bel) const = 0;
|
|
||||||
virtual bool isBelLocationValid(BelId bel) const = 0;
|
virtual bool isBelLocationValid(BelId bel) const = 0;
|
||||||
virtual typename R::CellTypeRangeT getCellTypes() const = 0;
|
virtual typename R::CellTypeRangeT getCellTypes() const = 0;
|
||||||
virtual typename R::BelBucketRangeT getBelBuckets() const = 0;
|
virtual typename R::BelBucketRangeT getBelBuckets() const = 0;
|
||||||
@ -1420,7 +1419,6 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
|||||||
{
|
{
|
||||||
return getBelBucketByName(cell_type);
|
return getBelBucketByName(cell_type);
|
||||||
};
|
};
|
||||||
virtual bool isValidBelForCell(CellInfo *cell, BelId bel) const override { return true; }
|
|
||||||
virtual bool isBelLocationValid(BelId bel) const override { return true; }
|
virtual bool isBelLocationValid(BelId bel) const override { return true; }
|
||||||
virtual typename R::CellTypeRangeT getCellTypes() const override
|
virtual typename R::CellTypeRangeT getCellTypes() const override
|
||||||
{
|
{
|
||||||
|
@ -118,8 +118,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
|||||||
}
|
}
|
||||||
IdString targetType = cell->type;
|
IdString targetType = cell->type;
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->isValidBelForCellType(targetType, bel) &&
|
if (ctx->isValidBelForCellType(targetType, bel)) {
|
||||||
(!require_legality || ctx->isValidBelForCell(cell, bel))) {
|
|
||||||
if (ctx->checkBelAvail(bel)) {
|
if (ctx->checkBelAvail(bel)) {
|
||||||
wirelen_t wirelen = get_cell_metric_at_bel(ctx, cell, bel, MetricType::COST);
|
wirelen_t wirelen = get_cell_metric_at_bel(ctx, cell, bel, MetricType::COST);
|
||||||
if (iters >= 4)
|
if (iters >= 4)
|
||||||
@ -155,12 +154,20 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
|||||||
ctx->unbindBel(ripup_target->bel);
|
ctx->unbindBel(ripup_target->bel);
|
||||||
best_bel = ripup_bel;
|
best_bel = ripup_bel;
|
||||||
} else {
|
} else {
|
||||||
|
ripup_target = nullptr;
|
||||||
all_placed = true;
|
all_placed = true;
|
||||||
}
|
}
|
||||||
|
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
||||||
|
if (require_legality && !ctx->isBelLocationValid(best_bel)) {
|
||||||
|
ctx->unbindBel(best_bel);
|
||||||
|
if (ripup_target != nullptr) {
|
||||||
|
ctx->bindBel(best_bel, ripup_target, STRENGTH_WEAK);
|
||||||
|
}
|
||||||
|
all_placed = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx), ctx->nameOfBel(best_bel));
|
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx), ctx->nameOfBel(best_bel));
|
||||||
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
|
||||||
|
|
||||||
cell = ripup_target;
|
cell = ripup_target;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -387,7 +394,7 @@ class ConstraintLegaliseWorker
|
|||||||
for (auto bel : ctx->getBelsByTile(cp.second.x, cp.second.y)) {
|
for (auto bel : ctx->getBelsByTile(cp.second.x, cp.second.y)) {
|
||||||
CellInfo *belCell = ctx->getBoundBelCell(bel);
|
CellInfo *belCell = ctx->getBoundBelCell(bel);
|
||||||
if (belCell != nullptr && !solution.count(belCell->name)) {
|
if (belCell != nullptr && !solution.count(belCell->name)) {
|
||||||
if (!ctx->isValidBelForCell(belCell, bel)) {
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
NPNR_ASSERT(belCell->belStrength < STRENGTH_STRONG);
|
NPNR_ASSERT(belCell->belStrength < STRENGTH_STRONG);
|
||||||
ctx->unbindBel(bel);
|
ctx->unbindBel(bel);
|
||||||
rippedCells.insert(belCell->name);
|
rippedCells.insert(belCell->name);
|
||||||
|
@ -167,13 +167,6 @@ class SAPlacer
|
|||||||
"\'%s\' of type \'%s\'\n",
|
"\'%s\' of type \'%s\'\n",
|
||||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||||
}
|
}
|
||||||
if (!ctx->isValidBelForCell(cell, bel)) {
|
|
||||||
IdString bel_type = ctx->getBelType(bel);
|
|
||||||
log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
|
|
||||||
"\'%s\' of type \'%s\'\n",
|
|
||||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto bound_cell = ctx->getBoundBelCell(bel);
|
auto bound_cell = ctx->getBoundBelCell(bel);
|
||||||
if (bound_cell) {
|
if (bound_cell) {
|
||||||
log_error(
|
log_error(
|
||||||
@ -182,6 +175,12 @@ class SAPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindBel(bel, cell, STRENGTH_USER);
|
ctx->bindBel(bel, cell, STRENGTH_USER);
|
||||||
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
|
IdString bel_type = ctx->getBelType(bel);
|
||||||
|
log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
|
||||||
|
"\'%s\' of type \'%s\'\n",
|
||||||
|
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||||
|
}
|
||||||
locked_bels.insert(bel);
|
locked_bels.insert(bel);
|
||||||
placed_cells++;
|
placed_cells++;
|
||||||
}
|
}
|
||||||
@ -444,7 +443,7 @@ class SAPlacer
|
|||||||
IdString targetType = cell->type;
|
IdString targetType = cell->type;
|
||||||
|
|
||||||
auto proc_bel = [&](BelId bel) {
|
auto proc_bel = [&](BelId bel) {
|
||||||
if (ctx->isValidBelForCellType(targetType, bel) && ctx->isValidBelForCell(cell, bel)) {
|
if (ctx->isValidBelForCellType(targetType, bel)) {
|
||||||
if (ctx->checkBelAvail(bel)) {
|
if (ctx->checkBelAvail(bel)) {
|
||||||
uint64_t score = ctx->rng64();
|
uint64_t score = ctx->rng64();
|
||||||
if (score <= best_score) {
|
if (score <= best_score) {
|
||||||
@ -480,10 +479,20 @@ class SAPlacer
|
|||||||
ctx->unbindBel(ripup_target->bel);
|
ctx->unbindBel(ripup_target->bel);
|
||||||
best_bel = ripup_bel;
|
best_bel = ripup_bel;
|
||||||
} else {
|
} else {
|
||||||
|
ripup_target = nullptr;
|
||||||
all_placed = true;
|
all_placed = true;
|
||||||
}
|
}
|
||||||
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
||||||
|
|
||||||
|
if (!ctx->isBelLocationValid(best_bel)) {
|
||||||
|
ctx->unbindBel(best_bel);
|
||||||
|
if (ripup_target != nullptr) {
|
||||||
|
ctx->bindBel(best_bel, ripup_target, STRENGTH_WEAK);
|
||||||
|
}
|
||||||
|
all_placed = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Back annotate location
|
// Back annotate location
|
||||||
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
||||||
cell = ripup_target;
|
cell = ripup_target;
|
||||||
|
@ -392,13 +392,6 @@ class HeAPPlacer
|
|||||||
"\'%s\' of type \'%s\'\n",
|
"\'%s\' of type \'%s\'\n",
|
||||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||||
}
|
}
|
||||||
if (!ctx->isValidBelForCell(cell, bel)) {
|
|
||||||
IdString bel_type = ctx->getBelType(bel);
|
|
||||||
log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
|
|
||||||
"\'%s\' of type \'%s\'\n",
|
|
||||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto bound_cell = ctx->getBoundBelCell(bel);
|
auto bound_cell = ctx->getBoundBelCell(bel);
|
||||||
if (bound_cell) {
|
if (bound_cell) {
|
||||||
log_error("Cell \'%s\' cannot be bound to bel \'%s\' since it is already bound to cell \'%s\'\n",
|
log_error("Cell \'%s\' cannot be bound to bel \'%s\' since it is already bound to cell \'%s\'\n",
|
||||||
@ -406,6 +399,12 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindBel(bel, cell, STRENGTH_USER);
|
ctx->bindBel(bel, cell, STRENGTH_USER);
|
||||||
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
|
IdString bel_type = ctx->getBelType(bel);
|
||||||
|
log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
|
||||||
|
"\'%s\' of type \'%s\'\n",
|
||||||
|
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||||
|
}
|
||||||
placed_cells++;
|
placed_cells++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,12 +570,13 @@ class HeAPPlacer
|
|||||||
place_cells.push_back(ci);
|
place_cells.push_back(ci);
|
||||||
placed = true;
|
placed = true;
|
||||||
} else {
|
} else {
|
||||||
if (ctx->isValidBelForCell(ci, bel)) {
|
ctx->bindBel(bel, ci, STRENGTH_STRONG);
|
||||||
ctx->bindBel(bel, ci, STRENGTH_STRONG);
|
if (ctx->isBelLocationValid(bel)) {
|
||||||
cell_locs[cell.first].locked = true;
|
cell_locs[cell.first].locked = true;
|
||||||
placed = true;
|
placed = true;
|
||||||
bels_used.insert(bel);
|
bels_used.insert(bel);
|
||||||
} else {
|
} else {
|
||||||
|
ctx->unbindBel(bel);
|
||||||
available_bels.at(ci->type).push_front(bel);
|
available_bels.at(ci->type).push_front(bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,8 +652,8 @@ strict legality enforcement. It is not required that all bels within a bucket
|
|||||||
are strictly equivelant.
|
are strictly equivelant.
|
||||||
|
|
||||||
Strict legality step will enforce those differences, along with additional
|
Strict legality step will enforce those differences, along with additional
|
||||||
local constraints. `isValidBelForCell`, `isValidBelForCellType`, and
|
local constraints. `isValidBelForCellType`, and `isBelLocationValid` are used
|
||||||
`isBelLocationValid` are used to enforce strict legality checks.
|
to enforce strict legality checks.
|
||||||
|
|
||||||
### BelBucketRangeT getBelBuckets() const
|
### BelBucketRangeT getBelBuckets() const
|
||||||
|
|
||||||
@ -702,18 +702,10 @@ return the same value regardless if other cells are placed within the fabric.
|
|||||||
|
|
||||||
*BaseArch default: returns `cell_type == getBelType(bel)`*
|
*BaseArch default: returns `cell_type == getBelType(bel)`*
|
||||||
|
|
||||||
### bool isValidBelForCell(CellInfo \*cell, BelId bel) const
|
|
||||||
|
|
||||||
Returns true if the given cell can be bound to the given bel, considering
|
|
||||||
other bound resources. For example, this can be used if there is only
|
|
||||||
a certain number of different clock signals allowed for a group of bels.
|
|
||||||
|
|
||||||
*BaseArch default: returns true*
|
|
||||||
|
|
||||||
### bool isBelLocationValid(BelId bel) const
|
### bool isBelLocationValid(BelId bel) const
|
||||||
|
|
||||||
Returns true if a bell in the current configuration is valid, i.e. if
|
Returns true if a bel in the current configuration is legal (for example,
|
||||||
`isValidBelForCell()` would return true for the current mapping.
|
a flipflop's clock signal is correctly shared with all bels in a slice.)
|
||||||
|
|
||||||
*BaseArch default: returns true*
|
*BaseArch default: returns true*
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ The job of the placer in nextpnr is to find a suitable bel for each cell in the
|
|||||||
|
|
||||||
Placers might want to create their own indices of bels (for example, bels by type and location) to speed up the search.
|
Placers might want to create their own indices of bels (for example, bels by type and location) to speed up the search.
|
||||||
|
|
||||||
As nextpnr allows arbitrary constraints on bels for more advanced packer-free flows and complex real-world architectures; placements must be checked for legality using `isValidBelForCell` (before placement) or `isBelLocationValid` (after placement) and the placement rejected if invalid. For analytical placement algorithms; after creating a spread-out AP solution the legality of placing each cell needs to be checked. In practice, the cost of this is fairly low as the architecture should ensure these functions are as fast as possible.
|
As nextpnr allows arbitrary constraints on bels for more advanced packer-free flows and complex real-world architectures; placements must be checked for legality using `isBelLocationValid` (after placement) and the placement rejected if invalid. For analytical placement algorithms; after creating a spread-out AP solution the legality of placing each cell needs to be checked. In practice, the cost of this is fairly low as the architecture should ensure these functions are as fast as possible.
|
||||||
|
|
||||||
There are several routes for timing information in the placer:
|
There are several routes for timing information in the placer:
|
||||||
- sink `PortRef`s have a `budget` value annotated by calling `assign_budget` which is an estimate of the maximum delay that an arc may have
|
- sink `PortRef`s have a `budget` value annotated by calling `assign_budget` which is an estimate of the maximum delay that an arc may have
|
||||||
|
@ -864,7 +864,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// Placement validity checks
|
// Placement validity checks
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override;
|
|
||||||
bool isBelLocationValid(BelId bel) const override;
|
bool isBelLocationValid(BelId bel) const override;
|
||||||
|
|
||||||
// Helper function for above
|
// Helper function for above
|
||||||
|
@ -82,38 +82,14 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
return slices_compatible(bel_cells);
|
return slices_compatible(bel_cells);
|
||||||
} else {
|
} else {
|
||||||
CellInfo *cell = getBoundBelCell(bel);
|
CellInfo *cell = getBoundBelCell(bel);
|
||||||
if (cell == nullptr)
|
if (cell == nullptr) {
|
||||||
|
return true;
|
||||||
|
} else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) {
|
||||||
|
return args.type != ArchArgs::LFE5U_25F && args.type != ArchArgs::LFE5U_45F &&
|
||||||
|
args.type != ArchArgs::LFE5U_85F;
|
||||||
|
} else {
|
||||||
return true;
|
return true;
|
||||||
else
|
|
||||||
return isValidBelForCell(cell, bel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|
||||||
{
|
|
||||||
if (cell->type == id_TRELLIS_SLICE) {
|
|
||||||
NPNR_ASSERT(getBelType(bel) == id_TRELLIS_SLICE);
|
|
||||||
|
|
||||||
std::vector<const CellInfo *> bel_cells;
|
|
||||||
Loc bel_loc = getBelLocation(bel);
|
|
||||||
|
|
||||||
if (cell->sliceInfo.has_l6mux && ((bel_loc.z % 2) == 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
|
||||||
CellInfo *cell_other = getBoundBelCell(bel_other);
|
|
||||||
if (cell_other != nullptr && bel_other != bel) {
|
|
||||||
bel_cells.push_back(cell_other);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bel_cells.push_back(cell);
|
|
||||||
return slices_compatible(bel_cells);
|
|
||||||
} else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) {
|
|
||||||
return args.type != ArchArgs::LFE5U_25F && args.type != ArchArgs::LFE5U_45F && args.type != ArchArgs::LFE5U_85F;
|
|
||||||
} else {
|
|
||||||
// other checks
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +44,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
.def("place", &Context::place)
|
.def("place", &Context::place)
|
||||||
.def("route", &Context::route);
|
.def("route", &Context::route);
|
||||||
|
|
||||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCell), &Context::isValidBelForCell, pass_through<bool>,
|
|
||||||
addr_and_unwrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "isValidBelForCell");
|
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
||||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||||
|
@ -403,33 +403,35 @@ class Ecp5GlobalRouter
|
|||||||
bool dedicated_routing = false;
|
bool dedicated_routing = false;
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) {
|
if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) {
|
||||||
if (ctx->isValidBelForCell(dcc, bel)) {
|
std::string belname = ctx->loc_info(bel)->bel_data[bel.index].name.get();
|
||||||
std::string belname = ctx->loc_info(bel)->bel_data[bel.index].name.get();
|
if (belname.at(0) == 'D' && using_ce)
|
||||||
if (belname.at(0) == 'D' && using_ce)
|
continue; // don't allow DCCs with CE at center
|
||||||
continue; // don't allow DCCs with CE at center
|
ctx->bindBel(bel, dcc, STRENGTH_LOCKED);
|
||||||
ctx->bindBel(bel, dcc, STRENGTH_LOCKED);
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing);
|
|
||||||
if (wirelen < best_wirelen) {
|
|
||||||
if (dedicated_routing) {
|
|
||||||
best_bel_pclkcib = WireId();
|
|
||||||
} else {
|
|
||||||
bool found_pclkcib = false;
|
|
||||||
for (WireId pclkcib : get_candidate_pclkcibs(bel)) {
|
|
||||||
if (used_pclkcib.count(pclkcib))
|
|
||||||
continue;
|
|
||||||
found_pclkcib = true;
|
|
||||||
best_bel_pclkcib = pclkcib;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!found_pclkcib)
|
|
||||||
goto pclkcib_fail;
|
|
||||||
}
|
|
||||||
best_bel = bel;
|
|
||||||
best_wirelen = wirelen;
|
|
||||||
}
|
|
||||||
pclkcib_fail:
|
|
||||||
ctx->unbindBel(bel);
|
ctx->unbindBel(bel);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing);
|
||||||
|
if (wirelen < best_wirelen) {
|
||||||
|
if (dedicated_routing) {
|
||||||
|
best_bel_pclkcib = WireId();
|
||||||
|
} else {
|
||||||
|
bool found_pclkcib = false;
|
||||||
|
for (WireId pclkcib : get_candidate_pclkcibs(bel)) {
|
||||||
|
if (used_pclkcib.count(pclkcib))
|
||||||
|
continue;
|
||||||
|
found_pclkcib = true;
|
||||||
|
best_bel_pclkcib = pclkcib;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found_pclkcib)
|
||||||
|
goto pclkcib_fail;
|
||||||
|
}
|
||||||
|
best_bel = bel;
|
||||||
|
best_wirelen = wirelen;
|
||||||
|
}
|
||||||
|
pclkcib_fail:
|
||||||
|
ctx->unbindBel(bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NPNR_ASSERT(best_bel != BelId());
|
NPNR_ASSERT(best_bel != BelId());
|
||||||
|
@ -1280,17 +1280,6 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
return bel_info(chip_info, bel).valid_cells[get_cell_type_index(cell_type)];
|
return bel_info(chip_info, bel).valid_cells[get_cell_type_index(cell_type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether or not a given cell can be placed at a given Bel
|
|
||||||
// This is not intended for Bel type checks, but finer-grained constraints
|
|
||||||
// such as conflicting set/reset signals, etc
|
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override
|
|
||||||
{
|
|
||||||
NPNR_ASSERT(isValidBelForCellType(cell->type, bel));
|
|
||||||
|
|
||||||
// FIXME: Implement this
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true whether all Bels at a given location are valid
|
// Return true whether all Bels at a given location are valid
|
||||||
bool isBelLocationValid(BelId bel) const override
|
bool isBelLocationValid(BelId bel) const override
|
||||||
{
|
{
|
||||||
|
@ -44,9 +44,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
.def("place", &Context::place)
|
.def("place", &Context::place)
|
||||||
.def("route", &Context::route);
|
.def("route", &Context::route);
|
||||||
|
|
||||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCell), &Context::isValidBelForCell, pass_through<bool>,
|
|
||||||
addr_and_unwrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "isValidBelForCell");
|
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
||||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||||
|
@ -650,21 +650,6 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
return tmg.clockingInfo.at(port).at(index);
|
return tmg.clockingInfo.at(port).at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|
||||||
{
|
|
||||||
std::vector<const CellInfo *> cells;
|
|
||||||
cells.push_back(cell);
|
|
||||||
Loc loc = getBelLocation(bel);
|
|
||||||
for (auto tbel : getBelsByTile(loc.x, loc.y)) {
|
|
||||||
if (tbel == bel)
|
|
||||||
continue;
|
|
||||||
CellInfo *bound = getBoundBelCell(tbel);
|
|
||||||
if (bound != nullptr)
|
|
||||||
cells.push_back(bound);
|
|
||||||
}
|
|
||||||
return cellsCompatible(cells.data(), int(cells.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
std::vector<const CellInfo *> cells;
|
std::vector<const CellInfo *> cells;
|
||||||
|
@ -357,7 +357,6 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override;
|
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override;
|
||||||
|
|
||||||
bool isValidBelForCellType(IdString cell_type, BelId bel) const override { return cell_type == getBelType(bel); }
|
bool isValidBelForCellType(IdString cell_type, BelId bel) const override { return cell_type == getBelType(bel); }
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override;
|
|
||||||
bool isBelLocationValid(BelId bel) const override;
|
bool isBelLocationValid(BelId bel) const override;
|
||||||
|
|
||||||
static const std::string defaultPlacer;
|
static const std::string defaultPlacer;
|
||||||
|
@ -1092,21 +1092,6 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
return tmg.clockingInfo.at(port).at(index);
|
return tmg.clockingInfo.at(port).at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|
||||||
{
|
|
||||||
std::vector<const CellInfo *> cells;
|
|
||||||
cells.push_back(cell);
|
|
||||||
Loc loc = getBelLocation(bel);
|
|
||||||
for (auto tbel : getBelsByTile(loc.x, loc.y)) {
|
|
||||||
if (tbel == bel)
|
|
||||||
continue;
|
|
||||||
CellInfo *bound = getBoundBelCell(tbel);
|
|
||||||
if (bound != nullptr)
|
|
||||||
cells.push_back(bound);
|
|
||||||
}
|
|
||||||
return cellsCompatible(cells.data(), int(cells.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
std::vector<const CellInfo *> cells;
|
std::vector<const CellInfo *> cells;
|
||||||
|
@ -449,7 +449,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const;
|
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const;
|
||||||
|
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
|
|
||||||
bool isBelLocationValid(BelId bel) const;
|
bool isBelLocationValid(BelId bel) const;
|
||||||
|
|
||||||
static const std::string defaultPlacer;
|
static const std::string defaultPlacer;
|
||||||
|
@ -834,11 +834,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Perform placement validity checks, returning false on failure (all
|
// Perform placement validity checks, returning false on failure (all
|
||||||
// implemented in arch_place.cc)
|
// implemented in arch_place.cc)
|
||||||
|
|
||||||
// Whether or not a given cell can be placed at a given Bel
|
|
||||||
// This is not intended for Bel type checks, but finer-grained constraints
|
|
||||||
// such as conflicting set/reset signals, etc
|
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override;
|
|
||||||
|
|
||||||
// Return true whether all Bels at a given location are valid
|
// Return true whether all Bels at a given location are valid
|
||||||
bool isBelLocationValid(BelId bel) const override;
|
bool isBelLocationValid(BelId bel) const override;
|
||||||
|
|
||||||
|
@ -70,6 +70,18 @@ bool Arch::logic_cells_compatible(const CellInfo **it, const size_t size) const
|
|||||||
return locals_count <= 32;
|
return locals_count <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool _io_pintype_need_clk_in(unsigned pin_type) { return (pin_type & 0x01) == 0x00; }
|
||||||
|
|
||||||
|
static inline bool _io_pintype_need_clk_out(unsigned pin_type)
|
||||||
|
{
|
||||||
|
return ((pin_type & 0x30) == 0x30) || ((pin_type & 0x3c) && ((pin_type & 0x0c) != 0x08));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _io_pintype_need_clk_en(unsigned pin_type)
|
||||||
|
{
|
||||||
|
return _io_pintype_need_clk_in(pin_type) || _io_pintype_need_clk_out(pin_type);
|
||||||
|
}
|
||||||
|
|
||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
if (getBelType(bel) == id_ICESTORM_LC) {
|
if (getBelType(bel) == id_ICESTORM_LC) {
|
||||||
@ -83,136 +95,103 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
}
|
}
|
||||||
return logic_cells_compatible(bel_cells.data(), num_cells);
|
return logic_cells_compatible(bel_cells.data(), num_cells);
|
||||||
} else {
|
} else {
|
||||||
CellInfo *ci = getBoundBelCell(bel);
|
CellInfo *cell = getBoundBelCell(bel);
|
||||||
if (ci == nullptr)
|
if (cell == nullptr)
|
||||||
return true;
|
return true;
|
||||||
else
|
else if (cell->type == id_SB_IO) {
|
||||||
return isValidBelForCell(ci, bel);
|
// Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool _io_pintype_need_clk_in(unsigned pin_type) { return (pin_type & 0x01) == 0x00; }
|
// Find shared PLL by looking for driving bel siblings from D_IN_0
|
||||||
|
// that are a PLL clock output.
|
||||||
|
auto wire = getBelPinWire(bel, id_D_IN_0);
|
||||||
|
for (auto pin : getWireBelPins(wire)) {
|
||||||
|
if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) {
|
||||||
|
// Is there a PLL there ?
|
||||||
|
auto pll_cell = getBoundBelCell(pin.bel);
|
||||||
|
if (pll_cell == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
static inline bool _io_pintype_need_clk_out(unsigned pin_type)
|
// Is that port actually used ?
|
||||||
{
|
if ((pin.pin == id_PLLOUT_B) && !is_sb_pll40_dual(this, pll_cell))
|
||||||
return ((pin_type & 0x30) == 0x30) || ((pin_type & 0x3c) && ((pin_type & 0x0c) != 0x08));
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool _io_pintype_need_clk_en(unsigned pin_type)
|
// Is that SB_IO used at an input ?
|
||||||
{
|
if ((cell->ports[id_D_IN_0].net == nullptr) && (cell->ports[id_D_IN_1].net == nullptr))
|
||||||
return _io_pintype_need_clk_in(pin_type) || _io_pintype_need_clk_out(pin_type);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
||||||
{
|
if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(getCtx()))
|
||||||
if (cell->type == id_ICESTORM_LC) {
|
return true;
|
||||||
NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC);
|
|
||||||
|
|
||||||
std::array<const CellInfo *, 8> bel_cells;
|
// Conflict
|
||||||
size_t num_cells = 0;
|
return false;
|
||||||
|
}
|
||||||
Loc bel_loc = getBelLocation(bel);
|
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
|
||||||
CellInfo *ci_other = getBoundBelCell(bel_other);
|
|
||||||
if (ci_other != nullptr && bel_other != bel)
|
|
||||||
bel_cells[num_cells++] = ci_other;
|
|
||||||
}
|
|
||||||
|
|
||||||
bel_cells[num_cells++] = cell;
|
|
||||||
return logic_cells_compatible(bel_cells.data(), num_cells);
|
|
||||||
} else if (cell->type == id_SB_IO) {
|
|
||||||
// Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
|
|
||||||
|
|
||||||
// Find shared PLL by looking for driving bel siblings from D_IN_0
|
|
||||||
// that are a PLL clock output.
|
|
||||||
auto wire = getBelPinWire(bel, id_D_IN_0);
|
|
||||||
for (auto pin : getWireBelPins(wire)) {
|
|
||||||
if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) {
|
|
||||||
// Is there a PLL there ?
|
|
||||||
auto pll_cell = getBoundBelCell(pin.bel);
|
|
||||||
if (pll_cell == nullptr)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Is that port actually used ?
|
|
||||||
if ((pin.pin == id_PLLOUT_B) && !is_sb_pll40_dual(this, pll_cell))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Is that SB_IO used at an input ?
|
|
||||||
if ((cell->ports[id_D_IN_0].net == nullptr) && (cell->ports[id_D_IN_1].net == nullptr))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
|
||||||
if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(getCtx()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Conflict
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Loc ioLoc = getBelLocation(bel);
|
Loc ioLoc = getBelLocation(bel);
|
||||||
Loc compLoc = ioLoc;
|
Loc compLoc = ioLoc;
|
||||||
compLoc.z = 1 - compLoc.z;
|
compLoc.z = 1 - compLoc.z;
|
||||||
|
|
||||||
// Check LVDS pairing
|
// Check LVDS pairing
|
||||||
if (cell->ioInfo.lvds) {
|
if (cell->ioInfo.lvds) {
|
||||||
// Check correct z and complement location is free
|
// Check correct z and complement location is free
|
||||||
if (ioLoc.z != 0)
|
if (ioLoc.z != 0)
|
||||||
return false;
|
return false;
|
||||||
BelId compBel = getBelByLocation(compLoc);
|
BelId compBel = getBelByLocation(compLoc);
|
||||||
CellInfo *compCell = getBoundBelCell(compBel);
|
CellInfo *compCell = getBoundBelCell(compBel);
|
||||||
if (compCell)
|
if (compCell)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Check LVDS IO is not placed at complement location
|
||||||
|
BelId compBel = getBelByLocation(compLoc);
|
||||||
|
CellInfo *compCell = getBoundBelCell(compBel);
|
||||||
|
if (compCell && compCell->ioInfo.lvds)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check for conflicts on shared nets
|
||||||
|
// - CLOCK_ENABLE
|
||||||
|
// - OUTPUT_CLK
|
||||||
|
// - INPUT_CLK
|
||||||
|
if (compCell) {
|
||||||
|
bool use[6] = {
|
||||||
|
_io_pintype_need_clk_in(cell->ioInfo.pintype),
|
||||||
|
_io_pintype_need_clk_in(compCell->ioInfo.pintype),
|
||||||
|
_io_pintype_need_clk_out(cell->ioInfo.pintype),
|
||||||
|
_io_pintype_need_clk_out(compCell->ioInfo.pintype),
|
||||||
|
_io_pintype_need_clk_en(cell->ioInfo.pintype),
|
||||||
|
_io_pintype_need_clk_en(compCell->ioInfo.pintype),
|
||||||
|
};
|
||||||
|
NetInfo *nets[] = {
|
||||||
|
cell->ports[id_INPUT_CLK].net, compCell->ports[id_INPUT_CLK].net,
|
||||||
|
cell->ports[id_OUTPUT_CLK].net, compCell->ports[id_OUTPUT_CLK].net,
|
||||||
|
cell->ports[id_CLOCK_ENABLE].net, compCell->ports[id_CLOCK_ENABLE].net,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
if (use[i] && (nets[i] != nets[i ^ 1]) && (use[i ^ 1] || (nets[i ^ 1] != nullptr)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_bel_package_pin(bel) != "";
|
||||||
|
} else if (cell->type == id_SB_GB) {
|
||||||
|
if (cell->gbInfo.forPadIn)
|
||||||
|
return true;
|
||||||
|
NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr);
|
||||||
|
const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net;
|
||||||
|
int glb_id = get_driven_glb_netwk(bel);
|
||||||
|
if (net->is_reset && net->is_enable)
|
||||||
return false;
|
return false;
|
||||||
|
else if (net->is_reset)
|
||||||
|
return (glb_id % 2) == 0;
|
||||||
|
else if (net->is_enable)
|
||||||
|
return (glb_id % 2) == 1;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Check LVDS IO is not placed at complement location
|
// TODO: IO cell clock checks
|
||||||
BelId compBel = getBelByLocation(compLoc);
|
return true;
|
||||||
CellInfo *compCell = getBoundBelCell(compBel);
|
|
||||||
if (compCell && compCell->ioInfo.lvds)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check for conflicts on shared nets
|
|
||||||
// - CLOCK_ENABLE
|
|
||||||
// - OUTPUT_CLK
|
|
||||||
// - INPUT_CLK
|
|
||||||
if (compCell) {
|
|
||||||
bool use[6] = {
|
|
||||||
_io_pintype_need_clk_in(cell->ioInfo.pintype),
|
|
||||||
_io_pintype_need_clk_in(compCell->ioInfo.pintype),
|
|
||||||
_io_pintype_need_clk_out(cell->ioInfo.pintype),
|
|
||||||
_io_pintype_need_clk_out(compCell->ioInfo.pintype),
|
|
||||||
_io_pintype_need_clk_en(cell->ioInfo.pintype),
|
|
||||||
_io_pintype_need_clk_en(compCell->ioInfo.pintype),
|
|
||||||
};
|
|
||||||
NetInfo *nets[] = {
|
|
||||||
cell->ports[id_INPUT_CLK].net, compCell->ports[id_INPUT_CLK].net,
|
|
||||||
cell->ports[id_OUTPUT_CLK].net, compCell->ports[id_OUTPUT_CLK].net,
|
|
||||||
cell->ports[id_CLOCK_ENABLE].net, compCell->ports[id_CLOCK_ENABLE].net,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
if (use[i] && (nets[i] != nets[i ^ 1]) && (use[i ^ 1] || (nets[i ^ 1] != nullptr)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_bel_package_pin(bel) != "";
|
|
||||||
} else if (cell->type == id_SB_GB) {
|
|
||||||
if (cell->gbInfo.forPadIn)
|
|
||||||
return true;
|
|
||||||
NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr);
|
|
||||||
const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net;
|
|
||||||
int glb_id = get_driven_glb_netwk(bel);
|
|
||||||
if (net->is_reset && net->is_enable)
|
|
||||||
return false;
|
|
||||||
else if (net->is_reset)
|
|
||||||
return (glb_id % 2) == 0;
|
|
||||||
else if (net->is_enable)
|
|
||||||
return (glb_id % 2) == 1;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// TODO: IO cell clock checks
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +60,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
.def("place", &Context::place)
|
.def("place", &Context::place)
|
||||||
.def("route", &Context::route);
|
.def("route", &Context::route);
|
||||||
|
|
||||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCell), &Context::isValidBelForCell, pass_through<bool>,
|
|
||||||
addr_and_unwrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "isValidBelForCell");
|
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
||||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||||
|
@ -448,14 +448,6 @@ bool Arch::route()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|
||||||
{
|
|
||||||
// FIXME: Unlike ECP5, SLICEs in a given tile do not share a clock, so
|
|
||||||
// any SLICE Cell is valid for any BEL, even if some cells are already
|
|
||||||
// bound to BELs in the tile. However, this may need to be filled in once
|
|
||||||
// more than one LUT4 and DFF type is supported.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
|
@ -650,7 +650,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
bool route() override;
|
bool route() override;
|
||||||
|
|
||||||
// Placer
|
// Placer
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override;
|
|
||||||
bool isBelLocationValid(BelId bel) const override;
|
bool isBelLocationValid(BelId bel) const override;
|
||||||
|
|
||||||
static const std::string defaultPlacer;
|
static const std::string defaultPlacer;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
@ -44,9 +45,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
.def("place", &Context::place)
|
.def("place", &Context::place)
|
||||||
.def("route", &Context::route);
|
.def("route", &Context::route);
|
||||||
|
|
||||||
fn_wrapper_2a<Context, decltype(&Context::isValidBelForCell), &Context::isValidBelForCell, pass_through<bool>,
|
|
||||||
addr_and_unwrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "isValidBelForCell");
|
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
|
||||||
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
|
||||||
typedef std::unordered_map<IdString, IdString> AliasMap;
|
typedef std::unordered_map<IdString, IdString> AliasMap;
|
||||||
|
@ -1209,11 +1209,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Perform placement validity checks, returning false on failure (all
|
// Perform placement validity checks, returning false on failure (all
|
||||||
// implemented in arch_place.cc)
|
// implemented in arch_place.cc)
|
||||||
|
|
||||||
// Whether or not a given cell can be placed at a given Bel
|
|
||||||
// This is not intended for Bel type checks, but finer-grained constraints
|
|
||||||
// such as conflicting set/reset signals, etc
|
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const override;
|
|
||||||
|
|
||||||
// Return true whether all Bels at a given location are valid
|
// Return true whether all Bels at a given location are valid
|
||||||
bool isBelLocationValid(BelId bel) const override;
|
bool isBelLocationValid(BelId bel) const override;
|
||||||
|
|
||||||
|
@ -96,12 +96,6 @@ bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|
||||||
{
|
|
||||||
// FIXME
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
if (bel_tile_is(bel, LOC_LOGIC)) {
|
if (bel_tile_is(bel, LOC_LOGIC)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user