aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange/site_lut_mapping_cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fpga_interchange/site_lut_mapping_cache.cc')
-rw-r--r--fpga_interchange/site_lut_mapping_cache.cc196
1 files changed, 196 insertions, 0 deletions
diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc
new file mode 100644
index 00000000..0cf741f2
--- /dev/null
+++ b/fpga_interchange/site_lut_mapping_cache.cc
@@ -0,0 +1,196 @@
+/*
+ * 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_lut_mapping_cache.h"
+#include "nextpnr.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.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
+ // when the actual global net names are different.
+ dict<IdString, int32_t> netMap;
+ for (CellInfo *cellInfo : lutCells) {
+
+ NPNR_ASSERT(key.numCells < SiteLutMappingKey::MAX_LUT_CELLS);
+ auto &cell = key.cells[key.numCells++];
+
+ 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;
+
+ // 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;
+
+ auto it = netMap.find(netInfo->name);
+ if (it != netMap.end()) {
+ netId = it->second;
+ } else {
+ netId = (int32_t)netMap.size() + 1;
+ netMap[netInfo->name] = netId;
+ }
+ }
+
+ NPNR_ASSERT(portId < SiteLutMappingKey::MAX_LUT_INPUTS);
+ cell.conns[portId++] = netId;
+ }
+ }
+
+ // Compute hash
+ key.computeHash();
+
+ 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) {
+ 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];
+ }
+
+ // 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;
+}
+
+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, 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