aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Rothman <537074+litghost@users.noreply.github.com>2021-03-22 17:38:15 -0700
committerKeith Rothman <537074+litghost@users.noreply.github.com>2021-03-23 09:03:07 -0700
commit831b94cdac7af66e11d0e3d67fa3bbff29678d05 (patch)
treef87d796b133ad79be4602f4436a4cfc6c0bb4001
parentae71206e1f9522542b919b0dd5b3e634a680dc03 (diff)
downloadnextpnr-831b94cdac7af66e11d0e3d67fa3bbff29678d05.tar.gz
nextpnr-831b94cdac7af66e11d0e3d67fa3bbff29678d05.tar.bz2
nextpnr-831b94cdac7af66e11d0e3d67fa3bbff29678d05.zip
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>
-rw-r--r--fpga_interchange/arch.cc31
-rw-r--r--fpga_interchange/arch.h6
-rw-r--r--fpga_interchange/site_arch.h7
-rw-r--r--fpga_interchange/site_arch.impl.h45
-rw-r--r--fpga_interchange/site_router.cc26
-rw-r--r--fpga_interchange/site_routing_cache.cc16
-rw-r--r--fpga_interchange/site_routing_cache.h8
7 files changed, 131 insertions, 8 deletions
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<ArchRanges>
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<SitePip>::const_iterator solution_begin(size_t idx) const { return solution.solution_begin(idx); }
std::vector<SitePip>::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<SitePip>::const_iterator pips_begin;
std::vector<SitePip>::const_iterator pips_end;
+ bool inverted = false;
+ bool can_invert = false;
};
bool test_solution(SiteArch *ctx, SiteNetInfo *net, std::vector<SitePip>::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<size_t> solution_offsets;
std::vector<SitePip> solution_storage;
std::vector<SiteWire> solution_sinks;
+ std::vector<uint8_t> inverted;
+ std::vector<uint8_t> can_invert;
};
struct SiteRoutingKey