diff options
author | David Shah <dave@ds0.me> | 2020-11-11 11:31:14 +0000 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2020-11-30 08:45:28 +0000 |
commit | 9b89a82573500118269515154265f811cef6191c (patch) | |
tree | 0f847e6600b16998094b3de217a03f4db84480c1 /nexus | |
parent | 8c1f25cf31644c95e4ba0a1c2a2b212abd622167 (diff) | |
download | nextpnr-9b89a82573500118269515154265f811cef6191c.tar.gz nextpnr-9b89a82573500118269515154265f811cef6191c.tar.bz2 nextpnr-9b89a82573500118269515154265f811cef6191c.zip |
nexus: Add LUTRAM and WIDEFN9 timing support
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'nexus')
-rw-r--r-- | nexus/arch.cc | 25 | ||||
-rw-r--r-- | nexus/constids.inc | 1 | ||||
-rw-r--r-- | nexus/pack.cc | 11 |
3 files changed, 33 insertions, 4 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc index b6181011..5cd8ab9b 100644 --- a/nexus/arch.cc +++ b/nexus/arch.cc @@ -449,7 +449,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort } return result; } else { - if (toPort == id_F) + if (toPort == id_F || toPort == id_OFX) return lookup_cell_delay(cell->tmg_index, fromPort, toPort, delay); } } @@ -460,11 +460,12 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in { auto disconnected = [cell](IdString p) { return !cell->ports.count(p) || cell->ports.at(p).net == nullptr; }; if (cell->type == id_OXIDE_COMB) { - if (port == id_A || port == id_B || port == id_C || port == id_D || port == id_FCI) + if (port == id_A || port == id_B || port == id_C || port == id_D || port == id_SEL || port == id_F1 || + port == id_FCI || port == id_WDI) return TMG_COMB_INPUT; if (port == id_F || port == id_OFX || port == id_FCO) { if (disconnected(id_A) && disconnected(id_B) && disconnected(id_C) && disconnected(id_D) && - disconnected(id_FCI) && disconnected(id_SEL)) + disconnected(id_FCI) && disconnected(id_SEL) && disconnected(id_WDI)) return TMG_IGNORE; else return TMG_COMB_OUTPUT; @@ -479,6 +480,17 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in clockInfoCount = 1; return TMG_REGISTER_INPUT; } + } else if (cell->type == id_RAMW) { + if (port == id_CLK) + return TMG_CLOCK_INPUT; + else if (port == id_WDO0 || port == id_WDO1 || port == id_WDO2 || port == id_WDO3) { + clockInfoCount = 1; + return TMG_REGISTER_OUTPUT; + } else if (port == id_A0 || port == id_A1 || port == id_B0 || port == id_B1 || port == id_C0 || port == id_C1 || + port == id_D0 || port == id_D1) { + clockInfoCount = 1; + return TMG_REGISTER_INPUT; + } } return TMG_IGNORE; } @@ -493,6 +505,13 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port NPNR_ASSERT(lookup_cell_delay(cell->tmg_index, id_CLK, port, info.clockToQ)); else lookup_cell_setuphold(cell->tmg_index, port, id_CLK, info.setup, info.hold); + } else if (cell->type == id_RAMW) { + info.edge = (cell->ffInfo.ctrlset.clkmux == ID_INV) ? FALLING_EDGE : RISING_EDGE; + info.clock_port = id_CLK; + if (port == id_WDO0 || port == id_WDO1 || port == id_WDO2 || port == id_WDO3) + NPNR_ASSERT(lookup_cell_delay(cell->tmg_index, id_CLK, port, info.clockToQ)); + else + lookup_cell_setuphold(cell->tmg_index, port, id_CLK, info.setup, info.hold); } else { NPNR_ASSERT_FALSE("missing clocking info"); } diff --git a/nexus/constids.inc b/nexus/constids.inc index b4d53265..a43104e2 100644 --- a/nexus/constids.inc +++ b/nexus/constids.inc @@ -171,6 +171,7 @@ X(CLKO) X(DPR16X4) X(INITVAL) +X(DPRAM) X(DP16K) X(PDP16K) diff --git a/nexus/pack.cc b/nexus/pack.cc index 481dcbf6..bfa45d38 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -990,6 +990,8 @@ struct NexusPacker if (initval & (1ULL << (4 * j + i))) split_init |= (1 << j); combs[i]->params[id_INIT] = Property(split_init, 16); + + combs[i]->params[id_MODE] = std::string("DPRAM"); } // Setup relative constraints @@ -1264,13 +1266,19 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lutInfo.mux2_used = port_used(cell, id_OFX); cell->lutInfo.f = get_net_or_empty(cell, id_F); cell->lutInfo.ofx = get_net_or_empty(cell, id_OFX); - cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, cell->lutInfo.is_carry ? id_CCU2 : id_LUT4); if (cell->lutInfo.is_carry) { cell->tmg_portmap[id_A] = id_A0; cell->tmg_portmap[id_B] = id_B0; cell->tmg_portmap[id_C] = id_C0; cell->tmg_portmap[id_D] = id_D0; cell->tmg_portmap[id_F] = id_F0; + cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, id_CCU2); + } else if (cell->lutInfo.ofx != nullptr) { + cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, id_WIDEFN9); + } else if (cell->lutInfo.is_memory) { + cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, id_DPRAM); + } else { + cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, id_LUT4); } } else if (cell->type == id_OXIDE_FF) { cell->ffInfo.ctrlset.async = str_or_default(cell->params, id_SRMODE, "LSR_OVER_CE") == "ASYNC"; @@ -1297,6 +1305,7 @@ void Arch::assignCellInfo(CellInfo *cell) cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR); cell->ffInfo.di = nullptr; cell->ffInfo.m = nullptr; + cell->tmg_index = get_cell_timing_idx(id_RAMW); } } |