From dc07054ee8c28b9c553be4a61562c5b294de0c06 Mon Sep 17 00:00:00 2001
From: "William D. Jones" <thor0505@comcast.net>
Date: Sat, 5 Dec 2020 22:01:28 -0500
Subject: machxo2: Implement functions to get device utilization (throws
 std::out_of_range during place phase).

---
 machxo2/arch.cc    |  6 +---
 machxo2/arch.h     | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 machxo2/archdefs.h | 52 ++++++++++++++++++++++++++++++++-
 3 files changed, 134 insertions(+), 9 deletions(-)

diff --git a/machxo2/arch.cc b/machxo2/arch.cc
index 0a3f345f..431fcc88 100644
--- a/machxo2/arch.cc
+++ b/machxo2/arch.cc
@@ -116,7 +116,7 @@ BelId Arch::getBelByName(IdString name) const
     return BelId();
 }
 
-IdString Arch::getBelName(BelId bel) const { return bel; }
+IdString Arch::getBelName(BelId bel) const { return IdString(); }
 
 Loc Arch::getBelLocation(BelId bel) const
 {
@@ -154,10 +154,6 @@ CellInfo *Arch::getBoundBelCell(BelId bel) const { return nullptr; }
 
 CellInfo *Arch::getConflictingBelCell(BelId bel) const { return nullptr; }
 
-const std::vector<BelId> &Arch::getBels() const { return bel_id_dummy; }
-
-IdString Arch::getBelType(BelId bel) const { return IdString(); }
-
 const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; }
 
 WireId Arch::getBelPinWire(BelId bel, IdString pin) const
diff --git a/machxo2/arch.h b/machxo2/arch.h
index 762412e2..1d62a84e 100644
--- a/machxo2/arch.h
+++ b/machxo2/arch.h
@@ -139,7 +139,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
     int32_t num_tiles;
     int32_t num_packages, num_pios;
     int32_t const_id_count;
-    RelPtr<TileTypePOD> locations;
+    RelPtr<TileTypePOD> tiles;
     RelPtr<RelPtr<char>> tiletype_names;
     RelPtr<PackageInfoPOD> package_info;
     RelPtr<PIOInfoPOD> pio_info;
@@ -148,6 +148,59 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
 
 /************************ End of chipdb section. ************************/
 
+// Iterators
+struct BelIterator
+{
+    const ChipInfoPOD *chip;
+    int cursor_index;
+    int cursor_tile;
+
+    BelIterator operator++()
+    {
+        cursor_index++;
+        while (cursor_tile < chip->num_tiles &&
+               cursor_index >= chip->tiles[cursor_tile].num_bels) {
+            cursor_index = 0;
+            cursor_tile++;
+        }
+        return *this;
+    }
+    BelIterator operator++(int)
+    {
+        BelIterator prior(*this);
+        ++(*this);
+        return prior;
+    }
+
+    bool operator!=(const BelIterator &other) const
+    {
+        return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
+    }
+
+    bool operator==(const BelIterator &other) const
+    {
+        return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
+    }
+
+    BelId operator*() const
+    {
+        BelId ret;
+        ret.location.x = cursor_tile % chip->width;
+        ret.location.y = cursor_tile / chip->width;
+        ret.index = cursor_index;
+        return ret;
+    }
+};
+
+struct BelRange
+{
+    BelIterator b, e;
+    BelIterator begin() const { return b; }
+    BelIterator end() const { return e; }
+};
+
+// -----------------------------------------------------------------------
+
 struct ArchArgs
 {
     enum ArchArgsTypes
@@ -268,6 +321,12 @@ struct Arch : BaseCtx
     std::vector<GraphicElement> graphic_element_dummy;
     std::map<IdString, std::string> attrs_dummy;
 
+    // Helpers
+    template <typename Id> const TileTypePOD *tileInfo(Id &id) const
+    {
+        return &(chip_info->tiles[id.location.y * chip_info->width + id.location.x]);
+    }
+
     // ---------------------------------------------------------------
     // Common Arch API. Every arch must provide the following methods.
 
@@ -299,8 +358,28 @@ struct Arch : BaseCtx
     bool checkBelAvail(BelId bel) const;
     CellInfo *getBoundBelCell(BelId bel) const;
     CellInfo *getConflictingBelCell(BelId bel) const;
-    const std::vector<BelId> &getBels() const;
-    IdString getBelType(BelId bel) const;
+
+    BelRange getBels() const
+    {
+        BelRange range;
+        range.b.cursor_tile = 0;
+        range.b.cursor_index = -1;
+        range.b.chip = chip_info;
+        ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile
+        range.e.cursor_tile = chip_info->width * chip_info->height;
+        range.e.cursor_index = 0;
+        range.e.chip = chip_info;
+        return range;
+    }
+
+    IdString getBelType(BelId bel) const
+    {
+        NPNR_ASSERT(bel != BelId());
+        IdString id;
+        id.index = tileInfo(bel)->bel_data[bel.index].type;
+        return id;
+    }
+
     const std::map<IdString, std::string> &getBelAttrs(BelId bel) const;
     WireId getBelPinWire(BelId bel, IdString pin) const;
     PortType getBelPinType(BelId bel, IdString pin) const;
diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h
index 56b546da..d33a3a3d 100644
--- a/machxo2/archdefs.h
+++ b/machxo2/archdefs.h
@@ -62,7 +62,34 @@ enum ConstIds
 
 NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; });
 
-typedef IdString BelId;
+struct Location
+{
+    int16_t x = -1, y = -1;
+    Location() : x(-1), y(-1){};
+    Location(int16_t x, int16_t y) : x(x), y(y){};
+    Location(const LocationPOD &pod) : x(pod.x), y(pod.y){};
+    Location(const Location &loc) : x(loc.x), y(loc.y){};
+
+    bool operator==(const Location &other) const { return x == other.x && y == other.y; }
+    bool operator!=(const Location &other) const { return x != other.x || y != other.y; }
+    bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; }
+};
+
+inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
+
+struct BelId
+{
+    Location location;
+    int32_t index = -1;
+
+    bool operator==(const BelId &other) const { return index == other.index && location == other.location; }
+    bool operator!=(const BelId &other) const { return index != other.index || location != other.location; }
+    bool operator<(const BelId &other) const
+    {
+        return location == other.location ? index < other.index : location < other.location;
+    }
+};
+
 typedef IdString WireId;
 typedef IdString PipId;
 typedef IdString GroupId;
@@ -86,3 +113,26 @@ struct ArchCellInfo
 };
 
 NEXTPNR_NAMESPACE_END
+
+namespace std {
+template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Location>
+{
+    std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept
+    {
+        std::size_t seed = std::hash<int>()(loc.x);
+        seed ^= std::hash<int>()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+        return seed;
+    }
+};
+
+template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelId>
+{
+    std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept
+    {
+        std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(bel.location);
+        seed ^= std::hash<int>()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+        return seed;
+    }
+};
+
+}
-- 
cgit v1.2.3