diff options
author | myrtle <gatecat@ds0.me> | 2022-05-13 09:09:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-13 09:09:50 +0100 |
commit | 4ecbf6c6e941699413e0d0bba660fc9dc18efcfe (patch) | |
tree | 4dc7868ffbb4d86e45fb5874e17b88d747e72bfc | |
parent | 41936fefac2b819ad77204f0ed64ba01e9138c2a (diff) | |
parent | d75c45c63f444af0349463346101c9d7d7ae6283 (diff) | |
download | nextpnr-4ecbf6c6e941699413e0d0bba660fc9dc18efcfe.tar.gz nextpnr-4ecbf6c6e941699413e0d0bba660fc9dc18efcfe.tar.bz2 nextpnr-4ecbf6c6e941699413e0d0bba660fc9dc18efcfe.zip |
Merge pull request #985 from antmicro/interchange-lut-constants
[interchange] Tying unused LUT inputs according to architecture
-rw-r--r-- | fpga_interchange/arch.cc | 54 | ||||
-rw-r--r-- | fpga_interchange/luts.cc | 86 | ||||
-rw-r--r-- | fpga_interchange/luts.h | 13 | ||||
-rw-r--r-- | fpga_interchange/site_arch.cc | 81 | ||||
-rw-r--r-- | fpga_interchange/site_lut_mapping_cache.cc | 4 |
5 files changed, 180 insertions, 58 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index e55c94af..6a7c4fe1 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -301,6 +301,12 @@ void Arch::init() for (size_t tile_type = 0; tile_type < chip_info->tile_types.size(); ++tile_type) { pseudo_pip_data.init_tile_type(getCtx(), tile_type); } + + // Warn if there is no preferred constant net defined in the architecture + IdString const_net_name(getCtx()->chip_info->constants->best_constant_net); + if (const_net_name == IdString()) { + log_warning("The architecture does not specify preferred constant net. Using VCC as default.\n"); + } } // ----------------------------------------------------------------------- @@ -874,17 +880,31 @@ 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 == IdString() || const_net_name == vcc_net_name || const_net_name == gnd_net_name); + + // FIXME: Use VCC if the architecture does not device the best constant + if (const_net_name == IdString()) { + const_net_name = vcc_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 +916,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..2a847253 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,39 @@ 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::Const); + } else { + cell.lutCell.pin_connections.emplace(lutBel.pins.at(bel_pin_idx), LutCell::PinConnection::Signal); } } } // 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::Const); + } else { + cell.lutCell.pin_connections.emplace(lutBel.pins.at(bel_pin_idx), LutCell::PinConnection::Signal); } } } +#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 +466,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..d0a5c48c 100644 --- a/fpga_interchange/site_arch.cc +++ b/fpga_interchange/site_arch.cc @@ -133,8 +133,20 @@ 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 == IdString() || const_net_name == vcc_net_name || const_net_name == gnd_net_name); + + // FIXME: Use VCC if the architecture does not device the best constant + if (const_net_name == IdString()) { + const_net_name = vcc_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 +157,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 +261,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 +271,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; |