2021-03-20 09:26:00 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
|
|
|
* Copyright (C) 2021 Symbiflow Authors
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* 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 "site_arch.h"
|
|
|
|
#include "site_arch.impl.h"
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
SiteInformation::SiteInformation(const Context *ctx, int32_t tile, int32_t site,
|
2021-06-02 17:01:36 +08:00
|
|
|
const pool<CellInfo *, hash_ptr_ops> &cells_in_site)
|
2021-03-20 09:26:00 +08:00
|
|
|
: ctx(ctx), tile(tile), tile_type(ctx->chip_info->tiles[tile].type), site(site), cells_in_site(cells_in_site)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SiteArch::bindPip(const SitePip &pip, SiteNetInfo *net)
|
|
|
|
{
|
|
|
|
SiteWire src = getPipSrcWire(pip);
|
|
|
|
SiteWire dst = getPipDstWire(pip);
|
|
|
|
|
|
|
|
if (!bindWire(src, net)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!bindWire(dst, net)) {
|
|
|
|
unbindWire(src);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto result = net->wires.emplace(dst, SitePipMap{pip, 1});
|
|
|
|
if (!result.second) {
|
|
|
|
if (result.first->second.pip != pip) {
|
|
|
|
// Pip conflict!
|
|
|
|
if (debug()) {
|
|
|
|
log_info("Pip conflict binding pip %s to wire %s, conflicts with pip %s\n", nameOfPip(pip),
|
|
|
|
nameOfWire(dst), nameOfPip(result.first->second.pip));
|
|
|
|
}
|
|
|
|
|
|
|
|
unbindWire(src);
|
|
|
|
unbindWire(dst);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.first->second.count += 1;
|
|
|
|
}
|
|
|
|
|
2021-03-26 08:11:06 +08:00
|
|
|
if (debug()) {
|
|
|
|
log_info("Bound pip %s to wire %s\n", nameOfPip(pip), nameOfWire(dst));
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:26:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SiteArch::unbindPip(const SitePip &pip)
|
|
|
|
{
|
|
|
|
SiteWire src = getPipSrcWire(pip);
|
|
|
|
SiteWire dst = getPipDstWire(pip);
|
|
|
|
|
2021-03-26 08:11:06 +08:00
|
|
|
if (debug()) {
|
|
|
|
log_info("Unbinding pip %s from wire %s\n", nameOfPip(pip), nameOfWire(dst));
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:26:00 +08:00
|
|
|
SiteNetInfo *src_net = unbindWire(src);
|
|
|
|
SiteNetInfo *dst_net = unbindWire(dst);
|
|
|
|
NPNR_ASSERT(src_net == dst_net);
|
|
|
|
auto iter = dst_net->wires.find(dst);
|
|
|
|
NPNR_ASSERT(iter != dst_net->wires.end());
|
|
|
|
NPNR_ASSERT(iter->second.count >= 1);
|
|
|
|
iter->second.count -= 1;
|
|
|
|
|
|
|
|
if (iter->second.count == 0) {
|
|
|
|
dst_net->wires.erase(iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SiteArch::archcheck()
|
|
|
|
{
|
|
|
|
for (SiteWire wire : getWires()) {
|
|
|
|
for (SitePip pip : getPipsDownhill(wire)) {
|
|
|
|
SiteWire wire2 = getPipSrcWire(pip);
|
|
|
|
log_assert(wire == wire2);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (SitePip pip : getPipsUphill(wire)) {
|
|
|
|
SiteWire wire2 = getPipDstWire(pip);
|
|
|
|
log_assert(wire == wire2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 21:53:47 +08:00
|
|
|
SiteArch::SiteArch(const SiteInformation *site_info)
|
|
|
|
: ctx(site_info->ctx), site_info(site_info), blocking_net(site_info->ctx->id("$nextpnr_blocked_net"))
|
2021-03-20 09:26:00 +08:00
|
|
|
{
|
|
|
|
// Build list of input and output site ports
|
|
|
|
//
|
|
|
|
// FIXME: This doesn't need to be computed over and over, move to
|
|
|
|
// arch/chip db.
|
|
|
|
const TileTypeInfoPOD &tile_type = loc_info(&site_info->chip_info(), *site_info);
|
|
|
|
PipId pip;
|
|
|
|
pip.tile = site_info->tile;
|
|
|
|
for (size_t pip_index = 0; pip_index < tile_type.pip_data.size(); ++pip_index) {
|
|
|
|
if (tile_type.pip_data[pip_index].site != site_info->site) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pip.index = pip_index;
|
|
|
|
|
|
|
|
if (!site_info->is_site_port(pip)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
WireId src_wire = ctx->getPipSrcWire(pip);
|
|
|
|
if (site_info->is_wire_in_site(src_wire)) {
|
|
|
|
output_site_ports.push_back(pip);
|
|
|
|
} else {
|
|
|
|
input_site_ports.push_back(pip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create list of out of site sources and sinks.
|
2021-03-25 07:25:15 +08:00
|
|
|
bool have_vcc_pins = false;
|
2022-04-28 23:18:26 +08:00
|
|
|
bool have_gnd_pins = false;
|
|
|
|
|
|
|
|
IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name);
|
|
|
|
IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name);
|
|
|
|
|
|
|
|
IdString const_net_name(ctx->chip_info->constants->best_constant_net);
|
|
|
|
NPNR_ASSERT(const_net_name == vcc_net_name || const_net_name == gnd_net_name);
|
|
|
|
|
2021-03-20 09:26:00 +08:00
|
|
|
for (CellInfo *cell : site_info->cells_in_site) {
|
|
|
|
for (const auto &pin_pair : cell->cell_bel_pins) {
|
2021-04-25 23:29:13 +08:00
|
|
|
if (!cell->ports.count(pin_pair.first))
|
|
|
|
continue;
|
2021-03-20 09:26:00 +08:00
|
|
|
const PortInfo &port = cell->ports.at(pin_pair.first);
|
|
|
|
if (port.net != nullptr) {
|
|
|
|
nets.emplace(port.net, SiteNetInfo{port.net});
|
|
|
|
}
|
|
|
|
}
|
2021-03-25 07:25:15 +08:00
|
|
|
|
2022-04-28 23:18:26 +08:00
|
|
|
for (const auto &conn : cell->lut_cell.pin_connections) {
|
|
|
|
if (conn.second == LutCell::PinConnection::Vcc) {
|
|
|
|
have_vcc_pins = true;
|
|
|
|
} else if (conn.second == LutCell::PinConnection::Gnd) {
|
|
|
|
have_gnd_pins = true;
|
|
|
|
} else if (conn.second == LutCell::PinConnection::Const) {
|
|
|
|
if (const_net_name == vcc_net_name) {
|
|
|
|
have_vcc_pins = true;
|
|
|
|
} else if (const_net_name == gnd_net_name) {
|
|
|
|
have_gnd_pins = true;
|
|
|
|
}
|
|
|
|
}
|
2021-03-25 07:25:15 +08:00
|
|
|
}
|
2021-03-20 09:26:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &net_pair : nets) {
|
|
|
|
NetInfo *net = net_pair.first;
|
|
|
|
SiteNetInfo &net_info = net_pair.second;
|
|
|
|
|
|
|
|
// All nets require drivers
|
2021-06-14 17:58:42 +08:00
|
|
|
if (net->driver.cell == nullptr)
|
|
|
|
continue;
|
2021-03-20 09:26:00 +08:00
|
|
|
|
|
|
|
bool net_driven_out_of_site = false;
|
|
|
|
if (net->driver.cell->bel == BelId()) {
|
|
|
|
// The driver of this site hasn't been placed, so treat it as
|
|
|
|
// out of site.
|
|
|
|
out_of_site_sources.push_back(SiteWire::make(site_info, PORT_OUT, net));
|
|
|
|
net_info.driver = out_of_site_sources.back();
|
|
|
|
net_driven_out_of_site = true;
|
|
|
|
} else {
|
|
|
|
if (!site_info->is_bel_in_site(net->driver.cell->bel)) {
|
|
|
|
|
|
|
|
// The driver of this site has been placed, it is an out
|
|
|
|
// of site source.
|
|
|
|
out_of_site_sources.push_back(SiteWire::make(site_info, PORT_OUT, net));
|
|
|
|
// out_of_site_sources.back().wire = ctx->getNetinfoSourceWire(net);
|
|
|
|
net_info.driver = out_of_site_sources.back();
|
|
|
|
|
|
|
|
net_driven_out_of_site = true;
|
|
|
|
} else {
|
|
|
|
net_info.driver = SiteWire::make(site_info, ctx->getNetinfoSourceWire(net));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_driven_out_of_site) {
|
|
|
|
// Because this net is driven from a source out of the site,
|
|
|
|
// no out of site sink is required.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Examine net to determine if it has any users not in this site.
|
|
|
|
bool net_used_out_of_site = false;
|
|
|
|
for (const PortRef &user : net->users) {
|
|
|
|
NPNR_ASSERT(user.cell != nullptr);
|
|
|
|
|
|
|
|
if (user.cell->bel == BelId()) {
|
|
|
|
// Because this net has a user that has not been placed,
|
|
|
|
// and this net is being driven from this site, make sure
|
|
|
|
// this net can be routed from this site.
|
|
|
|
net_used_out_of_site = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!site_info->is_bel_in_site(user.cell->bel)) {
|
|
|
|
net_used_out_of_site = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_used_out_of_site) {
|
|
|
|
out_of_site_sinks.push_back(SiteWire::make(site_info, PORT_IN, net));
|
|
|
|
net_info.users.emplace(out_of_site_sinks.back());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point all nets have a driver SiteWire, but user SiteWire's
|
|
|
|
// within the site are not present. Add them now.
|
|
|
|
for (auto &net_pair : nets) {
|
|
|
|
NetInfo *net = net_pair.first;
|
|
|
|
SiteNetInfo &net_info = net_pair.second;
|
|
|
|
|
|
|
|
for (const PortRef &user : net->users) {
|
|
|
|
if (!site_info->is_bel_in_site(user.cell->bel)) {
|
|
|
|
// Only care about BELs within the site at this point.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (IdString bel_pin : ctx->getBelPinsForCellPin(user.cell, user.port)) {
|
|
|
|
SiteWire wire = getBelPinWire(user.cell->bel, bel_pin);
|
|
|
|
// Don't add users that are trivially routable!
|
|
|
|
if (wire != net_info.driver) {
|
|
|
|
#ifdef DEBUG_SITE_ARCH
|
|
|
|
if (ctx->debug) {
|
|
|
|
log_info("Add user %s because it isn't driver %s\n", nameOfWire(wire),
|
|
|
|
nameOfWire(net_info.driver));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
net_info.users.emplace(wire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-25 07:25:15 +08:00
|
|
|
NetInfo *vcc_net = ctx->nets.at(vcc_net_name).get();
|
2022-04-28 23:18:26 +08:00
|
|
|
auto vcc_iter = nets.find(vcc_net);
|
|
|
|
if (vcc_iter == nets.end() && have_vcc_pins) {
|
2021-03-25 07:25:15 +08:00
|
|
|
// VCC net isn't present, add it.
|
|
|
|
SiteNetInfo net_info;
|
|
|
|
net_info.net = vcc_net;
|
|
|
|
net_info.driver.type = SiteWire::OUT_OF_SITE_SOURCE;
|
|
|
|
net_info.driver.net = vcc_net;
|
|
|
|
auto result = nets.emplace(vcc_net, net_info);
|
|
|
|
NPNR_ASSERT(result.second);
|
2022-04-28 23:18:26 +08:00
|
|
|
vcc_iter = result.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
NetInfo *gnd_net = ctx->nets.at(gnd_net_name).get();
|
|
|
|
auto gnd_iter = nets.find(gnd_net);
|
|
|
|
if (gnd_iter == nets.end() && have_gnd_pins) {
|
|
|
|
// GND net isn't present, add it.
|
|
|
|
SiteNetInfo net_info;
|
|
|
|
net_info.net = gnd_net;
|
|
|
|
net_info.driver.type = SiteWire::OUT_OF_SITE_SOURCE;
|
|
|
|
net_info.driver.net = gnd_net;
|
|
|
|
auto result = nets.emplace(gnd_net, net_info);
|
|
|
|
NPNR_ASSERT(result.second);
|
|
|
|
gnd_iter = result.first;
|
2021-03-25 07:25:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (CellInfo *cell : site_info->cells_in_site) {
|
2022-04-28 23:18:26 +08:00
|
|
|
for (const auto &it : cell->lut_cell.pin_connections) {
|
|
|
|
const auto &pin = it.first;
|
|
|
|
const auto &conn = it.second;
|
|
|
|
|
|
|
|
if (conn == LutCell::PinConnection::Unconnected || conn == LutCell::PinConnection::Signal) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn == LutCell::PinConnection::Vcc) {
|
|
|
|
SiteWire wire = getBelPinWire(cell->bel, pin);
|
|
|
|
vcc_iter->second.users.emplace(wire);
|
|
|
|
} else if (conn == LutCell::PinConnection::Gnd) {
|
|
|
|
SiteWire wire = getBelPinWire(cell->bel, pin);
|
|
|
|
gnd_iter->second.users.emplace(wire);
|
|
|
|
} else if (conn == LutCell::PinConnection::Const) {
|
|
|
|
SiteWire wire = getBelPinWire(cell->bel, pin);
|
|
|
|
if (const_net_name == vcc_net_name) {
|
|
|
|
vcc_iter->second.users.emplace(wire);
|
|
|
|
}
|
|
|
|
if (const_net_name == gnd_net_name) {
|
|
|
|
gnd_iter->second.users.emplace(wire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_LUT_MAPPING
|
|
|
|
if (ctx->verbose) {
|
|
|
|
log_info("Tying %s.%s to %s\n", cell->name.c_str(ctx), pin.c_str(ctx),
|
|
|
|
LutCell::nameOfPinConnection(conn).c_str());
|
|
|
|
}
|
|
|
|
#endif
|
2021-03-25 07:25:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:26:00 +08:00
|
|
|
for (auto &net_pair : nets) {
|
2021-06-14 17:58:42 +08:00
|
|
|
if (net_pair.first->driver.cell == nullptr)
|
|
|
|
continue;
|
2021-03-20 09:26:00 +08:00
|
|
|
SiteNetInfo *net_info = &net_pair.second;
|
|
|
|
auto result = wire_to_nets.emplace(net_info->driver, SiteNetMap{net_info, 1});
|
|
|
|
// By this point, trivial congestion at sources should already by
|
|
|
|
// avoided, and there should be no duplicates in the
|
|
|
|
// driver/users data.
|
|
|
|
NPNR_ASSERT(result.second);
|
|
|
|
|
|
|
|
for (const auto &user : net_info->users) {
|
|
|
|
result = wire_to_nets.emplace(user, SiteNetMap{net_info, 1});
|
|
|
|
NPNR_ASSERT(result.second);
|
|
|
|
}
|
|
|
|
}
|
2021-04-03 07:20:12 +08:00
|
|
|
|
|
|
|
blocking_site_net.net = &blocking_net;
|
2021-03-20 09:26:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *SiteArch::nameOfWire(const SiteWire &wire) const
|
|
|
|
{
|
|
|
|
switch (wire.type) {
|
|
|
|
case SiteWire::SITE_WIRE:
|
|
|
|
return ctx->nameOfWire(wire.wire);
|
|
|
|
case SiteWire::SITE_PORT_SINK:
|
|
|
|
return ctx->nameOfWire(wire.wire);
|
|
|
|
case SiteWire::SITE_PORT_SOURCE:
|
|
|
|
return ctx->nameOfWire(wire.wire);
|
2021-03-26 08:11:06 +08:00
|
|
|
case SiteWire::OUT_OF_SITE_SOURCE: {
|
|
|
|
std::string &str = ctx->log_strs.next();
|
|
|
|
str = stringf("Out of site source for net %s", wire.net->name.c_str(ctx));
|
|
|
|
return str.c_str();
|
|
|
|
}
|
|
|
|
case SiteWire::OUT_OF_SITE_SINK: {
|
|
|
|
std::string &str = ctx->log_strs.next();
|
|
|
|
str = stringf("Out of sink source for net %s", wire.net->name.c_str(ctx));
|
|
|
|
return str.c_str();
|
|
|
|
}
|
2021-03-20 09:26:00 +08:00
|
|
|
default:
|
|
|
|
// Unreachable!
|
|
|
|
NPNR_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *SiteArch::nameOfPip(const SitePip &pip) const
|
|
|
|
{
|
|
|
|
switch (pip.type) {
|
|
|
|
case SitePip::SITE_PIP:
|
|
|
|
return ctx->nameOfPip(pip.pip);
|
|
|
|
case SitePip::SITE_PORT:
|
|
|
|
return ctx->nameOfPip(pip.pip);
|
2021-03-26 08:11:06 +08:00
|
|
|
case SitePip::SOURCE_TO_SITE_PORT: {
|
|
|
|
std::string &str = ctx->log_strs.next();
|
|
|
|
str = stringf("Out of site source for net %s => %s", pip.wire.net->name.c_str(ctx),
|
|
|
|
ctx->nameOfWire(ctx->getPipSrcWire(pip.pip)));
|
|
|
|
return str.c_str();
|
|
|
|
}
|
|
|
|
case SitePip::SITE_PORT_TO_SINK: {
|
|
|
|
std::string &str = ctx->log_strs.next();
|
|
|
|
str = stringf("%s => Out of site sink for net %s", ctx->nameOfWire(ctx->getPipDstWire(pip.pip)),
|
|
|
|
pip.wire.net->name.c_str(ctx));
|
|
|
|
return str.c_str();
|
|
|
|
}
|
|
|
|
case SitePip::SITE_PORT_TO_SITE_PORT: {
|
|
|
|
std::string &str = ctx->log_strs.next();
|
|
|
|
str = stringf("%s => %s", ctx->nameOfWire(ctx->getPipSrcWire(pip.pip)),
|
|
|
|
ctx->nameOfWire(ctx->getPipDstWire(pip.other_pip)));
|
|
|
|
return str.c_str();
|
|
|
|
}
|
2021-03-20 09:26:00 +08:00
|
|
|
default:
|
|
|
|
// Unreachable!
|
|
|
|
NPNR_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *SiteArch::nameOfNet(const SiteNetInfo *net) const { return net->net->name.c_str(ctx); }
|
|
|
|
|
|
|
|
bool SiteArch::debug() const { return ctx->debug; }
|
|
|
|
|
|
|
|
SitePipUphillRange::SitePipUphillRange(const SiteArch *site_arch, SiteWire site_wire)
|
|
|
|
: site_arch(site_arch), site_wire(site_wire)
|
|
|
|
{
|
|
|
|
switch (site_wire.type) {
|
|
|
|
case SiteWire::SITE_WIRE:
|
|
|
|
pip_range = site_arch->ctx->getPipsUphill(site_wire.wire);
|
|
|
|
break;
|
|
|
|
case SiteWire::OUT_OF_SITE_SOURCE:
|
|
|
|
// No normal pips!
|
|
|
|
break;
|
|
|
|
case SiteWire::OUT_OF_SITE_SINK:
|
|
|
|
// No normal pips!
|
|
|
|
break;
|
|
|
|
case SiteWire::SITE_PORT_SINK:
|
|
|
|
// No normal pips!
|
|
|
|
break;
|
|
|
|
case SiteWire::SITE_PORT_SOURCE:
|
|
|
|
// No normal pips!
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unreachable!
|
|
|
|
NPNR_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SitePip SitePipUphillIterator::operator*() const
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case NORMAL_PIPS:
|
|
|
|
return SitePip::make(site_arch->site_info, *iter);
|
|
|
|
case PORT_SRC_TO_PORT_SINK:
|
|
|
|
return SitePip::make(site_arch->site_info, site_arch->output_site_ports.at(cursor), site_wire.pip);
|
|
|
|
case OUT_OF_SITE_SOURCES:
|
|
|
|
return SitePip::make(site_arch->site_info, site_arch->out_of_site_sources.at(cursor), site_wire.pip);
|
|
|
|
case OUT_OF_SITE_SINK_TO_PORT_SINK:
|
|
|
|
return SitePip::make(site_arch->site_info, site_arch->output_site_ports.at(cursor), site_wire);
|
|
|
|
case SITE_PORT:
|
|
|
|
return SitePip::make(site_arch->site_info, site_wire.pip);
|
|
|
|
default:
|
|
|
|
// Unreachable!
|
|
|
|
NPNR_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SiteWire SiteWireIterator::operator*() const
|
|
|
|
{
|
|
|
|
WireId wire;
|
|
|
|
PipId pip;
|
|
|
|
SiteWire site_wire;
|
|
|
|
switch (state) {
|
|
|
|
case NORMAL_WIRES:
|
|
|
|
wire.tile = site_arch->site_info->tile;
|
|
|
|
wire.index = cursor;
|
|
|
|
return SiteWire::make(site_arch->site_info, wire);
|
|
|
|
case INPUT_SITE_PORTS:
|
|
|
|
pip = site_arch->input_site_ports.at(cursor);
|
|
|
|
site_wire = SiteWire::make_site_port(site_arch->site_info, pip, /*dst_wire=*/false);
|
|
|
|
NPNR_ASSERT(site_wire.type == SiteWire::SITE_PORT_SOURCE);
|
|
|
|
return site_wire;
|
|
|
|
case OUTPUT_SITE_PORTS:
|
|
|
|
pip = site_arch->output_site_ports.at(cursor);
|
|
|
|
site_wire = SiteWire::make_site_port(site_arch->site_info, pip, /*dst_wire=*/true);
|
|
|
|
NPNR_ASSERT(site_wire.type == SiteWire::SITE_PORT_SINK);
|
|
|
|
return site_wire;
|
|
|
|
case OUT_OF_SITE_SOURCES:
|
|
|
|
return site_arch->out_of_site_sources.at(cursor);
|
|
|
|
case OUT_OF_SITE_SINKS:
|
|
|
|
return site_arch->out_of_site_sinks.at(cursor);
|
|
|
|
default:
|
|
|
|
// Unreachable!
|
|
|
|
NPNR_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SiteWireIterator SiteWireRange::begin() const
|
|
|
|
{
|
|
|
|
SiteWireIterator b;
|
|
|
|
|
|
|
|
b.state = SiteWireIterator::BEGIN;
|
|
|
|
b.site_arch = site_arch;
|
|
|
|
b.tile_type = &loc_info(&site_arch->site_info->chip_info(), *site_arch->site_info);
|
|
|
|
|
|
|
|
++b;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|