ecp5: Flatten bel_to_cell for performance

Signed-off-by: David Shah <davey1576@gmail.com>
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index fec1011..d6152e9 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -92,6 +92,8 @@
 
     if (!package_info)
         log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str());
+
+    bel_to_cell.resize(chip_info->height * chip_info->width * max_loc_bels, nullptr);
 }
 
 // -----------------------------------------------------------------------
@@ -436,7 +438,7 @@
     decalxy.decal.type = DecalId::TYPE_BEL;
     decalxy.decal.location = bel.location;
     decalxy.decal.z = bel.index;
-    decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != nullptr);
+    decalxy.decal.active = (bel_to_cell.at(getBelFlatIndex(bel)) != nullptr);
     return decalxy;
 }
 
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 5b2738b..410ab15 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -404,7 +404,7 @@
     mutable std::unordered_map<IdString, WireId> wire_by_name;
     mutable std::unordered_map<IdString, PipId> pip_by_name;
 
-    std::unordered_map<BelId, CellInfo *> bel_to_cell;
+    std::vector<CellInfo *> bel_to_cell;
     std::unordered_map<WireId, NetInfo *> wire_to_net;
     std::unordered_map<PipId, NetInfo *> pip_to_net;
 
@@ -443,11 +443,18 @@
 
     uint32_t getBelChecksum(BelId bel) const { return bel.index; }
 
+    const int max_loc_bels = 20;
+    int getBelFlatIndex(BelId bel) const
+    {
+        return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index;
+    }
+
     void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
     {
         NPNR_ASSERT(bel != BelId());
-        NPNR_ASSERT(bel_to_cell[bel] == nullptr);
-        bel_to_cell[bel] = cell;
+        int idx = getBelFlatIndex(bel);
+        NPNR_ASSERT(bel_to_cell.at(idx) == nullptr);
+        bel_to_cell[idx] = cell;
         cell->bel = bel;
         cell->belStrength = strength;
         refreshUiBel(bel);
@@ -456,10 +463,11 @@
     void unbindBel(BelId bel)
     {
         NPNR_ASSERT(bel != BelId());
-        NPNR_ASSERT(bel_to_cell[bel] != nullptr);
-        bel_to_cell[bel]->bel = BelId();
-        bel_to_cell[bel]->belStrength = STRENGTH_NONE;
-        bel_to_cell[bel] = nullptr;
+        int idx = getBelFlatIndex(bel);
+        NPNR_ASSERT(bel_to_cell.at(idx) != nullptr);
+        bel_to_cell[idx]->bel = BelId();
+        bel_to_cell[idx]->belStrength = STRENGTH_NONE;
+        bel_to_cell[idx] = nullptr;
         refreshUiBel(bel);
     }
 
@@ -480,31 +488,19 @@
     bool checkBelAvail(BelId bel) const
     {
         NPNR_ASSERT(bel != BelId());
-        auto found = bel_to_cell.find(bel);
-        if (found == bel_to_cell.end())
-            return true;
-        else
-            return found->second == nullptr;
+        return bel_to_cell[getBelFlatIndex(bel)] == nullptr;
     }
 
     CellInfo *getBoundBelCell(BelId bel) const
     {
         NPNR_ASSERT(bel != BelId());
-        auto found = bel_to_cell.find(bel);
-        if (found == bel_to_cell.end())
-            return nullptr;
-        else
-            return found->second;
+        return bel_to_cell[getBelFlatIndex(bel)];
     }
 
     CellInfo *getConflictingBelCell(BelId bel) const
     {
         NPNR_ASSERT(bel != BelId());
-        auto found = bel_to_cell.find(bel);
-        if (found == bel_to_cell.end())
-            return nullptr;
-        else
-            return found->second;
+        return bel_to_cell[getBelFlatIndex(bel)];
     }
 
     BelRange getBels() const