nextpnr/common/nextpnr.cc
Clifford Wolf d904a37138 flush logs when throwing an assertion_failure
Signed-off-by: Clifford Wolf <clifford@clifford.at>
2018-11-10 23:50:08 +01:00

286 lines
9.5 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "nextpnr.h"
#include "log.h"
NEXTPNR_NAMESPACE_BEGIN
assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line)
: runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg),
expr_str(expr_str), filename(filename), line(line)
{
log_flush();
}
void IdString::set(const BaseCtx *ctx, const std::string &s)
{
auto it = ctx->idstring_str_to_idx->find(s);
if (it == ctx->idstring_str_to_idx->end()) {
index = ctx->idstring_idx_to_str->size();
auto insert_rc = ctx->idstring_str_to_idx->insert({s, index});
ctx->idstring_idx_to_str->push_back(&insert_rc.first->first);
} else {
index = it->second;
}
}
const std::string &IdString::str(const BaseCtx *ctx) const { return *ctx->idstring_idx_to_str->at(index); }
const char *IdString::c_str(const BaseCtx *ctx) const { return str(ctx).c_str(); }
void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx)
{
NPNR_ASSERT(ctx->idstring_str_to_idx->count(s) == 0);
NPNR_ASSERT(int(ctx->idstring_idx_to_str->size()) == idx);
auto insert_rc = ctx->idstring_str_to_idx->insert({s, idx});
ctx->idstring_idx_to_str->push_back(&insert_rc.first->first);
}
WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
{
if (net_info->driver.cell == nullptr)
return WireId();
auto src_bel = net_info->driver.cell->bel;
if (src_bel == BelId())
return WireId();
IdString driver_port = net_info->driver.port;
auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
if (driver_port_it != net_info->driver.cell->pins.end())
driver_port = driver_port_it->second;
return getBelPinWire(src_bel, driver_port);
}
WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &user_info) const
{
auto dst_bel = user_info.cell->bel;
if (dst_bel == BelId())
return WireId();
IdString user_port = user_info.port;
auto user_port_it = user_info.cell->pins.find(user_port);
if (user_port_it != user_info.cell->pins.end())
user_port = user_port_it->second;
return getBelPinWire(dst_bel, user_port);
}
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
{
#ifdef ARCH_ECP5
if (net_info->is_global)
return 0;
#endif
WireId src_wire = getNetinfoSourceWire(net_info);
if (src_wire == WireId())
return 0;
WireId dst_wire = getNetinfoSinkWire(net_info, user_info);
WireId cursor = dst_wire;
delay_t delay = 0;
while (cursor != WireId() && cursor != src_wire) {
auto it = net_info->wires.find(cursor);
if (it == net_info->wires.end())
break;
PipId pip = it->second.pip;
delay += getPipDelay(pip).maxDelay();
delay += getWireDelay(cursor).maxDelay();
cursor = getPipSrcWire(pip);
}
if (cursor == src_wire)
return delay + getWireDelay(src_wire).maxDelay();
return predictDelay(net_info, user_info);
}
static uint32_t xorshift32(uint32_t x)
{
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return x;
}
uint32_t Context::checksum() const
{
uint32_t cksum = xorshift32(123456789);
uint32_t cksum_nets_sum = 0;
for (auto &it : nets) {
auto &ni = *it.second;
uint32_t x = 123456789;
x = xorshift32(x + xorshift32(it.first.index));
x = xorshift32(x + xorshift32(ni.name.index));
if (ni.driver.cell)
x = xorshift32(x + xorshift32(ni.driver.cell->name.index));
x = xorshift32(x + xorshift32(ni.driver.port.index));
x = xorshift32(x + xorshift32(getDelayChecksum(ni.driver.budget)));
for (auto &u : ni.users) {
if (u.cell)
x = xorshift32(x + xorshift32(u.cell->name.index));
x = xorshift32(x + xorshift32(u.port.index));
x = xorshift32(x + xorshift32(getDelayChecksum(u.budget)));
}
uint32_t attr_x_sum = 0;
for (auto &a : ni.attrs) {
uint32_t attr_x = 123456789;
attr_x = xorshift32(attr_x + xorshift32(a.first.index));
for (uint8_t ch : a.second)
attr_x = xorshift32(attr_x + xorshift32(ch));
attr_x_sum += attr_x;
}
x = xorshift32(x + xorshift32(attr_x_sum));
uint32_t wire_x_sum = 0;
for (auto &w : ni.wires) {
uint32_t wire_x = 123456789;
wire_x = xorshift32(wire_x + xorshift32(getWireChecksum(w.first)));
wire_x = xorshift32(wire_x + xorshift32(getPipChecksum(w.second.pip)));
wire_x = xorshift32(wire_x + xorshift32(int(w.second.strength)));
wire_x_sum += wire_x;
}
x = xorshift32(x + xorshift32(wire_x_sum));
cksum_nets_sum += x;
}
cksum = xorshift32(cksum + xorshift32(cksum_nets_sum));
uint32_t cksum_cells_sum = 0;
for (auto &it : cells) {
auto &ci = *it.second;
uint32_t x = 123456789;
x = xorshift32(x + xorshift32(it.first.index));
x = xorshift32(x + xorshift32(ci.name.index));
x = xorshift32(x + xorshift32(ci.type.index));
uint32_t port_x_sum = 0;
for (auto &p : ci.ports) {
uint32_t port_x = 123456789;
port_x = xorshift32(port_x + xorshift32(p.first.index));
port_x = xorshift32(port_x + xorshift32(p.second.name.index));
if (p.second.net)
port_x = xorshift32(port_x + xorshift32(p.second.net->name.index));
port_x = xorshift32(port_x + xorshift32(p.second.type));
port_x_sum += port_x;
}
x = xorshift32(x + xorshift32(port_x_sum));
uint32_t attr_x_sum = 0;
for (auto &a : ci.attrs) {
uint32_t attr_x = 123456789;
attr_x = xorshift32(attr_x + xorshift32(a.first.index));
for (uint8_t ch : a.second)
attr_x = xorshift32(attr_x + xorshift32(ch));
attr_x_sum += attr_x;
}
x = xorshift32(x + xorshift32(attr_x_sum));
uint32_t param_x_sum = 0;
for (auto &p : ci.params) {
uint32_t param_x = 123456789;
param_x = xorshift32(param_x + xorshift32(p.first.index));
for (uint8_t ch : p.second)
param_x = xorshift32(param_x + xorshift32(ch));
param_x_sum += param_x;
}
x = xorshift32(x + xorshift32(param_x_sum));
x = xorshift32(x + xorshift32(getBelChecksum(ci.bel)));
x = xorshift32(x + xorshift32(ci.belStrength));
uint32_t pin_x_sum = 0;
for (auto &a : ci.pins) {
uint32_t pin_x = 123456789;
pin_x = xorshift32(pin_x + xorshift32(a.first.index));
pin_x = xorshift32(pin_x + xorshift32(a.second.index));
pin_x_sum += pin_x;
}
x = xorshift32(x + xorshift32(pin_x_sum));
cksum_cells_sum += x;
}
cksum = xorshift32(cksum + xorshift32(cksum_cells_sum));
return cksum;
}
void Context::check() const
{
for (auto &n : nets) {
auto ni = n.second.get();
NPNR_ASSERT(n.first == ni->name);
for (auto &w : ni->wires) {
NPNR_ASSERT(ni == getBoundWireNet(w.first));
if (w.second.pip != PipId()) {
NPNR_ASSERT(w.first == getPipDstWire(w.second.pip));
NPNR_ASSERT(ni == getBoundPipNet(w.second.pip));
}
}
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);
}
}
for (auto w : getWires()) {
auto ni = getBoundWireNet(w);
if (ni != nullptr) {
NPNR_ASSERT(ni->wires.count(w));
}
}
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);
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);
} 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);
}
}
}
}
}
NEXTPNR_NAMESPACE_END