diff --git a/common/timing.cc b/common/timing.cc index a2d48ed9..8351b1f3 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -530,8 +530,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p Fmax = 1000 / ctx->getDelayNS(path.second.path_delay); else Fmax = 500 / ctx->getDelayNS(path.second.path_delay); - if (!clock_fmax.count(a.clock) || - Fmax < clock_fmax.at(a.clock)) { + if (!clock_fmax.count(a.clock) || Fmax < clock_fmax.at(a.clock)) { clock_reports[a.clock] = path; clock_fmax[a.clock] = Fmax; } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 91331f7e..a7bebd61 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -539,10 +539,10 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort return true; } #if 0 // FIXME - if (fromPort == id_WCK && (toPort == id_F0 || toPort == id_F1)) { - delay.delay = 717; - return true; - } + if (fromPort == id_WCK && (toPort == id_F0 || toPort == id_F1)) { + delay.delay = 717; + return true; + } #endif if ((fromPort == id_A0 && toPort == id_WADO3) || (fromPort == id_A1 && toPort == id_WDO1) || (fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) || @@ -576,10 +576,10 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort } } -TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const { auto disconnected = [cell](IdString p) { return !cell->ports.count(p) || cell->ports.at(p).net == nullptr; }; - + clockInfoCount = 0; if (cell->type == id_TRELLIS_SLICE) { int sd0 = int_or_default(cell->params, id("REG0_SD"), 0), sd1 = int_or_default(cell->params, id("REG1_SD"), 0); if (port == id_CLK || port == id_WCK) @@ -598,13 +598,13 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_COMB_OUTPUT; if (port == id_DI0 || port == id_DI1 || port == id_CE || port == id_LSR || (sd0 == 1 && port == id_M0) || (sd1 == 1 && port == id_M1)) { - clockPort = id_CLK; + clockInfoCount = 1; return TMG_REGISTER_INPUT; } if (port == id_M0 || port == id_M1) return TMG_COMB_INPUT; if (port == id_Q0 || port == id_Q1) { - clockPort = id_CLK; + clockInfoCount = 1; return TMG_REGISTER_OUTPUT; } @@ -614,7 +614,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 || port == id_WAD3 || port == id_WRE) { - clockPort = id_WCK; + clockInfoCount = 1; return TMG_REGISTER_INPUT; } @@ -638,10 +638,8 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id for (auto c : boost::adaptors::reverse(port_name)) { if (std::isdigit(c)) continue; - if (c == 'A') - clockPort = id_CLKA; - else if (c == 'B') - clockPort = id_CLKB; + if (c == 'A' || c == 'B') + clockInfoCount = 1; else NPNR_ASSERT_FALSE_STR("bad ram port"); return (cell->ports.at(port).type == PORT_OUT) ? TMG_REGISTER_OUTPUT : TMG_REGISTER_INPUT; @@ -658,6 +656,57 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id } } +TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const +{ + TimingClockingInfo info; + info.setup.delay = 0; + info.hold.delay = 0; + info.clockToQ.delay = 0; + if (cell->type == id_TRELLIS_SLICE) { + int sd0 = int_or_default(cell->params, id("REG0_SD"), 0), sd1 = int_or_default(cell->params, id("REG1_SD"), 0); + + if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 || + port == id_WAD3 || port == id_WRE) { + info.edge = RISING_EDGE; + info.clock_port = id_WCK; + info.setup.delay = 100; + info.hold.delay = 0; + } else if (port == id_DI0 || port == id_DI1 || port == id_CE || port == id_LSR || (sd0 == 1 && port == id_M0) || + (sd1 == 1 && port == id_M1)) { + info.edge = cell->sliceInfo.clkmux == id("INV") ? FALLING_EDGE : RISING_EDGE; + info.clock_port = id_CLK; + info.setup.delay = 100; + info.hold.delay = 0; + } else { + info.edge = cell->sliceInfo.clkmux == id("INV") ? FALLING_EDGE : RISING_EDGE; + info.clock_port = id_CLK; + info.clockToQ.delay = 395; + } + } else if (cell->type == id_DP16KD) { + for (auto c : boost::adaptors::reverse(port.str(this))) { + if (std::isdigit(c)) + continue; + if (c == 'A') + info.clock_port = id_CLKA; + else if (c == 'B') + info.clock_port = id_CLKB; + else + NPNR_ASSERT_FALSE_STR("bad ram port"); + } + info.edge = (str_or_default(cell->params, info.clock_port == id_CLKB ? id("CLKBMUX") : id("CLKAMUX"), "CLK") == + "INV") + ? FALLING_EDGE + : RISING_EDGE; + if (cell->ports.at(port).type == PORT_OUT) { + info.clockToQ.delay = 4280; + } else { + info.setup.delay = 100; + info.hold.delay = 0; + } + } + return info; +} + std::vector> Arch::getTilesAtLocation(int row, int col) { std::vector> ret; diff --git a/ecp5/arch.h b/ecp5/arch.h index 583d539f..07b1e65d 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -855,6 +855,12 @@ struct Arch : BaseCtx delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } float getDelayNS(delay_t v) const { return v * 0.001; } + DelayInfo getDelayFromNS(float ns) const + { + DelayInfo del; + del.delay = delay_t(ns * 1000); + return del; + } uint32_t getDelayChecksum(delay_t v) const { return v; } bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; @@ -878,8 +884,10 @@ struct Arch : BaseCtx // Get the delay through a cell from one port to another, returning false // if no path exists bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; - // Get the port class, also setting clockPort if applicable - TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const; + // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; + // Get the TimingClockingInfo of a port + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const;