diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/arch_pybindings_shared.h | 2 | ||||
-rw-r--r-- | common/nextpnr.cc | 6 | ||||
-rw-r--r-- | common/nextpnr.h | 58 | ||||
-rw-r--r-- | common/pybindings.cc | 25 | ||||
-rw-r--r-- | common/sdf.cc | 20 | ||||
-rw-r--r-- | common/timing.cc | 18 | ||||
-rw-r--r-- | common/timing_opt.cc | 4 |
7 files changed, 98 insertions, 35 deletions
diff --git a/common/arch_pybindings_shared.h b/common/arch_pybindings_shared.h index 1cd70c99..81469df3 100644 --- a/common/arch_pybindings_shared.h +++ b/common/arch_pybindings_shared.h @@ -103,7 +103,7 @@ fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWir conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire"); fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire"); -fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>, +fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay"); fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap( diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 11acf991..9a73affc 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -656,9 +656,9 @@ void Context::check() const void BaseCtx::addClock(IdString net, float freq) { std::unique_ptr<ClockConstraint> cc(new ClockConstraint()); - cc->period = getCtx()->getDelayFromNS(1000 / freq); - cc->high = getCtx()->getDelayFromNS(500 / freq); - cc->low = getCtx()->getDelayFromNS(500 / freq); + cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq)); + cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq)); + cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq)); if (!net_aliases.count(net)) { log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this)); } else { diff --git a/common/nextpnr.h b/common/nextpnr.h index f2bcb90d..c2fe5192 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -556,6 +556,44 @@ struct Property inline bool operator==(const Property &a, const Property &b) { return a.is_string == b.is_string && a.str == b.str; } inline bool operator!=(const Property &a, const Property &b) { return a.is_string != b.is_string || a.str != b.str; } +// minimum and maximum delay +struct DelayPair +{ + DelayPair(){}; + explicit DelayPair(delay_t delay) : min_delay(delay), max_delay(delay){}; + DelayPair(delay_t min_delay, delay_t max_delay) : min_delay(min_delay), max_delay(max_delay){}; + delay_t minDelay() const { return min_delay; }; + delay_t maxDelay() const { return max_delay; }; + delay_t min_delay, max_delay; + DelayPair operator+(const DelayPair &other) const + { + return {min_delay + other.min_delay, max_delay + other.max_delay}; + } +}; + +// four-quadrant, min and max rise and fall delay +struct DelayQuad +{ + DelayPair rise, fall; + DelayQuad(){}; + explicit DelayQuad(delay_t delay) : rise(delay), fall(delay){}; + DelayQuad(delay_t min_delay, delay_t max_delay) : rise(min_delay, max_delay), fall(min_delay, max_delay){}; + DelayQuad(DelayPair rise, DelayPair fall) : rise(rise), fall(fall){}; + DelayQuad(delay_t min_rise, delay_t max_rise, delay_t min_fall, delay_t max_fall) + : rise(min_rise, max_rise), fall(min_fall, max_fall){}; + + delay_t minRiseDelay() const { return rise.minDelay(); }; + delay_t maxRiseDelay() const { return rise.maxDelay(); }; + delay_t minFallDelay() const { return fall.minDelay(); }; + delay_t maxFallDelay() const { return fall.maxDelay(); }; + delay_t minDelay() const { return std::min<delay_t>(rise.minDelay(), fall.minDelay()); }; + delay_t maxDelay() const { return std::max<delay_t>(rise.maxDelay(), fall.maxDelay()); }; + + DelayPair delayPair() const { return DelayPair(minDelay(), maxDelay()); }; + + DelayQuad operator+(const DelayQuad &other) const { return {rise + other.rise, fall + other.fall}; } +}; + struct ClockConstraint; struct NetInfo : ArchNetInfo @@ -651,15 +689,15 @@ struct TimingClockingInfo { IdString clock_port; // Port name of clock domain ClockEdge edge; - DelayInfo setup, hold; // Input timing checks - DelayInfo clockToQ; // Output clock-to-Q time + DelayPair setup, hold; // Input timing checks + DelayQuad clockToQ; // Output clock-to-Q time }; struct ClockConstraint { - DelayInfo high; - DelayInfo low; - DelayInfo period; + DelayPair high; + DelayPair low; + DelayPair period; TimingConstrObjectId domain_tmg_id; }; @@ -1117,7 +1155,7 @@ template <typename R> struct ArchAPI : BaseCtx virtual NetInfo *getBoundWireNet(WireId wire) const = 0; virtual WireId getConflictingWireWire(WireId wire) const = 0; virtual NetInfo *getConflictingWireNet(WireId wire) const = 0; - virtual DelayInfo getWireDelay(WireId wire) const = 0; + virtual DelayQuad getWireDelay(WireId wire) const = 0; // Pip methods virtual typename R::AllPipsRangeT getPips() const = 0; virtual PipId getPipByName(IdStringList name) const = 0; @@ -1133,7 +1171,7 @@ template <typename R> struct ArchAPI : BaseCtx virtual NetInfo *getConflictingPipNet(PipId pip) const = 0; virtual WireId getPipSrcWire(PipId pip) const = 0; virtual WireId getPipDstWire(PipId pip) const = 0; - virtual DelayInfo getPipDelay(PipId pip) const = 0; + virtual DelayQuad getPipDelay(PipId pip) const = 0; virtual Loc getPipLocation(PipId pip) const = 0; // Group methods virtual GroupId getGroupByName(IdStringList name) const = 0; @@ -1148,7 +1186,7 @@ template <typename R> struct ArchAPI : BaseCtx virtual delay_t getDelayEpsilon() const = 0; virtual delay_t getRipupDelayPenalty() const = 0; virtual float getDelayNS(delay_t v) const = 0; - virtual DelayInfo getDelayFromNS(float ns) const = 0; + virtual delay_t getDelayFromNS(float ns) const = 0; virtual uint32_t getDelayChecksum(delay_t v) const = 0; virtual bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const = 0; virtual delay_t estimateDelay(WireId src, WireId dst) const = 0; @@ -1160,7 +1198,7 @@ template <typename R> struct ArchAPI : BaseCtx virtual DecalXY getPipDecal(PipId pip) const = 0; virtual DecalXY getGroupDecal(GroupId group) const = 0; // Cell timing methods - virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const = 0; + virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const = 0; virtual TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const = 0; virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0; // Placement validity checks @@ -1391,7 +1429,7 @@ template <typename R> struct BaseArch : ArchAPI<R> virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); } // Cell timing methods - virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override + virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override { return false; } diff --git a/common/pybindings.cc b/common/pybindings.cc index a72da78e..504074e1 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -139,6 +139,31 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m) .value("STRENGTH_USER", STRENGTH_USER) .export_values(); + py::class_<DelayPair>(m, "DelayPair") + .def(py::init<>()) + .def(py::init<delay_t>()) + .def(py::init<delay_t, delay_t>()) + .def_readwrite("min_delay", &DelayPair::min_delay) + .def_readwrite("max_delay", &DelayPair::max_delay) + .def("minDelay", &DelayPair::minDelay) + .def("maxDelay", &DelayPair::maxDelay); + + py::class_<DelayQuad>(m, "DelayQuad") + .def(py::init<>()) + .def(py::init<delay_t>()) + .def(py::init<delay_t, delay_t>()) + .def(py::init<delay_t, delay_t, delay_t, delay_t>()) + .def(py::init<DelayPair, DelayPair>()) + .def_readwrite("rise", &DelayQuad::rise) + .def_readwrite("fall", &DelayQuad::fall) + .def("minDelay", &DelayQuad::minDelay) + .def("minRiseDelay", &DelayQuad::minRiseDelay) + .def("minFallDelay", &DelayQuad::minFallDelay) + .def("maxDelay", &DelayQuad::maxDelay) + .def("maxRiseDelay", &DelayQuad::maxRiseDelay) + .def("maxFallDelay", &DelayQuad::maxFallDelay) + .def("delayPair", &DelayQuad::delayPair); + typedef std::unordered_map<IdString, Property> AttrMap; typedef std::unordered_map<IdString, PortInfo> PortMap; typedef std::unordered_map<IdString, IdString> IdIdMap; diff --git a/common/sdf.cc b/common/sdf.cc index b9606907..5c3d0a5a 100644 --- a/common/sdf.cc +++ b/common/sdf.cc @@ -231,19 +231,19 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const wr.program = "nextpnr"; const double delay_scale = 1000; - // Convert from DelayInfo to SDF-friendly RiseFallDelay - auto convert_delay = [&](const DelayInfo &dly) { + // Convert from DelayQuad to SDF-friendly RiseFallDelay + auto convert_delay = [&](const DelayQuad &dly) { RiseFallDelay rf; - rf.rise.min = getDelayNS(dly.minRaiseDelay()) * delay_scale; - rf.rise.typ = getDelayNS((dly.minRaiseDelay() + dly.maxRaiseDelay()) / 2) * delay_scale; // fixme: typ delays? - rf.rise.max = getDelayNS(dly.maxRaiseDelay()) * delay_scale; + rf.rise.min = getDelayNS(dly.minRiseDelay()) * delay_scale; + rf.rise.typ = getDelayNS((dly.minRiseDelay() + dly.maxRiseDelay()) / 2) * delay_scale; // fixme: typ delays? + rf.rise.max = getDelayNS(dly.maxRiseDelay()) * delay_scale; rf.fall.min = getDelayNS(dly.minFallDelay()) * delay_scale; rf.fall.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays? rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale; return rf; }; - auto convert_setuphold = [&](const DelayInfo &setup, const DelayInfo &hold) { + auto convert_setuphold = [&](const DelayPair &setup, const DelayPair &hold) { RiseFallDelay rf; rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale; rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays? @@ -273,7 +273,7 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const continue; if (other.second.type == PORT_OUT) continue; - DelayInfo dly; + DelayQuad dly; if (!getCellDelay(ci, other.first, port.first, dly)) continue; IOPath iop; @@ -323,12 +323,12 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const ic.from.port = ni->driver.port.str(this); ic.to.cell = usr.cell->name.str(this); ic.to.port = usr.port.str(this); - // FIXME: min/max routing delay - or at least constructing DelayInfo here - ic.delay = convert_delay(getDelayFromNS(getDelayNS(getNetinfoRouteDelay(ni, usr)))); + // FIXME: min/max routing delay + ic.delay = convert_delay(DelayQuad(getNetinfoRouteDelay(ni, usr))); wr.conn.push_back(ic); } } wr.write(out); } -NEXTPNR_NAMESPACE_END
\ No newline at end of file +NEXTPNR_NAMESPACE_END diff --git a/common/timing.cc b/common/timing.cc index a741c6ee..0c62b1a0 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -121,7 +121,7 @@ struct Timing delay_t walk_paths() { - const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq")).maxDelay(); + const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq")); // First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph // TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops @@ -188,7 +188,7 @@ struct Timing // Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and // the current output port, increment fanin counter for (auto i : input_ports) { - DelayInfo comb_delay; + DelayQuad comb_delay; NetInfo *i_net = cell.second->ports[i].net; if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name)) continue; @@ -238,7 +238,7 @@ struct Timing if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE || portClass == TMG_GEN_CLOCK) continue; - DelayInfo comb_delay; + DelayQuad comb_delay; bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); if (!is_path) continue; @@ -309,7 +309,7 @@ struct Timing for (auto port : usr.cell->ports) { if (port.second.type != PORT_OUT || !port.second.net) continue; - DelayInfo comb_delay; + DelayQuad comb_delay; // Look up delay through this path bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); if (!is_path) @@ -421,7 +421,7 @@ struct Timing for (const auto &port : usr.cell->ports) { if (port.second.type != PORT_OUT || !port.second.net) continue; - DelayInfo comb_delay; + DelayQuad comb_delay; bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); if (!is_path) continue; @@ -452,7 +452,7 @@ struct Timing for (const auto &port : crit_net->driver.cell->ports) { if (port.second.type != PORT_IN || !port.second.net) continue; - DelayInfo comb_delay; + DelayQuad comb_delay; bool is_path = ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay); if (!is_path) @@ -563,7 +563,7 @@ struct Timing for (const auto &port : drv.cell->ports) { if (port.second.type != PORT_IN || !port.second.net) continue; - DelayInfo comb_delay; + DelayQuad comb_delay; bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay); if (!is_path) continue; @@ -843,14 +843,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p auto net = port.net; auto &driver = net->driver; auto driver_cell = driver.cell; - DelayInfo comb_delay; + DelayQuad comb_delay; if (clock_start != -1) { auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start); comb_delay = clockInfo.clockToQ; clock_start = -1; } else if (last_port == driver.port) { // Case where we start with a STARTPOINT etc - comb_delay = ctx->getDelayFromNS(0); + comb_delay = DelayQuad(0); } else { ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay); } diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 9c601e48..28b7f2cf 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -328,7 +328,7 @@ class TimingOptimiser if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty()) continue; int ccount; - DelayInfo combDelay; + DelayQuad combDelay; TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount); if (tpclass != TMG_COMB_INPUT) continue; @@ -367,7 +367,7 @@ class TimingOptimiser if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty()) continue; int ccount; - DelayInfo combDelay; + DelayQuad combDelay; TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount); if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT) continue; |