aboutsummaryrefslogtreecommitdiffstats
path: root/common/basectx.cc
diff options
context:
space:
mode:
authorKeith Rothman <537074+litghost@users.noreply.github.com>2021-03-12 13:09:44 -0800
committerKeith Rothman <537074+litghost@users.noreply.github.com>2021-03-15 09:05:23 -0700
commitfe4608386eb163c70a75ed84beb07516af378b36 (patch)
tree05f1371ad44da5a69617f43cf68005cf271be5e1 /common/basectx.cc
parent035b797ec230aa3d686d9013e0e15d79cd2982c3 (diff)
downloadnextpnr-fe4608386eb163c70a75ed84beb07516af378b36.tar.gz
nextpnr-fe4608386eb163c70a75ed84beb07516af378b36.tar.bz2
nextpnr-fe4608386eb163c70a75ed84beb07516af378b36.zip
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>
Diffstat (limited to 'common/basectx.cc')
-rw-r--r--common/basectx.cc334
1 files changed, 334 insertions, 0 deletions
diff --git a/common/basectx.cc b/common/basectx.cc
new file mode 100644
index 00000000..f271f0f3
--- /dev/null
+++ b/common/basectx.cc
@@ -0,0 +1,334 @@
+/*
+ * 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 "basectx.h"
+
+#include <boost/algorithm/string.hpp>
+
+#include "design_utils.h"
+#include "context.h"
+#include "log.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+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));
+}
+
+void BaseCtx::addClock(IdString net, float freq)
+{
+ std::unique_ptr<ClockConstraint> 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<Region> 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<std::string> 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<std::string> 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<NetInfo> 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<WireId> 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<CellInfo> 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);
+ }
+}
+
+NEXTPNR_NAMESPACE_END