Merge pull request #520 from YosysHQ/dave/improved-check

nextpnr: Improve error reporting in Context::check
This commit is contained in:
David Shah 2020-11-26 16:10:35 +00:00 committed by GitHub
commit 839fbb3fe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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)