aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-11-26 11:04:08 +0000
committerDavid Shah <dave@ds0.me>2020-11-26 11:12:20 +0000
commit70de8b3a03a62cd1be8732cf5916800322a12a17 (patch)
treea9ce96b0fc307049d42657975bec766a43af8510 /common
parent89552307121099c247f0a953462849cbf5ec6d3e (diff)
downloadnextpnr-70de8b3a03a62cd1be8732cf5916800322a12a17.tar.gz
nextpnr-70de8b3a03a62cd1be8732cf5916800322a12a17.tar.bz2
nextpnr-70de8b3a03a62cd1be8732cf5916800322a12a17.zip
nextpnr: Improve error reporting in Context::check
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/nextpnr.cc84
1 files changed, 67 insertions, 17 deletions
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index c44cec02..07b88471 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -459,49 +459,99 @@ uint32_t Context::checksum() const
void Context::check() const
{
+ bool check_failed = false;
+
+#define CHECK_FAIL(...) \
+ do { \
+ log_nonfatal_error(__VA_ARGS__); \
+ check_failed = true; \
+ } while (false)
+
for (auto &n : nets) {
auto ni = n.second.get();
- NPNR_ASSERT(n.first == ni->name);
+ if (n.first != ni->name)
+ CHECK_FAIL("net key '%s' not equal to name '%s'\n", nameOf(n.first), nameOf(ni->name));
for (auto &w : ni->wires) {
- NPNR_ASSERT(ni == getBoundWireNet(w.first));
+ if (ni != getBoundWireNet(w.first))
+ CHECK_FAIL("net '%s' not bound to wire '%s' in wires map\n", nameOf(n.first), nameOfWire(w.first));
if (w.second.pip != PipId()) {
- NPNR_ASSERT(w.first == getPipDstWire(w.second.pip));
- NPNR_ASSERT(ni == getBoundPipNet(w.second.pip));
+ if (w.first != getPipDstWire(w.second.pip))
+ CHECK_FAIL("net '%s' has dest mismatch '%s' vs '%s' in for pip '%s'\n", nameOf(n.first),
+ nameOfWire(w.first), nameOfWire(getPipDstWire(w.second.pip)), nameOfPip(w.second.pip));
+ if (ni != getBoundPipNet(w.second.pip))
+ CHECK_FAIL("net '%s' not bound to pip '%s' in wires map\n", nameOf(n.first),
+ nameOfPip(w.second.pip));
+ }
+ }
+ if (ni->driver.cell != nullptr) {
+ if (!ni->driver.cell->ports.count(ni->driver.port)) {
+ CHECK_FAIL("net '%s' driver port '%s' missing on cell '%s'\n", nameOf(n.first), nameOf(ni->driver.port),
+ nameOf(ni->driver.cell));
+ } else {
+ const NetInfo *p_net = ni->driver.cell->ports.at(ni->driver.port).net;
+ if (p_net != ni)
+ CHECK_FAIL("net '%s' driver port '%s.%s' connected to incorrect net '%s'\n", nameOf(n.first),
+ nameOf(ni->driver.cell), nameOf(ni->driver.port), p_net ? nameOf(p_net) : "<nullptr>");
}
}
- if (ni->driver.cell != nullptr)
- NPNR_ASSERT(ni->driver.cell->ports.at(ni->driver.port).net == ni);
for (auto user : ni->users) {
- NPNR_ASSERT(user.cell->ports.at(user.port).net == ni);
+ if (!user.cell->ports.count(user.port)) {
+ CHECK_FAIL("net '%s' user port '%s' missing on cell '%s'\n", nameOf(n.first), nameOf(user.port),
+ nameOf(user.cell));
+ } else {
+ const NetInfo *p_net = user.cell->ports.at(user.port).net;
+ if (p_net != ni)
+ CHECK_FAIL("net '%s' user port '%s.%s' connected to incorrect net '%s'\n", nameOf(n.first),
+ nameOf(user.cell), nameOf(user.port), p_net ? nameOf(p_net) : "<nullptr>");
+ }
}
}
for (auto w : getWires()) {
auto ni = getBoundWireNet(w);
if (ni != nullptr) {
- NPNR_ASSERT(ni->wires.count(w));
+ if (!ni->wires.count(w))
+ CHECK_FAIL("wire '%s' missing in wires map of bound net '%s'\n", nameOfWire(w), nameOf(ni));
}
}
for (auto &c : cells) {
auto ci = c.second.get();
- NPNR_ASSERT(c.first == ci->name);
- if (ci->bel != BelId())
- NPNR_ASSERT(getBoundBelCell(c.second->bel) == ci);
+ if (c.first != ci->name)
+ CHECK_FAIL("cell key '%s' not equal to name '%s'\n", nameOf(c.first), nameOf(ci->name));
+ if (ci->bel != BelId()) {
+ if (getBoundBelCell(c.second->bel) != ci)
+ CHECK_FAIL("cell '%s' not bound to bel '%s' in bel field\n", nameOf(c.first), nameOfBel(ci->bel));
+ }
for (auto &port : c.second->ports) {
NetInfo *net = port.second.net;
if (net != nullptr) {
- NPNR_ASSERT(nets.find(net->name) != nets.end());
- if (port.second.type == PORT_OUT) {
- NPNR_ASSERT(net->driver.cell == c.second.get() && net->driver.port == port.first);
+ if (nets.find(net->name) == nets.end()) {
+ CHECK_FAIL("cell port '%s.%s' connected to non-existent net '%s'\n", nameOf(c.first),
+ nameOf(port.first), nameOf(net->name));
+ } else if (port.second.type == PORT_OUT) {
+ if (net->driver.cell != c.second.get() || net->driver.port != port.first) {
+ CHECK_FAIL("output cell port '%s.%s' not in driver field of net '%s'\n", nameOf(c.first),
+ nameOf(port.first), nameOf(net));
+ }
} else if (port.second.type == PORT_IN) {
- NPNR_ASSERT(std::count_if(net->users.begin(), net->users.end(), [&](const PortRef &pr) {
- return pr.cell == c.second.get() && pr.port == port.first;
- }) == 1);
+ int usr_count = std::count_if(net->users.begin(), net->users.end(), [&](const PortRef &pr) {
+ return pr.cell == c.second.get() && pr.port == port.first;
+ });
+ if (usr_count != 1)
+ CHECK_FAIL("input cell port '%s.%s' appears %d rather than expected 1 times in users vector of "
+ "net '%s'\n",
+ nameOf(c.first), nameOf(port.first), usr_count, nameOf(net));
}
}
}
}
+
+#undef CHECK_FAIL
+
+ if (check_failed)
+ log_error("INTERNAL CHECK FAILED: please report this error with the design and full log output. Failure "
+ "details are above this message.\n");
}
void BaseCtx::addClock(IdString net, float freq)