diff options
Diffstat (limited to 'nexus')
-rw-r--r-- | nexus/arch.cc | 15 | ||||
-rw-r--r-- | nexus/constids.inc | 7 | ||||
-rw-r--r-- | nexus/fasm.cc | 11 | ||||
-rw-r--r-- | nexus/global.cc | 2 | ||||
-rw-r--r-- | nexus/pack.cc | 27 |
5 files changed, 58 insertions, 4 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc index 0241e832..39e51a5b 100644 --- a/nexus/arch.cc +++ b/nexus/arch.cc @@ -486,6 +486,12 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort if (fromPort == id_CLK) return false; // don't include delays that are actually clock-to-out here return lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay); + } else if(cell->type == id_DCS) { + if (fromPort == id_SELFORCE || fromPort == id_SEL) { + return false; + } + int index = get_cell_timing_idx(id_DCS, id_DCS); + return lookup_cell_delay(index, fromPort, toPort, delay); } return false; } @@ -553,6 +559,15 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in return TMG_GEN_CLOCK; else if (port == id_CE) return TMG_COMB_INPUT; + } else if (cell->type == id_DCS) { + // FIXME: Making inputs TMG_CLOCK_INPUT and the output TMG_CLOCK_GEN + // yielded in error in the timing analyzer. For now keep those as + // regular combinational ports. + if (port == id_CLK0 || port == id_CLK1) + return TMG_COMB_INPUT; + else if (port == id_DCSOUT) { + return TMG_COMB_OUTPUT; + } return TMG_IGNORE; } return TMG_IGNORE; diff --git a/nexus/constids.inc b/nexus/constids.inc index 11726d3b..bdf8867b 100644 --- a/nexus/constids.inc +++ b/nexus/constids.inc @@ -532,6 +532,13 @@ X(SCLK) X(LOCAL_VCC) +X(DCS) +X(CLK0) +X(CLK1) +X(SELFORCE) +X(DCSOUT) +X(DCSMODE) + X(BEL_TYPE) X(BEL_Z) X(CEOUTMUX) diff --git a/nexus/fasm.cc b/nexus/fasm.cc index c8404587..e2eb2305 100644 --- a/nexus/fasm.cc +++ b/nexus/fasm.cc @@ -536,6 +536,15 @@ struct NexusFasmWriter write_cell_muxes(cell); pop(2); } + // Write config for DCS + void write_dcs(const CellInfo *cell) + { + BelId bel = cell->bel; + push_tile(bel.tile, ctx->id("CMUX_0")); + push_belname(bel); + write_enum(cell, "DCSMODE", "VCC"); + pop(2); + } // Write config for an OXIDE_EBR cell void write_bram(const CellInfo *cell) { @@ -939,6 +948,8 @@ struct NexusFasmWriter write_iol(ci); else if (ci->type == id_DCC) write_dcc(ci); + else if (ci->type == id_DCS) + write_dcs(ci); blank(); } // Handle DCC route-throughs diff --git a/nexus/global.cc b/nexus/global.cc index 31bf0a6b..37629f64 100644 --- a/nexus/global.cc +++ b/nexus/global.cc @@ -193,7 +193,7 @@ struct NexusGlobalRouter CellInfo *drv = ni->driver.cell; if (drv == nullptr) continue; - if (drv->type == id_DCC) { + if (drv->type == id_DCC || drv->type == id_DCS) { route_clk_net(ni); continue; } diff --git a/nexus/pack.cc b/nexus/pack.cc index 66d897a8..bb62ec85 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -860,6 +860,9 @@ struct NexusPacker // Skip undriven nets; and nets that are already global if (ni->driver.cell == nullptr) continue; + if (ni->driver.cell->type == id_DCS) { + continue; + } if (ni->driver.cell->type == id_DCC) { --available_globals; continue; @@ -1981,19 +1984,37 @@ struct NexusPacker if (user.port == id_CLKI || user.port == id_REFCK) changed_cells.insert(user.cell->name); auto &drv = ctx->nets.at(net)->driver; - if (iter == 1 && drv.cell != nullptr && (drv.port == id_HFCLKOUT || drv.port == id_LFCLKOUT)) - changed_cells.insert(drv.cell->name); + if (iter == 1 && drv.cell != nullptr) { + if (drv.cell->type == id_OSC_CORE && (drv.port == id_HFCLKOUT || drv.port == id_LFCLKOUT)) + changed_cells.insert(drv.cell->name); + if (drv.cell->type == id_DCC && drv.port == id_CLKO) + changed_cells.insert(drv.cell->name); + if (drv.cell->type == id_DCS && drv.port == id_DCSOUT) + changed_cells.insert(drv.cell->name); + } } changed_nets.clear(); for (auto cell : changed_cells) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->type == id_DCC) { copy_constraint(ci, id_CLKI, id_CLKO, 1); + } else if (ci->type == id_DCS) { + // For DCC copy the worst case ("fastest") constraint + delay_t period_clk0 = 0, period_clk1 = 0; + bool have_clk0 = get_period(ci, id_CLK0, period_clk0); + bool have_clk1 = get_period(ci, id_CLK1, period_clk1); + if (have_clk0 && !have_clk1) { + copy_constraint(ci, id_CLK0, id_DCSOUT); + } else if (!have_clk0 && have_clk1) { + copy_constraint(ci, id_CLK1, id_DCSOUT); + } else if ( have_clk0 && have_clk1) { + set_period(ci, id_DCSOUT, std::min(period_clk0, period_clk1)); + } } else if (ci->type == id_OSC_CORE) { int div = int_or_default(ci->params, id_HF_CLK_DIV, 128); const float tol = 1.07f; // OSCA has +/-7% frequency tolerance, assume the worst case. set_period(ci, id_HFCLKOUT, delay_t((1.0e6 / 450) * (div + 1) / tol)); - set_period(ci, id_LFCLKOUT, delay_t((1.0e3 / 10) / tol)); + set_period(ci, id_LFCLKOUT, delay_t((1.0e9 / 32) / tol)); } else if (ci->type == id_PLL_CORE) { static const std::array<IdString, 6> div{id_DIVA, id_DIVB, id_DIVC, id_DIVD, id_DIVE, id_DIVF}; static const std::array<IdString, 6> output{id_CLKOP, id_CLKOS, id_CLKOS2, |