Replace DelayInfo with DelayPair/DelayQuad

This replaces the arch-specific DelayInfo structure with new DelayPair
(min/max only) and DelayQuad (min/max for both rise and fall) structures
that form part of common code.

This further reduces the amount of arch-specific code; and also provides
useful data structures for timing analysis which will need to delay
with pairs/quads of delays as it is improved.

While there may be a small performance cost to arches that didn't
separate the rise/fall cases (arches that aren't currently separating
the min/max cases just need to be fixed...) in DelayInfo, my expectation
is that inlining will mean this doesn't make much difference.

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-02-19 10:39:57 +00:00
parent 8376db94a7
commit 7922b3bfc4
33 changed files with 243 additions and 498 deletions

View File

@ -103,7 +103,7 @@ fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWir
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>, fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire"); 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"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap( fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(

View File

@ -656,9 +656,9 @@ void Context::check() const
void BaseCtx::addClock(IdString net, float freq) void BaseCtx::addClock(IdString net, float freq)
{ {
std::unique_ptr<ClockConstraint> cc(new ClockConstraint()); std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
cc->period = getCtx()->getDelayFromNS(1000 / freq); cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq));
cc->high = getCtx()->getDelayFromNS(500 / freq); cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq));
cc->low = getCtx()->getDelayFromNS(500 / freq); cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq));
if (!net_aliases.count(net)) { if (!net_aliases.count(net)) {
log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this)); log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this));
} else { } else {

View File

@ -575,6 +575,7 @@ struct DelayPair
struct DelayQuad struct DelayQuad
{ {
DelayPair rise, fall; DelayPair rise, fall;
DelayQuad(){};
explicit DelayQuad(delay_t delay) : rise(delay), fall(delay){}; 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(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(DelayPair rise, DelayPair fall) : rise(rise), fall(fall){};
@ -588,6 +589,8 @@ struct DelayQuad
delay_t minDelay() const { return std::min<delay_t>(rise.minDelay(), fall.minDelay()); }; 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()); }; 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}; } DelayQuad operator+(const DelayQuad &other) const { return {rise + other.rise, fall + other.fall}; }
}; };
@ -686,15 +689,15 @@ struct TimingClockingInfo
{ {
IdString clock_port; // Port name of clock domain IdString clock_port; // Port name of clock domain
ClockEdge edge; ClockEdge edge;
DelayInfo setup, hold; // Input timing checks DelayPair setup, hold; // Input timing checks
DelayInfo clockToQ; // Output clock-to-Q time DelayQuad clockToQ; // Output clock-to-Q time
}; };
struct ClockConstraint struct ClockConstraint
{ {
DelayInfo high; DelayPair high;
DelayInfo low; DelayPair low;
DelayInfo period; DelayPair period;
TimingConstrObjectId domain_tmg_id; TimingConstrObjectId domain_tmg_id;
}; };
@ -1152,7 +1155,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual NetInfo *getBoundWireNet(WireId wire) const = 0; virtual NetInfo *getBoundWireNet(WireId wire) const = 0;
virtual WireId getConflictingWireWire(WireId wire) const = 0; virtual WireId getConflictingWireWire(WireId wire) const = 0;
virtual NetInfo *getConflictingWireNet(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 // Pip methods
virtual typename R::AllPipsRangeT getPips() const = 0; virtual typename R::AllPipsRangeT getPips() const = 0;
virtual PipId getPipByName(IdStringList name) const = 0; virtual PipId getPipByName(IdStringList name) const = 0;
@ -1168,7 +1171,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual NetInfo *getConflictingPipNet(PipId pip) const = 0; virtual NetInfo *getConflictingPipNet(PipId pip) const = 0;
virtual WireId getPipSrcWire(PipId pip) const = 0; virtual WireId getPipSrcWire(PipId pip) const = 0;
virtual WireId getPipDstWire(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; virtual Loc getPipLocation(PipId pip) const = 0;
// Group methods // Group methods
virtual GroupId getGroupByName(IdStringList name) const = 0; virtual GroupId getGroupByName(IdStringList name) const = 0;
@ -1183,7 +1186,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual delay_t getDelayEpsilon() const = 0; virtual delay_t getDelayEpsilon() const = 0;
virtual delay_t getRipupDelayPenalty() const = 0; virtual delay_t getRipupDelayPenalty() const = 0;
virtual float getDelayNS(delay_t v) 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 uint32_t getDelayChecksum(delay_t v) const = 0;
virtual bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) 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; virtual delay_t estimateDelay(WireId src, WireId dst) const = 0;
@ -1195,7 +1198,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual DecalXY getPipDecal(PipId pip) const = 0; virtual DecalXY getPipDecal(PipId pip) const = 0;
virtual DecalXY getGroupDecal(GroupId group) const = 0; virtual DecalXY getGroupDecal(GroupId group) const = 0;
// Cell timing methods // 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 TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const = 0;
virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0; virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0;
// Placement validity checks // Placement validity checks
@ -1426,7 +1429,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); } virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); }
// Cell timing methods // 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; return false;
} }

View File

@ -231,19 +231,19 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
wr.program = "nextpnr"; wr.program = "nextpnr";
const double delay_scale = 1000; const double delay_scale = 1000;
// Convert from DelayInfo to SDF-friendly RiseFallDelay // Convert from DelayQuad to SDF-friendly RiseFallDelay
auto convert_delay = [&](const DelayInfo &dly) { auto convert_delay = [&](const DelayQuad &dly) {
RiseFallDelay rf; RiseFallDelay rf;
rf.rise.min = getDelayNS(dly.minRaiseDelay()) * delay_scale; rf.rise.min = getDelayNS(dly.minRiseDelay()) * delay_scale;
rf.rise.typ = getDelayNS((dly.minRaiseDelay() + dly.maxRaiseDelay()) / 2) * delay_scale; // fixme: typ delays? rf.rise.typ = getDelayNS((dly.minRiseDelay() + dly.maxRiseDelay()) / 2) * delay_scale; // fixme: typ delays?
rf.rise.max = getDelayNS(dly.maxRaiseDelay()) * delay_scale; rf.rise.max = getDelayNS(dly.maxRiseDelay()) * delay_scale;
rf.fall.min = getDelayNS(dly.minFallDelay()) * 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.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays?
rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale; rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale;
return rf; return rf;
}; };
auto convert_setuphold = [&](const DelayInfo &setup, const DelayInfo &hold) { auto convert_setuphold = [&](const DelayPair &setup, const DelayPair &hold) {
RiseFallDelay rf; RiseFallDelay rf;
rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale; rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale;
rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays? 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; continue;
if (other.second.type == PORT_OUT) if (other.second.type == PORT_OUT)
continue; continue;
DelayInfo dly; DelayQuad dly;
if (!getCellDelay(ci, other.first, port.first, dly)) if (!getCellDelay(ci, other.first, port.first, dly))
continue; continue;
IOPath iop; 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.from.port = ni->driver.port.str(this);
ic.to.cell = usr.cell->name.str(this); ic.to.cell = usr.cell->name.str(this);
ic.to.port = usr.port.str(this); ic.to.port = usr.port.str(this);
// FIXME: min/max routing delay - or at least constructing DelayInfo here // FIXME: min/max routing delay
ic.delay = convert_delay(getDelayFromNS(getDelayNS(getNetinfoRouteDelay(ni, usr)))); ic.delay = convert_delay(DelayQuad(getNetinfoRouteDelay(ni, usr)));
wr.conn.push_back(ic); wr.conn.push_back(ic);
} }
} }
wr.write(out); wr.write(out);
} }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -121,7 +121,7 @@ struct Timing
delay_t walk_paths() 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 // 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 // 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 // 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 // the current output port, increment fanin counter
for (auto i : input_ports) { for (auto i : input_ports) {
DelayInfo comb_delay; DelayQuad comb_delay;
NetInfo *i_net = cell.second->ports[i].net; NetInfo *i_net = cell.second->ports[i].net;
if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name)) if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name))
continue; continue;
@ -238,7 +238,7 @@ struct Timing
if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE || if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE ||
portClass == TMG_GEN_CLOCK) portClass == TMG_GEN_CLOCK)
continue; continue;
DelayInfo comb_delay; DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path) if (!is_path)
continue; continue;
@ -309,7 +309,7 @@ struct Timing
for (auto port : usr.cell->ports) { for (auto port : usr.cell->ports) {
if (port.second.type != PORT_OUT || !port.second.net) if (port.second.type != PORT_OUT || !port.second.net)
continue; continue;
DelayInfo comb_delay; DelayQuad comb_delay;
// Look up delay through this path // Look up delay through this path
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path) if (!is_path)
@ -421,7 +421,7 @@ struct Timing
for (const auto &port : usr.cell->ports) { for (const auto &port : usr.cell->ports) {
if (port.second.type != PORT_OUT || !port.second.net) if (port.second.type != PORT_OUT || !port.second.net)
continue; continue;
DelayInfo comb_delay; DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay); bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path) if (!is_path)
continue; continue;
@ -452,7 +452,7 @@ struct Timing
for (const auto &port : crit_net->driver.cell->ports) { for (const auto &port : crit_net->driver.cell->ports) {
if (port.second.type != PORT_IN || !port.second.net) if (port.second.type != PORT_IN || !port.second.net)
continue; continue;
DelayInfo comb_delay; DelayQuad comb_delay;
bool is_path = bool is_path =
ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay); ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay);
if (!is_path) if (!is_path)
@ -563,7 +563,7 @@ struct Timing
for (const auto &port : drv.cell->ports) { for (const auto &port : drv.cell->ports) {
if (port.second.type != PORT_IN || !port.second.net) if (port.second.type != PORT_IN || !port.second.net)
continue; continue;
DelayInfo comb_delay; DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay); bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay);
if (!is_path) if (!is_path)
continue; continue;
@ -843,14 +843,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
auto net = port.net; auto net = port.net;
auto &driver = net->driver; auto &driver = net->driver;
auto driver_cell = driver.cell; auto driver_cell = driver.cell;
DelayInfo comb_delay; DelayQuad comb_delay;
if (clock_start != -1) { if (clock_start != -1) {
auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start); auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
comb_delay = clockInfo.clockToQ; comb_delay = clockInfo.clockToQ;
clock_start = -1; clock_start = -1;
} else if (last_port == driver.port) { } else if (last_port == driver.port) {
// Case where we start with a STARTPOINT etc // Case where we start with a STARTPOINT etc
comb_delay = ctx->getDelayFromNS(0); comb_delay = DelayQuad(0);
} else { } else {
ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay); ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
} }

View File

@ -328,7 +328,7 @@ class TimingOptimiser
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty()) if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
continue; continue;
int ccount; int ccount;
DelayInfo combDelay; DelayQuad combDelay;
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount); TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
if (tpclass != TMG_COMB_INPUT) if (tpclass != TMG_COMB_INPUT)
continue; continue;
@ -367,7 +367,7 @@ class TimingOptimiser
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty()) if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
continue; continue;
int ccount; int ccount;
DelayInfo combDelay; DelayQuad combDelay;
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount); TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT) if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
continue; continue;

View File

@ -43,21 +43,6 @@ With the exception of `ArchNetInfo` and `ArchCellInfo`, the following types shou
A scalar type that is used to represent delays. May be an integer or float type. A scalar type that is used to represent delays. May be an integer or float type.
### DelayInfo
A struct representing the delay across a timing arc. Must provide a `+` operator for getting the combined delay of two arcs, and the following methods to access concrete timings:
```
delay_t minRaiseDelay() const { return delay; }
delay_t maxRaiseDelay() const { return delay; }
delay_t minFallDelay() const { return delay; }
delay_t maxFallDelay() const { return delay; }
delay_t minDelay() const { return delay; }
delay_t maxDelay() const { return delay; }
```
### BelId ### BelId
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`. A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`.
@ -332,7 +317,7 @@ will make the given wire available.
*BaseArch default: returns `getBoundWireNet(wire)`* *BaseArch default: returns `getBoundWireNet(wire)`*
### DelayInfo getWireDelay(WireId wire) const ### DelayQuad getWireDelay(WireId wire) const
Get the delay for a wire. Get the delay for a wire.
@ -448,7 +433,7 @@ Get the destination wire for a pip.
Bi-directional switches (transfer gates) are modeled using two Bi-directional switches (transfer gates) are modeled using two
anti-parallel pips. anti-parallel pips.
### DelayInfo getPipDelay(PipId pip) const ### DelayQuad getPipDelay(PipId pip) const
Get the delay for a pip. Get the delay for a pip.
@ -541,9 +526,9 @@ actual penalty used is a multiple of this value (i.e. a weighted version of this
Convert an `delay_t` to an actual real-world delay in nanoseconds. Convert an `delay_t` to an actual real-world delay in nanoseconds.
### DelayInfo getDelayFromNS(float v) const ### delay_t getDelayFromNS(float v) const
Convert a real-world delay in nanoseconds to a DelayInfo with equal min/max rising/falling values. Convert a real-world delay in nanoseconds to a `delay_t`.
### uint32\_t getDelayChecksum(delay\_t v) const ### uint32\_t getDelayChecksum(delay\_t v) const
@ -609,7 +594,7 @@ Return the decal and X/Y position for the graphics representing a group.
Cell Delay Methods Cell Delay Methods
------------------ ------------------
### bool getCellDelay(const CellInfo \*cell, IdString fromPort, IdString toPort, DelayInfo &delay) const ### bool getCellDelay(const CellInfo \*cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
Returns the delay for the specified path through a cell in the `&delay` argument. The method returns Returns the delay for the specified path through a cell in the `&delay` argument. The method returns
false if there is no timing relationship from `fromPort` to `toPort`. false if there is no timing relationship from `fromPort` to `toPort`.

View File

@ -721,7 +721,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayInfo &delay) const bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayQuad &delay) const
{ {
auto fnd_dk = celldelay_cache.find({tctype, from, to}); auto fnd_dk = celldelay_cache.find({tctype, from, to});
if (fnd_dk != celldelay_cache.end()) { if (fnd_dk != celldelay_cache.end()) {
@ -732,21 +732,20 @@ bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, De
if (tc.cell_type == tctype.index) { if (tc.cell_type == tctype.index) {
for (auto &dly : tc.prop_delays) { for (auto &dly : tc.prop_delays) {
if (dly.from_port == from.index && dly.to_port == to.index) { if (dly.from_port == from.index && dly.to_port == to.index) {
delay.max_delay = dly.max_delay; delay = DelayQuad(dly.min_delay, dly.max_delay);
delay.min_delay = dly.min_delay;
celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay); celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay);
return true; return true;
} }
} }
celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayInfo()); celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayQuad());
return false; return false;
} }
} }
NPNR_ASSERT_FALSE("failed to find timing cell in db"); NPNR_ASSERT_FALSE("failed to find timing cell in db");
} }
void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayInfo &setup, void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup,
DelayInfo &hold) const DelayPair &hold) const
{ {
for (auto &tc : speed_grade->cell_timings) { for (auto &tc : speed_grade->cell_timings) {
if (tc.cell_type == tctype.index) { if (tc.cell_type == tctype.index) {
@ -764,7 +763,7 @@ void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString p
NPNR_ASSERT_FALSE("failed to find timing cell in db"); NPNR_ASSERT_FALSE("failed to find timing cell in db");
} }
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
// Data for -8 grade // Data for -8 grade
if (cell->type == id_TRELLIS_SLICE) { if (cell->type == id_TRELLIS_SLICE) {
@ -779,15 +778,13 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
(fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) || (fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) ||
(fromPort == id_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) || (fromPort == id_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) ||
(fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) { (fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) {
delay.min_delay = 0; delay = DelayQuad(0);
delay.max_delay = 0;
return true; return true;
} }
return false; return false;
} else if (cell->type == id_DCCA) { } else if (cell->type == id_DCCA) {
if (fromPort == id_CLKI && toPort == id_CLKO) { if (fromPort == id_CLKI && toPort == id_CLKO) {
delay.min_delay = 0; delay = DelayQuad(0);
delay.max_delay = 0;
return true; return true;
} }
return false; return false;
@ -987,9 +984,9 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
{ {
TimingClockingInfo info; TimingClockingInfo info;
info.setup = getDelayFromNS(0); info.setup = DelayPair(0);
info.hold = getDelayFromNS(0); info.hold = DelayPair(0);
info.clockToQ = getDelayFromNS(0); info.clockToQ = DelayQuad(0);
if (cell->type == id_TRELLIS_SLICE) { if (cell->type == id_TRELLIS_SLICE) {
int sd0 = cell->sliceInfo.sd0, sd1 = cell->sliceInfo.sd1; int sd0 = cell->sliceInfo.sd0, sd1 = cell->sliceInfo.sd1;
if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 || if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 ||
@ -1058,26 +1055,26 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
else if (prefix == "CH1_FF_RX") else if (prefix == "CH1_FF_RX")
info.clock_port = id_CH1_FF_RXI_CLK; info.clock_port = id_CH1_FF_RXI_CLK;
if (cell->ports.at(port).type == PORT_OUT) { if (cell->ports.at(port).type == PORT_OUT) {
info.clockToQ = getDelayFromNS(0.7); info.clockToQ = DelayQuad(getDelayFromNS(0.7));
} else { } else {
info.setup = getDelayFromNS(1); info.setup = DelayPair(getDelayFromNS(1));
info.hold = getDelayFromNS(0); info.hold = DelayPair(getDelayFromNS(0));
} }
} else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) { } else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) {
info.clock_port = id_CLK; info.clock_port = id_CLK;
if (cell->ports.at(port).type == PORT_OUT) { if (cell->ports.at(port).type == PORT_OUT) {
info.clockToQ = getDelayFromNS(0.5); info.clockToQ = DelayQuad(getDelayFromNS(0.5));
} else { } else {
info.setup = getDelayFromNS(0.1); info.setup = DelayPair(getDelayFromNS(0.1));
info.hold = getDelayFromNS(0); info.hold = DelayPair(getDelayFromNS(0));
} }
} else if (cell->type == id_DQSBUFM) { } else if (cell->type == id_DQSBUFM) {
info.clock_port = id_SCLK; info.clock_port = id_SCLK;
if (port == id_DATAVALID) { if (port == id_DATAVALID) {
info.clockToQ = getDelayFromNS(0.2); info.clockToQ = DelayQuad(getDelayFromNS(0.2));
} else if (port == id_READ0 || port == id_READ1) { } else if (port == id_READ0 || port == id_READ1) {
info.setup = getDelayFromNS(0.5); info.setup = DelayPair(getDelayFromNS(0.5));
info.hold = getDelayFromNS(-0.4); info.hold = DelayPair(getDelayFromNS(-0.4));
} else { } else {
NPNR_ASSERT_FALSE("unknown DQSBUFM register port"); NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
} }

View File

@ -643,13 +643,7 @@ struct Arch : BaseArch<ArchRanges>
BaseArch::unbindWire(wire); BaseArch::unbindWire(wire);
} }
DelayInfo getWireDelay(WireId wire) const override DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
{
DelayInfo delay;
delay.min_delay = 0;
delay.max_delay = 0;
return delay;
}
WireRange getWires() const override WireRange getWires() const override
{ {
@ -729,21 +723,20 @@ struct Arch : BaseArch<ArchRanges>
return wire; return wire;
} }
DelayInfo getPipDelay(PipId pip) const override DelayQuad getPipDelay(PipId pip) const override
{ {
DelayInfo delay;
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
int fanout = 0; int fanout = 0;
auto fnd_fanout = wire_fanout.find(getPipSrcWire(pip)); auto fnd_fanout = wire_fanout.find(getPipSrcWire(pip));
if (fnd_fanout != wire_fanout.end()) if (fnd_fanout != wire_fanout.end())
fanout = fnd_fanout->second; fanout = fnd_fanout->second;
delay.min_delay = delay_t min_dly =
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay + speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay +
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder; fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder;
delay.max_delay = delay_t max_dly =
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay + speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay +
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder; fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder;
return delay; return DelayQuad(min_dly, max_dly);
} }
PipRange getPipsDownhill(WireId wire) const override PipRange getPipsDownhill(WireId wire) const override
@ -821,13 +814,7 @@ struct Arch : BaseArch<ArchRanges>
delay_t getDelayEpsilon() const override { return 20; } delay_t getDelayEpsilon() const override { return 20; }
delay_t getRipupDelayPenalty() const override; delay_t getRipupDelayPenalty() const override;
float getDelayNS(delay_t v) const override { return v * 0.001; } float getDelayNS(delay_t v) const override { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
{
DelayInfo del;
del.min_delay = delay_t(ns * 1000);
del.max_delay = delay_t(ns * 1000);
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return v; } uint32_t getDelayChecksum(delay_t v) const override { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
@ -850,7 +837,7 @@ struct Arch : BaseArch<ArchRanges>
// Get the delay through a cell from one port to another, returning false // Get the delay through a cell from one port to another, returning false
// if no path exists // if no path exists
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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 override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port
@ -858,9 +845,9 @@ struct Arch : BaseArch<ArchRanges>
// Return true if a port is a net // Return true if a port is a net
bool is_global_net(const NetInfo *net) const; bool is_global_net(const NetInfo *net) const;
bool get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayInfo &delay) const; bool get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayQuad &delay) const;
void get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayInfo &setup, void get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup,
DelayInfo &hold) const; DelayPair &hold) const;
// ------------------------------------------------- // -------------------------------------------------
// Placement validity checks // Placement validity checks
@ -929,7 +916,7 @@ struct Arch : BaseArch<ArchRanges>
std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides; std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides;
void setup_wire_locations(); void setup_wire_locations();
mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache; mutable std::unordered_map<DelayKey, std::pair<bool, DelayQuad>> celldelay_cache;
static const std::string defaultPlacer; static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers; static const std::vector<std::string> availablePlacers;

View File

@ -28,28 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef int delay_t; typedef int delay_t;
struct DelayInfo
{
delay_t min_delay = 0, max_delay = 0;
delay_t minRaiseDelay() const { return min_delay; }
delay_t maxRaiseDelay() const { return max_delay; }
delay_t minFallDelay() const { return min_delay; }
delay_t maxFallDelay() const { return max_delay; }
delay_t minDelay() const { return min_delay; }
delay_t maxDelay() const { return max_delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.min_delay = this->min_delay + other.min_delay;
ret.max_delay = this->max_delay + other.max_delay;
return ret;
}
};
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// https://bugreports.qt.io/browse/QTBUG-80789 // https://bugreports.qt.io/browse/QTBUG-80789

View File

@ -2851,7 +2851,7 @@ class Ecp5Packer
NetInfo *from = ci->ports.at(port).net; NetInfo *from = ci->ports.at(port).net;
if (from == nullptr || from->clkconstr == nullptr) if (from == nullptr || from->clkconstr == nullptr)
return false; return false;
period = from->clkconstr->period.min_delay; period = from->clkconstr->period.minDelay();
return true; return true;
}; };
@ -2862,7 +2862,7 @@ class Ecp5Packer
if (to == nullptr) if (to == nullptr)
return; return;
if (to->clkconstr != nullptr) { if (to->clkconstr != nullptr) {
if (!equals_epsilon(to->clkconstr->period.min_delay, period) && user_constrained.count(to->name)) if (!equals_epsilon(to->clkconstr->period.minDelay(), period) && user_constrained.count(to->name))
log_warning( log_warning(
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of " " Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
"%.1f MHz.\n", "%.1f MHz.\n",
@ -2870,13 +2870,10 @@ class Ecp5Packer
return; return;
} }
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
to->clkconstr->low.min_delay = period / 2; to->clkconstr->low = DelayPair(period / 2);
to->clkconstr->low.max_delay = period / 2; to->clkconstr->high = DelayPair(period / 2);
to->clkconstr->high.min_delay = period / 2; to->clkconstr->period = DelayPair(period);
to->clkconstr->high.max_delay = period / 2; log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.minDelay()),
to->clkconstr->period.min_delay = period;
to->clkconstr->period.max_delay = period;
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
to->name.c_str(ctx)); to->name.c_str(ctx));
changed_nets.insert(to->name); changed_nets.insert(to->name);
}; };
@ -2888,21 +2885,24 @@ class Ecp5Packer
if (from == nullptr || from->clkconstr == nullptr || to == nullptr) if (from == nullptr || from->clkconstr == nullptr || to == nullptr)
return; return;
if (to->clkconstr != nullptr) { if (to->clkconstr != nullptr) {
if (!equals_epsilon(to->clkconstr->period.min_delay, if (!equals_epsilon(to->clkconstr->period.minDelay(),
delay_t(from->clkconstr->period.min_delay / ratio)) && delay_t(from->clkconstr->period.minDelay() / ratio)) &&
user_constrained.count(to->name)) user_constrained.count(to->name))
log_warning( log_warning(
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of " " Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
"%.1f MHz.\n", "%.1f MHz.\n",
MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx), MHz(to->clkconstr->period.minDelay()), to->name.c_str(ctx),
MHz(delay_t(from->clkconstr->period.min_delay / ratio))); MHz(delay_t(from->clkconstr->period.minDelay() / ratio)));
return; return;
} }
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio); to->clkconstr->low =
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio); DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio));
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio); to->clkconstr->high =
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay), DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio));
to->clkconstr->period =
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio));
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.minDelay()),
to->name.c_str(ctx)); to->name.c_str(ctx));
changed_nets.insert(to->name); changed_nets.insert(to->name);
}; };

View File

@ -686,7 +686,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
return 0; return 0;
} }
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
// FIXME: Implement when adding timing-driven place and route. // FIXME: Implement when adding timing-driven place and route.
return false; return false;

View File

@ -1127,12 +1127,7 @@ struct Arch : ArchAPI<ArchRanges>
return w2n == wire_to_net.end() ? nullptr : w2n->second; return w2n == wire_to_net.end() ? nullptr : w2n->second;
} }
DelayInfo getWireDelay(WireId wire) const override DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
{
DelayInfo delay;
delay.delay = 0;
return delay;
}
TileWireRange get_tile_wire_range(WireId wire) const TileWireRange get_tile_wire_range(WireId wire) const
{ {
@ -1279,7 +1274,7 @@ struct Arch : ArchAPI<ArchRanges>
return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].dst_index); return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].dst_index);
} }
DelayInfo getPipDelay(PipId pip) const override { return DelayInfo(); } DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
DownhillPipRange getPipsDownhill(WireId wire) const override DownhillPipRange getPipsDownhill(WireId wire) const override
{ {
@ -1333,12 +1328,7 @@ struct Arch : ArchAPI<ArchRanges>
delay_t getDelayEpsilon() const override { return 20; } delay_t getDelayEpsilon() const override { return 20; }
delay_t getRipupDelayPenalty() const override { return 120; } delay_t getRipupDelayPenalty() const override { return 120; }
float getDelayNS(delay_t v) const override { return v * 0.001; } float getDelayNS(delay_t v) const override { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
{
DelayInfo del;
del.delay = delay_t(ns * 1000);
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return v; } uint32_t getDelayChecksum(delay_t v) const override { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
@ -1363,7 +1353,7 @@ struct Arch : ArchAPI<ArchRanges>
// Get the delay through a cell from one port to another, returning false // Get the delay through a cell from one port to another, returning false
// if no path exists. This only considers combinational delays, as required by the Arch API // if no path exists. This only considers combinational delays, as required by the Arch API
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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 override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port

View File

@ -28,27 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef int delay_t; typedef int delay_t;
struct DelayInfo
{
delay_t delay = 0;
delay_t minRaiseDelay() const { return delay; }
delay_t maxRaiseDelay() const { return delay; }
delay_t minFallDelay() const { return delay; }
delay_t maxFallDelay() const { return delay; }
delay_t minDelay() const { return delay; }
delay_t maxDelay() const { return delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.delay = this->delay + other.delay;
return ret;
}
};
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
struct BelId struct BelId

View File

@ -64,8 +64,7 @@ void Arch::addWire(IdStringList name, IdString type, int x, int y)
wire_ids.push_back(name); wire_ids.push_back(name);
} }
void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay, void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc)
Loc loc)
{ {
NPNR_ASSERT(pips.count(name) == 0); NPNR_ASSERT(pips.count(name) == 0);
PipInfo &pi = pips[name]; PipInfo &pi = pips[name];
@ -219,32 +218,32 @@ void Arch::setDelayScaling(double scale, double offset)
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; } void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay) void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, delay_t delay)
{ {
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE) if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT; cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE) if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE)
cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT; cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT;
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay; cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = DelayQuad(delay);
} }
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold) void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, delay_t setup, delay_t hold)
{ {
TimingClockingInfo ci; TimingClockingInfo ci;
ci.clock_port = clock; ci.clock_port = clock;
ci.edge = RISING_EDGE; ci.edge = RISING_EDGE;
ci.setup = setup; ci.setup = DelayPair(setup);
ci.hold = hold; ci.hold = DelayPair(hold);
cellTiming[cell].clockingInfo[port].push_back(ci); cellTiming[cell].clockingInfo[port].push_back(ci);
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT; cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
} }
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq) void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, delay_t clktoq)
{ {
TimingClockingInfo ci; TimingClockingInfo ci;
ci.clock_port = clock; ci.clock_port = clock;
ci.edge = RISING_EDGE; ci.edge = RISING_EDGE;
ci.clockToQ = clktoq; ci.clockToQ = DelayQuad(clktoq);
cellTiming[cell].clockingInfo[port].push_back(ci); cellTiming[cell].clockingInfo[port].push_back(ci);
cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT; cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT;
} }
@ -465,7 +464,7 @@ WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; } WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; } DelayQuad Arch::getPipDelay(PipId pip) const { return DelayQuad(pips.at(pip).delay); }
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; } const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
@ -615,7 +614,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decal
// --------------------------------------------------------------- // ---------------------------------------------------------------
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
if (!cellTiming.count(cell->name)) if (!cellTiming.count(cell->name))
return false; return false;

View File

@ -41,7 +41,7 @@ struct PipInfo
std::map<IdString, std::string> attrs; std::map<IdString, std::string> attrs;
NetInfo *bound_net; NetInfo *bound_net;
WireId srcWire, dstWire; WireId srcWire, dstWire;
DelayInfo delay; delay_t delay;
DecalXY decalxy; DecalXY decalxy;
Loc loc; Loc loc;
}; };
@ -113,7 +113,7 @@ NEXTPNR_NAMESPACE_BEGIN
struct CellTiming struct CellTiming
{ {
std::unordered_map<IdString, TimingPortClass> portClasses; std::unordered_map<IdString, TimingPortClass> portClasses;
std::unordered_map<CellDelayKey, DelayInfo> combDelays; std::unordered_map<CellDelayKey, DelayQuad> combDelays;
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo; std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
}; };
@ -177,7 +177,7 @@ struct Arch : ArchAPI<ArchRanges>
std::unordered_map<IdString, CellTiming> cellTiming; std::unordered_map<IdString, CellTiming> cellTiming;
void addWire(IdStringList name, IdString type, int x, int y); void addWire(IdStringList name, IdString type, int x, int y);
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay, Loc loc); void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc);
void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden); void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
void addBelInput(IdStringList bel, IdString name, IdStringList wire); void addBelInput(IdStringList bel, IdString name, IdStringList wire);
@ -203,9 +203,9 @@ struct Arch : ArchAPI<ArchRanges>
void setDelayScaling(double scale, double offset); void setDelayScaling(double scale, double offset);
void addCellTimingClock(IdString cell, IdString port); void addCellTimingClock(IdString cell, IdString port);
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay); void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, delay_t delay);
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold); void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, delay_t setup, delay_t hold);
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq); void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, delay_t clktoq);
void clearCellBelPinMap(IdString cell, IdString cell_pin); void clearCellBelPinMap(IdString cell, IdString cell_pin);
void addCellBelPinMapping(IdString cell, IdString cell_pin, IdString bel_pin); void addCellBelPinMapping(IdString cell, IdString cell_pin, IdString bel_pin);
@ -260,7 +260,7 @@ struct Arch : ArchAPI<ArchRanges>
NetInfo *getBoundWireNet(WireId wire) const override; NetInfo *getBoundWireNet(WireId wire) const override;
WireId getConflictingWireWire(WireId wire) const override { return wire; } WireId getConflictingWireWire(WireId wire) const override { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const override; NetInfo *getConflictingWireNet(WireId wire) const override;
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); } DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
const std::vector<WireId> &getWires() const override; const std::vector<WireId> &getWires() const override;
const std::vector<BelPin> &getWireBelPins(WireId wire) const override; const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
@ -279,7 +279,7 @@ struct Arch : ArchAPI<ArchRanges>
Loc getPipLocation(PipId pip) const override; Loc getPipLocation(PipId pip) const override;
WireId getPipSrcWire(PipId pip) const override; WireId getPipSrcWire(PipId pip) const override;
WireId getPipDstWire(PipId pip) const override; WireId getPipDstWire(PipId pip) const override;
DelayInfo getPipDelay(PipId pip) const override; DelayQuad getPipDelay(PipId pip) const override;
const std::vector<PipId> &getPipsDownhill(WireId wire) const override; const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
const std::vector<PipId> &getPipsUphill(WireId wire) const override; const std::vector<PipId> &getPipsUphill(WireId wire) const override;
@ -297,12 +297,7 @@ struct Arch : ArchAPI<ArchRanges>
delay_t getRipupDelayPenalty() const override { return 0.015; } delay_t getRipupDelayPenalty() const override { return 0.015; }
float getDelayNS(delay_t v) const override { return v; } float getDelayNS(delay_t v) const override { return v; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return ns; }
{
DelayInfo del;
del.delay = ns;
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return 0; } uint32_t getDelayChecksum(delay_t v) const override { return 0; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
@ -350,7 +345,7 @@ struct Arch : ArchAPI<ArchRanges>
DecalXY getPipDecal(PipId pip) const override; DecalXY getPipDecal(PipId pip) const override;
DecalXY getGroupDecal(GroupId group) const override; DecalXY getGroupDecal(GroupId group) const override;
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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 override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port

View File

@ -60,8 +60,6 @@ void arch_wrap_python(py::module &m)
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
py::class_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>, fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType"); conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>, fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
@ -126,10 +124,10 @@ void arch_wrap_python(py::module &m)
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>, fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire"); 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"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<DelayInfo>, fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS"); pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap( fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
@ -159,8 +157,8 @@ void arch_wrap_python(py::module &m)
"y"_a); "y"_a);
fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdStringList>, fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdStringList>,
conv_from_str<IdString>, conv_from_str<IdStringList>, conv_from_str<IdStringList>, conv_from_str<IdString>, conv_from_str<IdStringList>, conv_from_str<IdStringList>,
pass_through<DelayInfo>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a, pass_through<delay_t>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
"srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a); "srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a);
fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>, fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>, conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>,
@ -215,16 +213,16 @@ void arch_wrap_python(py::module &m)
"port"_a); "port"_a);
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay, fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay,
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a, pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a, "toPort"_a,
"toPort"_a, "delay"_a); "delay"_a);
fn_wrapper_5a_v<Context, decltype(&Context::addCellTimingSetupHold), &Context::addCellTimingSetupHold, fn_wrapper_5a_v<Context, decltype(&Context::addCellTimingSetupHold), &Context::addCellTimingSetupHold,
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<DelayInfo>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<delay_t>,
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a, pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a,
"setup"_a, "hold"_a); "setup"_a, "hold"_a);
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut, fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut,
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a, pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a, "clock"_a,
"clock"_a, "clktoq"_a); "clktoq"_a);
fn_wrapper_2a_v<Context, decltype(&Context::clearCellBelPinMap), &Context::clearCellBelPinMap, fn_wrapper_2a_v<Context, decltype(&Context::clearCellBelPinMap), &Context::clearCellBelPinMap,
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "clearCellBelPinMap", "cell"_a, conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "clearCellBelPinMap", "cell"_a,

View File

@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef float delay_t; typedef float delay_t;
struct DelayInfo
{
delay_t delay = 0;
delay_t minRaiseDelay() const { return delay; }
delay_t maxRaiseDelay() const { return delay; }
delay_t minFallDelay() const { return delay; }
delay_t maxFallDelay() const { return delay; }
delay_t minDelay() const { return delay; }
delay_t maxDelay() const { return delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.delay = this->delay + other.delay;
return ret;
}
};
typedef IdStringList BelId; typedef IdStringList BelId;
typedef IdStringList WireId; typedef IdStringList WireId;
typedef IdStringList PipId; typedef IdStringList PipId;

View File

@ -68,7 +68,7 @@ void Arch::addWire(IdString name, IdString type, int x, int y)
wire_ids.push_back(name); wire_ids.push_back(name);
} }
void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc) void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc)
{ {
NPNR_ASSERT(pips.count(name) == 0); NPNR_ASSERT(pips.count(name) == 0);
PipInfo &pi = pips[name]; PipInfo &pi = pips[name];
@ -226,7 +226,7 @@ void Arch::setDelayScaling(double scale, double offset)
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; } void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay) void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay)
{ {
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE) if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT; cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
@ -235,7 +235,7 @@ void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort,
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay; cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay;
} }
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold) void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold)
{ {
TimingClockingInfo ci; TimingClockingInfo ci;
ci.clock_port = clock; ci.clock_port = clock;
@ -246,7 +246,7 @@ void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock,
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT; cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
} }
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq) void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq)
{ {
TimingClockingInfo ci; TimingClockingInfo ci;
ci.clock_port = clock; ci.clock_port = clock;
@ -340,27 +340,24 @@ template <class T, class C> const T *genericLookup(const T *first, int len, cons
} }
} }
DelayInfo delayLookup(const TimingPOD *first, int len, IdString name) DelayQuad delayLookup(const TimingPOD *first, int len, IdString name)
{ {
TimingPOD needle; TimingPOD needle;
needle.name_id = name.index; needle.name_id = name.index;
const TimingPOD *timing = genericLookup(first, len, needle, timingCompare); const TimingPOD *timing = genericLookup(first, len, needle, timingCompare);
DelayInfo info; DelayQuad delay;
if (timing != nullptr) { if (timing != nullptr) {
info.maxFall = std::max(timing->ff, timing->rf) / 1000; delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000;
info.minFall = std::min(timing->ff, timing->rf) / 1000; delay.fall.min_delay = std::min(timing->ff, timing->rf) / 1000;
info.maxRaise = std::max(timing->rr, timing->fr) / 1000; delay.rise.max_delay = std::max(timing->rr, timing->fr) / 1000;
info.minRaise = std::min(timing->rr, timing->fr) / 1000; delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000;
} else { } else {
info.maxFall = 0; delay = DelayQuad(0);
info.minFall = 0;
info.maxRaise = 0;
info.minRaise = 0;
} }
return info; return delay;
} }
DelayInfo Arch::getWireTypeDelay(IdString wire) DelayQuad Arch::getWireTypeDelay(IdString wire)
{ {
IdString len; IdString len;
IdString glbsrc; IdString glbsrc;
@ -480,12 +477,7 @@ DelayInfo Arch::getWireTypeDelay(IdString wire)
} else if (glbsrc != IdString()) { } else if (glbsrc != IdString()) {
return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc); return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc);
} else { } else {
DelayInfo info; return DelayQuad(0);
info.maxFall = 0;
info.minFall = 0;
info.maxRaise = 0;
info.minRaise = 0;
return info;
} }
} }
@ -720,7 +712,7 @@ Arch::Arch(ArchArgs args) : args(args)
snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this)); snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this));
IdString pipname = id(buf); IdString pipname = id(buf);
DelayInfo delay = getWireTypeDelay(destid); DelayQuad delay = getWireTypeDelay(destid);
// local alias // local alias
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index); auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
// std::cout << "srcid " << srcid.str(this) << std::endl; // std::cout << "srcid " << srcid.str(this) << std::endl;
@ -934,7 +926,7 @@ WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; } WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; } DelayQuad Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; }
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; } const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
@ -1067,7 +1059,7 @@ bool Arch::route()
// --------------------------------------------------------------- // ---------------------------------------------------------------
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
if (!cellTiming.count(cell->name)) if (!cellTiming.count(cell->name))
return false; return false;
@ -1145,19 +1137,17 @@ void Arch::assignArchInfo()
addCellTimingClock(cname, id_CLK); addCellTimingClock(cname, id_CLK);
IdString ports[4] = {id_A, id_B, id_C, id_D}; IdString ports[4] = {id_A, id_B, id_C, id_D};
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
DelayInfo setup = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos); DelayPair setup =
DelayInfo hold = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos); delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos).delayPair();
// DelayInfo setup = getDelayFromNS(0.1); DelayPair hold =
// DelayInfo hold = getDelayFromNS(0.1); delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos).delayPair();
addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold); addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold);
} }
DelayInfo clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos); DelayQuad clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos);
// DelayInfo clkout = getDelayFromNS(0.1);
addCellTimingClockToOut(cname, id_Q, id_CLK, clkout); addCellTimingClockToOut(cname, id_Q, id_CLK, clkout);
IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f}; IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f};
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
DelayInfo delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]); DelayQuad delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
// DelayInfo delay = getDelayFromNS(0.1);
addCellTimingDelay(cname, ports[i], id_F, delay); addCellTimingDelay(cname, ports[i], id_F, delay);
} }

View File

@ -170,7 +170,7 @@ struct PipInfo
std::map<IdString, std::string> attrs; std::map<IdString, std::string> attrs;
NetInfo *bound_net; NetInfo *bound_net;
WireId srcWire, dstWire; WireId srcWire, dstWire;
DelayInfo delay; DelayQuad delay;
DecalXY decalxy; DecalXY decalxy;
Loc loc; Loc loc;
}; };
@ -239,7 +239,7 @@ NEXTPNR_NAMESPACE_BEGIN
struct CellTiming struct CellTiming
{ {
std::unordered_map<IdString, TimingPortClass> portClasses; std::unordered_map<IdString, TimingPortClass> portClasses;
std::unordered_map<CellDelayKey, DelayInfo> combDelays; std::unordered_map<CellDelayKey, DelayQuad> combDelays;
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo; std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
}; };
@ -302,7 +302,7 @@ struct Arch : BaseArch<ArchRanges>
std::unordered_map<IdString, CellTiming> cellTiming; std::unordered_map<IdString, CellTiming> cellTiming;
void addWire(IdString name, IdString type, int x, int y); void addWire(IdString name, IdString type, int x, int y);
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc); void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
void addBel(IdString name, IdString type, Loc loc, bool gb); void addBel(IdString name, IdString type, Loc loc, bool gb);
void addBelInput(IdString bel, IdString name, IdString wire); void addBelInput(IdString bel, IdString name, IdString wire);
@ -327,12 +327,12 @@ struct Arch : BaseArch<ArchRanges>
void setDelayScaling(double scale, double offset); void setDelayScaling(double scale, double offset);
void addCellTimingClock(IdString cell, IdString port); void addCellTimingClock(IdString cell, IdString port);
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay); void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay);
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold); void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold);
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq); void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq);
IdString wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString &wire); IdString wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString &wire);
DelayInfo getWireTypeDelay(IdString wire); DelayQuad getWireTypeDelay(IdString wire);
void read_cst(std::istream &in); void read_cst(std::istream &in);
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -384,7 +384,7 @@ struct Arch : BaseArch<ArchRanges>
NetInfo *getBoundWireNet(WireId wire) const override; NetInfo *getBoundWireNet(WireId wire) const override;
WireId getConflictingWireWire(WireId wire) const override { return wire; } WireId getConflictingWireWire(WireId wire) const override { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const override; NetInfo *getConflictingWireNet(WireId wire) const override;
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); } DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
const std::vector<WireId> &getWires() const override; const std::vector<WireId> &getWires() const override;
const std::vector<BelPin> &getWireBelPins(WireId wire) const override; const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
@ -402,7 +402,7 @@ struct Arch : BaseArch<ArchRanges>
Loc getPipLocation(PipId pip) const override; Loc getPipLocation(PipId pip) const override;
WireId getPipSrcWire(PipId pip) const override; WireId getPipSrcWire(PipId pip) const override;
WireId getPipDstWire(PipId pip) const override; WireId getPipDstWire(PipId pip) const override;
DelayInfo getPipDelay(PipId pip) const override; DelayQuad getPipDelay(PipId pip) const override;
const std::vector<PipId> &getPipsDownhill(WireId wire) const override; const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
const std::vector<PipId> &getPipsUphill(WireId wire) const override; const std::vector<PipId> &getPipsUphill(WireId wire) const override;
@ -420,15 +420,7 @@ struct Arch : BaseArch<ArchRanges>
delay_t getRipupDelayPenalty() const override { return 0.4; } delay_t getRipupDelayPenalty() const override { return 0.4; }
float getDelayNS(delay_t v) const override { return v; } float getDelayNS(delay_t v) const override { return v; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return ns; }
{
DelayInfo del;
del.maxRaise = ns;
del.maxFall = ns;
del.minRaise = ns;
del.minFall = ns;
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return 0; } uint32_t getDelayChecksum(delay_t v) const override { return 0; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
@ -439,7 +431,7 @@ struct Arch : BaseArch<ArchRanges>
bool place() override; bool place() override;
bool route() override; bool route() override;
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port

View File

@ -59,8 +59,6 @@ void arch_wrap_python(py::module &m)
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
py::class_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>, fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType"); conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>, fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
@ -125,10 +123,10 @@ void arch_wrap_python(py::module &m)
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>, fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire"); 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"); conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<DelayInfo>, fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS"); pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap( fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(

View File

@ -26,33 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef float delay_t; typedef float delay_t;
struct DelayInfo
{
delay_t minRaise = 0;
delay_t minFall = 0;
delay_t maxRaise = 0;
delay_t maxFall = 0;
delay_t minRaiseDelay() const { return minRaise; }
delay_t maxRaiseDelay() const { return maxRaise; }
delay_t minFallDelay() const { return minFall; }
delay_t maxFallDelay() const { return maxFall; }
delay_t minDelay() const { return std::min(minFall, minRaise); }
delay_t maxDelay() const { return std::max(maxFall, maxRaise); }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.minRaise = this->minRaise + other.minRaise;
ret.maxRaise = this->maxRaise + other.maxRaise;
ret.minFall = this->minFall + other.minFall;
ret.maxFall = this->maxFall + other.maxFall;
return ret;
}
};
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
enum ConstIds enum ConstIds
{ {

View File

@ -652,11 +652,11 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
} }
DelayInfo delay = ctx->getWireDelay(wire); DelayQuad delay = ctx->getWireDelay(wire);
QtProperty *delayItem = addSubGroup(topItem, "Delay"); QtProperty *delayItem = addSubGroup(topItem, "Delay");
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay()); addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay()); addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay()); addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay()); addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
@ -721,11 +721,11 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
} }
DelayInfo delay = ctx->getPipDelay(pip); DelayQuad delay = ctx->getPipDelay(pip);
QtProperty *delayItem = addSubGroup(topItem, "Delay"); QtProperty *delayItem = addSubGroup(topItem, "Delay");
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay()); addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay()); addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay()); addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay()); addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
} else if (type == ElementType::NET) { } else if (type == ElementType::NET) {

View File

@ -921,7 +921,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) { if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) {
if (toPort == id_O) if (toPort == id_O)
@ -932,16 +932,16 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
return get_cell_delay_internal(cell, fromPort, toPort, delay); return get_cell_delay_internal(cell, fromPort, toPort, delay);
} }
bool Arch::get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
for (auto &tc : chip_info->cell_timing) { for (auto &tc : chip_info->cell_timing) {
if (tc.type == cell->type.index) { if (tc.type == cell->type.index) {
for (auto &path : tc.path_delays) { for (auto &path : tc.path_delays) {
if (path.from_port == fromPort.index && path.to_port == toPort.index) { if (path.from_port == fromPort.index && path.to_port == toPort.index) {
if (fast_part) if (fast_part)
delay.delay = path.fast_delay; delay = DelayQuad(path.fast_delay);
else else
delay.delay = path.slow_delay; delay = DelayQuad(path.slow_delay);
return true; return true;
} }
} }
@ -1088,22 +1088,22 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
NPNR_ASSERT(has_clktoq); NPNR_ASSERT(has_clktoq);
} else { } else {
if (port == id_I0 || port == id_I1 || port == id_I2 || port == id_I3) { if (port == id_I0 || port == id_I1 || port == id_I2 || port == id_I3) {
DelayInfo dlut; DelayQuad dlut;
bool has_ld = get_cell_delay_internal(cell, port, id_O, dlut); bool has_ld = get_cell_delay_internal(cell, port, id_O, dlut);
NPNR_ASSERT(has_ld); NPNR_ASSERT(has_ld);
if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K || args.type == ArchArgs::LP8K || if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K || args.type == ArchArgs::LP8K ||
args.type == ArchArgs::LP384) { args.type == ArchArgs::LP384) {
info.setup.delay = 30 + dlut.delay; info.setup = DelayPair(30 + dlut.maxDelay());
} else if (args.type == ArchArgs::UP3K || args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K || } else if (args.type == ArchArgs::UP3K || args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K ||
args.type == ArchArgs::U1K || args.type == ArchArgs::U2K) { // XXX verify u4k args.type == ArchArgs::U1K || args.type == ArchArgs::U2K) { // XXX verify u4k
info.setup.delay = dlut.delay - 50; info.setup = DelayPair(dlut.maxDelay() - 50);
} else { } else {
info.setup.delay = 20 + dlut.delay; info.setup = DelayPair(20 + dlut.maxDelay());
} }
} else { } else {
info.setup.delay = 100; info.setup = DelayPair(100);
} }
info.hold.delay = 0; info.hold = DelayPair(0);
} }
} else if (cell->type == id_ICESTORM_RAM) { } else if (cell->type == id_ICESTORM_RAM) {
if (port.str(this)[0] == 'R') { if (port.str(this)[0] == 'R') {
@ -1117,8 +1117,8 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ); bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
NPNR_ASSERT(has_clktoq); NPNR_ASSERT(has_clktoq);
} else { } else {
info.setup.delay = 100; info.setup = DelayPair(100);
info.hold.delay = 0; info.hold = DelayPair(0);
} }
} else if (cell->type == id_SB_IO) { } else if (cell->type == id_SB_IO) {
delay_t io_setup = 80, io_clktoq = 140; delay_t io_setup = 80, io_clktoq = 140;
@ -1133,26 +1133,26 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
if (port == id_CLOCK_ENABLE) { if (port == id_CLOCK_ENABLE) {
info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK; info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK;
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
info.setup.delay = io_setup; info.setup = DelayPair(io_setup);
info.hold.delay = 0; info.hold = DelayPair(0);
} else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) { } else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) {
info.clock_port = id_OUTPUT_CLK; info.clock_port = id_OUTPUT_CLK;
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
info.setup.delay = io_setup; info.setup = DelayPair(io_setup);
info.hold.delay = 0; info.hold = DelayPair(0);
} else if (port == id_D_OUT_1) { } else if (port == id_D_OUT_1) {
info.clock_port = id_OUTPUT_CLK; info.clock_port = id_OUTPUT_CLK;
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE; info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
info.setup.delay = io_setup; info.setup = DelayPair(io_setup);
info.hold.delay = 0; info.hold = DelayPair(0);
} else if (port == id_D_IN_0) { } else if (port == id_D_IN_0) {
info.clock_port = id_INPUT_CLK; info.clock_port = id_INPUT_CLK;
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
info.clockToQ.delay = io_clktoq; info.clockToQ = DelayQuad(io_clktoq);
} else if (port == id_D_IN_1) { } else if (port == id_D_IN_1) {
info.clock_port = id_INPUT_CLK; info.clock_port = id_INPUT_CLK;
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE; info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
info.clockToQ.delay = io_clktoq; info.clockToQ = DelayQuad(io_clktoq);
} else { } else {
NPNR_ASSERT_FALSE("no clock data for IO cell port"); NPNR_ASSERT_FALSE("no clock data for IO cell port");
} }
@ -1162,21 +1162,21 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
if (cell->ports.at(port).type == PORT_OUT) { if (cell->ports.at(port).type == PORT_OUT) {
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ); bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
if (!has_clktoq) if (!has_clktoq)
info.clockToQ.delay = 100; info.clockToQ = DelayQuad(100);
} else { } else {
info.setup.delay = 100; info.setup = DelayPair(100);
info.hold.delay = 0; info.hold = DelayPair(0);
} }
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) { } else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
info.clock_port = this->id("SBCLKI"); info.clock_port = this->id("SBCLKI");
info.edge = RISING_EDGE; info.edge = RISING_EDGE;
if (cell->ports.at(port).type == PORT_OUT) { if (cell->ports.at(port).type == PORT_OUT) {
/* Dummy number */ /* Dummy number */
info.clockToQ.delay = 1500; info.clockToQ = DelayQuad(1500);
} else { } else {
/* Dummy number */ /* Dummy number */
info.setup.delay = 1500; info.setup = DelayPair(1500);
info.hold.delay = 0; info.hold = DelayPair(0);
} }
} else { } else {
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo"); NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");

View File

@ -578,15 +578,13 @@ struct Arch : BaseArch<ArchRanges>
return wire_to_net[wire.index]; return wire_to_net[wire.index];
} }
DelayInfo getWireDelay(WireId wire) const override DelayQuad getWireDelay(WireId wire) const override
{ {
DelayInfo delay;
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
if (fast_part) if (fast_part)
delay.delay = chip_info->wire_data[wire.index].fast_delay; return DelayQuad(chip_info->wire_data[wire.index].fast_delay);
else else
delay.delay = chip_info->wire_data[wire.index].slow_delay; return DelayQuad(chip_info->wire_data[wire.index].slow_delay);
return delay;
} }
BelPinRange getWireBelPins(WireId wire) const override BelPinRange getWireBelPins(WireId wire) const override
@ -739,15 +737,13 @@ struct Arch : BaseArch<ArchRanges>
return wire; return wire;
} }
DelayInfo getPipDelay(PipId pip) const override DelayQuad getPipDelay(PipId pip) const override
{ {
DelayInfo delay;
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
if (fast_part) if (fast_part)
delay.delay = chip_info->pip_data[pip.index].fast_delay; return DelayQuad(chip_info->pip_data[pip.index].fast_delay);
else else
delay.delay = chip_info->pip_data[pip.index].slow_delay; return DelayQuad(chip_info->pip_data[pip.index].slow_delay);
return delay;
} }
PipRange getPipsDownhill(WireId wire) const override PipRange getPipsDownhill(WireId wire) const override
@ -788,12 +784,7 @@ struct Arch : BaseArch<ArchRanges>
delay_t getDelayEpsilon() const override { return 20; } delay_t getDelayEpsilon() const override { return 20; }
delay_t getRipupDelayPenalty() const override { return 200; } delay_t getRipupDelayPenalty() const override { return 200; }
float getDelayNS(delay_t v) const override { return v * 0.001; } float getDelayNS(delay_t v) const override { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
{
DelayInfo del;
del.delay = delay_t(ns * 1000);
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return v; } uint32_t getDelayChecksum(delay_t v) const override { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
@ -818,10 +809,10 @@ struct Arch : BaseArch<ArchRanges>
// Get the delay through a cell from one port to another, returning false // Get the delay through a cell from one port to another, returning false
// if no path exists. This only considers combinational delays, as required by the Arch API // if no path exists. This only considers combinational delays, as required by the Arch API
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// get_cell_delay_internal is similar to the above, but without false path checks and including clock to out delays // get_cell_delay_internal is similar to the above, but without false path checks and including clock to out delays
// for internal arch use only // for internal arch use only
bool get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; bool get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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 override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port

View File

@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef int delay_t; typedef int delay_t;
struct DelayInfo
{
delay_t delay = 0;
delay_t minRaiseDelay() const { return delay; }
delay_t maxRaiseDelay() const { return delay; }
delay_t minFallDelay() const { return delay; }
delay_t maxFallDelay() const { return delay; }
delay_t minDelay() const { return delay; }
delay_t maxDelay() const { return delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.delay = this->delay + other.delay;
return ret;
}
};
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// https://bugreports.qt.io/browse/QTBUG-80789 // https://bugreports.qt.io/browse/QTBUG-80789

View File

@ -1085,17 +1085,17 @@ void set_period(Context *ctx, CellInfo *ci, IdString port, delay_t period)
if (to == nullptr) if (to == nullptr)
return; return;
if (to->clkconstr != nullptr) { if (to->clkconstr != nullptr) {
if (!equals_epsilon(to->clkconstr->period.delay, period)) if (!equals_epsilon(to->clkconstr->period.maxDelay(), period))
log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of " log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
"%.1f MHz.\n", "%.1f MHz.\n",
MHz(ctx, to->clkconstr->period.delay), to->name.c_str(ctx), MHz(ctx, period)); MHz(ctx, to->clkconstr->period.maxDelay()), to->name.c_str(ctx), MHz(ctx, period));
return; return;
} }
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
to->clkconstr->low.delay = period / 2; to->clkconstr->low = DelayPair(period / 2);
to->clkconstr->high.delay = period / 2; to->clkconstr->high = DelayPair(period / 2);
to->clkconstr->period.delay = period; to->clkconstr->period = DelayPair(period);
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.delay), log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.maxDelay()),
to->name.c_str(ctx)); to->name.c_str(ctx));
}; };
bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period) bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period)
@ -1105,7 +1105,7 @@ bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period)
NetInfo *from = ci->ports.at(port).net; NetInfo *from = ci->ports.at(port).net;
if (from == nullptr || from->clkconstr == nullptr) if (from == nullptr || from->clkconstr == nullptr)
return false; return false;
period = from->clkconstr->period.delay; period = from->clkconstr->period.maxDelay();
return true; return true;
}; };

View File

@ -509,7 +509,7 @@ struct Arch : BaseArch<ArchRanges>
return IdStringList(ids); return IdStringList(ids);
} }
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); } DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
WireRange getWires() const override WireRange getWires() const override
{ {
@ -582,14 +582,7 @@ struct Arch : BaseArch<ArchRanges>
return wire; return wire;
} }
DelayInfo getPipDelay(PipId pip) const override DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
{
DelayInfo delay;
delay.delay = 0.01;
return delay;
}
PipRange getPipsDownhill(WireId wire) const override PipRange getPipsDownhill(WireId wire) const override
{ {
@ -633,12 +626,7 @@ struct Arch : BaseArch<ArchRanges>
delay_t getRipupDelayPenalty() const override { return 0.015; } delay_t getRipupDelayPenalty() const override { return 0.015; }
float getDelayNS(delay_t v) const override { return v; } float getDelayNS(delay_t v) const override { return v; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return ns; }
{
DelayInfo del;
del.delay = ns;
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return v; } uint32_t getDelayChecksum(delay_t v) const override { return v; }

View File

@ -26,27 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef float delay_t; typedef float delay_t;
struct DelayInfo
{
delay_t delay = 0;
delay_t minRaiseDelay() const { return delay; }
delay_t maxRaiseDelay() const { return delay; }
delay_t minFallDelay() const { return delay; }
delay_t maxFallDelay() const { return delay; }
delay_t minDelay() const { return delay; }
delay_t maxDelay() const { return delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.delay = this->delay + other.delay;
return ret;
}
};
enum ConstIds enum ConstIds
{ {
ID_NONE ID_NONE

View File

@ -432,7 +432,7 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
{ {
auto lookup_port = [&](IdString p) { auto lookup_port = [&](IdString p) {
auto fnd = cell->tmg_portmap.find(p); auto fnd = cell->tmg_portmap.find(p);
@ -443,8 +443,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
bool result = lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay); bool result = lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay);
// Because CCU2 = 2x OXIDE_COMB // Because CCU2 = 2x OXIDE_COMB
if (result && fromPort == id_FCI && toPort == id_FCO) { if (result && fromPort == id_FCI && toPort == id_FCO) {
delay.min_delay /= 2; delay = DelayQuad(delay.minDelay() / 2, delay.maxDelay() / 2);
delay.max_delay /= 2;
} }
return result; return result;
} else { } else {
@ -870,7 +869,7 @@ int Arch::get_cell_timing_idx(IdString cell_type, IdString cell_variant) const
std::make_pair(cell_type.index, cell_variant.index)); std::make_pair(cell_type.index, cell_variant.index));
} }
bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayQuad &delay) const
{ {
NPNR_ASSERT(type_idx != -1); NPNR_ASSERT(type_idx != -1);
const auto &ct = speed_grade->cell_types[type_idx]; const auto &ct = speed_grade->cell_types[type_idx];
@ -880,13 +879,12 @@ bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port,
std::make_pair(to_port.index, from_port.index)); std::make_pair(to_port.index, from_port.index));
if (dly_idx == -1) if (dly_idx == -1)
return false; return false;
delay.min_delay = ct.prop_delays[dly_idx].min_delay; delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
return true; return true;
} }
void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup, void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
DelayInfo &hold) const DelayPair &hold) const
{ {
NPNR_ASSERT(type_idx != -1); NPNR_ASSERT(type_idx != -1);
const auto &ct = speed_grade->cell_types[type_idx]; const auto &ct = speed_grade->cell_types[type_idx];
@ -901,8 +899,8 @@ void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString cloc
hold.max_delay = ct.setup_holds[dly_idx].max_hold; hold.max_delay = ct.setup_holds[dly_idx].max_hold;
} }
void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup, void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
DelayInfo &hold) const DelayPair &hold) const
{ {
NPNR_ASSERT(type_idx != -1); NPNR_ASSERT(type_idx != -1);
const auto &ct = speed_grade->cell_types[type_idx]; const auto &ct = speed_grade->cell_types[type_idx];
@ -916,7 +914,7 @@ void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdStrin
hold.min_delay = ct.setup_holds[dly_idx].min_hold; hold.min_delay = ct.setup_holds[dly_idx].min_hold;
hold.max_delay = ct.setup_holds[dly_idx].max_hold; hold.max_delay = ct.setup_holds[dly_idx].max_hold;
} }
void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayInfo &delay) const void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayQuad &delay) const
{ {
NPNR_ASSERT(type_idx != -1); NPNR_ASSERT(type_idx != -1);
const auto &ct = speed_grade->cell_types[type_idx]; const auto &ct = speed_grade->cell_types[type_idx];
@ -925,9 +923,9 @@ void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock
to_port.index); to_port.index);
NPNR_ASSERT(dly_idx != -1); NPNR_ASSERT(dly_idx != -1);
clock = IdString(ct.prop_delays[dly_idx].from_port); clock = IdString(ct.prop_delays[dly_idx].from_port);
delay.min_delay = ct.prop_delays[dly_idx].min_delay; delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
} }
TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const
{ {
if (dir == PORT_IN) { if (dir == PORT_IN) {
@ -940,7 +938,7 @@ TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir
std::make_pair(port.index, clock.index)); std::make_pair(port.index, clock.index));
return (sh_idx != -1) ? TMG_REGISTER_INPUT : TMG_COMB_INPUT; return (sh_idx != -1) ? TMG_REGISTER_INPUT : TMG_COMB_INPUT;
} else { } else {
DelayInfo dly; DelayQuad dly;
// If a clock-to-out entry exists, then this is a register output // If a clock-to-out entry exists, then this is a register output
return lookup_cell_delay(type_idx, clock, port, dly) ? TMG_REGISTER_OUTPUT : TMG_COMB_OUTPUT; return lookup_cell_delay(type_idx, clock, port, dly) ? TMG_REGISTER_OUTPUT : TMG_COMB_OUTPUT;
} }

View File

@ -1042,13 +1042,7 @@ struct Arch : BaseArch<ArchRanges>
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const override; std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const override;
DelayInfo getWireDelay(WireId wire) const override DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
{
DelayInfo delay;
delay.min_delay = 0;
delay.max_delay = 0;
return delay;
}
BelPinRange getWireBelPins(WireId wire) const override BelPinRange getWireBelPins(WireId wire) const override
{ {
@ -1120,13 +1114,10 @@ struct Arch : BaseArch<ArchRanges>
WireId getPipDstWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).to_wire); } WireId getPipDstWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).to_wire); }
DelayInfo getPipDelay(PipId pip) const override DelayQuad getPipDelay(PipId pip) const override
{ {
DelayInfo delay;
auto &cls = speed_grade->pip_classes[pip_data(pip).timing_class]; auto &cls = speed_grade->pip_classes[pip_data(pip).timing_class];
delay.min_delay = std::max(0, cls.min_delay); return DelayQuad(cls.min_delay, cls.max_delay);
delay.max_delay = std::max(0, cls.max_delay);
return delay;
} }
UpDownhillPipRange getPipsDownhill(WireId wire) const override UpDownhillPipRange getPipsDownhill(WireId wire) const override
@ -1179,13 +1170,7 @@ struct Arch : BaseArch<ArchRanges>
delay_t getRipupDelayPenalty() const override { return 120; } delay_t getRipupDelayPenalty() const override { return 120; }
delay_t getWireRipupDelayPenalty(WireId wire) const; delay_t getWireRipupDelayPenalty(WireId wire) const;
float getDelayNS(delay_t v) const override { return v * 0.001; } float getDelayNS(delay_t v) const override { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const override delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
{
DelayInfo del;
del.min_delay = delay_t(ns * 1000);
del.max_delay = delay_t(ns * 1000);
return del;
}
uint32_t getDelayChecksum(delay_t v) const override { return v; } uint32_t getDelayChecksum(delay_t v) const override { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override; ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override;
@ -1198,7 +1183,7 @@ struct Arch : BaseArch<ArchRanges>
// Get the delay through a cell from one port to another, returning false // Get the delay through a cell from one port to another, returning false
// if no path exists. This only considers combinational delays, as required by the Arch API // if no path exists. This only considers combinational delays, as required by the Arch API
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port // 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 override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
// Get the TimingClockingInfo of a port // Get the TimingClockingInfo of a port
@ -1385,15 +1370,15 @@ struct Arch : BaseArch<ArchRanges>
// Given cell type and variant, get the index inside the speed grade timing data // Given cell type and variant, get the index inside the speed grade timing data
int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const; int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const;
// Return true and set delay if a comb path exists in a given cell timing index // Return true and set delay if a comb path exists in a given cell timing index
bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const; bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayQuad &delay) const;
// Get setup and hold time for a given cell timing index and signal/clock pair // Get setup and hold time for a given cell timing index and signal/clock pair
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup, void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
DelayInfo &hold) const; DelayPair &hold) const;
// Get setup and hold time and associated clock for a given cell timing index and signal // Get setup and hold time and associated clock for a given cell timing index and signal
void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup, void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
DelayInfo &hold) const; DelayPair &hold) const;
// Similar to lookup_cell_delay but only needs the 'to' signal, intended for clk->out delays // Similar to lookup_cell_delay but only needs the 'to' signal, intended for clk->out delays
void lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayInfo &delay) const; void lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayQuad &delay) const;
// Attempt to look up port type based on database // Attempt to look up port type based on database
TimingPortClass lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const; TimingPortClass lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const;
// ------------------------------------------------- // -------------------------------------------------

View File

@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
typedef int delay_t; typedef int delay_t;
struct DelayInfo
{
delay_t min_delay = 0, max_delay = 0;
delay_t minRaiseDelay() const { return min_delay; }
delay_t maxRaiseDelay() const { return max_delay; }
delay_t minFallDelay() const { return min_delay; }
delay_t maxFallDelay() const { return max_delay; }
delay_t minDelay() const { return min_delay; }
delay_t maxDelay() const { return max_delay; }
DelayInfo operator+(const DelayInfo &other) const
{
DelayInfo ret;
ret.min_delay = this->min_delay + other.min_delay;
ret.max_delay = this->max_delay + other.max_delay;
return ret;
}
};
// https://bugreports.qt.io/browse/QTBUG-80789 // https://bugreports.qt.io/browse/QTBUG-80789
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN

View File

@ -1862,9 +1862,12 @@ struct NexusPacker
return; return;
} }
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio); to->clkconstr->low =
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio); DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio));
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio); to->clkconstr->high =
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio));
to->clkconstr->period =
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio));
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay), log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
to->name.c_str(ctx)); to->name.c_str(ctx));
changed_nets.insert(to->name); changed_nets.insert(to->name);