From fe4608386eb163c70a75ed84beb07516af378b36 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 12 Mar 2021 13:09:44 -0800 Subject: Split nextpnr.h to allow for linear inclusion. "nextpnr.h" is no longer the god header. Important improvements: - Functions in log.h can be used without including BaseCtx/Arch/Context. This means that log_X functions can be called without included "nextpnr.h" - NPNR_ASSERT can be used without including "nextpnr.h" by including "nextpnr_assertions.h". This allows NPNR_ASSERT to be used safely in any header file. - Types defined in "archdefs.h" are now available without including BaseCtx/Arch/Context. This means that utility classes that will be used inside of BaseCtx/Arch/Context can be defined safely in a self-contained header. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- common/nextpnr.cc | 866 ------------------------------------------------------ 1 file changed, 866 deletions(-) (limited to 'common/nextpnr.cc') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index f05f4a55..1229a7df 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -17,12 +17,6 @@ * */ -#include "nextpnr.h" -#include -#include "design_utils.h" -#include "log.h" -#include "util.h" - #if defined(__wasm) extern "C" { // FIXME: WASI does not currently support exceptions. @@ -35,863 +29,3 @@ namespace boost { void throw_exception(std::exception const &e) { NEXTPNR_NAMESPACE::log_error("boost::exception(): %s\n", e.what()); } } // namespace boost #endif - -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); -} - -IdStringList IdStringList::parse(Context *ctx, const std::string &str) -{ - char delim = ctx->getNameDelimiter(); - size_t id_count = std::count(str.begin(), str.end(), delim) + 1; - IdStringList list(id_count); - size_t start = 0; - for (size_t i = 0; i < id_count; i++) { - size_t end = str.find(delim, start); - NPNR_ASSERT((i == (id_count - 1)) || (end != std::string::npos)); - list.ids[i] = ctx->id(str.substr(start, end - start)); - start = end + 1; - } - return list; -} - -void IdStringList::build_str(const Context *ctx, std::string &str) const -{ - char delim = ctx->getNameDelimiter(); - bool first = true; - str.clear(); - for (auto entry : ids) { - if (!first) - str += delim; - str += entry.str(ctx); - first = false; - } -} - -std::string IdStringList::str(const Context *ctx) const -{ - std::string s; - build_str(ctx, s); - return s; -} - -std::string &StrRingBuffer::next() -{ - std::string &s = buffer.at(index++); - if (index >= N) - index = 0; - return s; -} - -Property::Property() : is_string(false), str(""), intval(0) {} - -Property::Property(int64_t intval, int width) : is_string(false), intval(intval) -{ - str.reserve(width); - for (int i = 0; i < width; i++) - str.push_back((intval & (1ULL << i)) ? S1 : S0); -} - -Property::Property(const std::string &strval) : is_string(true), str(strval), intval(0xDEADBEEF) {} - -Property::Property(State bit) : is_string(false), str(std::string("") + char(bit)), intval(bit == S1) {} - -void CellInfo::addInput(IdString name) -{ - ports[name].name = name; - ports[name].type = PORT_IN; -} -void CellInfo::addOutput(IdString name) -{ - ports[name].name = name; - ports[name].type = PORT_OUT; -} -void CellInfo::addInout(IdString name) -{ - ports[name].name = name; - ports[name].type = PORT_INOUT; -} - -void CellInfo::setParam(IdString name, Property value) { params[name] = value; } -void CellInfo::unsetParam(IdString name) { params.erase(name); } -void CellInfo::setAttr(IdString name, Property value) { attrs[name] = value; } -void CellInfo::unsetAttr(IdString name) { attrs.erase(name); } - -bool CellInfo::isConstrained(bool include_abs_z_constr) const -{ - return constr_parent != nullptr || !constr_children.empty() || (include_abs_z_constr && constr_abs_z); -} - -bool CellInfo::testRegion(BelId bel) const -{ - return region == nullptr || !region->constr_bels || region->bels.count(bel); -} -Loc CellInfo::getConstrainedLoc(Loc parent_loc) const -{ - NPNR_ASSERT(constr_parent != nullptr); - Loc cloc = parent_loc; - if (constr_x != UNCONSTR) - cloc.x += constr_x; - if (constr_y != UNCONSTR) - cloc.y += constr_y; - if (constr_z != UNCONSTR) - cloc.z = constr_abs_z ? constr_z : (parent_loc.z + constr_z); - return cloc; -} - -std::string Property::to_string() const -{ - if (is_string) { - std::string result = str; - int state = 0; - for (char c : str) { - if (state == 0) { - if (c == '0' || c == '1' || c == 'x' || c == 'z') - state = 0; - else if (c == ' ') - state = 1; - else - state = 2; - } else if (state == 1 && c != ' ') - state = 2; - } - if (state < 2) - result += " "; - return result; - } else { - return std::string(str.rbegin(), str.rend()); - } -} - -Property Property::from_string(const std::string &s) -{ - Property p; - - size_t cursor = s.find_first_not_of("01xz"); - if (cursor == std::string::npos) { - p.str = std::string(s.rbegin(), s.rend()); - p.is_string = false; - p.update_intval(); - } else if (s.find_first_not_of(' ', cursor) == std::string::npos) { - p = Property(s.substr(0, s.size() - 1)); - } else { - p = Property(s); - } - return p; -} - -const char *BaseCtx::nameOfBel(BelId bel) const -{ - const Context *ctx = getCtx(); - std::string &s = ctx->log_strs.next(); - ctx->getBelName(bel).build_str(ctx, s); - return s.c_str(); -} - -const char *BaseCtx::nameOfWire(WireId wire) const -{ - const Context *ctx = getCtx(); - std::string &s = ctx->log_strs.next(); - ctx->getWireName(wire).build_str(ctx, s); - return s.c_str(); -} - -const char *BaseCtx::nameOfPip(PipId pip) const -{ - const Context *ctx = getCtx(); - std::string &s = ctx->log_strs.next(); - ctx->getPipName(pip).build_str(ctx, s); - return s.c_str(); -} - -const char *BaseCtx::nameOfGroup(GroupId group) const -{ - const Context *ctx = getCtx(); - std::string &s = ctx->log_strs.next(); - ctx->getGroupName(group).build_str(ctx, s); - return s.c_str(); -} - -BelId BaseCtx::getBelByNameStr(const std::string &str) -{ - Context *ctx = getCtx(); - return ctx->getBelByName(IdStringList::parse(ctx, str)); -} - -WireId BaseCtx::getWireByNameStr(const std::string &str) -{ - Context *ctx = getCtx(); - return ctx->getWireByName(IdStringList::parse(ctx, str)); -} - -PipId BaseCtx::getPipByNameStr(const std::string &str) -{ - Context *ctx = getCtx(); - return ctx->getPipByName(IdStringList::parse(ctx, str)); -} - -GroupId BaseCtx::getGroupByNameStr(const std::string &str) -{ - Context *ctx = getCtx(); - return ctx->getGroupByName(IdStringList::parse(ctx, str)); -} - -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(); - - auto bel_pins = getBelPinsForCellPin(net_info->driver.cell, net_info->driver.port); - auto iter = bel_pins.begin(); - if (iter == bel_pins.end()) - return WireId(); - WireId driver = getBelPinWire(src_bel, *iter); - ++iter; - NPNR_ASSERT(iter == bel_pins.end()); // assert there is only one driver bel pin; - return driver; -} - -SSOArray Context::getNetinfoSinkWires(const NetInfo *net_info, const PortRef &user_info) const -{ - auto dst_bel = user_info.cell->bel; - if (dst_bel == BelId()) - return SSOArray(0, WireId()); - size_t bel_pin_count = 0; - // We use an SSOArray here because it avoids any heap allocation for the 99.9% case of 1 or 2 sink wires - // but as SSOArray doesn't (currently) support resizing to keep things simple it does mean we have to do - // two loops - for (auto s : getBelPinsForCellPin(user_info.cell, user_info.port)) { - (void)s; // unused - ++bel_pin_count; - } - SSOArray result(bel_pin_count, WireId()); - bel_pin_count = 0; - for (auto pin : getBelPinsForCellPin(user_info.cell, user_info.port)) { - result[bel_pin_count++] = getBelPinWire(dst_bel, pin); - } - return result; -} - -size_t Context::getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const -{ - size_t count = 0; - for (auto s : getNetinfoSinkWires(net_info, sink)) { - (void)s; // unused - ++count; - } - return count; -} - -WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink, size_t phys_idx) const -{ - size_t count = 0; - for (auto s : getNetinfoSinkWires(net_info, sink)) { - if (count == phys_idx) - return s; - ++count; - } - /* TODO: This should be an assertion failure, but for the zero-wire case of unplaced sinks; legacy code currently - assumes WireId Remove once the refactoring process is complete. - */ - return WireId(); -} - -delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const -{ -#ifdef ARCH_ECP5 - if (net_info->is_global) - return 0; -#endif - - if (net_info->wires.empty()) - return predictDelay(net_info, user_info); - - WireId src_wire = getNetinfoSourceWire(net_info); - if (src_wire == WireId()) - return 0; - - delay_t max_delay = 0; - - for (auto dst_wire : getNetinfoSinkWires(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; - if (pip == PipId()) - break; - - delay += getPipDelay(pip).maxDelay(); - delay += getWireDelay(cursor).maxDelay(); - cursor = getPipSrcWire(pip); - } - - if (cursor == src_wire) - max_delay = std::max(max_delay, delay + getWireDelay(src_wire).maxDelay()); // routed - else - max_delay = std::max(max_delay, predictDelay(net_info, user_info)); // unrouted - } - return max_delay; -} - -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 (char ch : a.second.str) - attr_x = xorshift32(attr_x + xorshift32((int)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 (char ch : a.second.str) - attr_x = xorshift32(attr_x + xorshift32((int)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 (char ch : p.second.str) - param_x = xorshift32(param_x + xorshift32((int)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)); - - cksum_cells_sum += x; - } - cksum = xorshift32(cksum + xorshift32(cksum_cells_sum)); - - return cksum; -} - -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(); - 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) { - 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()) { - 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) : ""); - } - } - for (auto user : ni->users) { - 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) : ""); - } - } - } -#ifdef CHECK_WIRES - for (auto w : getWires()) { - auto ni = getBoundWireNet(w); - if (ni != nullptr) { - if (!ni->wires.count(w)) - CHECK_FAIL("wire '%s' missing in wires map of bound net '%s'\n", nameOfWire(w), nameOf(ni)); - } - } -#endif - for (auto &c : cells) { - auto ci = c.second.get(); - 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) { - 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) { - 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) -{ - std::unique_ptr cc(new ClockConstraint()); - cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq)); - cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq)); - cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq)); - if (!net_aliases.count(net)) { - log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this)); - } else { - getNetByAlias(net)->clkconstr = std::move(cc); - log_info("constraining clock net '%s' to %.02f MHz\n", net.c_str(this), freq); - } -} - -void BaseCtx::createRectangularRegion(IdString name, int x0, int y0, int x1, int y1) -{ - std::unique_ptr new_region(new Region()); - new_region->name = name; - new_region->constr_bels = true; - new_region->constr_pips = false; - new_region->constr_wires = false; - for (int x = x0; x <= x1; x++) { - for (int y = y0; y <= y1; y++) { - for (auto bel : getCtx()->getBelsByTile(x, y)) - new_region->bels.insert(bel); - } - } - region[name] = std::move(new_region); -} -void BaseCtx::addBelToRegion(IdString name, BelId bel) { region[name]->bels.insert(bel); } -void BaseCtx::constrainCellToRegion(IdString cell, IdString region_name) -{ - // Support hierarchical cells as well as leaf ones - bool matched = false; - if (hierarchy.count(cell)) { - auto &hc = hierarchy.at(cell); - for (auto &lc : hc.leaf_cells) - constrainCellToRegion(lc.second, region_name); - for (auto &hsc : hc.hier_cells) - constrainCellToRegion(hsc.second, region_name); - matched = true; - } - if (cells.count(cell)) { - cells.at(cell)->region = region[region_name].get(); - matched = true; - } - if (!matched) - log_warning("No cell matched '%s' when constraining to region '%s'\n", nameOf(cell), nameOf(region_name)); -} -DecalXY BaseCtx::constructDecalXY(DecalId decal, float x, float y) -{ - DecalXY dxy; - dxy.decal = decal; - dxy.x = x; - dxy.y = y; - return dxy; -} - -void BaseCtx::archInfoToAttributes() -{ - for (auto &cell : cells) { - auto ci = cell.second.get(); - if (ci->bel != BelId()) { - if (ci->attrs.find(id("BEL")) != ci->attrs.end()) { - ci->attrs.erase(ci->attrs.find(id("BEL"))); - } - ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(getCtx()); - ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength; - } - if (ci->constr_x != ci->UNCONSTR) - ci->attrs[id("CONSTR_X")] = ci->constr_x; - if (ci->constr_y != ci->UNCONSTR) - ci->attrs[id("CONSTR_Y")] = ci->constr_y; - if (ci->constr_z != ci->UNCONSTR) { - ci->attrs[id("CONSTR_Z")] = ci->constr_z; - ci->attrs[id("CONSTR_ABS_Z")] = ci->constr_abs_z ? 1 : 0; - } - if (ci->constr_parent != nullptr) - ci->attrs[id("CONSTR_PARENT")] = ci->constr_parent->name.str(this); - if (!ci->constr_children.empty()) { - std::string constr = ""; - for (auto &item : ci->constr_children) { - if (!constr.empty()) - constr += std::string(";"); - constr += item->name.c_str(this); - } - ci->attrs[id("CONSTR_CHILDREN")] = constr; - } - } - for (auto &net : getCtx()->nets) { - auto ni = net.second.get(); - std::string routing; - bool first = true; - for (auto &item : ni->wires) { - if (!first) - routing += ";"; - routing += getCtx()->getWireName(item.first).str(getCtx()); - routing += ";"; - if (item.second.pip != PipId()) - routing += getCtx()->getPipName(item.second.pip).str(getCtx()); - routing += ";" + std::to_string(item.second.strength); - first = false; - } - ni->attrs[id("ROUTING")] = routing; - } -} - -void BaseCtx::attributesToArchInfo() -{ - for (auto &cell : cells) { - auto ci = cell.second.get(); - auto val = ci->attrs.find(id("NEXTPNR_BEL")); - if (val != ci->attrs.end()) { - auto str = ci->attrs.find(id("BEL_STRENGTH")); - PlaceStrength strength = PlaceStrength::STRENGTH_USER; - if (str != ci->attrs.end()) - strength = (PlaceStrength)str->second.as_int64(); - - BelId b = getCtx()->getBelByNameStr(val->second.as_string()); - getCtx()->bindBel(b, ci, strength); - } - - val = ci->attrs.find(id("CONSTR_PARENT")); - if (val != ci->attrs.end()) { - auto parent = cells.find(id(val->second.str)); - if (parent != cells.end()) - ci->constr_parent = parent->second.get(); - else - continue; - } - - val = ci->attrs.find(id("CONSTR_X")); - if (val != ci->attrs.end()) - ci->constr_x = val->second.as_int64(); - - val = ci->attrs.find(id("CONSTR_Y")); - if (val != ci->attrs.end()) - ci->constr_y = val->second.as_int64(); - - val = ci->attrs.find(id("CONSTR_Z")); - if (val != ci->attrs.end()) - ci->constr_z = val->second.as_int64(); - - val = ci->attrs.find(id("CONSTR_ABS_Z")); - if (val != ci->attrs.end()) - ci->constr_abs_z = val->second.as_int64() == 1; - - val = ci->attrs.find(id("CONSTR_PARENT")); - if (val != ci->attrs.end()) { - auto parent = cells.find(id(val->second.as_string())); - if (parent != cells.end()) - ci->constr_parent = parent->second.get(); - } - val = ci->attrs.find(id("CONSTR_CHILDREN")); - if (val != ci->attrs.end()) { - std::vector strs; - auto children = val->second.as_string(); - boost::split(strs, children, boost::is_any_of(";")); - for (auto val : strs) { - if (cells.count(id(val.c_str()))) - ci->constr_children.push_back(cells.find(id(val.c_str()))->second.get()); - } - } - } - for (auto &net : getCtx()->nets) { - auto ni = net.second.get(); - auto val = ni->attrs.find(id("ROUTING")); - if (val != ni->attrs.end()) { - std::vector strs; - auto routing = val->second.as_string(); - boost::split(strs, routing, boost::is_any_of(";")); - for (size_t i = 0; i < strs.size() / 3; i++) { - std::string wire = strs[i * 3]; - std::string pip = strs[i * 3 + 1]; - PlaceStrength strength = (PlaceStrength)std::stoi(strs[i * 3 + 2]); - if (pip.empty()) - getCtx()->bindWire(getCtx()->getWireByName(IdStringList::parse(getCtx(), wire)), ni, strength); - else - getCtx()->bindPip(getCtx()->getPipByName(IdStringList::parse(getCtx(), pip)), ni, strength); - } - } - } - getCtx()->assignArchInfo(); -} - -NetInfo *BaseCtx::createNet(IdString name) -{ - NPNR_ASSERT(!nets.count(name)); - NPNR_ASSERT(!net_aliases.count(name)); - std::unique_ptr net{new NetInfo}; - net->name = name; - net_aliases[name] = name; - NetInfo *ptr = net.get(); - nets[name] = std::move(net); - refreshUi(); - return ptr; -} - -void BaseCtx::connectPort(IdString net, IdString cell, IdString port) -{ - NetInfo *net_info = getNetByAlias(net); - CellInfo *cell_info = cells.at(cell).get(); - connect_port(getCtx(), net_info, cell_info, port); -} - -void BaseCtx::disconnectPort(IdString cell, IdString port) -{ - CellInfo *cell_info = cells.at(cell).get(); - disconnect_port(getCtx(), cell_info, port); -} - -void BaseCtx::ripupNet(IdString name) -{ - NetInfo *net_info = getNetByAlias(name); - std::vector to_unbind; - for (auto &wire : net_info->wires) - to_unbind.push_back(wire.first); - for (auto &unbind : to_unbind) - getCtx()->unbindWire(unbind); -} -void BaseCtx::lockNetRouting(IdString name) -{ - NetInfo *net_info = getNetByAlias(name); - for (auto &wire : net_info->wires) - wire.second.strength = STRENGTH_USER; -} - -CellInfo *BaseCtx::createCell(IdString name, IdString type) -{ - NPNR_ASSERT(!cells.count(name)); - std::unique_ptr cell{new CellInfo}; - cell->name = name; - cell->type = type; - CellInfo *ptr = cell.get(); - cells[name] = std::move(cell); - refreshUi(); - return ptr; -} - -void BaseCtx::copyBelPorts(IdString cell, BelId bel) -{ - CellInfo *cell_info = cells.at(cell).get(); - for (auto pin : getCtx()->getBelPins(bel)) { - cell_info->ports[pin].name = pin; - cell_info->ports[pin].type = getCtx()->getBelPinType(bel, pin); - } -} - -namespace { -struct FixupHierarchyWorker -{ - FixupHierarchyWorker(Context *ctx) : ctx(ctx){}; - Context *ctx; - void run() - { - trim_hierarchy(ctx->top_module); - rebuild_hierarchy(); - }; - // Remove cells and nets that no longer exist in the netlist - std::vector todelete_cells, todelete_nets; - void trim_hierarchy(IdString path) - { - auto &h = ctx->hierarchy.at(path); - todelete_cells.clear(); - todelete_nets.clear(); - for (auto &lc : h.leaf_cells) { - if (!ctx->cells.count(lc.second)) - todelete_cells.push_back(lc.first); - } - for (auto &n : h.nets) - if (!ctx->nets.count(n.second)) - todelete_nets.push_back(n.first); - for (auto tdc : todelete_cells) { - h.leaf_cells_by_gname.erase(h.leaf_cells.at(tdc)); - h.leaf_cells.erase(tdc); - } - for (auto tdn : todelete_nets) { - h.nets_by_gname.erase(h.nets.at(tdn)); - h.nets.erase(tdn); - } - for (auto &sc : h.hier_cells) - trim_hierarchy(sc.second); - } - - IdString construct_local_name(HierarchicalCell &hc, IdString global_name, bool is_cell) - { - std::string gn = global_name.str(ctx); - auto dp = gn.find_last_of('.'); - if (dp != std::string::npos) - gn = gn.substr(dp + 1); - IdString name = ctx->id(gn); - // Make sure name is unique - int adder = 0; - while (is_cell ? hc.leaf_cells.count(name) : hc.nets.count(name)) { - ++adder; - name = ctx->id(gn + "$" + std::to_string(adder)); - } - return name; - } - - // Update hierarchy structure for nets and cells that have hiercell set - void rebuild_hierarchy() - { - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - if (ci->hierpath == IdString()) - ci->hierpath = ctx->top_module; - auto &hc = ctx->hierarchy.at(ci->hierpath); - if (hc.leaf_cells_by_gname.count(ci->name)) - continue; // already known - IdString local_name = construct_local_name(hc, ci->name, true); - hc.leaf_cells_by_gname[ci->name] = local_name; - hc.leaf_cells[local_name] = ci->name; - } - } -}; -} // namespace - -void Context::fixupHierarchy() { FixupHierarchyWorker(this).run(); } - -NEXTPNR_NAMESPACE_END -- cgit v1.2.3