From d52516756cf32ecb53b75e8a6f032ebeeb427a71 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 9 Jul 2021 15:40:06 +0200 Subject: Working site LUT mapping cache Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/arch.cc | 7 ++ fpga_interchange/arch.h | 2 + fpga_interchange/luts.cc | 107 +++++++++++++++--- fpga_interchange/luts.h | 12 +- fpga_interchange/site_lut_mapping_cache.cc | 172 +++++++++++++++++++++++++++++ fpga_interchange/site_lut_mapping_cache.h | 130 ++++++++++++++++++++++ fpga_interchange/site_router.cc | 82 +++++++++----- 7 files changed, 470 insertions(+), 42 deletions(-) create mode 100644 fpga_interchange/site_lut_mapping_cache.cc create mode 100644 fpga_interchange/site_lut_mapping_cache.h (limited to 'fpga_interchange') diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 901725d4..33720e98 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -813,6 +813,10 @@ bool Arch::place() getCtx()->attrs[getCtx()->id("step")] = std::string("place"); archInfoToAttributes(); + // Print site LUT mapping caching stats + log_info("Site LUT mapping cache miss ratio: %.1f%%\n", + getCtx()->site_lut_mapping_cache.getMissRatio() * 100.0f); + getCtx()->check(); return true; @@ -836,6 +840,9 @@ static void prepare_sites_for_routing(Context *ctx) // pins to ensure a routeable pin choice. ctx->site_routing_cache.clear(); + // Clear the LUT mapping cache + ctx->site_lut_mapping_cache.clear(); + // Have site router bind site routing (via bindPip and bindWire). // This is important so that the pseudo pips are correctly blocked prior // to handing the design to the generalized router algorithms. diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 896a603a..de7232d4 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -41,6 +41,7 @@ #include "pseudo_pip_model.h" #include "site_router.h" #include "site_routing_cache.h" +#include "site_lut_mapping_cache.h" NEXTPNR_NAMESPACE_BEGIN @@ -1130,6 +1131,7 @@ struct Arch : ArchAPI<ArchRanges> Lookahead lookahead; mutable RouteNodeStorage node_storage; mutable SiteRoutingCache site_routing_cache; + mutable SiteLutMappingCache site_lut_mapping_cache; bool disallow_site_routing; CellParameters cell_parameters; diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc index 0156d379..2ac3b6da 100644 --- a/fpga_interchange/luts.cc +++ b/fpga_interchange/luts.cc @@ -22,6 +22,8 @@ #include "log.h" #include "nextpnr.h" +#include "site_lut_mapping_cache.h" + //#define DEBUG_LUT_ROTATION NEXTPNR_NAMESPACE_BEGIN @@ -253,7 +255,7 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_ return vcc_mask; } -bool LutMapper::remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops> *blocked_luts) +bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping, pool<const LutBel *, hash_ptr_ops> *blocked_luts) { dict<NetInfo *, LutPin, hash_ptr_ops> lut_pin_map; std::vector<const LutBel *> lut_bels; @@ -377,6 +379,94 @@ bool LutMapper::remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops } } + // Not all LUT inputs are used + uint32_t vcc_pins = 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); +#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 + } + + // Fill in the LUT mapping result + + // Push new cell -> BEL pin maps out to cells now that equations have been + // verified! + lut_mapping->cells.reserve(cells.size()); + for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { + CellInfo *cellInfo = cells[cell_idx]; + auto &lutBel = *lut_bels[cell_idx]; + + // Add the cell data + SiteLutMappingResult::Cell cell; + cell.belIndex = cellInfo->bel.index; + + // Cell to BEL pin map + for (size_t pin_idx = 0; pin_idx < cellInfo->lut_cell.pins.size(); ++pin_idx) { + IdString cellPin = cellInfo->lut_cell.pins[pin_idx]; + IdString belPin = lutBel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]]; + cell.belPins[cellPin] = belPin; + } + + cell.lutCell.vcc_pins.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)); + } + } + } + // 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) { + 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); + } + } + } + + lut_mapping->cells.push_back(cell); + } + +/* +#ifdef DEBUG_LUT_ROTATION + log_info("Final mapping:\n"); + for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { + CellInfo *cell = cells[cell_idx]; + for (auto &cell_pin_pair : cell->cell_bel_pins) { + log_info("%s %s %s =>", cell->type.c_str(ctx), cell->name.c_str(ctx), cell_pin_pair.first.c_str(ctx)); + for (auto bel_pin : cell_pin_pair.second) { + log(" %s", bel_pin.c_str(ctx)); + } + log("\n"); + } + } +#endif +*/ + + + + +/* + // Push new cell -> BEL pin maps out to cells now that equations have been // verified! for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { @@ -434,20 +524,7 @@ bool LutMapper::remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops } } } - -#ifdef DEBUG_LUT_ROTATION - log_info("Final mapping:\n"); - for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { - CellInfo *cell = cells[cell_idx]; - for (auto &cell_pin_pair : cell->cell_bel_pins) { - log_info("%s %s %s =>", cell->type.c_str(ctx), cell->name.c_str(ctx), cell_pin_pair.first.c_str(ctx)); - for (auto bel_pin : cell_pin_pair.second) { - log(" %s", bel_pin.c_str(ctx)); - } - log("\n"); - } - } -#endif +*/ return true; } diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h index cbb817c9..7b6ce758 100644 --- a/fpga_interchange/luts.h +++ b/fpga_interchange/luts.h @@ -31,6 +31,8 @@ NEXTPNR_NAMESPACE_BEGIN struct CellInfo; struct Context; +struct SiteLutMappingResult; + enum LogicLevel { LL_Zero, @@ -66,6 +68,14 @@ struct LutBel int32_t max_pin; }; +struct SiteLutMapping +{ + struct LutCellMapping { + LutCell lut_cell; + }; +}; + + // Work forward from cell definition and cell -> bel pin map and check that // equation is valid. void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel, @@ -89,7 +99,7 @@ struct LutMapper std::vector<CellInfo *> cells; - bool remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops> *blocked_luts); + bool remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping, pool<const LutBel *, hash_ptr_ops> *blocked_luts); // Determine which wires given the current mapping must be tied to the // default constant. diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc new file mode 100644 index 00000000..bcde7621 --- /dev/null +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -0,0 +1,172 @@ +/* + * 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 "nextpnr.h" +#include "archdefs.h" +#include "site_arch.h" +#include "site_lut_mapping_cache.h" + +NEXTPNR_NAMESPACE_BEGIN + +// ============================================================================ + +SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { + const Context *ctx = siteInfo.ctx; + + // Look for LUT cells in the site + std::vector<CellInfo*> lutCells; + lutCells.reserve(siteInfo.cells_in_site.size()); + + for (CellInfo* cellInfo : siteInfo.cells_in_site) { + + // Not a LUT cell + if (cellInfo->lut_cell.pins.empty()) { + continue; + } + + // Not bound to a LUT BEL + BelId bel = cellInfo->bel; + const auto &bel_data = bel_info(ctx->chip_info, bel); + if (bel_data.lut_element == -1) { + continue; + } + + lutCells.push_back(cellInfo); + } + + // Sort cells by BEL indices to maintain always the same order + std::sort(lutCells.begin(), lutCells.end(), + [](const CellInfo* a, const CellInfo* b) + { + return a->bel.index > b->bel.index; + }); + + // Initialize the key + SiteLutMappingKey key; + key.tileType = siteInfo.tile_type; + key.siteType = ctx->chip_info->sites[siteInfo.site].site_type; + key.cells.reserve(lutCells.size()); + + // Get bound nets. Store localized (to the LUT cluster) net indices only + // to get always the same key for the same LUT port configuration even + // when the actual global net names are different. + dict<IdString, int32_t> netMap; + for (CellInfo* cellInfo : lutCells) { + + SiteLutMappingKey::Cell cell; + cell.type = cellInfo->type; + cell.belIndex = cellInfo->bel.index; + + for (const auto& port : cellInfo->ports) { + const auto& portInfo = port.second; + if (portInfo.net != nullptr) { + auto netInfo = portInfo.net; + int32_t netId = -1; + + auto it = netMap.find(netInfo->name); + if (it != netMap.end()) { + netId = it->second; + } + else { + netId = (int32_t)netMap.size(); + netMap[netInfo->name] = netId; + } + + cell.conns[portInfo.name] = netId; + } + } + + // Add the cell entry + key.cells.push_back(cell); + } + + return key; +} + +// ============================================================================ + + +bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { + + Context *ctx = const_cast<Context*>(siteInfo.ctx); + TileStatus &tileStatus = ctx->get_tile_status(siteInfo.tile); + + for (auto& cell : cells) { + + // Get the bound cell + CellInfo* cellInfo = tileStatus.boundcells[cell.belIndex]; + NPNR_ASSERT(cellInfo); + + // Double check BEL binding + NPNR_ASSERT(cellInfo->bel.tile = siteInfo.tile); + NPNR_ASSERT(cellInfo->bel.index = cell.belIndex); + + // Cell <-> BEL pin map + size_t numPins = cellInfo->lut_cell.pins.size(); + for (size_t pinIdx = 0; pinIdx < numPins; ++pinIdx) { + IdString cellPin = cellInfo->lut_cell.pins[pinIdx]; + auto &belPins = cellInfo->cell_bel_pins[cellPin]; + + belPins.resize(1); + belPins[0] = cell.belPins[cellPin]; + } + + // 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); + } + + return true; +} + +// ============================================================================ + +void SiteLutMappingCache::add (const SiteLutMappingKey& key, + const SiteLutMappingResult& result) +{ + cache_[key] = result; +} + +bool SiteLutMappingCache::get (const SiteLutMappingKey& key, + SiteLutMappingResult* result) +{ + if (cache_.count(key) == 0) { + numMisses++; + return false; + } + + numHits++; + *result = cache_[key]; + return true; +} + +void SiteLutMappingCache::clear () { + cache_.clear(); + clearStats(); +} + +void SiteLutMappingCache::clearStats () { + numHits = 0; + numMisses = 0; +} + +// ============================================================================ + +NEXTPNR_NAMESPACE_END + diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h new file mode 100644 index 00000000..4a81711f --- /dev/null +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -0,0 +1,130 @@ +/* + * 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. + * + */ + +#ifndef SITE_LUT_MAPPING_CACHE_H +#define SITE_LUT_MAPPING_CACHE_H + +#include "idstring.h" +#include "nextpnr_namespaces.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Key structure used in site LUT mapping cache +struct SiteLutMappingKey { + + // LUT Cell data + struct Cell { + IdString type; // Cell type + int32_t belIndex; // Bound BEL index + + // Port to net assignments. These are local net ids generated during + // key creation. This is to abstract connections from actual design + // net names. + dict<IdString, int32_t> conns; + + bool operator == (const Cell& other) const { + return (type == other.type) && + (belIndex == other.belIndex) && + (conns == other.conns); + } + + bool operator < (const Cell& other) const { + return belIndex < other.belIndex; + } + }; + + int32_t tileType; // Tile type + int32_t siteType; // Site type in that tile type + std::vector<Cell> cells; // LUT cell data + + static SiteLutMappingKey create (const SiteInformation& siteInfo); + + bool operator == (const SiteLutMappingKey &other) const { + return (tileType == other.tileType) && + (siteType == other.siteType) && + (cells == other.cells); + } + + bool operator != (const SiteLutMappingKey &other) const { + return (tileType != other.tileType) || + (siteType != other.siteType) || + (cells != other.cells); + } + + unsigned int hash () const { + unsigned int h = 0; + h = mkhash(h, tileType); + h = mkhash(h, siteType); + for (const auto& cell : cells) { + h = mkhash(h, cell.type.index); + h = mkhash(h, cell.belIndex); + for (const auto& conn : cell.conns) { + h = mkhash(h, conn.first.index); + h = mkhash(h, conn.second); + } + } + return h; + } +}; + +// Site LUT mapping result data +struct SiteLutMappingResult { + + // LUT cell data + struct Cell { + int32_t belIndex; // BEL in tile index + LutCell lutCell; // LUT mapping data + dict<IdString, IdString> belPins; // Cell to BEL pin mapping + }; + + bool isValid; // Validity flag + std::vector<Cell> cells; // Cell data + + pool<std::pair<IdString, IdString>> blockedWires; + + // Applies the mapping result to the site + bool apply (const SiteInformation& siteInfo); +}; + +// Site LUT mapping cache object +class SiteLutMappingCache { +public: + + void add (const SiteLutMappingKey& key, const SiteLutMappingResult& result); + bool get (const SiteLutMappingKey& key, SiteLutMappingResult* result); + + void clear (); + void clearStats (); + + float getMissRatio () const { + return (float)numMisses / (float)(numHits + numMisses); + } + +private: + + dict<SiteLutMappingKey, SiteLutMappingResult> cache_; + + size_t numHits = 0; + size_t numMisses = 0; +}; + + +NEXTPNR_NAMESPACE_END + +#endif /* SITE_LUT_MAPPING_CACHE_H */ diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index 92176d86..bcfe4539 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -1041,42 +1041,71 @@ static void apply_routing(Context *ctx, const SiteArch &site_arch, pool<std::pai static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<IdString, IdString>> *blocked_wires) { const Context *ctx = site_info.ctx; - const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type); - std::vector<LutMapper> lut_mappers; - lut_mappers.reserve(lut_elements.size()); - for (size_t i = 0; i < lut_elements.size(); ++i) { - lut_mappers.push_back(LutMapper(lut_elements[i])); - } - for (CellInfo *cell : site_info.cells_in_site) { - if (cell->lut_cell.pins.empty()) { - continue; - } + // Create a site LUT mapping key + SiteLutMappingKey key = SiteLutMappingKey::create(site_info); - BelId bel = cell->bel; - const auto &bel_data = bel_info(ctx->chip_info, bel); - if (bel_data.lut_element != -1) { - lut_mappers[bel_data.lut_element].cells.push_back(cell); - } - } + // Get the solution from cache. If not found then compute it + SiteLutMappingResult lutMapping; + if (!ctx->site_lut_mapping_cache.get(key, &lutMapping)) { - blocked_wires->clear(); - for (LutMapper lut_mapper : lut_mappers) { - if (lut_mapper.cells.empty()) { - continue; + const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type); + std::vector<LutMapper> lut_mappers; + lut_mappers.reserve(lut_elements.size()); + for (size_t i = 0; i < lut_elements.size(); ++i) { + lut_mappers.push_back(LutMapper(lut_elements[i])); } - pool<const LutBel *, hash_ptr_ops> blocked_luts; - if (!lut_mapper.remap_luts(ctx, &blocked_luts)) { - return false; + for (CellInfo *cell : site_info.cells_in_site) { + if (cell->lut_cell.pins.empty()) { + continue; + } + + BelId bel = cell->bel; + const auto &bel_data = bel_info(ctx->chip_info, bel); + if (bel_data.lut_element != -1) { + lut_mappers[bel_data.lut_element].cells.push_back(cell); + } } - for (const LutBel *lut_bel : blocked_luts) { - blocked_wires->emplace(std::make_pair(lut_bel->name, lut_bel->output_pin)); + bool res = true; + + lutMapping.blockedWires.clear(); + for (LutMapper lut_mapper : lut_mappers) { + if (lut_mapper.cells.empty()) { + continue; + } + + pool<const LutBel *, hash_ptr_ops> blocked_luts; + if (!lut_mapper.remap_luts(ctx, &lutMapping, &blocked_luts)) { + res = false; + break; + } + + for (const LutBel *lut_bel : blocked_luts) { + lutMapping.blockedWires.emplace(std::make_pair(lut_bel->name, lut_bel->output_pin)); + } } + + lutMapping.isValid = res; + + // Add the solution to the cache + ctx->site_lut_mapping_cache.add(key, lutMapping); } - return true; + // Apply the solution if valid + if (lutMapping.isValid) { + + lutMapping.apply(site_info); + + blocked_wires->clear(); + blocked_wires->insert( + lutMapping.blockedWires.begin(), + lutMapping.blockedWires.end() + ); + } + + return lutMapping.isValid; } // Block outputs of unavailable LUTs to prevent site router from using them. @@ -1246,6 +1275,7 @@ bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_sta // Because site routing checks are expensive, cache them. // SiteRouter::bindBel/unbindBel should correctly invalid the cache by // setting dirty=true. + if (!dirty) { return site_ok; } -- cgit v1.2.3 From 044c9ba2d4e66cf34214fdfd62fb90a872da64b1 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 13:28:40 +0200 Subject: LUT mapping cache optimizations 1 Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/site_lut_mapping_cache.cc | 28 ++++++++++++---- fpga_interchange/site_lut_mapping_cache.h | 52 +++++++++++++++--------------- 2 files changed, 48 insertions(+), 32 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index bcde7621..03ef03be 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -73,29 +73,44 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { cell.type = cellInfo->type; cell.belIndex = cellInfo->bel.index; + memset((void*)cell.conns, 0, + sizeof(int32_t) * SiteLutMappingKey::MAX_LUT_INPUTS); + + size_t portId = 0; for (const auto& port : cellInfo->ports) { const auto& portInfo = port.second; + + // Consider only LUT inputs + if (portInfo.type != PORT_IN) { + continue; + } + + // Assign net id if any + int32_t netId = 0; if (portInfo.net != nullptr) { auto netInfo = portInfo.net; - int32_t netId = -1; auto it = netMap.find(netInfo->name); if (it != netMap.end()) { netId = it->second; } else { - netId = (int32_t)netMap.size(); + netId = (int32_t)netMap.size() + 1; netMap[netInfo->name] = netId; } - - cell.conns[portInfo.name] = netId; } + + NPNR_ASSERT(portId < SiteLutMappingKey::MAX_LUT_INPUTS); + cell.conns[portId++] = netId; } // Add the cell entry key.cells.push_back(cell); } + // Compute hash + key.computeHash(); + return key; } @@ -120,9 +135,10 @@ bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { // Cell <-> BEL pin map size_t numPins = cellInfo->lut_cell.pins.size(); for (size_t pinIdx = 0; pinIdx < numPins; ++pinIdx) { - IdString cellPin = cellInfo->lut_cell.pins[pinIdx]; - auto &belPins = cellInfo->cell_bel_pins[cellPin]; + const IdString& cellPin = cellInfo->lut_cell.pins[pinIdx]; + auto &belPins = cellInfo->cell_bel_pins[cellPin]; + // There is only one pin belPins.resize(1); belPins[0] = cell.belPins[cellPin]; } diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index 4a81711f..b07e3e77 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -28,6 +28,11 @@ NEXTPNR_NAMESPACE_BEGIN // Key structure used in site LUT mapping cache struct SiteLutMappingKey { + // Maximum number of LUT cells + static constexpr size_t MAX_LUT_CELLS = 8; + // Maximum number of LUT inputs per cell + static constexpr size_t MAX_LUT_INPUTS = 6; + // LUT Cell data struct Cell { IdString type; // Cell type @@ -35,51 +40,46 @@ struct SiteLutMappingKey { // Port to net assignments. These are local net ids generated during // key creation. This is to abstract connections from actual design - // net names. - dict<IdString, int32_t> conns; - - bool operator == (const Cell& other) const { - return (type == other.type) && - (belIndex == other.belIndex) && - (conns == other.conns); - } - - bool operator < (const Cell& other) const { - return belIndex < other.belIndex; - } + // net names. the Id 0 means unconnected. + int32_t conns [MAX_LUT_INPUTS]; }; int32_t tileType; // Tile type int32_t siteType; // Site type in that tile type std::vector<Cell> cells; // LUT cell data + unsigned int hash_; // Precomputed hash + static SiteLutMappingKey create (const SiteInformation& siteInfo); + + void computeHash () { + hash_ = mkhash(0, tileType); + hash_ = mkhash(hash_, siteType); + for (const auto& cell : cells) { + hash_ = mkhash(hash_, cell.type.index); + hash_ = mkhash(hash_, cell.belIndex); + for (size_t i=0; i<MAX_LUT_INPUTS; ++i) { + hash_ = mkhash(hash_, cell.conns[i]); + } + } + } bool operator == (const SiteLutMappingKey &other) const { - return (tileType == other.tileType) && + return (hash_ == other.hash_) && + (tileType == other.tileType) && (siteType == other.siteType) && (cells == other.cells); } bool operator != (const SiteLutMappingKey &other) const { - return (tileType != other.tileType) || + return (hash_ != other.hash_) || + (tileType != other.tileType) || (siteType != other.siteType) || (cells != other.cells); } unsigned int hash () const { - unsigned int h = 0; - h = mkhash(h, tileType); - h = mkhash(h, siteType); - for (const auto& cell : cells) { - h = mkhash(h, cell.type.index); - h = mkhash(h, cell.belIndex); - for (const auto& conn : cell.conns) { - h = mkhash(h, conn.first.index); - h = mkhash(h, conn.second); - } - } - return h; + return hash_; } }; -- cgit v1.2.3 From 0336f55b16373874cf4ac5661d9724d0a358454c Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 13:55:19 +0200 Subject: LUT mapping ceche optimizations 2 Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/luts.cc | 80 ------------------------------ fpga_interchange/site_lut_mapping_cache.cc | 9 ++-- fpga_interchange/site_lut_mapping_cache.h | 21 +++++--- 3 files changed, 17 insertions(+), 93 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc index 2ac3b6da..9c68739e 100644 --- a/fpga_interchange/luts.cc +++ b/fpga_interchange/luts.cc @@ -446,86 +446,6 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping lut_mapping->cells.push_back(cell); } -/* -#ifdef DEBUG_LUT_ROTATION - log_info("Final mapping:\n"); - for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { - CellInfo *cell = cells[cell_idx]; - for (auto &cell_pin_pair : cell->cell_bel_pins) { - log_info("%s %s %s =>", cell->type.c_str(ctx), cell->name.c_str(ctx), cell_pin_pair.first.c_str(ctx)); - for (auto bel_pin : cell_pin_pair.second) { - log(" %s", bel_pin.c_str(ctx)); - } - log("\n"); - } - } -#endif -*/ - - - - -/* - - // Push new cell -> BEL pin maps out to cells now that equations have been - // verified! - for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { - CellInfo *cell = cells[cell_idx]; - auto &lut_bel = *lut_bels[cell_idx]; - - for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) { - auto &bel_pins = cell->cell_bel_pins[cell->lut_cell.pins[pin_idx]]; - bel_pins.clear(); - bel_pins.push_back(lut_bel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]]); - } - } - - if (cells.size() == element.lut_bels.size()) { - for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { - CellInfo *cell = cells[cell_idx]; - auto &lut_bel = *lut_bels[cell_idx]; - cell->lut_cell.vcc_pins.clear(); - for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.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->lut_cell.vcc_pins.emplace(lut_bel.pins.at(bel_pin_idx)); - } - } - } - } else { - // 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. - uint32_t vcc_pins = 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 - - for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { - CellInfo *cell = cells[cell_idx]; - auto &lut_bel = *lut_bels[cell_idx]; - cell->lut_cell.vcc_pins.clear(); - for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) { - if ((vcc_pins & (1 << bel_pin_idx)) != 0) { - NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1); - auto pin = lut_bel.pins.at(bel_pin_idx); - cell->lut_cell.vcc_pins.emplace(pin); - } - } - } - } -*/ - return true; } diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index 03ef03be..44a72772 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -61,7 +61,7 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { SiteLutMappingKey key; key.tileType = siteInfo.tile_type; key.siteType = ctx->chip_info->sites[siteInfo.site].site_type; - key.cells.reserve(lutCells.size()); + key.numCells = 0; // Get bound nets. Store localized (to the LUT cluster) net indices only // to get always the same key for the same LUT port configuration even @@ -69,7 +69,9 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { dict<IdString, int32_t> netMap; for (CellInfo* cellInfo : lutCells) { - SiteLutMappingKey::Cell cell; + NPNR_ASSERT(key.numCells < SiteLutMappingKey::MAX_LUT_CELLS); + auto& cell = key.cells[key.numCells++]; + cell.type = cellInfo->type; cell.belIndex = cellInfo->bel.index; @@ -103,9 +105,6 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { NPNR_ASSERT(portId < SiteLutMappingKey::MAX_LUT_INPUTS); cell.conns[portId++] = netId; } - - // Add the cell entry - key.cells.push_back(cell); } // Compute hash diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index b07e3e77..df1ce474 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -28,7 +28,7 @@ NEXTPNR_NAMESPACE_BEGIN // Key structure used in site LUT mapping cache struct SiteLutMappingKey { - // Maximum number of LUT cells + // Maximum number of LUT cells per site static constexpr size_t MAX_LUT_CELLS = 8; // Maximum number of LUT inputs per cell static constexpr size_t MAX_LUT_INPUTS = 6; @@ -44,18 +44,21 @@ struct SiteLutMappingKey { int32_t conns [MAX_LUT_INPUTS]; }; - int32_t tileType; // Tile type - int32_t siteType; // Site type in that tile type - std::vector<Cell> cells; // LUT cell data + int32_t tileType; // Tile type + int32_t siteType; // Site type in that tile type + size_t numCells; // LUT cell count + Cell cells[MAX_LUT_CELLS]; // LUT cell data - unsigned int hash_; // Precomputed hash + unsigned int hash_; // Precomputed hash static SiteLutMappingKey create (const SiteInformation& siteInfo); void computeHash () { hash_ = mkhash(0, tileType); hash_ = mkhash(hash_, siteType); - for (const auto& cell : cells) { + hash_ = mkhash(hash_, numCells); + for (size_t j=0; j<numCells; ++j) { + const auto& cell = cells[j]; hash_ = mkhash(hash_, cell.type.index); hash_ = mkhash(hash_, cell.belIndex); for (size_t i=0; i<MAX_LUT_INPUTS; ++i) { @@ -68,14 +71,16 @@ struct SiteLutMappingKey { return (hash_ == other.hash_) && (tileType == other.tileType) && (siteType == other.siteType) && - (cells == other.cells); + (numCells == other.numCells) && + (!memcmp(cells, other.cells, sizeof(Cell) * numCells)); } bool operator != (const SiteLutMappingKey &other) const { return (hash_ != other.hash_) || (tileType != other.tileType) || (siteType != other.siteType) || - (cells != other.cells); + (numCells != other.numCells) || + (memcmp(cells, other.cells, sizeof(Cell) * numCells)); } unsigned int hash () const { -- cgit v1.2.3 From 857961a6bb9302847ecf605971015f1610dae476 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 14:55:45 +0200 Subject: Migrated C arrays to std::array containers. Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/site_lut_mapping_cache.cc | 3 +-- fpga_interchange/site_lut_mapping_cache.h | 37 ++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index 44a72772..3796d7ab 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -75,8 +75,7 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { cell.type = cellInfo->type; cell.belIndex = cellInfo->bel.index; - memset((void*)cell.conns, 0, - sizeof(int32_t) * SiteLutMappingKey::MAX_LUT_INPUTS); + cell.conns.fill(0); size_t portId = 0; for (const auto& port : cellInfo->ports) { diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index df1ce474..42a10ba7 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -41,13 +41,25 @@ struct SiteLutMappingKey { // Port to net assignments. These are local net ids generated during // key creation. This is to abstract connections from actual design // net names. the Id 0 means unconnected. - int32_t conns [MAX_LUT_INPUTS]; + std::array<int32_t, MAX_LUT_INPUTS> conns; + + bool operator == (const Cell& other) const { + return (type == other.type) && + (belIndex == other.belIndex) && + (conns == other.conns); + } + + bool operator != (const Cell& other) const { + return (type != other.type) || + (belIndex != other.belIndex) || + (conns != other.conns); + } }; int32_t tileType; // Tile type int32_t siteType; // Site type in that tile type size_t numCells; // LUT cell count - Cell cells[MAX_LUT_CELLS]; // LUT cell data + std::array<Cell, MAX_LUT_CELLS> cells; // LUT cell data unsigned int hash_; // Precomputed hash @@ -66,21 +78,32 @@ struct SiteLutMappingKey { } } } - + + bool compareCells (const SiteLutMappingKey &other) const { + if (numCells != other.numCells) { + return false; + } + + for (size_t i=0; i<numCells; ++i) { + if (cells[i] != other.cells[i]) { + return false; + } + } + return true; + } + bool operator == (const SiteLutMappingKey &other) const { return (hash_ == other.hash_) && (tileType == other.tileType) && (siteType == other.siteType) && - (numCells == other.numCells) && - (!memcmp(cells, other.cells, sizeof(Cell) * numCells)); + compareCells(other); } bool operator != (const SiteLutMappingKey &other) const { return (hash_ != other.hash_) || (tileType != other.tileType) || (siteType != other.siteType) || - (numCells != other.numCells) || - (memcmp(cells, other.cells, sizeof(Cell) * numCells)); + !compareCells(other); } unsigned int hash () const { -- cgit v1.2.3 From c95aa86a8e4fe290bdb030977b7ca40e619a0c30 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 15:16:31 +0200 Subject: Fixed assertion typos Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/site_lut_mapping_cache.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index 3796d7ab..86f39f2c 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -127,8 +127,8 @@ bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { NPNR_ASSERT(cellInfo); // Double check BEL binding - NPNR_ASSERT(cellInfo->bel.tile = siteInfo.tile); - NPNR_ASSERT(cellInfo->bel.index = cell.belIndex); + NPNR_ASSERT(cellInfo->bel.tile == siteInfo.tile); + NPNR_ASSERT(cellInfo->bel.index == cell.belIndex); // Cell <-> BEL pin map size_t numPins = cellInfo->lut_cell.pins.size(); -- cgit v1.2.3 From ccf2bb123c4c2f52142c82c3b6338856df4fbb80 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 15:53:00 +0200 Subject: Added computing and reporting LUT mapping cache size Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/site_lut_mapping_cache.cc | 15 +++++++++++++++ fpga_interchange/site_lut_mapping_cache.h | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) (limited to 'fpga_interchange') diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index 86f39f2c..7edb0818 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -149,6 +149,21 @@ bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { return true; } +size_t SiteLutMappingResult::getSizeInBytes () const { + + size_t size = 0; + + size += sizeof(SiteLutMappingResult); + size += blockedWires.size() * sizeof(std::pair<IdString, IdString>); + + for (const auto& cell : cells) { + size += sizeof(Cell); + size += cell.belPins.size() * sizeof(decltype(cell.belPins)::value_type); + } + + return size; +} + // ============================================================================ void SiteLutMappingCache::add (const SiteLutMappingKey& key, diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index 42a10ba7..b4c074c7 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -65,6 +65,10 @@ struct SiteLutMappingKey { static SiteLutMappingKey create (const SiteInformation& siteInfo); + size_t getSizeInBytes () const { + return sizeof(SiteLutMappingKey); + } + void computeHash () { hash_ = mkhash(0, tileType); hash_ = mkhash(hash_, siteType); @@ -128,6 +132,9 @@ struct SiteLutMappingResult { // Applies the mapping result to the site bool apply (const SiteInformation& siteInfo); + + // Returns size in bytes + size_t getSizeInBytes () const; }; // Site LUT mapping cache object @@ -144,6 +151,21 @@ public: return (float)numMisses / (float)(numHits + numMisses); } + size_t getCount () const { + return cache_.size(); + } + + size_t getSizeMB () const { + size_t size = 0; + for (const auto& it : cache_) { + size += it.first.getSizeInBytes(); + size += it.second.getSizeInBytes(); + } + + const size_t MB = 1024L * 1024L; + return (size + MB - 1) / MB; // Round up to megabytes + } + private: dict<SiteLutMappingKey, SiteLutMappingResult> cache_; -- cgit v1.2.3 From 8fc16a57c9dee5e7e0f83752a62612f70f18a38e Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Fri, 16 Jul 2021 16:01:21 +0200 Subject: Added more code comments, formatted the code Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/arch.cc | 6 +- fpga_interchange/luts.cc | 5 +- fpga_interchange/luts.h | 7 +- fpga_interchange/site_lut_mapping_cache.cc | 69 ++++++------- fpga_interchange/site_lut_mapping_cache.h | 155 +++++++++++++++-------------- fpga_interchange/site_router.cc | 5 +- 6 files changed, 124 insertions(+), 123 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 33720e98..64eef2ad 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -814,8 +814,10 @@ bool Arch::place() archInfoToAttributes(); // Print site LUT mapping caching stats - log_info("Site LUT mapping cache miss ratio: %.1f%%\n", - getCtx()->site_lut_mapping_cache.getMissRatio() * 100.0f); + log_info("Site LUT mapping cache stats:\n"); + log_info(" miss ratio: %.1f%%\n", getCtx()->site_lut_mapping_cache.getMissRatio() * 100.0f); + log_info(" peak size : %zuMB (%zu items)\n", getCtx()->site_lut_mapping_cache.getSizeMB(), + getCtx()->site_lut_mapping_cache.getCount()); getCtx()->check(); diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc index 9c68739e..d9e17ca9 100644 --- a/fpga_interchange/luts.cc +++ b/fpga_interchange/luts.cc @@ -255,7 +255,8 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_ return vcc_mask; } -bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping, pool<const LutBel *, hash_ptr_ops> *blocked_luts) +bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping, + pool<const LutBel *, hash_ptr_ops> *blocked_luts) { dict<NetInfo *, LutPin, hash_ptr_ops> lut_pin_map; std::vector<const LutBel *> lut_bels; @@ -417,7 +418,7 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping // Cell to BEL pin map for (size_t pin_idx = 0; pin_idx < cellInfo->lut_cell.pins.size(); ++pin_idx) { IdString cellPin = cellInfo->lut_cell.pins[pin_idx]; - IdString belPin = lutBel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]]; + IdString belPin = lutBel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]]; cell.belPins[cellPin] = belPin; } diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h index 7b6ce758..8f33507a 100644 --- a/fpga_interchange/luts.h +++ b/fpga_interchange/luts.h @@ -70,12 +70,12 @@ struct LutBel struct SiteLutMapping { - struct LutCellMapping { + struct LutCellMapping + { LutCell lut_cell; }; }; - // Work forward from cell definition and cell -> bel pin map and check that // equation is valid. void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel, @@ -99,7 +99,8 @@ struct LutMapper std::vector<CellInfo *> cells; - bool remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping, pool<const LutBel *, hash_ptr_ops> *blocked_luts); + bool remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping, + pool<const LutBel *, hash_ptr_ops> *blocked_luts); // Determine which wires given the current mapping must be tied to the // default constant. diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index 7edb0818..0cf741f2 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -17,23 +17,22 @@ * */ -#include "nextpnr.h" -#include "archdefs.h" -#include "site_arch.h" #include "site_lut_mapping_cache.h" +#include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN // ============================================================================ -SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { +SiteLutMappingKey SiteLutMappingKey::create(const SiteInformation &siteInfo) +{ const Context *ctx = siteInfo.ctx; // Look for LUT cells in the site - std::vector<CellInfo*> lutCells; + std::vector<CellInfo *> lutCells; lutCells.reserve(siteInfo.cells_in_site.size()); - for (CellInfo* cellInfo : siteInfo.cells_in_site) { + for (CellInfo *cellInfo : siteInfo.cells_in_site) { // Not a LUT cell if (cellInfo->lut_cell.pins.empty()) { @@ -52,10 +51,7 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { // Sort cells by BEL indices to maintain always the same order std::sort(lutCells.begin(), lutCells.end(), - [](const CellInfo* a, const CellInfo* b) - { - return a->bel.index > b->bel.index; - }); + [](const CellInfo *a, const CellInfo *b) { return a->bel.index > b->bel.index; }); // Initialize the key SiteLutMappingKey key; @@ -67,19 +63,19 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { // to get always the same key for the same LUT port configuration even // when the actual global net names are different. dict<IdString, int32_t> netMap; - for (CellInfo* cellInfo : lutCells) { + for (CellInfo *cellInfo : lutCells) { NPNR_ASSERT(key.numCells < SiteLutMappingKey::MAX_LUT_CELLS); - auto& cell = key.cells[key.numCells++]; + auto &cell = key.cells[key.numCells++]; - cell.type = cellInfo->type; - cell.belIndex = cellInfo->bel.index; + cell.type = cellInfo->type; + cell.belIndex = cellInfo->bel.index; cell.conns.fill(0); size_t portId = 0; - for (const auto& port : cellInfo->ports) { - const auto& portInfo = port.second; + for (const auto &port : cellInfo->ports) { + const auto &portInfo = port.second; // Consider only LUT inputs if (portInfo.type != PORT_IN) { @@ -89,13 +85,12 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { // Assign net id if any int32_t netId = 0; if (portInfo.net != nullptr) { - auto netInfo = portInfo.net; + auto netInfo = portInfo.net; auto it = netMap.find(netInfo->name); if (it != netMap.end()) { netId = it->second; - } - else { + } else { netId = (int32_t)netMap.size() + 1; netMap[netInfo->name] = netId; } @@ -114,27 +109,27 @@ SiteLutMappingKey SiteLutMappingKey::create (const SiteInformation& siteInfo) { // ============================================================================ +bool SiteLutMappingResult::apply(const SiteInformation &siteInfo) +{ -bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { - - Context *ctx = const_cast<Context*>(siteInfo.ctx); + Context *ctx = const_cast<Context *>(siteInfo.ctx); TileStatus &tileStatus = ctx->get_tile_status(siteInfo.tile); - for (auto& cell : cells) { + for (auto &cell : cells) { // Get the bound cell - CellInfo* cellInfo = tileStatus.boundcells[cell.belIndex]; + CellInfo *cellInfo = tileStatus.boundcells[cell.belIndex]; NPNR_ASSERT(cellInfo); // Double check BEL binding - NPNR_ASSERT(cellInfo->bel.tile == siteInfo.tile); + NPNR_ASSERT(cellInfo->bel.tile == siteInfo.tile); NPNR_ASSERT(cellInfo->bel.index == cell.belIndex); // Cell <-> BEL pin map size_t numPins = cellInfo->lut_cell.pins.size(); for (size_t pinIdx = 0; pinIdx < numPins; ++pinIdx) { - const IdString& cellPin = cellInfo->lut_cell.pins[pinIdx]; - auto &belPins = cellInfo->cell_bel_pins[cellPin]; + const IdString &cellPin = cellInfo->lut_cell.pins[pinIdx]; + auto &belPins = cellInfo->cell_bel_pins[cellPin]; // There is only one pin belPins.resize(1); @@ -149,14 +144,15 @@ bool SiteLutMappingResult::apply (const SiteInformation& siteInfo) { return true; } -size_t SiteLutMappingResult::getSizeInBytes () const { +size_t SiteLutMappingResult::getSizeInBytes() const +{ size_t size = 0; size += sizeof(SiteLutMappingResult); size += blockedWires.size() * sizeof(std::pair<IdString, IdString>); - for (const auto& cell : cells) { + for (const auto &cell : cells) { size += sizeof(Cell); size += cell.belPins.size() * sizeof(decltype(cell.belPins)::value_type); } @@ -166,14 +162,12 @@ size_t SiteLutMappingResult::getSizeInBytes () const { // ============================================================================ -void SiteLutMappingCache::add (const SiteLutMappingKey& key, - const SiteLutMappingResult& result) +void SiteLutMappingCache::add(const SiteLutMappingKey &key, const SiteLutMappingResult &result) { cache_[key] = result; } -bool SiteLutMappingCache::get (const SiteLutMappingKey& key, - SiteLutMappingResult* result) +bool SiteLutMappingCache::get(const SiteLutMappingKey &key, SiteLutMappingResult *result) { if (cache_.count(key) == 0) { numMisses++; @@ -185,17 +179,18 @@ bool SiteLutMappingCache::get (const SiteLutMappingKey& key, return true; } -void SiteLutMappingCache::clear () { +void SiteLutMappingCache::clear() +{ cache_.clear(); clearStats(); } -void SiteLutMappingCache::clearStats () { - numHits = 0; +void SiteLutMappingCache::clearStats() +{ + numHits = 0; numMisses = 0; } // ============================================================================ NEXTPNR_NAMESPACE_END - diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index b4c074c7..0025b889 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -20,75 +20,80 @@ #ifndef SITE_LUT_MAPPING_CACHE_H #define SITE_LUT_MAPPING_CACHE_H -#include "idstring.h" #include "nextpnr_namespaces.h" +#include "idstring.h" +#include "site_arch.h" NEXTPNR_NAMESPACE_BEGIN // Key structure used in site LUT mapping cache -struct SiteLutMappingKey { +struct SiteLutMappingKey +{ // Maximum number of LUT cells per site - static constexpr size_t MAX_LUT_CELLS = 8; + static constexpr size_t MAX_LUT_CELLS = 8; // Maximum number of LUT inputs per cell static constexpr size_t MAX_LUT_INPUTS = 6; // LUT Cell data - struct Cell { - IdString type; // Cell type - int32_t belIndex; // Bound BEL index - + struct Cell + { + IdString type; // Cell type + int32_t belIndex; // Bound BEL index + // Port to net assignments. These are local net ids generated during // key creation. This is to abstract connections from actual design // net names. the Id 0 means unconnected. std::array<int32_t, MAX_LUT_INPUTS> conns; - bool operator == (const Cell& other) const { - return (type == other.type) && - (belIndex == other.belIndex) && - (conns == other.conns); + bool operator==(const Cell &other) const + { + return (type == other.type) && (belIndex == other.belIndex) && (conns == other.conns); } - bool operator != (const Cell& other) const { - return (type != other.type) || - (belIndex != other.belIndex) || - (conns != other.conns); + bool operator!=(const Cell &other) const + { + return (type != other.type) || (belIndex != other.belIndex) || (conns != other.conns); } }; - int32_t tileType; // Tile type - int32_t siteType; // Site type in that tile type - size_t numCells; // LUT cell count + int32_t tileType; // Tile type + int32_t siteType; // Site type in that tile type + size_t numCells; // LUT cell count std::array<Cell, MAX_LUT_CELLS> cells; // LUT cell data - unsigned int hash_; // Precomputed hash + unsigned int hash_; // Precomputed hash - static SiteLutMappingKey create (const SiteInformation& siteInfo); + // Creates a key from the given site state + static SiteLutMappingKey create(const SiteInformation &siteInfo); - size_t getSizeInBytes () const { - return sizeof(SiteLutMappingKey); - } + // Returns size in bytes of the key + size_t getSizeInBytes() const { return sizeof(SiteLutMappingKey); } - void computeHash () { + // Precomputes hash of the key and stores it within + void computeHash() + { hash_ = mkhash(0, tileType); hash_ = mkhash(hash_, siteType); hash_ = mkhash(hash_, numCells); - for (size_t j=0; j<numCells; ++j) { - const auto& cell = cells[j]; + for (size_t j = 0; j < numCells; ++j) { + const auto &cell = cells[j]; hash_ = mkhash(hash_, cell.type.index); hash_ = mkhash(hash_, cell.belIndex); - for (size_t i=0; i<MAX_LUT_INPUTS; ++i) { + for (size_t i = 0; i < MAX_LUT_INPUTS; ++i) { hash_ = mkhash(hash_, cell.conns[i]); } } } - bool compareCells (const SiteLutMappingKey &other) const { + // Compares cell data of this and other key + bool compareCells(const SiteLutMappingKey &other) const + { if (numCells != other.numCells) { return false; } - for (size_t i=0; i<numCells; ++i) { + for (size_t i = 0; i < numCells; ++i) { if (cells[i] != other.cells[i]) { return false; } @@ -96,68 +101,70 @@ struct SiteLutMappingKey { return true; } - bool operator == (const SiteLutMappingKey &other) const { - return (hash_ == other.hash_) && - (tileType == other.tileType) && - (siteType == other.siteType) && + bool operator==(const SiteLutMappingKey &other) const + { + return (hash_ == other.hash_) && (tileType == other.tileType) && (siteType == other.siteType) && compareCells(other); } - bool operator != (const SiteLutMappingKey &other) const { - return (hash_ != other.hash_) || - (tileType != other.tileType) || - (siteType != other.siteType) || + bool operator!=(const SiteLutMappingKey &other) const + { + return (hash_ != other.hash_) || (tileType != other.tileType) || (siteType != other.siteType) || !compareCells(other); } - unsigned int hash () const { - return hash_; - } + unsigned int hash() const { return hash_; } }; // Site LUT mapping result data -struct SiteLutMappingResult { +struct SiteLutMappingResult +{ // LUT cell data - struct Cell { - int32_t belIndex; // BEL in tile index - LutCell lutCell; // LUT mapping data - dict<IdString, IdString> belPins; // Cell to BEL pin mapping + struct Cell + { + int32_t belIndex; // BEL in tile index + LutCell lutCell; // LUT mapping data + dict<IdString, IdString> belPins; // Cell to BEL pin mapping }; - bool isValid; // Validity flag - std::vector<Cell> cells; // Cell data + bool isValid; // Validity flag + std::vector<Cell> cells; // Cell data - pool<std::pair<IdString, IdString>> blockedWires; + pool<std::pair<IdString, IdString>> blockedWires; // Set of blocked wires // Applies the mapping result to the site - bool apply (const SiteInformation& siteInfo); + bool apply(const SiteInformation &siteInfo); // Returns size in bytes - size_t getSizeInBytes () const; + size_t getSizeInBytes() const; }; // Site LUT mapping cache object -class SiteLutMappingCache { -public: - - void add (const SiteLutMappingKey& key, const SiteLutMappingResult& result); - bool get (const SiteLutMappingKey& key, SiteLutMappingResult* result); - - void clear (); - void clearStats (); - - float getMissRatio () const { - return (float)numMisses / (float)(numHits + numMisses); - } - - size_t getCount () const { - return cache_.size(); - } - - size_t getSizeMB () const { +class SiteLutMappingCache +{ + public: + // Adds an entry to the cache + void add(const SiteLutMappingKey &key, const SiteLutMappingResult &result); + // Retrieves an entry from the cache. Returns false if not found + bool get(const SiteLutMappingKey &key, SiteLutMappingResult *result); + + // Clears the cache + void clear(); + // Clears statistics counters of the cache + void clearStats(); + + // Return get() miss ratio + float getMissRatio() const { return (float)numMisses / (float)(numHits + numMisses); } + + // Returns count of entries in the cache + size_t getCount() const { return cache_.size(); } + + // Returns size of the cache rounded upwards to full MBs. + size_t getSizeMB() const + { size_t size = 0; - for (const auto& it : cache_) { + for (const auto &it : cache_) { size += it.first.getSizeInBytes(); size += it.second.getSizeInBytes(); } @@ -166,15 +173,13 @@ public: return (size + MB - 1) / MB; // Round up to megabytes } -private: - - dict<SiteLutMappingKey, SiteLutMappingResult> cache_; + private: + dict<SiteLutMappingKey, SiteLutMappingResult> cache_; // The cache - size_t numHits = 0; - size_t numMisses = 0; + size_t numHits = 0; // Hit count + size_t numMisses = 0; // Miss count }; - NEXTPNR_NAMESPACE_END #endif /* SITE_LUT_MAPPING_CACHE_H */ diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index bcfe4539..4094b331 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -1099,10 +1099,7 @@ static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<Id lutMapping.apply(site_info); blocked_wires->clear(); - blocked_wires->insert( - lutMapping.blockedWires.begin(), - lutMapping.blockedWires.end() - ); + blocked_wires->insert(lutMapping.blockedWires.begin(), lutMapping.blockedWires.end()); } return lutMapping.isValid; -- cgit v1.2.3 From 580a45485afe48a77272f44f8aa99875cdd4d441 Mon Sep 17 00:00:00 2001 From: Maciej Kurc <mkurc@antmicro.com> Date: Thu, 22 Jul 2021 14:07:35 +0200 Subject: Added an option to disable the LUT mapping cache Signed-off-by: Maciej Kurc <mkurc@antmicro.com> --- fpga_interchange/arch.cc | 10 ++++++---- fpga_interchange/arch.h | 3 ++- fpga_interchange/main.cc | 2 ++ fpga_interchange/site_lut_mapping_cache.h | 2 +- fpga_interchange/site_router.cc | 7 +++++-- 5 files changed, 16 insertions(+), 8 deletions(-) (limited to 'fpga_interchange') diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 64eef2ad..3b0572fa 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -814,10 +814,12 @@ bool Arch::place() archInfoToAttributes(); // Print site LUT mapping caching stats - log_info("Site LUT mapping cache stats:\n"); - log_info(" miss ratio: %.1f%%\n", getCtx()->site_lut_mapping_cache.getMissRatio() * 100.0f); - log_info(" peak size : %zuMB (%zu items)\n", getCtx()->site_lut_mapping_cache.getSizeMB(), - getCtx()->site_lut_mapping_cache.getCount()); + if (!getCtx()->arch_args.disable_lut_mapping_cache) { + log_info("Site LUT mapping cache stats:\n"); + log_info(" miss ratio: %.1f%%\n", getCtx()->site_lut_mapping_cache.getMissRatio() * 100.0f); + log_info(" peak size : %zuMB (%zu items)\n", getCtx()->site_lut_mapping_cache.getSizeMB(), + getCtx()->site_lut_mapping_cache.getCount()); + } getCtx()->check(); diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index de7232d4..36f6a7dc 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -39,9 +39,9 @@ #include "dedicated_interconnect.h" #include "lookahead.h" #include "pseudo_pip_model.h" +#include "site_lut_mapping_cache.h" #include "site_router.h" #include "site_routing_cache.h" -#include "site_lut_mapping_cache.h" NEXTPNR_NAMESPACE_BEGIN @@ -51,6 +51,7 @@ struct ArchArgs std::string package; bool rebuild_lookahead; bool dont_write_lookahead; + bool disable_lut_mapping_cache; }; struct ArchRanges diff --git a/fpga_interchange/main.cc b/fpga_interchange/main.cc index 64a15e62..5423c17d 100644 --- a/fpga_interchange/main.cc +++ b/fpga_interchange/main.cc @@ -57,6 +57,7 @@ po::options_description FpgaInterchangeCommandHandler::getArchOptions() specific.add_options()("package", po::value<std::string>(), "Package to use"); specific.add_options()("rebuild-lookahead", "Ignore lookahead cache and rebuild"); specific.add_options()("dont-write-lookahead", "Don't write the lookahead file"); + specific.add_options()("disable-lut-mapping-cache", "Disable caching of LUT mapping solutions in site router"); return specific; } @@ -76,6 +77,7 @@ std::unique_ptr<Context> FpgaInterchangeCommandHandler::createContext(dict<std:: ArchArgs chipArgs; chipArgs.rebuild_lookahead = vm.count("rebuild_lookahead") != 0; chipArgs.dont_write_lookahead = vm.count("dont_write_lookahead") != 0; + chipArgs.disable_lut_mapping_cache = vm.count("disable-lut-mapping-cache") != 0; if (!vm.count("chipdb")) { log_error("chip database binary must be provided\n"); diff --git a/fpga_interchange/site_lut_mapping_cache.h b/fpga_interchange/site_lut_mapping_cache.h index 0025b889..7b1d60a4 100644 --- a/fpga_interchange/site_lut_mapping_cache.h +++ b/fpga_interchange/site_lut_mapping_cache.h @@ -20,8 +20,8 @@ #ifndef SITE_LUT_MAPPING_CACHE_H #define SITE_LUT_MAPPING_CACHE_H -#include "nextpnr_namespaces.h" #include "idstring.h" +#include "nextpnr_namespaces.h" #include "site_arch.h" NEXTPNR_NAMESPACE_BEGIN diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index 4094b331..820b8d68 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -1041,13 +1041,14 @@ static void apply_routing(Context *ctx, const SiteArch &site_arch, pool<std::pai static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<IdString, IdString>> *blocked_wires) { const Context *ctx = site_info.ctx; + bool enable_cache = !ctx->arch_args.disable_lut_mapping_cache; // Create a site LUT mapping key SiteLutMappingKey key = SiteLutMappingKey::create(site_info); // Get the solution from cache. If not found then compute it SiteLutMappingResult lutMapping; - if (!ctx->site_lut_mapping_cache.get(key, &lutMapping)) { + if (!enable_cache || !ctx->site_lut_mapping_cache.get(key, &lutMapping)) { const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type); std::vector<LutMapper> lut_mappers; @@ -1090,7 +1091,9 @@ static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<Id lutMapping.isValid = res; // Add the solution to the cache - ctx->site_lut_mapping_cache.add(key, lutMapping); + if (enable_cache) { + ctx->site_lut_mapping_cache.add(key, lutMapping); + } } // Apply the solution if valid -- cgit v1.2.3