From f7354d092ddcb6020f1fc0a23267920884cf8641 Mon Sep 17 00:00:00 2001
From: gatecat <gatecat@ds0.me>
Date: Wed, 10 Aug 2022 15:47:22 +0100
Subject: nexus: Add timing data for LRAM

Signed-off-by: gatecat <gatecat@ds0.me>
---
 nexus/arch.cc      | 16 ++++++++++++++++
 nexus/constids.inc |  1 +
 nexus/pack.cc      | 13 +++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/nexus/arch.cc b/nexus/arch.cc
index b2ae22ce..4a956fae 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -543,6 +543,14 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
             return TMG_CLOCK_INPUT;
         clockInfoCount = 1;
         return (cell->ports.at(port).type == PORT_IN) ? TMG_REGISTER_INPUT : TMG_REGISTER_OUTPUT;
+    } else if (cell->type == id_LRAM_CORE) {
+        if (port.in(id_OPCGLDCK, id_OPCGLOADCLK, id_SCANCLK, id_SCANRST, id_TBISTN, id_INITN, id_STDBYN, id_IGN,
+                    id_DPS))
+            return TMG_IGNORE;
+        if (port == id_CLK)
+            return TMG_CLOCK_INPUT;
+        clockInfoCount = 1;
+        return (cell->ports.at(port).type == PORT_IN) ? TMG_REGISTER_INPUT : TMG_REGISTER_OUTPUT;
     } else if (cell->type == id_MULT18_CORE || cell->type == id_MULT18X36_CORE || cell->type == id_MULT36_CORE) {
         return (cell->ports.at(port).type == PORT_IN) ? TMG_COMB_INPUT : TMG_COMB_OUTPUT;
     } else if (cell->type == id_PREADD9_CORE || cell->type == id_REG18_CORE || cell->type == id_MULT9_CORE) {
@@ -602,6 +610,14 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
         }
         // Lookup edge based on inversion
         info.edge = (get_cell_pinmux(cell, info.clock_port) == PINMUX_INV) ? FALLING_EDGE : RISING_EDGE;
+    } else if (cell->type == id_LRAM_CORE) {
+        info.clock_port = id_CLK;
+        if (cell->ports.at(port).type == PORT_IN) {
+            lookup_cell_setuphold(cell->tmg_index, lookup_port(port), id_CLK, info.setup, info.hold);
+        } else {
+            NPNR_ASSERT(lookup_cell_delay(cell->tmg_index, id_CLK, lookup_port(port), info.clockToQ));
+        }
+        info.edge = (get_cell_pinmux(cell, info.clock_port) == PINMUX_INV) ? FALLING_EDGE : RISING_EDGE;
     } else if (cell->type == id_PREADD9_CORE || cell->type == id_REG18_CORE || cell->type == id_MULT9_CORE) {
         info.clock_port = id_CLK;
         if (cell->ports.at(port).type == PORT_IN) {
diff --git a/nexus/constids.inc b/nexus/constids.inc
index bdf8867b..8731fad7 100644
--- a/nexus/constids.inc
+++ b/nexus/constids.inc
@@ -465,6 +465,7 @@ X(TBISTN)
 X(WE)
 X(CEOUTA)
 X(CEOUTB)
+X(OPCGLOADCLK)
 
 X(MULTADDSUB9X9WIDE)
 X(MULTADDSUB18X18WIDE)
diff --git a/nexus/pack.cc b/nexus/pack.cc
index 0aa61144..e727364d 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -2614,6 +2614,19 @@ void Arch::assignCellInfo(CellInfo *cell)
 
         cell->tmg_index = get_cell_timing_idx(id(str_or_default(cell->params, id_MODE, "DP16K") + "_MODE"));
         NPNR_ASSERT(cell->tmg_index != -1);
+    } else if (cell->type == id_LRAM_CORE) {
+        // Strip off bus indices to get the timing ports
+        // as timing is generally word-wide
+        for (const auto &port : cell->ports) {
+            const std::string &name = port.first.str(this);
+            size_t idx_end = name.find_last_not_of("0123456789");
+            std::string base = name.substr(0, idx_end + 1);
+            // Strip off bus index
+            cell->tmg_portmap[port.first] = id(base);
+        }
+
+        cell->tmg_index = get_cell_timing_idx(id_LRAM_CORE);
+        NPNR_ASSERT(cell->tmg_index != -1);
     } else if (is_dsp_cell(cell)) {
         // Strip off bus indices to get the timing ports
         // as timing is generally word-wide
-- 
cgit v1.2.3