ecp5: Add GSR/SGSR support

Signed-off-by: David Shah <dave@ds0.me>
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 01a4346..a293668 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -440,7 +440,10 @@
 
     auto est_location = [&](WireId w) -> std::pair<int, int> {
         const auto &wire = locInfo(w)->wire_data[w.index];
-        if (wire.num_bel_pins > 0) {
+        if (w == gsrclk_wire) {
+            auto phys_wire = getPipSrcWire(*(getPipsUphill(w).begin()));
+            return std::make_pair(int(phys_wire.location.x), int(phys_wire.location.y));
+        } else if (wire.num_bel_pins > 0) {
             return std::make_pair(w.location.x + wire.bel_pins[0].rel_bel_loc.x,
                                   w.location.y + wire.bel_pins[0].rel_bel_loc.y);
         } else if (wire.num_downhill > 0) {
@@ -711,7 +714,8 @@
         std::string fn = fromPort.str(this), tn = toPort.str(this);
         if (fn.size() > 1 && (fn.front() == 'A' || fn.front() == 'B') && std::isdigit(fn.at(1))) {
             if (tn.size() > 1 && tn.front() == 'P' && std::isdigit(tn.at(1)))
-                return getDelayFromTimingDatabase(id_MULT18X18D_REGS_NONE, id(std::string("") + fn.front()), id_P, delay);
+                return getDelayFromTimingDatabase(id_MULT18X18D_REGS_NONE, id(std::string("") + fn.front()), id_P,
+                                                  delay);
         }
         return false;
     } else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) {
diff --git a/ecp5/arch.h b/ecp5/arch.h
index cee071e..e85d9c4 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -1044,6 +1044,10 @@
     IdString id_clkmux, id_lsrmux;
     IdString id_srmode, id_mode;
 
+    // Special case for delay estimates due to its physical location
+    // being far from the logical location of its primitive
+    WireId gsrclk_wire;
+
     mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache;
 
     static const std::string defaultPlacer;
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 1e0dcad..cac1186 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -1277,7 +1277,7 @@
             cc.tiles[ctx->getTileByType("EFB3_PICB1")].add_enum("CCLK.MODE", "USRMCLK");
         } else if (ci->type == id_GSR) {
             cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum(
-                    "GSR.GSRMODE", str_or_default(ci->params, ctx->id("MODE"), "ACTIVE_HIGH"));
+                    "GSR.GSRMODE", str_or_default(ci->params, ctx->id("MODE"), "ACTIVE_LOW"));
             cc.tiles[ctx->getTileByType("VIQ_BUF")].add_enum("GSR.SYNCMODE",
                                                              str_or_default(ci->params, ctx->id("SYNCMODE"), "ASYNC"));
         } else if (ci->type == id_JTAGG) {
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 7cf9df7..e610dfe 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -1411,6 +1411,17 @@
                 rename_port(ctx, ci, ctx->id("USRMCLKI"), id_PADDO);
                 rename_port(ctx, ci, ctx->id("USRMCLKTS"), id_PADDT);
                 rename_port(ctx, ci, ctx->id("USRMCLKO"), id_PADDI);
+            } else if (ci->type == id_GSR || ci->type == ctx->id("SGSR")) {
+                ci->params[ctx->id("MODE")] = std::string("ACTIVE_LOW");
+                ci->params[ctx->id("SYNCMODE")] =
+                        ci->type == ctx->id("SGSR") ? std::string("SYNC") : std::string("ASYNC");
+                ci->type = id_GSR;
+                for (BelId bel : ctx->getBels()) {
+                    if (ctx->getBelType(bel) != id_GSR)
+                        continue;
+                    ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
+                    ctx->gsrclk_wire = ctx->getBelPinWire(bel, id_CLK);
+                }
             }
         }
     }