From 831b94cdac7af66e11d0e3d67fa3bbff29678d05 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 22 Mar 2021 17:38:15 -0700 Subject: Initial version of inverter logic. For now just implements some inspection capabilities, and the site router (for now) avoids inverted paths. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fpga_interchange/arch.cc | 31 +++++++++++++++++++++++ fpga_interchange/arch.h | 6 +++++ fpga_interchange/site_arch.h | 7 ++++++ fpga_interchange/site_arch.impl.h | 45 ++++++++++++++++++++++++++++++++++ fpga_interchange/site_router.cc | 26 ++++++++++++++------ fpga_interchange/site_routing_cache.cc | 16 ++++++++++++ fpga_interchange/site_routing_cache.h | 8 ++++++ 7 files changed, 131 insertions(+), 8 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index b5bcc7c5..a0e516c2 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -1747,6 +1747,37 @@ bool Arch::checkPipAvail(PipId pip) const { return checkPipAvailForNet(pip, null std::string Arch::get_chipdb_hash() const { return chipdb_hash; } +bool Arch::is_inverting(PipId pip) const +{ + auto &tile_type = loc_info(chip_info, pip); + auto &pip_info = tile_type.pip_data[pip.index]; + if (pip_info.site == -1) { + // FIXME: Some routing pips are inverters, but this is missing from + // the chipdb. + return false; + } + + auto &bel_data = tile_type.bel_data[pip_info.bel]; + + // Is a fixed inverter if the non_inverting_pin is another pin. + return bel_data.non_inverting_pin != pip_info.extra_data && bel_data.inverting_pin == pip_info.extra_data; +} + +bool Arch::can_invert(PipId pip) const +{ + auto &tile_type = loc_info(chip_info, pip); + auto &pip_info = tile_type.pip_data[pip.index]; + if (pip_info.site == -1) { + return false; + } + + auto &bel_data = tile_type.bel_data[pip_info.bel]; + + // Can optionally invert if this pip is both the non_inverting_pin and + // inverting pin. + return bel_data.non_inverting_pin == pip_info.extra_data && bel_data.inverting_pin == pip_info.extra_data; +} + // Instance constraint templates. template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange); template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange); diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 8e08f17b..1f0eb80d 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -1028,6 +1028,12 @@ struct Arch : ArchAPI return wire_data.site != -1; } + // Does this pip always invert its signal? + bool is_inverting(PipId pip) const; + + // Can this pip optional invert its signal? + bool can_invert(PipId pip) const; + void merge_constant_nets(); void report_invalid_bel(BelId bel, CellInfo *cell) const; diff --git a/fpga_interchange/site_arch.h b/fpga_interchange/site_arch.h index f8524586..95b6fcba 100644 --- a/fpga_interchange/site_arch.h +++ b/fpga_interchange/site_arch.h @@ -289,6 +289,12 @@ struct SiteArch inline SiteWire getPipSrcWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE; inline SiteWire getPipDstWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE; + // Does this site pip always invert its signal? + inline bool isInverting(const SitePip &site_pip) const NPNR_ALWAYS_INLINE; + + // Can this site pip optional invert its signal? + inline bool canInvert(const SitePip &site_pip) const NPNR_ALWAYS_INLINE; + inline SitePipDownhillRange getPipsDownhill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE; inline SitePipUphillRange getPipsUphill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE; SiteWireRange getWires() const; @@ -341,6 +347,7 @@ struct SiteArch void archcheck(); bool is_pip_synthetic(const SitePip &pip) const NPNR_ALWAYS_INLINE; + SyntheticType pip_synthetic_type(const SitePip &pip) const NPNR_ALWAYS_INLINE; }; struct SitePipDownhillIterator diff --git a/fpga_interchange/site_arch.impl.h b/fpga_interchange/site_arch.impl.h index 4702b592..0be298c9 100644 --- a/fpga_interchange/site_arch.impl.h +++ b/fpga_interchange/site_arch.impl.h @@ -202,6 +202,20 @@ inline bool SiteArch::is_pip_synthetic(const SitePip &pip) const } } +inline SyntheticType SiteArch::pip_synthetic_type(const SitePip &pip) const +{ + if (pip.type != SitePip::SITE_PORT) { + // This isn't a site port, so its valid! + return NOT_SYNTH; + } + + auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type]; + auto &pip_data = tile_type.pip_data[pip.pip.index]; + NPNR_ASSERT(pip_data.site != -1); + auto &bel_data = tile_type.bel_data[pip_data.bel]; + return SyntheticType(bel_data.synthetic); +} + inline SitePip SitePipDownhillIterator::operator*() const { switch (state) { @@ -250,6 +264,37 @@ inline SitePipDownhillIterator SitePipDownhillRange::begin() const return b; } +inline bool SiteArch::isInverting(const SitePip &site_pip) const +{ + if (site_pip.type != SitePip::SITE_PIP) { + return false; + } + + auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type]; + auto &pip_data = tile_type.pip_data[site_pip.pip.index]; + NPNR_ASSERT(pip_data.site != -1); + auto &bel_data = tile_type.bel_data[pip_data.bel]; + + // Is a fixed inverter if the non_inverting_pin is another pin. + return bel_data.non_inverting_pin != pip_data.extra_data && bel_data.inverting_pin == pip_data.extra_data; +} + +inline bool SiteArch::canInvert(const SitePip &site_pip) const +{ + if (site_pip.type != SitePip::SITE_PIP) { + return false; + } + + auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type]; + auto &pip_data = tile_type.pip_data[site_pip.pip.index]; + NPNR_ASSERT(pip_data.site != -1); + auto &bel_data = tile_type.bel_data[pip_data.bel]; + + // Can optionally invert if this pip is both the non_inverting_pin and + // inverting pin. + return bel_data.non_inverting_pin == pip_data.extra_data && bel_data.inverting_pin == pip_data.extra_data; +} + NEXTPNR_NAMESPACE_END #endif /* SITE_ARCH_H */ diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index c470f3f6..14c7bb4d 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -92,18 +92,16 @@ bool check_initial_wires(const Context *ctx, SiteInformation *site_info) return true; } -bool is_invalid_site_port(const SiteArch *ctx, const SiteNetInfo *net, const SitePip &pip) +static bool is_invalid_site_port(const SiteArch *ctx, const SiteNetInfo *net, const SitePip &pip) { - if (ctx->is_pip_synthetic(pip)) { - // FIXME: Not all synthetic pips are for constant networks. - // FIXME: Need to mark if synthetic site ports are for the GND or VCC - // network, and only allow the right one. Otherwise site router - // could route a VCC on a GND only net (or equiv). + SyntheticType type = ctx->pip_synthetic_type(pip); + if (type == SYNTH_GND) { IdString gnd_net_name(ctx->ctx->chip_info->constants->gnd_net_name); + return net->net->name != gnd_net_name; + } else if (type == SYNTH_VCC) { IdString vcc_net_name(ctx->ctx->chip_info->constants->vcc_net_name); - return net->net->name != gnd_net_name && net->net->name != vcc_net_name; + return net->net->name != vcc_net_name; } else { - // All non-synthetic site ports are valid return false; } } @@ -310,6 +308,8 @@ struct SiteExpansionLoop std::vector::const_iterator solution_begin(size_t idx) const { return solution.solution_begin(idx); } std::vector::const_iterator solution_end(size_t idx) const { return solution.solution_end(idx); } + bool solution_inverted(size_t idx) const { return solution.solution_inverted(idx); } + bool solution_can_invert(size_t idx) const { return solution.solution_can_invert(idx); } }; void print_current_state(const SiteArch *site_arch) @@ -363,6 +363,8 @@ struct PossibleSolutions SiteNetInfo *net = nullptr; std::vector::const_iterator pips_begin; std::vector::const_iterator pips_end; + bool inverted = false; + bool can_invert = false; }; bool test_solution(SiteArch *ctx, SiteNetInfo *net, std::vector::const_iterator pips_begin, @@ -567,6 +569,12 @@ bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeSt for (const auto *expansion : expansions) { for (size_t idx = 0; idx < expansion->num_solutions(); ++idx) { + if (expansion->solution_inverted(idx)) { + // FIXME: May prefer an inverted solution if constant net + // type. + continue; + } + SiteWire wire = expansion->solution_sink(idx); auto begin = expansion->solution_begin(idx); auto end = expansion->solution_end(idx); @@ -580,6 +588,8 @@ bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeSt solution.net = ctx->wire_to_nets.at(wire).net; solution.pips_begin = begin; solution.pips_end = end; + solution.inverted = expansion->solution_inverted(idx); + solution.can_invert = expansion->solution_can_invert(idx); for (auto iter = begin; iter != end; ++iter) { NPNR_ASSERT(ctx->getPipDstWire(*iter) == wire); diff --git a/fpga_interchange/site_routing_cache.cc b/fpga_interchange/site_routing_cache.cc index f7321a46..e6f4dc70 100644 --- a/fpga_interchange/site_routing_cache.cc +++ b/fpga_interchange/site_routing_cache.cc @@ -31,14 +31,27 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto clear(); solution_sinks.reserve(solutions.size()); + inverted.reserve(solutions.size()); + can_invert.reserve(solutions.size()); for (size_t route : solutions) { + bool sol_inverted = false; + bool sol_can_invert = false; + SiteWire wire = node_storage->get_node(route)->wire; solution_sinks.push_back(wire); solution_offsets.push_back(solution_storage.size()); Node cursor = node_storage->get_node(route); while (cursor.has_parent()) { + if (ctx->isInverting(cursor->pip) && !sol_can_invert) { + sol_inverted = !sol_inverted; + } + if (ctx->canInvert(cursor->pip)) { + sol_inverted = false; + sol_can_invert = true; + } + solution_storage.push_back(cursor->pip); Node parent = cursor.parent(); NPNR_ASSERT(ctx->getPipDstWire(cursor->pip) == cursor->wire); @@ -46,6 +59,9 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto cursor = parent; } + inverted.push_back(sol_inverted); + can_invert.push_back(sol_can_invert); + NPNR_ASSERT(cursor->wire == driver); } diff --git a/fpga_interchange/site_routing_cache.h b/fpga_interchange/site_routing_cache.h index 942375dc..6ad218c7 100644 --- a/fpga_interchange/site_routing_cache.h +++ b/fpga_interchange/site_routing_cache.h @@ -40,6 +40,8 @@ struct SiteRoutingSolution solution_offsets.clear(); solution_storage.clear(); solution_sinks.clear(); + inverted.clear(); + can_invert.clear(); } size_t num_solutions() const { return solution_sinks.size(); } @@ -58,9 +60,15 @@ struct SiteRoutingSolution return solution_storage.begin() + solution_offsets.at(solution + 1); } + bool solution_inverted(size_t solution) const { return inverted.at(solution) != 0; } + + bool solution_can_invert(size_t solution) const { return can_invert.at(solution) != 0; } + std::vector solution_offsets; std::vector solution_storage; std::vector solution_sinks; + std::vector inverted; + std::vector can_invert; }; struct SiteRoutingKey -- cgit v1.2.3