From e88bd34c02272ecdad6295123941d9040fa4f043 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 30 Dec 2021 13:18:34 +0000 Subject: Viaduct API for a hybrid between generic and full-custom arch Signed-off-by: gatecat --- generic/viaduct_helpers.cc | 163 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 generic/viaduct_helpers.cc (limited to 'generic/viaduct_helpers.cc') 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 + * + * 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 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 prefix{x_ids.at(x), y_ids.at(y)}; + return IdStringList::concat(IdStringList(prefix), base); +} + +void ViaductHelpers::remove_nextpnr_iobs(const pool &top_ports) +{ + std::vector 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 &src_ports, const pool &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 &vcc_params, + const dict &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 trim_cells; + std::vector 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 -- cgit v1.2.3