aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange
diff options
context:
space:
mode:
authorMaciej Kurc <mkurc@antmicro.com>2022-04-28 17:18:26 +0200
committerMaciej Kurc <mkurc@antmicro.com>2022-05-11 16:31:30 +0200
commitaafe1a176c821a3919e773b57ac08fb348c91597 (patch)
tree7c41b8d2bb8f89fd3d0fcacbf3f3bf1e6be45fc8 /fpga_interchange
parent41936fefac2b819ad77204f0ed64ba01e9138c2a (diff)
downloadnextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.tar.gz
nextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.tar.bz2
nextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.zip
Generalized representation of unused LUT pins connections
Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
Diffstat (limited to 'fpga_interchange')
-rw-r--r--fpga_interchange/arch.cc43
-rw-r--r--fpga_interchange/luts.cc82
-rw-r--r--fpga_interchange/luts.h13
-rw-r--r--fpga_interchange/site_arch.cc76
-rw-r--r--fpga_interchange/site_lut_mapping_cache.cc4
5 files changed, 160 insertions, 58 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index e55c94af..05b50ae2 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -874,17 +874,26 @@ static void prepare_sites_for_routing(Context *ctx)
// Fixup LUT vcc pins.
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);
+
for (BelId bel : ctx->getBels()) {
CellInfo *cell = ctx->getBoundBelCell(bel);
if (cell == nullptr) {
continue;
}
- if (cell->lut_cell.vcc_pins.empty()) {
- continue;
- }
+ for (const auto &it : cell->lut_cell.pin_connections) {
+ const auto &bel_pin = it.first;
+ const auto &conn = it.second;
+
+ // Connected to an active signal or unconnected
+ if (conn == LutCell::PinConnection::Signal || conn == LutCell::PinConnection::Unconnected) {
+ continue;
+ }
- for (auto bel_pin : cell->lut_cell.vcc_pins) {
// We can't rely on bel pins not clashing with cell names (for Xilinx they use different naming schemes, for
// Nexus they are the same) so add a prefix to the bel pin name to disambiguate it
IdString cell_pin = ctx->id(stringf("%s_PHYS", ctx->nameOf(bel_pin)));
@@ -896,17 +905,37 @@ static void prepare_sites_for_routing(Context *ctx)
#ifdef DEBUG_LUT_MAPPING
if (ctx->verbose) {
- log_info("%s must be tied to VCC, tying now\n", ctx->nameOfWire(lut_pin_wire));
+ log_info("%s must be tied to %s, tying now\n", ctx->nameOfWire(lut_pin_wire),
+ LutCell::nameOfPinConnection(conn).c_str());
}
#endif
+ IdString tie_net_name;
+ switch (conn) {
+ case LutCell::PinConnection::Vcc:
+ tie_net_name = vcc_net_name;
+ break;
+ case LutCell::PinConnection::Gnd:
+ tie_net_name = gnd_net_name;
+ break;
+ case LutCell::PinConnection::Const:
+ tie_net_name = const_net_name;
+ break;
+ default:
+ // Should never happen
+ NPNR_ASSERT_FALSE(
+ stringf("Invalid LUT cell pin connection '%s'", LutCell::nameOfPinConnection(conn).c_str())
+ .c_str());
+ break;
+ }
+
auto result = cell->ports.emplace(cell_pin, port_info);
if (result.second) {
cell->cell_bel_pins[cell_pin].push_back(bel_pin);
- ctx->connectPort(vcc_net_name, cell->name, cell_pin);
+ ctx->connectPort(tie_net_name, cell->name, cell_pin);
cell->const_ports.emplace(cell_pin);
} else {
- NPNR_ASSERT(result.first->second.net == ctx->getNetByAlias(vcc_net_name));
+ NPNR_ASSERT(result.first->second.net == ctx->getNetByAlias(tie_net_name));
auto result2 = cell->cell_bel_pins.emplace(cell_pin, std::vector<IdString>({bel_pin}));
NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
NPNR_ASSERT(result2.first->second.size() == 1);
diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc
index d9e17ca9..8c4672c7 100644
--- a/fpga_interchange/luts.cc
+++ b/fpga_interchange/luts.cc
@@ -47,14 +47,6 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> *result, const LutBel
// This address line is 0, so don't translate this bit to the cell
// address.
if ((bel_address & (1 << bel_pin_idx)) == 0) {
- // This pin is unused, so the line will be tied high, this
- // address is unreachable.
- //
- // FIXME: The assumption is that unused pins are tied VCC.
- // This is not generally true.
- //
- // Use Arch::prefered_constant_net_type to determine what
- // constant net should be used for unused pins.
if ((used_pins & (1 << bel_pin_idx)) == 0) {
address_reachable = false;
break;
@@ -132,6 +124,26 @@ struct LutPin
bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }
};
+const std::string LutCell::nameOfPinConnection(LutCell::PinConnection conn)
+{
+ switch (conn) {
+ case PinConnection::Unconnected:
+ return std::string("unconnected");
+ case PinConnection::Gnd:
+ return std::string("Gnd");
+ case PinConnection::Vcc:
+ return std::string("Vcc");
+ case PinConnection::Const:
+ return std::string("Const");
+ case PinConnection::Signal:
+ return std::string("Signal");
+ default:
+ // Should never happen
+ NPNR_ASSERT_FALSE("Invalid value of LutCell::PinConnection");
+ return std::string();
+ }
+}
+
uint32_t LutMapper::check_wires(const Context *ctx) const
{
// Unlike the 3 argument version of check_wires, this version needs to
@@ -184,12 +196,7 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_
}
}
- // FIXME: The assumption is that unused pins are tied VCC.
- // This is not generally true.
- //
- // Use Arch::prefered_constant_net_type to determine what
- // constant net should be used for unused pins.
- uint32_t vcc_mask = 0;
+ uint32_t pin_mask = 0;
DynamicBitarray<> wire_equation;
wire_equation.resize(2);
@@ -248,11 +255,11 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_
bool good_for_wire = valid_pin_for_wire && !invalid_pin_for_wire;
if (!good_for_wire) {
- vcc_mask |= (1 << pin_idx);
+ pin_mask |= (1 << pin_idx);
}
}
- return vcc_mask;
+ return pin_mask;
}
bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping,
@@ -381,26 +388,18 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping
}
// Not all LUT inputs are used
- uint32_t vcc_pins = 0;
+ uint32_t pin_mask = 0;
if (cells.size() != element.lut_bels.size()) {
- // Look to see if wires can be run from element inputs to unused
- // outputs. If not, block the BEL pin by tying to VCC.
- //
- // FIXME: The assumption is that unused pins are tied VCC.
- // This is not generally true.
- //
- // Use Arch::prefered_constant_net_type to determine what
- // constant net should be used for unused pins.
- vcc_pins = check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, blocked_luts);
+ pin_mask = check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, blocked_luts);
+ }
+
#if defined(DEBUG_LUT_ROTATION)
- log_info("vcc_pins = 0x%x", vcc_pins);
- for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
- CellInfo *cell = cells[cell_idx];
- log(", %s => %s", ctx->nameOfBel(cell->bel), cell->name.c_str(ctx));
- }
- log("\n");
-#endif
+ log_info("Cell bindings:\n");
+ for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
+ CellInfo *cell = cells[cell_idx];
+ log_info(" - %s => %s\n", ctx->nameOfBel(cell->bel), cell->name.c_str(ctx));
}
+#endif
// Fill in the LUT mapping result
@@ -422,28 +421,35 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping
cell.belPins[cellPin] = belPin;
}
- cell.lutCell.vcc_pins.clear();
+ cell.lutCell.pin_connections.clear();
// All LUT inputs used
if (cells.size() == element.lut_bels.size()) {
for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.pins.size(); ++bel_pin_idx) {
if ((used_pins & (1 << bel_pin_idx)) == 0) {
NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1);
- cell.lutCell.vcc_pins.emplace(lutBel.pins.at(bel_pin_idx));
+ cell.lutCell.pin_connections.emplace(lutBel.pins.at(bel_pin_idx), LutCell::PinConnection::Vcc);
}
}
}
// Only some LUT inputs used
else {
for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.pins.size(); ++bel_pin_idx) {
- if ((vcc_pins & (1 << bel_pin_idx)) != 0) {
+ if ((pin_mask & (1 << bel_pin_idx)) != 0) {
NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1);
auto pin = lutBel.pins.at(bel_pin_idx);
- cell.lutCell.vcc_pins.emplace(pin);
+ cell.lutCell.pin_connections.emplace(pin, LutCell::PinConnection::Vcc);
}
}
}
+#if defined(DEBUG_LUT_ROTATION)
+ log_info("Pin connections for LUT cell %s:\n", cellInfo->name.c_str(ctx));
+ for (const auto &it : cell.lutCell.pin_connections) {
+ log_info(" - %s : %s\n", it.first.c_str(ctx), LutCell::nameOfPinConnection(it.second).c_str());
+ }
+#endif
+
lut_mapping->cells.push_back(cell);
}
@@ -456,7 +462,7 @@ void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cel
std::vector<int8_t> pin_map;
pin_map.resize(lut_bel.pins.size(), -1);
- NPNR_ASSERT(lut_cell.pins.size() < std::numeric_limits<decltype(pin_map)::value_type>::max());
+ NPNR_ASSERT(lut_cell.pins.size() < (size_t)std::numeric_limits<decltype(pin_map)::value_type>::max());
for (size_t cell_pin_idx = 0; cell_pin_idx < lut_cell.pins.size(); ++cell_pin_idx) {
IdString cell_pin = lut_cell.pins[cell_pin_idx];
diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h
index 8f33507a..892f457c 100644
--- a/fpga_interchange/luts.h
+++ b/fpga_interchange/luts.h
@@ -42,11 +42,22 @@ enum LogicLevel
struct LutCell
{
+ enum class PinConnection
+ {
+ Unconnected,
+ Gnd,
+ Vcc,
+ Const,
+ Signal
+ };
+
// LUT cell pins for equation, LSB first.
std::vector<IdString> pins;
pool<IdString> lut_pins;
- pool<IdString> vcc_pins;
+ dict<IdString, PinConnection> pin_connections;
DynamicBitarray<> equation;
+
+ static const std::string nameOfPinConnection(PinConnection conn);
};
struct LutBel
diff --git a/fpga_interchange/site_arch.cc b/fpga_interchange/site_arch.cc
index f78e8af4..bb9c9a11 100644
--- a/fpga_interchange/site_arch.cc
+++ b/fpga_interchange/site_arch.cc
@@ -133,8 +133,15 @@ SiteArch::SiteArch(const SiteInformation *site_info)
}
// Create list of out of site sources and sinks.
-
bool have_vcc_pins = false;
+ 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);
+
for (CellInfo *cell : site_info->cells_in_site) {
for (const auto &pin_pair : cell->cell_bel_pins) {
if (!cell->ports.count(pin_pair.first))
@@ -145,8 +152,18 @@ SiteArch::SiteArch(const SiteInformation *site_info)
}
}
- if (!cell->lut_cell.vcc_pins.empty()) {
- have_vcc_pins = true;
+ 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;
+ }
+ }
}
}
@@ -239,10 +256,9 @@ SiteArch::SiteArch(const SiteInformation *site_info)
}
}
- IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name);
NetInfo *vcc_net = ctx->nets.at(vcc_net_name).get();
- auto iter = nets.find(vcc_net);
- if (iter == nets.end() && have_vcc_pins) {
+ auto vcc_iter = nets.find(vcc_net);
+ if (vcc_iter == nets.end() && have_vcc_pins) {
// VCC net isn't present, add it.
SiteNetInfo net_info;
net_info.net = vcc_net;
@@ -250,13 +266,53 @@ SiteArch::SiteArch(const SiteInformation *site_info)
net_info.driver.net = vcc_net;
auto result = nets.emplace(vcc_net, net_info);
NPNR_ASSERT(result.second);
- iter = result.first;
+ 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;
}
for (CellInfo *cell : site_info->cells_in_site) {
- for (IdString vcc_pin : cell->lut_cell.vcc_pins) {
- SiteWire wire = getBelPinWire(cell->bel, vcc_pin);
- iter->second.users.emplace(wire);
+ 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
}
}
diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc
index b7a71397..82832ed9 100644
--- a/fpga_interchange/site_lut_mapping_cache.cc
+++ b/fpga_interchange/site_lut_mapping_cache.cc
@@ -138,8 +138,8 @@ bool SiteLutMappingResult::apply(const SiteInformation &siteInfo)
}
// LUT data
- // FIXME: Is there any other info that is being updated than vcc_pins ?
- cellInfo->lut_cell.vcc_pins = std::move(cell.lutCell.vcc_pins);
+ // FIXME: Is there any other info that is being updated than pin_connections ?
+ cellInfo->lut_cell.pin_connections = std::move(cell.lutCell.pin_connections);
}
return true;