diff --git a/common/kernel/arch_api.h b/common/kernel/arch_api.h index 94a88338..56c5cf0a 100644 --- a/common/kernel/arch_api.h +++ b/common/kernel/arch_api.h @@ -135,7 +135,7 @@ template struct ArchAPI : BaseCtx virtual BelBucketId getBelBucketByName(IdString name) const = 0; virtual BelBucketId getBelBucketForBel(BelId bel) const = 0; virtual BelBucketId getBelBucketForCellType(IdString cell_type) const = 0; - virtual bool isBelLocationValid(BelId bel) const = 0; + virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const = 0; virtual typename R::CellTypeRangeT getCellTypes() const = 0; virtual typename R::BelBucketRangeT getBelBuckets() const = 0; virtual typename R::BucketBelRangeT getBelsInBucket(BelBucketId bucket) const = 0; diff --git a/common/kernel/arch_pybindings_shared.h b/common/kernel/arch_pybindings_shared.h index d78d240c..ac0eda07 100644 --- a/common/kernel/arch_pybindings_shared.h +++ b/common/kernel/arch_pybindings_shared.h @@ -127,8 +127,8 @@ fn_wrapper_0a, pass_through>::def_wrap(ctx_cls, "writeSVG"); -fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "isBelLocationValid"); +fn_wrapper_2a, + conv_from_str, pass_through>::def_wrap(ctx_cls, "isBelLocationValid"); // const\_range\ getBelBuckets() const fn_wrapper_0a struct BaseArch : ArchAPI { return getBelBucketByName(cell_type); }; - virtual bool isBelLocationValid(BelId bel) const override { return true; } + virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override { return true; } virtual typename R::CellTypeRangeT getCellTypes() const override { NPNR_ASSERT(cell_types_initialised); diff --git a/common/place/placer1.cc b/common/place/placer1.cc index 23264ce2..e37d3daf 100644 --- a/common/place/placer1.cc +++ b/common/place/placer1.cc @@ -173,7 +173,7 @@ class SAPlacer } ctx->bindBel(bel, cell, STRENGTH_USER); - if (!ctx->isBelLocationValid(bel)) { + if (!ctx->isBelLocationValid(bel, /* explain_invalid */ true)) { IdString bel_type = ctx->getBelType(bel); log_error("Bel \'%s\' of type \'%s\' is not valid for cell " "\'%s\' of type \'%s\'\n", @@ -404,7 +404,7 @@ class SAPlacer ctx->yield(); for (auto bel : ctx->getBels()) { CellInfo *cell = ctx->getBoundBelCell(bel); - if (!ctx->isBelLocationValid(bel)) { + if (!ctx->isBelLocationValid(bel, /* explain_invalid */ true)) { std::string cell_text = "no cell"; if (cell != nullptr) cell_text = std::string("cell '") + ctx->nameOf(cell) + "'"; diff --git a/common/place/placer_heap.cc b/common/place/placer_heap.cc index 8da4ee2e..0dfc29e6 100644 --- a/common/place/placer_heap.cc +++ b/common/place/placer_heap.cc @@ -327,7 +327,7 @@ class HeAPPlacer bool any_bad_placements = false; for (auto bel : ctx->getBels()) { CellInfo *cell = ctx->getBoundBelCell(bel); - if (!ctx->isBelLocationValid(bel)) { + if (!ctx->isBelLocationValid(bel, /* explain_invalid */ true)) { std::string cell_text = "no cell"; if (cell != nullptr) cell_text = std::string("cell '") + ctx->nameOf(cell) + "'"; @@ -434,7 +434,7 @@ class HeAPPlacer } ctx->bindBel(bel, cell, STRENGTH_USER); - if (!ctx->isBelLocationValid(bel)) { + if (!ctx->isBelLocationValid(bel, /* explain_invalid */ true)) { IdString bel_type = ctx->getBelType(bel); log_error("Bel \'%s\' of type \'%s\' is not valid for cell " "\'%s\' of type \'%s\'\n", diff --git a/docs/archapi.md b/docs/archapi.md index 39b2a6a9..3a7994de 100644 --- a/docs/archapi.md +++ b/docs/archapi.md @@ -698,11 +698,15 @@ return the same value regardless if other cells are placed within the fabric. *BaseArch default: returns `cell_type == getBelType(bel)`* -### bool isBelLocationValid(BelId bel) const +### bool isBelLocationValid(BelId bel, bool explain_invalid = false) const Returns true if a bel in the current configuration is legal (for example, a flipflop's clock signal is correctly shared with all bels in a slice.) +If and only if `explain_invalid` is set to true, then a message using +`log_nonfatal_error` should be printed explaining why the placement is invalid +to the end user. + *BaseArch default: returns true* ### static const std::string defaultPlacer diff --git a/docs/viaduct.md b/docs/viaduct.md index a59310f1..88398a05 100644 --- a/docs/viaduct.md +++ b/docs/viaduct.md @@ -64,7 +64,7 @@ X(F) ```c++ bool checkBelAvail(BelId bel) const; bool isValidBelForCellType(IdString cell_type, BelId bel) const; -bool isBelLocationValid(BelId bel) const; +bool isBelLocationValid(BelId bel, bool explain_invalid = false) const; bool checkWireAvail(WireId wire) const; bool checkPipAvail(PipId pip) const; bool checkPipAvailForNet(PipId pip, NetInfo *net) const; diff --git a/ecp5/arch.h b/ecp5/arch.h index a40719c1..6ce3c4ce 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -1010,7 +1010,7 @@ struct Arch : BaseArch // ------------------------------------------------- // Placement validity checks - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; // Helper function for above bool slices_compatible(LogicTileStatus *lts) const; diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index fed9c055..3151cc3e 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -178,7 +178,7 @@ bool Arch::slices_compatible(LogicTileStatus *lts) const return true; } -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { IdString bel_type = getBelType(bel); if (bel_type.in(id_TRELLIS_COMB, id_TRELLIS_FF, id_TRELLIS_RAMW)) { diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 7e373a56..a44c7c21 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -851,7 +851,7 @@ struct Arch : ArchAPI } // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const final + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const final { auto iter = tileStatus.find(bel.tile); if (iter == tileStatus.end()) { diff --git a/generic/arch.cc b/generic/arch.cc index c60c7674..579140b9 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -693,10 +693,10 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port return tmg.clockingInfo.at(port).at(index); } -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { if (uarch) - return uarch->isBelLocationValid(bel); + return uarch->isBelLocationValid(bel, explain_invalid); std::vector cells; Loc loc = getBelLocation(bel); for (auto tbel : getBelsByTile(loc.x, loc.y)) { diff --git a/generic/arch.h b/generic/arch.h index a27dc78e..2a177be9 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -386,7 +386,7 @@ struct Arch : BaseArch { return uarch ? uarch->isValidBelForCellType(cell_type, bel) : cell_type == getBelType(bel); } - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; static const std::string defaultPlacer; static const std::vector availablePlacers; diff --git a/generic/viaduct/example/example.cc b/generic/viaduct/example/example.cc index 987c3236..7a61a594 100644 --- a/generic/viaduct/example/example.cc +++ b/generic/viaduct/example/example.cc @@ -62,7 +62,7 @@ struct ExampleImpl : ViaductAPI void prePlace() override { assign_cell_info(); } - bool isBelLocationValid(BelId bel) const override + bool isBelLocationValid(BelId bel, bool explain_invalid) const override { Loc l = ctx->getBelLocation(bel); if (is_io(l.x, l.y)) { diff --git a/generic/viaduct/fabulous/fabulous.cc b/generic/viaduct/fabulous/fabulous.cc index 3c6f025f..e2fe1b74 100644 --- a/generic/viaduct/fabulous/fabulous.cc +++ b/generic/viaduct/fabulous/fabulous.cc @@ -81,7 +81,10 @@ struct FabulousImpl : ViaductAPI } void prePlace() override { assign_cell_info(); } - bool isBelLocationValid(BelId bel) const override { return blk_trk->check_validity(bel, cfg, cell_tags); } + bool isBelLocationValid(BelId bel, bool explain_invalid) const override + { + return blk_trk->check_validity(bel, cfg, cell_tags); + } private: FabricConfig cfg; // TODO: non-default config diff --git a/generic/viaduct/okami/okami.cc b/generic/viaduct/okami/okami.cc index 8142756f..4ff97cb3 100644 --- a/generic/viaduct/okami/okami.cc +++ b/generic/viaduct/okami/okami.cc @@ -64,7 +64,7 @@ struct OkamiImpl : ViaductAPI void prePlace() override { assign_cell_info(); } - bool isBelLocationValid(BelId bel) const override + bool isBelLocationValid(BelId bel, bool explain_invalid) const override { Loc l = ctx->getBelLocation(bel); if (is_io(l.x, l.y)) { diff --git a/generic/viaduct_api.h b/generic/viaduct_api.h index 6887f56c..3caa0ba1 100644 --- a/generic/viaduct_api.h +++ b/generic/viaduct_api.h @@ -67,7 +67,7 @@ struct ViaductAPI virtual BelBucketId getBelBucketForBel(BelId bel) const; virtual BelBucketId getBelBucketForCellType(IdString cell_type) const; virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const; - virtual bool isBelLocationValid(BelId bel) const { return true; } + virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const { return true; } // --- Wire and pip functions --- // Called when a wire/pip is placed/unplaced (with net=nullptr for a unbind) diff --git a/gowin/arch.cc b/gowin/arch.cc index 05b09363..28c0cb1e 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -2028,7 +2028,7 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port return tmg.clockingInfo.at(port).at(index); } -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { Loc loc = getBelLocation(bel); diff --git a/gowin/arch.h b/gowin/arch.h index 231fae6e..a929ef00 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -458,7 +458,7 @@ struct Arch : BaseArch // Get the TimingClockingInfo of a port TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override; - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; static const std::string defaultPlacer; static const std::vector availablePlacers; diff --git a/ice40/arch.h b/ice40/arch.h index 9d10cddf..d80d6f64 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -840,7 +840,7 @@ struct Arch : BaseArch // implemented in arch_place.cc) // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; // Helper function for above bool logic_cells_compatible(const CellInfo **it, const size_t size) const; diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 5c3fa3c5..d8232571 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -82,7 +82,7 @@ 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, bool explain_invalid) const { if (getBelType(bel) == id_ICESTORM_LC) { std::array bel_cells; diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 93eb4e60..d85921bc 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -451,7 +451,7 @@ bool Arch::route() // --------------------------------------------------------------- -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { // FIXME: Same deal as isValidBelForCell. return true; diff --git a/machxo2/arch.h b/machxo2/arch.h index ddcb9264..489a44ab 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -643,7 +643,7 @@ struct Arch : BaseArch bool route() override; // Placer - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; static const std::string defaultPlacer; static const std::vector availablePlacers; diff --git a/mistral/arch.cc b/mistral/arch.cc index ce4f93fb..f3e385d1 100644 --- a/mistral/arch.cc +++ b/mistral/arch.cc @@ -182,7 +182,7 @@ IdStringList Arch::getBelName(BelId bel) const return IdStringList(ids); } -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { auto &data = bel_data(bel); if (data.type.in(id_MISTRAL_COMB, id_MISTRAL_MCOMB)) { diff --git a/mistral/arch.h b/mistral/arch.h index 54a39771..aabe10c6 100644 --- a/mistral/arch.h +++ b/mistral/arch.h @@ -333,7 +333,7 @@ struct Arch : BaseArch PortType getBelPinType(BelId bel, IdString pin) const override { return bel_data(bel).pins.at(pin).dir; } std::vector getBelPins(BelId bel) const override; - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override { diff --git a/nexus/arch.h b/nexus/arch.h index 5ac16f28..eb3059a5 100644 --- a/nexus/arch.h +++ b/nexus/arch.h @@ -1322,7 +1322,7 @@ struct Arch : BaseArch // implemented in arch_place.cc) // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const override; + bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; // ------------------------------------------------- diff --git a/nexus/arch_place.cc b/nexus/arch_place.cc index 7b2c08ee..0bed30b4 100644 --- a/nexus/arch_place.cc +++ b/nexus/arch_place.cc @@ -96,7 +96,7 @@ bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const return true; } -bool Arch::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const { if (bel_tile_is(bel, LOC_LOGIC)) { LogicTileStatus *lts = tileStatus[bel.tile].lts;