From cdd7bb676fbb060c63ed2d0e285b3bdf324a5107 Mon Sep 17 00:00:00 2001 From: gatecat Date: Mon, 27 Feb 2023 09:04:11 +0100 Subject: fabulous: Support for complex flops in PnR Signed-off-by: gatecat --- generic/viaduct/fabulous/constids.inc | 3 +++ generic/viaduct/fabulous/fab_cfg.h | 3 ++- generic/viaduct/fabulous/fabulous.cc | 24 +++++++++++++++++++++--- generic/viaduct/fabulous/validity_check.cc | 11 +++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) (limited to 'generic/viaduct') diff --git a/generic/viaduct/fabulous/constids.inc b/generic/viaduct/fabulous/constids.inc index 7c8c3400..b7fe721d 100644 --- a/generic/viaduct/fabulous/constids.inc +++ b/generic/viaduct/fabulous/constids.inc @@ -110,5 +110,8 @@ X(VDD) X(_CONST0_DRV) X(_CONST1_DRV) +X(_CONST0) +X(_CONST1) + X(_LUT_PERM) X(_LUT_PERM_IN) diff --git a/generic/viaduct/fabulous/fab_cfg.h b/generic/viaduct/fabulous/fab_cfg.h index dc487fbd..17f066cc 100644 --- a/generic/viaduct/fabulous/fab_cfg.h +++ b/generic/viaduct/fabulous/fab_cfg.h @@ -43,8 +43,9 @@ struct ControlSetConfig signal can drive for a CLB with 8 FFs and 2 clocks split at halfway, the first entry would be 0x0F and the second 0xF0 */ - std::vector routing = {0b11111111}; // default 1 shared between all + std::vector routing; // default 1 shared between all bool have_signal = true; + int can_mask = -1; bool can_invert = false; }; diff --git a/generic/viaduct/fabulous/fabulous.cc b/generic/viaduct/fabulous/fabulous.cc index f3d0878c..d658ce24 100644 --- a/generic/viaduct/fabulous/fabulous.cc +++ b/generic/viaduct/fabulous/fabulous.cc @@ -52,6 +52,7 @@ struct FabulousImpl : ViaductAPI log_error("unrecognised fabulous option '%s'\n", a.first.c_str()); } } + ~FabulousImpl(){}; void init(Context *ctx) override { @@ -64,6 +65,7 @@ struct FabulousImpl : ViaductAPI else is_new_fab = false; log_info("Detected FABulous %s format project.\n", is_new_fab ? "2.0" : "1.0"); + init_default_ctrlset_cfg(); // To consider: a faster serialised form of the device data (like bba that other arches use) so we don't have to // go through the whole csv parsing malarkey each time blk_trk = std::make_unique(ctx, cfg); @@ -76,6 +78,22 @@ struct FabulousImpl : ViaductAPI ctx->ripup_penalty = 0.5; } + void init_default_ctrlset_cfg() + { + // TODO: loading from file or something + uint64_t default_routing = (1ULL << (cfg.clb.lc_per_clb * cfg.clb.ff_per_lc)) - 1; + auto setup_cfg = [&](ControlSetConfig &ctrl, int mask) { + ctrl.routing.clear(); + ctrl.routing.push_back(default_routing); + ctrl.can_mask = mask; + ctrl.can_invert = false; + }; + + setup_cfg(cfg.clb.clk, -1); + setup_cfg(cfg.clb.en, 1); + setup_cfg(cfg.clb.sr, 0); + } + void update_cell_timing(Context *ctx) { // These timings are not realistic. They just make sure nextpnr does some timing-driven optimisation... @@ -605,9 +623,9 @@ struct FabulousImpl : ViaductAPI return true; bool is_carry = cell_tags.get(lut).comb.carry_used; if (is_carry) { - // Because you have to make sure you route _something_ to each HA input in this mode (undefined I1/I2 inputs aren't OK) - // and you also can't swap I0 because it's fixed internally - // LUT permutation in carry mode is just more trouble than it's worth. + // Because you have to make sure you route _something_ to each HA input in this mode (undefined I1/I2 + // inputs aren't OK) and you also can't swap I0 because it's fixed internally LUT permutation in carry + // mode is just more trouble than it's worth. return false; } else { return true; // TODO: other cases where perm illegal; e.g. LUTRAM diff --git a/generic/viaduct/fabulous/validity_check.cc b/generic/viaduct/fabulous/validity_check.cc index 81f057c8..10b67c3e 100644 --- a/generic/viaduct/fabulous/validity_check.cc +++ b/generic/viaduct/fabulous/validity_check.cc @@ -62,6 +62,10 @@ void CellTagger::assign_for(const Context *ctx, const FabricConfig &cfg, const C auto get_ctrlsig = [&](IdString name) { const NetInfo *sig = ci->getPort(name); bool invert = sig && bool_or_default(ci->params, ctx->idf("NEG_%s", name.c_str(ctx))); + if (sig && sig->driver.cell && sig->driver.cell->type.in(id__CONST0_DRV, id__CONST1_DRV)) { + return ControlSig(((sig->driver.cell->type == id__CONST1_DRV) ^ invert) ? id__CONST1 : id__CONST0, + false); + } return ControlSig(sig ? sig->name : id___disconnected, invert); }; t.ff.clk = get_ctrlsig(id_CLK); @@ -132,6 +136,13 @@ bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_dat used_en(cfg.en.routing.size()); auto check_ctrlsig = [&](unsigned idx, ControlSig actual, const ControlSetConfig &ctrl, SSOArray &used) { + if (ctrl.can_mask != -1) { + // Using the per-entry control signal masking + if (actual.net == id___disconnected || (actual.net == id__CONST0 && ctrl.can_mask == 0) || + (actual.net == id__CONST1 && ctrl.can_mask == 0)) { + return true; + } + } // see if we have an already-matching signal available for (unsigned i = 0; i < ctrl.routing.size(); i++) { // doesn't route to this pin -- cgit v1.2.3