aboutsummaryrefslogtreecommitdiffstats
path: root/generic/viaduct_helpers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'generic/viaduct_helpers.cc')
-rw-r--r--generic/viaduct_helpers.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/generic/viaduct_helpers.cc b/generic/viaduct_helpers.cc
new file mode 100644
index 00000000..36bdd6be
--- /dev/null
+++ b/generic/viaduct_helpers.cc
@@ -0,0 +1,163 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2021 gatecat <gatecat@ds0.me>
+ *
+ * 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 "viaduct_helpers.h"
+#include "design_utils.h"
+#include "log.h"
+#include "nextpnr.h"
+#include "util.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+void ViaductHelpers::resize_ids(int x, int y)
+{
+ NPNR_ASSERT(x >= 0 && y >= 0 && x <= 20000 && y <= 20000);
+ while (int(x_ids.size()) <= x) {
+ IdString next = ctx->id(stringf("X%d", int(x_ids.size())));
+ x_ids.push_back(next);
+ }
+ while (int(y_ids.size()) <= y) {
+ IdString next = ctx->id(stringf("Y%d", int(y_ids.size())));
+ y_ids.push_back(next);
+ }
+}
+
+IdStringList ViaductHelpers::xy_id(int x, int y, IdString base)
+{
+ resize_ids(x, y);
+ std::array<IdString, 3> result{x_ids.at(x), y_ids.at(y), base};
+ return IdStringList(result);
+}
+
+IdStringList ViaductHelpers::xy_id(int x, int y, IdStringList base)
+{
+ resize_ids(x, y);
+ std::array<IdString, 2> prefix{x_ids.at(x), y_ids.at(y)};
+ return IdStringList::concat(IdStringList(prefix), base);
+}
+
+void ViaductHelpers::remove_nextpnr_iobs(const pool<CellTypePort> &top_ports)
+{
+ std::vector<IdString> to_remove;
+ for (auto &cell : ctx->cells) {
+ auto &ci = *cell.second;
+ if (!ci.type.in(ctx->id("$nextpnr_ibuf"), ctx->id("$nextpnr_obuf"), ctx->id("$nextpnr_iobuf")))
+ continue;
+ NetInfo *i = get_net_or_empty(&ci, ctx->id("I"));
+ if (i && i->driver.cell) {
+ if (!top_ports.count(CellTypePort(i->driver)))
+ log_error("Top-level port '%s' driven by illegal port %s.%s\n", ctx->nameOf(&ci),
+ ctx->nameOf(i->driver.cell), ctx->nameOf(i->driver.port));
+ }
+ NetInfo *o = get_net_or_empty(&ci, ctx->id("O"));
+ if (o) {
+ for (auto &usr : o->users) {
+ if (!top_ports.count(CellTypePort(usr)))
+ log_error("Top-level port '%s' driving illegal port %s.%s\n", ctx->nameOf(&ci),
+ ctx->nameOf(usr.cell), ctx->nameOf(usr.port));
+ }
+ }
+ disconnect_port(ctx, &ci, ctx->id("I"));
+ disconnect_port(ctx, &ci, ctx->id("O"));
+ to_remove.push_back(ci.name);
+ }
+ for (IdString cell_name : to_remove)
+ ctx->cells.erase(cell_name);
+}
+
+int ViaductHelpers::constrain_cell_pairs(const pool<CellTypePort> &src_ports, const pool<CellTypePort> &sink_ports,
+ int delta_z)
+{
+ int constrained = 0;
+ for (auto &cell : ctx->cells) {
+ auto &ci = *cell.second;
+ if (ci.cluster != ClusterId())
+ continue; // don't constrain already-constrained cells
+ bool done = false;
+ for (auto &port : ci.ports) {
+ // look for starting source ports
+ if (port.second.type != PORT_OUT || !port.second.net)
+ continue;
+ if (!src_ports.count(CellTypePort(ci.type, port.first)))
+ continue;
+ for (auto &usr : port.second.net->users) {
+ if (!sink_ports.count(CellTypePort(usr)))
+ continue;
+ if (usr.cell->cluster != ClusterId())
+ continue;
+ // Add the constraint
+ ci.cluster = ci.name;
+ ci.constr_abs_z = false;
+ ci.constr_children.push_back(usr.cell);
+ usr.cell->cluster = ci.name;
+ usr.cell->constr_x = 0;
+ usr.cell->constr_y = 0;
+ usr.cell->constr_z = delta_z;
+ usr.cell->constr_abs_z = false;
+ ++constrained;
+ done = true;
+ break;
+ }
+ if (done)
+ break;
+ }
+ }
+ return constrained;
+}
+
+void ViaductHelpers::replace_constants(CellTypePort vcc_driver, CellTypePort gnd_driver,
+ const dict<IdString, Property> &vcc_params,
+ const dict<IdString, Property> &gnd_params)
+{
+ CellInfo *vcc_drv = ctx->createCell(ctx->id("$PACKER_VCC_DRV"), vcc_driver.cell_type);
+ vcc_drv->addOutput(vcc_driver.port);
+ for (auto &p : vcc_params)
+ vcc_drv->params[p.first] = p.second;
+
+ CellInfo *gnd_drv = ctx->createCell(ctx->id("$PACKER_GND_DRV"), gnd_driver.cell_type);
+ gnd_drv->addOutput(gnd_driver.port);
+ for (auto &p : gnd_params)
+ gnd_drv->params[p.first] = p.second;
+
+ NetInfo *vcc_net = ctx->createNet(ctx->id("$PACKER_VCC"));
+ NetInfo *gnd_net = ctx->createNet(ctx->id("$PACKER_GND"));
+
+ std::vector<IdString> trim_cells;
+ std::vector<IdString> trim_nets;
+ for (auto &net : ctx->nets) {
+ auto &ni = *net.second;
+ if (!ni.driver.cell)
+ continue;
+ if (ni.driver.cell->type != ctx->id("GND") && ni.driver.cell->type != ctx->id("VCC"))
+ continue;
+ NetInfo *replace = (ni.driver.cell->type == ctx->id("VCC")) ? vcc_net : gnd_net;
+ for (auto &usr : ni.users) {
+ usr.cell->ports.at(usr.port).net = replace;
+ replace->users.push_back(usr);
+ }
+ trim_cells.push_back(ni.driver.cell->name);
+ trim_nets.push_back(ni.name);
+ }
+ for (IdString cell_name : trim_cells)
+ ctx->cells.erase(cell_name);
+ for (IdString net_name : trim_nets)
+ ctx->nets.erase(net_name);
+}
+
+NEXTPNR_NAMESPACE_END