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:
parent
8376db94a7
commit
7922b3bfc4
@ -103,7 +103,7 @@ fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWir
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||
|
||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||
|
@ -656,9 +656,9 @@ void Context::check() const
|
||||
void BaseCtx::addClock(IdString net, float freq)
|
||||
{
|
||||
std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
|
||||
cc->period = getCtx()->getDelayFromNS(1000 / freq);
|
||||
cc->high = getCtx()->getDelayFromNS(500 / freq);
|
||||
cc->low = getCtx()->getDelayFromNS(500 / freq);
|
||||
cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq));
|
||||
cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq));
|
||||
cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq));
|
||||
if (!net_aliases.count(net)) {
|
||||
log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this));
|
||||
} else {
|
||||
|
@ -575,6 +575,7 @@ struct DelayPair
|
||||
struct DelayQuad
|
||||
{
|
||||
DelayPair rise, fall;
|
||||
DelayQuad(){};
|
||||
explicit DelayQuad(delay_t delay) : rise(delay), fall(delay){};
|
||||
DelayQuad(delay_t min_delay, delay_t max_delay) : rise(min_delay, max_delay), fall(min_delay, max_delay){};
|
||||
DelayQuad(DelayPair rise, DelayPair fall) : rise(rise), fall(fall){};
|
||||
@ -588,6 +589,8 @@ struct DelayQuad
|
||||
delay_t minDelay() const { return std::min<delay_t>(rise.minDelay(), fall.minDelay()); };
|
||||
delay_t maxDelay() const { return std::max<delay_t>(rise.maxDelay(), fall.maxDelay()); };
|
||||
|
||||
DelayPair delayPair() const { return DelayPair(minDelay(), maxDelay()); };
|
||||
|
||||
DelayQuad operator+(const DelayQuad &other) const { return {rise + other.rise, fall + other.fall}; }
|
||||
};
|
||||
|
||||
@ -686,15 +689,15 @@ struct TimingClockingInfo
|
||||
{
|
||||
IdString clock_port; // Port name of clock domain
|
||||
ClockEdge edge;
|
||||
DelayInfo setup, hold; // Input timing checks
|
||||
DelayInfo clockToQ; // Output clock-to-Q time
|
||||
DelayPair setup, hold; // Input timing checks
|
||||
DelayQuad clockToQ; // Output clock-to-Q time
|
||||
};
|
||||
|
||||
struct ClockConstraint
|
||||
{
|
||||
DelayInfo high;
|
||||
DelayInfo low;
|
||||
DelayInfo period;
|
||||
DelayPair high;
|
||||
DelayPair low;
|
||||
DelayPair period;
|
||||
|
||||
TimingConstrObjectId domain_tmg_id;
|
||||
};
|
||||
@ -1152,7 +1155,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
||||
virtual NetInfo *getBoundWireNet(WireId wire) const = 0;
|
||||
virtual WireId getConflictingWireWire(WireId wire) const = 0;
|
||||
virtual NetInfo *getConflictingWireNet(WireId wire) const = 0;
|
||||
virtual DelayInfo getWireDelay(WireId wire) const = 0;
|
||||
virtual DelayQuad getWireDelay(WireId wire) const = 0;
|
||||
// Pip methods
|
||||
virtual typename R::AllPipsRangeT getPips() const = 0;
|
||||
virtual PipId getPipByName(IdStringList name) const = 0;
|
||||
@ -1168,7 +1171,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
||||
virtual NetInfo *getConflictingPipNet(PipId pip) const = 0;
|
||||
virtual WireId getPipSrcWire(PipId pip) const = 0;
|
||||
virtual WireId getPipDstWire(PipId pip) const = 0;
|
||||
virtual DelayInfo getPipDelay(PipId pip) const = 0;
|
||||
virtual DelayQuad getPipDelay(PipId pip) const = 0;
|
||||
virtual Loc getPipLocation(PipId pip) const = 0;
|
||||
// Group methods
|
||||
virtual GroupId getGroupByName(IdStringList name) const = 0;
|
||||
@ -1183,7 +1186,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
||||
virtual delay_t getDelayEpsilon() const = 0;
|
||||
virtual delay_t getRipupDelayPenalty() const = 0;
|
||||
virtual float getDelayNS(delay_t v) const = 0;
|
||||
virtual DelayInfo getDelayFromNS(float ns) const = 0;
|
||||
virtual delay_t getDelayFromNS(float ns) const = 0;
|
||||
virtual uint32_t getDelayChecksum(delay_t v) const = 0;
|
||||
virtual bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const = 0;
|
||||
virtual delay_t estimateDelay(WireId src, WireId dst) const = 0;
|
||||
@ -1195,7 +1198,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
||||
virtual DecalXY getPipDecal(PipId pip) const = 0;
|
||||
virtual DecalXY getGroupDecal(GroupId group) const = 0;
|
||||
// Cell timing methods
|
||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const = 0;
|
||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const = 0;
|
||||
virtual TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const = 0;
|
||||
virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0;
|
||||
// Placement validity checks
|
||||
@ -1426,7 +1429,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
||||
virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); }
|
||||
|
||||
// Cell timing methods
|
||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override
|
||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -231,19 +231,19 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
||||
wr.program = "nextpnr";
|
||||
|
||||
const double delay_scale = 1000;
|
||||
// Convert from DelayInfo to SDF-friendly RiseFallDelay
|
||||
auto convert_delay = [&](const DelayInfo &dly) {
|
||||
// Convert from DelayQuad to SDF-friendly RiseFallDelay
|
||||
auto convert_delay = [&](const DelayQuad &dly) {
|
||||
RiseFallDelay rf;
|
||||
rf.rise.min = getDelayNS(dly.minRaiseDelay()) * delay_scale;
|
||||
rf.rise.typ = getDelayNS((dly.minRaiseDelay() + dly.maxRaiseDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||
rf.rise.max = getDelayNS(dly.maxRaiseDelay()) * delay_scale;
|
||||
rf.rise.min = getDelayNS(dly.minRiseDelay()) * delay_scale;
|
||||
rf.rise.typ = getDelayNS((dly.minRiseDelay() + dly.maxRiseDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||
rf.rise.max = getDelayNS(dly.maxRiseDelay()) * delay_scale;
|
||||
rf.fall.min = getDelayNS(dly.minFallDelay()) * delay_scale;
|
||||
rf.fall.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||
rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale;
|
||||
return rf;
|
||||
};
|
||||
|
||||
auto convert_setuphold = [&](const DelayInfo &setup, const DelayInfo &hold) {
|
||||
auto convert_setuphold = [&](const DelayPair &setup, const DelayPair &hold) {
|
||||
RiseFallDelay rf;
|
||||
rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale;
|
||||
rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||
@ -273,7 +273,7 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
||||
continue;
|
||||
if (other.second.type == PORT_OUT)
|
||||
continue;
|
||||
DelayInfo dly;
|
||||
DelayQuad dly;
|
||||
if (!getCellDelay(ci, other.first, port.first, dly))
|
||||
continue;
|
||||
IOPath iop;
|
||||
@ -323,12 +323,12 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
||||
ic.from.port = ni->driver.port.str(this);
|
||||
ic.to.cell = usr.cell->name.str(this);
|
||||
ic.to.port = usr.port.str(this);
|
||||
// FIXME: min/max routing delay - or at least constructing DelayInfo here
|
||||
ic.delay = convert_delay(getDelayFromNS(getDelayNS(getNetinfoRouteDelay(ni, usr))));
|
||||
// FIXME: min/max routing delay
|
||||
ic.delay = convert_delay(DelayQuad(getNetinfoRouteDelay(ni, usr)));
|
||||
wr.conn.push_back(ic);
|
||||
}
|
||||
}
|
||||
wr.write(out);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -121,7 +121,7 @@ struct Timing
|
||||
|
||||
delay_t walk_paths()
|
||||
{
|
||||
const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq")).maxDelay();
|
||||
const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq"));
|
||||
|
||||
// First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph
|
||||
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
|
||||
@ -188,7 +188,7 @@ struct Timing
|
||||
// Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and
|
||||
// the current output port, increment fanin counter
|
||||
for (auto i : input_ports) {
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
NetInfo *i_net = cell.second->ports[i].net;
|
||||
if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name))
|
||||
continue;
|
||||
@ -238,7 +238,7 @@ struct Timing
|
||||
if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE ||
|
||||
portClass == TMG_GEN_CLOCK)
|
||||
continue;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||
if (!is_path)
|
||||
continue;
|
||||
@ -309,7 +309,7 @@ struct Timing
|
||||
for (auto port : usr.cell->ports) {
|
||||
if (port.second.type != PORT_OUT || !port.second.net)
|
||||
continue;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
// Look up delay through this path
|
||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||
if (!is_path)
|
||||
@ -421,7 +421,7 @@ struct Timing
|
||||
for (const auto &port : usr.cell->ports) {
|
||||
if (port.second.type != PORT_OUT || !port.second.net)
|
||||
continue;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||
if (!is_path)
|
||||
continue;
|
||||
@ -452,7 +452,7 @@ struct Timing
|
||||
for (const auto &port : crit_net->driver.cell->ports) {
|
||||
if (port.second.type != PORT_IN || !port.second.net)
|
||||
continue;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
bool is_path =
|
||||
ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay);
|
||||
if (!is_path)
|
||||
@ -563,7 +563,7 @@ struct Timing
|
||||
for (const auto &port : drv.cell->ports) {
|
||||
if (port.second.type != PORT_IN || !port.second.net)
|
||||
continue;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay);
|
||||
if (!is_path)
|
||||
continue;
|
||||
@ -843,14 +843,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
|
||||
auto net = port.net;
|
||||
auto &driver = net->driver;
|
||||
auto driver_cell = driver.cell;
|
||||
DelayInfo comb_delay;
|
||||
DelayQuad comb_delay;
|
||||
if (clock_start != -1) {
|
||||
auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
|
||||
comb_delay = clockInfo.clockToQ;
|
||||
clock_start = -1;
|
||||
} else if (last_port == driver.port) {
|
||||
// Case where we start with a STARTPOINT etc
|
||||
comb_delay = ctx->getDelayFromNS(0);
|
||||
comb_delay = DelayQuad(0);
|
||||
} else {
|
||||
ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ class TimingOptimiser
|
||||
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
||||
continue;
|
||||
int ccount;
|
||||
DelayInfo combDelay;
|
||||
DelayQuad combDelay;
|
||||
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
||||
if (tpclass != TMG_COMB_INPUT)
|
||||
continue;
|
||||
@ -367,7 +367,7 @@ class TimingOptimiser
|
||||
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
||||
continue;
|
||||
int ccount;
|
||||
DelayInfo combDelay;
|
||||
DelayQuad combDelay;
|
||||
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
||||
if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
|
||||
continue;
|
||||
|
@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
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)`*
|
||||
|
||||
### DelayInfo getWireDelay(WireId wire) const
|
||||
### DelayQuad getWireDelay(WireId wire) const
|
||||
|
||||
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
|
||||
anti-parallel pips.
|
||||
|
||||
### DelayInfo getPipDelay(PipId pip) const
|
||||
### DelayQuad getPipDelay(PipId pip) const
|
||||
|
||||
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.
|
||||
|
||||
### 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
|
||||
|
||||
@ -609,7 +594,7 @@ Return the decal and X/Y position for the graphics representing a group.
|
||||
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
|
||||
false if there is no timing relationship from `fromPort` to `toPort`.
|
||||
|
43
ecp5/arch.cc
43
ecp5/arch.cc
@ -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});
|
||||
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) {
|
||||
for (auto &dly : tc.prop_delays) {
|
||||
if (dly.from_port == from.index && dly.to_port == to.index) {
|
||||
delay.max_delay = dly.max_delay;
|
||||
delay.min_delay = dly.min_delay;
|
||||
delay = DelayQuad(dly.min_delay, dly.max_delay);
|
||||
celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayInfo());
|
||||
celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayQuad());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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,
|
||||
DelayInfo &hold) const
|
||||
void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup,
|
||||
DelayPair &hold) const
|
||||
{
|
||||
for (auto &tc : speed_grade->cell_timings) {
|
||||
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");
|
||||
}
|
||||
|
||||
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
|
||||
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_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) ||
|
||||
(fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) {
|
||||
delay.min_delay = 0;
|
||||
delay.max_delay = 0;
|
||||
delay = DelayQuad(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (cell->type == id_DCCA) {
|
||||
if (fromPort == id_CLKI && toPort == id_CLKO) {
|
||||
delay.min_delay = 0;
|
||||
delay.max_delay = 0;
|
||||
delay = DelayQuad(0);
|
||||
return true;
|
||||
}
|
||||
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 info;
|
||||
info.setup = getDelayFromNS(0);
|
||||
info.hold = getDelayFromNS(0);
|
||||
info.clockToQ = getDelayFromNS(0);
|
||||
info.setup = DelayPair(0);
|
||||
info.hold = DelayPair(0);
|
||||
info.clockToQ = DelayQuad(0);
|
||||
if (cell->type == id_TRELLIS_SLICE) {
|
||||
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 ||
|
||||
@ -1058,26 +1055,26 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
||||
else if (prefix == "CH1_FF_RX")
|
||||
info.clock_port = id_CH1_FF_RXI_CLK;
|
||||
if (cell->ports.at(port).type == PORT_OUT) {
|
||||
info.clockToQ = getDelayFromNS(0.7);
|
||||
info.clockToQ = DelayQuad(getDelayFromNS(0.7));
|
||||
} else {
|
||||
info.setup = getDelayFromNS(1);
|
||||
info.hold = getDelayFromNS(0);
|
||||
info.setup = DelayPair(getDelayFromNS(1));
|
||||
info.hold = DelayPair(getDelayFromNS(0));
|
||||
}
|
||||
} else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) {
|
||||
info.clock_port = id_CLK;
|
||||
if (cell->ports.at(port).type == PORT_OUT) {
|
||||
info.clockToQ = getDelayFromNS(0.5);
|
||||
info.clockToQ = DelayQuad(getDelayFromNS(0.5));
|
||||
} else {
|
||||
info.setup = getDelayFromNS(0.1);
|
||||
info.hold = getDelayFromNS(0);
|
||||
info.setup = DelayPair(getDelayFromNS(0.1));
|
||||
info.hold = DelayPair(getDelayFromNS(0));
|
||||
}
|
||||
} else if (cell->type == id_DQSBUFM) {
|
||||
info.clock_port = id_SCLK;
|
||||
if (port == id_DATAVALID) {
|
||||
info.clockToQ = getDelayFromNS(0.2);
|
||||
info.clockToQ = DelayQuad(getDelayFromNS(0.2));
|
||||
} else if (port == id_READ0 || port == id_READ1) {
|
||||
info.setup = getDelayFromNS(0.5);
|
||||
info.hold = getDelayFromNS(-0.4);
|
||||
info.setup = DelayPair(getDelayFromNS(0.5));
|
||||
info.hold = DelayPair(getDelayFromNS(-0.4));
|
||||
} else {
|
||||
NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
|
||||
}
|
||||
|
35
ecp5/arch.h
35
ecp5/arch.h
@ -643,13 +643,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
BaseArch::unbindWire(wire);
|
||||
}
|
||||
|
||||
DelayInfo getWireDelay(WireId wire) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
delay.min_delay = 0;
|
||||
delay.max_delay = 0;
|
||||
return delay;
|
||||
}
|
||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||
|
||||
WireRange getWires() const override
|
||||
{
|
||||
@ -729,21 +723,20 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return wire;
|
||||
}
|
||||
|
||||
DelayInfo getPipDelay(PipId pip) const override
|
||||
DelayQuad getPipDelay(PipId pip) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
int fanout = 0;
|
||||
auto fnd_fanout = wire_fanout.find(getPipSrcWire(pip));
|
||||
if (fnd_fanout != wire_fanout.end())
|
||||
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 +
|
||||
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 +
|
||||
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
|
||||
@ -821,13 +814,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
delay_t getDelayEpsilon() const override { return 20; }
|
||||
delay_t getRipupDelayPenalty() const override;
|
||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.min_delay = delay_t(ns * 1000);
|
||||
del.max_delay = delay_t(ns * 1000);
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||
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
|
||||
// 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||
// Get the TimingClockingInfo of a port
|
||||
@ -858,9 +845,9 @@ struct Arch : BaseArch<ArchRanges>
|
||||
// Return true if a port is a net
|
||||
bool is_global_net(const NetInfo *net) const;
|
||||
|
||||
bool get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayInfo &delay) const;
|
||||
void get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayInfo &setup,
|
||||
DelayInfo &hold) 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, DelayPair &setup,
|
||||
DelayPair &hold) const;
|
||||
|
||||
// -------------------------------------------------
|
||||
// Placement validity checks
|
||||
@ -929,7 +916,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides;
|
||||
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::vector<std::string> availablePlacers;
|
||||
|
@ -28,28 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
|
34
ecp5/pack.cc
34
ecp5/pack.cc
@ -2851,7 +2851,7 @@ class Ecp5Packer
|
||||
NetInfo *from = ci->ports.at(port).net;
|
||||
if (from == nullptr || from->clkconstr == nullptr)
|
||||
return false;
|
||||
period = from->clkconstr->period.min_delay;
|
||||
period = from->clkconstr->period.minDelay();
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -2862,7 +2862,7 @@ class Ecp5Packer
|
||||
if (to == nullptr)
|
||||
return;
|
||||
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(
|
||||
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
||||
"%.1f MHz.\n",
|
||||
@ -2870,13 +2870,10 @@ class Ecp5Packer
|
||||
return;
|
||||
}
|
||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||
to->clkconstr->low.min_delay = period / 2;
|
||||
to->clkconstr->low.max_delay = period / 2;
|
||||
to->clkconstr->high.min_delay = period / 2;
|
||||
to->clkconstr->high.max_delay = period / 2;
|
||||
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->clkconstr->low = DelayPair(period / 2);
|
||||
to->clkconstr->high = DelayPair(period / 2);
|
||||
to->clkconstr->period = DelayPair(period);
|
||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.minDelay()),
|
||||
to->name.c_str(ctx));
|
||||
changed_nets.insert(to->name);
|
||||
};
|
||||
@ -2888,21 +2885,24 @@ class Ecp5Packer
|
||||
if (from == nullptr || from->clkconstr == nullptr || to == nullptr)
|
||||
return;
|
||||
if (to->clkconstr != nullptr) {
|
||||
if (!equals_epsilon(to->clkconstr->period.min_delay,
|
||||
delay_t(from->clkconstr->period.min_delay / ratio)) &&
|
||||
if (!equals_epsilon(to->clkconstr->period.minDelay(),
|
||||
delay_t(from->clkconstr->period.minDelay() / ratio)) &&
|
||||
user_constrained.count(to->name))
|
||||
log_warning(
|
||||
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
||||
"%.1f MHz.\n",
|
||||
MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx),
|
||||
MHz(delay_t(from->clkconstr->period.min_delay / ratio)));
|
||||
MHz(to->clkconstr->period.minDelay()), to->name.c_str(ctx),
|
||||
MHz(delay_t(from->clkconstr->period.minDelay() / ratio)));
|
||||
return;
|
||||
}
|
||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio);
|
||||
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio);
|
||||
to->clkconstr->period = 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),
|
||||
to->clkconstr->low =
|
||||
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.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.minDelay()),
|
||||
to->name.c_str(ctx));
|
||||
changed_nets.insert(to->name);
|
||||
};
|
||||
|
@ -686,7 +686,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
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.
|
||||
return false;
|
||||
|
@ -1127,12 +1127,7 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
return w2n == wire_to_net.end() ? nullptr : w2n->second;
|
||||
}
|
||||
|
||||
DelayInfo getWireDelay(WireId wire) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
delay.delay = 0;
|
||||
return delay;
|
||||
}
|
||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DelayInfo getPipDelay(PipId pip) const override { return DelayInfo(); }
|
||||
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
||||
|
||||
DownhillPipRange getPipsDownhill(WireId wire) const override
|
||||
{
|
||||
@ -1333,12 +1328,7 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
delay_t getDelayEpsilon() const override { return 20; }
|
||||
delay_t getRipupDelayPenalty() const override { return 120; }
|
||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.delay = delay_t(ns * 1000);
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||
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
|
||||
// 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||
// Get the TimingClockingInfo of a port
|
||||
|
@ -28,27 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
|
@ -64,8 +64,7 @@ void Arch::addWire(IdStringList name, IdString type, int x, int y)
|
||||
wire_ids.push_back(name);
|
||||
}
|
||||
|
||||
void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay,
|
||||
Loc loc)
|
||||
void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc)
|
||||
{
|
||||
NPNR_ASSERT(pips.count(name) == 0);
|
||||
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::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)
|
||||
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
|
||||
if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE)
|
||||
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;
|
||||
ci.clock_port = clock;
|
||||
ci.edge = RISING_EDGE;
|
||||
ci.setup = setup;
|
||||
ci.hold = hold;
|
||||
ci.setup = DelayPair(setup);
|
||||
ci.hold = DelayPair(hold);
|
||||
cellTiming[cell].clockingInfo[port].push_back(ci);
|
||||
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;
|
||||
ci.clock_port = clock;
|
||||
ci.edge = RISING_EDGE;
|
||||
ci.clockToQ = clktoq;
|
||||
ci.clockToQ = DelayQuad(clktoq);
|
||||
cellTiming[cell].clockingInfo[port].push_back(ci);
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
@ -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))
|
||||
return false;
|
||||
|
@ -41,7 +41,7 @@ struct PipInfo
|
||||
std::map<IdString, std::string> attrs;
|
||||
NetInfo *bound_net;
|
||||
WireId srcWire, dstWire;
|
||||
DelayInfo delay;
|
||||
delay_t delay;
|
||||
DecalXY decalxy;
|
||||
Loc loc;
|
||||
};
|
||||
@ -113,7 +113,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
struct CellTiming
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
@ -177,7 +177,7 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
||||
|
||||
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 addBelInput(IdStringList bel, IdString name, IdStringList wire);
|
||||
@ -203,9 +203,9 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
void setDelayScaling(double scale, double offset);
|
||||
|
||||
void addCellTimingClock(IdString cell, IdString port);
|
||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay);
|
||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold);
|
||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq);
|
||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, delay_t delay);
|
||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, delay_t setup, delay_t hold);
|
||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, delay_t clktoq);
|
||||
|
||||
void clearCellBelPinMap(IdString cell, IdString cell_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;
|
||||
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
||||
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<BelPin> &getWireBelPins(WireId wire) const override;
|
||||
|
||||
@ -279,7 +279,7 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
Loc getPipLocation(PipId pip) const override;
|
||||
WireId getPipSrcWire(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> &getPipsUphill(WireId wire) const override;
|
||||
|
||||
@ -297,12 +297,7 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
||||
float getDelayNS(delay_t v) const override { return v; }
|
||||
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.delay = ns;
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
||||
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 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||
// Get the TimingClockingInfo of a port
|
||||
|
@ -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_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||
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");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||
|
||||
fn_wrapper_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");
|
||||
|
||||
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);
|
||||
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>,
|
||||
pass_through<DelayInfo>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
|
||||
"srcWire"_a, "dstWire"_a, "delay"_a, "loc"_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);
|
||||
|
||||
fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
|
||||
conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>,
|
||||
@ -215,16 +213,16 @@ void arch_wrap_python(py::module &m)
|
||||
"port"_a);
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a,
|
||||
"toPort"_a, "delay"_a);
|
||||
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a, "toPort"_a,
|
||||
"delay"_a);
|
||||
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>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a,
|
||||
"setup"_a, "hold"_a);
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<delay_t>,
|
||||
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a,
|
||||
"setup"_a, "hold"_a);
|
||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut,
|
||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a,
|
||||
"clock"_a, "clktoq"_a);
|
||||
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a, "clock"_a,
|
||||
"clktoq"_a);
|
||||
|
||||
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,
|
||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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 WireId;
|
||||
typedef IdStringList PipId;
|
||||
|
@ -68,7 +68,7 @@ void Arch::addWire(IdString name, IdString type, int x, int y)
|
||||
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);
|
||||
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::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)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
ci.clock_port = clock;
|
||||
@ -246,7 +246,7 @@ void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock,
|
||||
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;
|
||||
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;
|
||||
needle.name_id = name.index;
|
||||
const TimingPOD *timing = genericLookup(first, len, needle, timingCompare);
|
||||
DelayInfo info;
|
||||
DelayQuad delay;
|
||||
if (timing != nullptr) {
|
||||
info.maxFall = std::max(timing->ff, timing->rf) / 1000;
|
||||
info.minFall = std::min(timing->ff, timing->rf) / 1000;
|
||||
info.maxRaise = std::max(timing->rr, timing->fr) / 1000;
|
||||
info.minRaise = std::min(timing->rr, timing->fr) / 1000;
|
||||
delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000;
|
||||
delay.fall.min_delay = std::min(timing->ff, timing->rf) / 1000;
|
||||
delay.rise.max_delay = std::max(timing->rr, timing->fr) / 1000;
|
||||
delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000;
|
||||
} else {
|
||||
info.maxFall = 0;
|
||||
info.minFall = 0;
|
||||
info.maxRaise = 0;
|
||||
info.minRaise = 0;
|
||||
delay = DelayQuad(0);
|
||||
}
|
||||
return info;
|
||||
return delay;
|
||||
}
|
||||
|
||||
DelayInfo Arch::getWireTypeDelay(IdString wire)
|
||||
DelayQuad Arch::getWireTypeDelay(IdString wire)
|
||||
{
|
||||
IdString len;
|
||||
IdString glbsrc;
|
||||
@ -480,12 +477,7 @@ DelayInfo Arch::getWireTypeDelay(IdString wire)
|
||||
} else if (glbsrc != IdString()) {
|
||||
return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc);
|
||||
} else {
|
||||
DelayInfo info;
|
||||
info.maxFall = 0;
|
||||
info.minFall = 0;
|
||||
info.maxRaise = 0;
|
||||
info.minRaise = 0;
|
||||
return info;
|
||||
return DelayQuad(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
IdString pipname = id(buf);
|
||||
DelayInfo delay = getWireTypeDelay(destid);
|
||||
DelayQuad delay = getWireTypeDelay(destid);
|
||||
// local alias
|
||||
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
|
||||
// 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; }
|
||||
|
||||
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; }
|
||||
|
||||
@ -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))
|
||||
return false;
|
||||
@ -1145,19 +1137,17 @@ void Arch::assignArchInfo()
|
||||
addCellTimingClock(cname, id_CLK);
|
||||
IdString ports[4] = {id_A, id_B, id_C, id_D};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
DelayInfo setup = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos);
|
||||
DelayInfo hold = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos);
|
||||
// DelayInfo setup = getDelayFromNS(0.1);
|
||||
// DelayInfo hold = getDelayFromNS(0.1);
|
||||
DelayPair setup =
|
||||
delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos).delayPair();
|
||||
DelayPair hold =
|
||||
delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos).delayPair();
|
||||
addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold);
|
||||
}
|
||||
DelayInfo clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos);
|
||||
// DelayInfo clkout = getDelayFromNS(0.1);
|
||||
DelayQuad clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos);
|
||||
addCellTimingClockToOut(cname, id_Q, id_CLK, clkout);
|
||||
IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
DelayInfo delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
|
||||
// DelayInfo delay = getDelayFromNS(0.1);
|
||||
DelayQuad delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
|
||||
addCellTimingDelay(cname, ports[i], id_F, delay);
|
||||
}
|
||||
|
||||
|
30
gowin/arch.h
30
gowin/arch.h
@ -170,7 +170,7 @@ struct PipInfo
|
||||
std::map<IdString, std::string> attrs;
|
||||
NetInfo *bound_net;
|
||||
WireId srcWire, dstWire;
|
||||
DelayInfo delay;
|
||||
DelayQuad delay;
|
||||
DecalXY decalxy;
|
||||
Loc loc;
|
||||
};
|
||||
@ -239,7 +239,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
struct CellTiming
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
@ -302,7 +302,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
||||
|
||||
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 addBelInput(IdString bel, IdString name, IdString wire);
|
||||
@ -327,12 +327,12 @@ struct Arch : BaseArch<ArchRanges>
|
||||
void setDelayScaling(double scale, double offset);
|
||||
|
||||
void addCellTimingClock(IdString cell, IdString port);
|
||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay);
|
||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold);
|
||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq);
|
||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay);
|
||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold);
|
||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq);
|
||||
|
||||
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);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@ -384,7 +384,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
NetInfo *getBoundWireNet(WireId wire) const override;
|
||||
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
||||
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<BelPin> &getWireBelPins(WireId wire) const override;
|
||||
|
||||
@ -402,7 +402,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
Loc getPipLocation(PipId pip) const override;
|
||||
WireId getPipSrcWire(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> &getPipsUphill(WireId wire) const override;
|
||||
|
||||
@ -420,15 +420,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
delay_t getRipupDelayPenalty() const override { return 0.4; }
|
||||
float getDelayNS(delay_t v) const override { return v; }
|
||||
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.maxRaise = ns;
|
||||
del.maxFall = ns;
|
||||
del.minRaise = ns;
|
||||
del.minFall = ns;
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
||||
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 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
|
||||
// Get the TimingClockingInfo of a port
|
||||
|
@ -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_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
||||
|
||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||
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");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||
|
||||
fn_wrapper_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");
|
||||
|
||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||
|
@ -26,33 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
enum ConstIds
|
||||
{
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
DelayInfo delay = ctx->getWireDelay(wire);
|
||||
DelayQuad delay = ctx->getWireDelay(wire);
|
||||
|
||||
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
||||
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());
|
||||
}
|
||||
|
||||
DelayInfo delay = ctx->getPipDelay(pip);
|
||||
DelayQuad delay = ctx->getPipDelay(pip);
|
||||
|
||||
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
||||
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
|
||||
} else if (type == ElementType::NET) {
|
||||
|
@ -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 (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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (tc.type == cell->type.index) {
|
||||
for (auto &path : tc.path_delays) {
|
||||
if (path.from_port == fromPort.index && path.to_port == toPort.index) {
|
||||
if (fast_part)
|
||||
delay.delay = path.fast_delay;
|
||||
delay = DelayQuad(path.fast_delay);
|
||||
else
|
||||
delay.delay = path.slow_delay;
|
||||
delay = DelayQuad(path.slow_delay);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1088,22 +1088,22 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
||||
NPNR_ASSERT(has_clktoq);
|
||||
} else {
|
||||
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);
|
||||
NPNR_ASSERT(has_ld);
|
||||
if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K || args.type == ArchArgs::LP8K ||
|
||||
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 ||
|
||||
args.type == ArchArgs::U1K || args.type == ArchArgs::U2K) { // XXX verify u4k
|
||||
info.setup.delay = dlut.delay - 50;
|
||||
info.setup = DelayPair(dlut.maxDelay() - 50);
|
||||
} else {
|
||||
info.setup.delay = 20 + dlut.delay;
|
||||
info.setup = DelayPair(20 + dlut.maxDelay());
|
||||
}
|
||||
} else {
|
||||
info.setup.delay = 100;
|
||||
info.setup = DelayPair(100);
|
||||
}
|
||||
info.hold.delay = 0;
|
||||
info.hold = DelayPair(0);
|
||||
}
|
||||
} else if (cell->type == id_ICESTORM_RAM) {
|
||||
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);
|
||||
NPNR_ASSERT(has_clktoq);
|
||||
} else {
|
||||
info.setup.delay = 100;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(100);
|
||||
info.hold = DelayPair(0);
|
||||
}
|
||||
} else if (cell->type == id_SB_IO) {
|
||||
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) {
|
||||
info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK;
|
||||
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
||||
info.setup.delay = io_setup;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(io_setup);
|
||||
info.hold = DelayPair(0);
|
||||
} else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) {
|
||||
info.clock_port = id_OUTPUT_CLK;
|
||||
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
||||
info.setup.delay = io_setup;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(io_setup);
|
||||
info.hold = DelayPair(0);
|
||||
} else if (port == id_D_OUT_1) {
|
||||
info.clock_port = id_OUTPUT_CLK;
|
||||
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
||||
info.setup.delay = io_setup;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(io_setup);
|
||||
info.hold = DelayPair(0);
|
||||
} else if (port == id_D_IN_0) {
|
||||
info.clock_port = id_INPUT_CLK;
|
||||
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) {
|
||||
info.clock_port = id_INPUT_CLK;
|
||||
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
||||
info.clockToQ.delay = io_clktoq;
|
||||
info.clockToQ = DelayQuad(io_clktoq);
|
||||
} else {
|
||||
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) {
|
||||
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
|
||||
if (!has_clktoq)
|
||||
info.clockToQ.delay = 100;
|
||||
info.clockToQ = DelayQuad(100);
|
||||
} else {
|
||||
info.setup.delay = 100;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(100);
|
||||
info.hold = DelayPair(0);
|
||||
}
|
||||
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
|
||||
info.clock_port = this->id("SBCLKI");
|
||||
info.edge = RISING_EDGE;
|
||||
if (cell->ports.at(port).type == PORT_OUT) {
|
||||
/* Dummy number */
|
||||
info.clockToQ.delay = 1500;
|
||||
info.clockToQ = DelayQuad(1500);
|
||||
} else {
|
||||
/* Dummy number */
|
||||
info.setup.delay = 1500;
|
||||
info.hold.delay = 0;
|
||||
info.setup = DelayPair(1500);
|
||||
info.hold = DelayPair(0);
|
||||
}
|
||||
} else {
|
||||
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
||||
|
27
ice40/arch.h
27
ice40/arch.h
@ -578,15 +578,13 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
DelayInfo getWireDelay(WireId wire) const override
|
||||
DelayQuad getWireDelay(WireId wire) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
if (fast_part)
|
||||
delay.delay = chip_info->wire_data[wire.index].fast_delay;
|
||||
return DelayQuad(chip_info->wire_data[wire.index].fast_delay);
|
||||
else
|
||||
delay.delay = chip_info->wire_data[wire.index].slow_delay;
|
||||
return delay;
|
||||
return DelayQuad(chip_info->wire_data[wire.index].slow_delay);
|
||||
}
|
||||
|
||||
BelPinRange getWireBelPins(WireId wire) const override
|
||||
@ -739,15 +737,13 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return wire;
|
||||
}
|
||||
|
||||
DelayInfo getPipDelay(PipId pip) const override
|
||||
DelayQuad getPipDelay(PipId pip) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
if (fast_part)
|
||||
delay.delay = chip_info->pip_data[pip.index].fast_delay;
|
||||
return DelayQuad(chip_info->pip_data[pip.index].fast_delay);
|
||||
else
|
||||
delay.delay = chip_info->pip_data[pip.index].slow_delay;
|
||||
return delay;
|
||||
return DelayQuad(chip_info->pip_data[pip.index].slow_delay);
|
||||
}
|
||||
|
||||
PipRange getPipsDownhill(WireId wire) const override
|
||||
@ -788,12 +784,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
delay_t getDelayEpsilon() const override { return 20; }
|
||||
delay_t getRipupDelayPenalty() const override { return 200; }
|
||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.delay = delay_t(ns * 1000);
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||
// Get the TimingClockingInfo of a port
|
||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
|
@ -1085,17 +1085,17 @@ void set_period(Context *ctx, CellInfo *ci, IdString port, delay_t period)
|
||||
if (to == nullptr)
|
||||
return;
|
||||
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 "
|
||||
"%.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;
|
||||
}
|
||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||
to->clkconstr->low.delay = period / 2;
|
||||
to->clkconstr->high.delay = period / 2;
|
||||
to->clkconstr->period.delay = period;
|
||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.delay),
|
||||
to->clkconstr->low = DelayPair(period / 2);
|
||||
to->clkconstr->high = DelayPair(period / 2);
|
||||
to->clkconstr->period = DelayPair(period);
|
||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.maxDelay()),
|
||||
to->name.c_str(ctx));
|
||||
};
|
||||
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;
|
||||
if (from == nullptr || from->clkconstr == nullptr)
|
||||
return false;
|
||||
period = from->clkconstr->period.delay;
|
||||
period = from->clkconstr->period.maxDelay();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -509,7 +509,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return IdStringList(ids);
|
||||
}
|
||||
|
||||
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); }
|
||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||
|
||||
WireRange getWires() const override
|
||||
{
|
||||
@ -582,14 +582,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return wire;
|
||||
}
|
||||
|
||||
DelayInfo getPipDelay(PipId pip) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
|
||||
delay.delay = 0.01;
|
||||
|
||||
return delay;
|
||||
}
|
||||
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
||||
|
||||
PipRange getPipsDownhill(WireId wire) const override
|
||||
{
|
||||
@ -633,12 +626,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
||||
float getDelayNS(delay_t v) const override { return v; }
|
||||
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.delay = ns;
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||
|
||||
|
@ -26,27 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
{
|
||||
ID_NONE
|
||||
|
@ -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 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);
|
||||
// Because CCU2 = 2x OXIDE_COMB
|
||||
if (result && fromPort == id_FCI && toPort == id_FCO) {
|
||||
delay.min_delay /= 2;
|
||||
delay.max_delay /= 2;
|
||||
delay = DelayQuad(delay.minDelay() / 2, delay.maxDelay() / 2);
|
||||
}
|
||||
return result;
|
||||
} 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));
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
if (dly_idx == -1)
|
||||
return false;
|
||||
delay.min_delay = ct.prop_delays[dly_idx].min_delay;
|
||||
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
|
||||
delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup,
|
||||
DelayInfo &hold) const
|
||||
void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
|
||||
DelayPair &hold) const
|
||||
{
|
||||
NPNR_ASSERT(type_idx != -1);
|
||||
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;
|
||||
}
|
||||
|
||||
void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup,
|
||||
DelayInfo &hold) const
|
||||
void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
|
||||
DelayPair &hold) const
|
||||
{
|
||||
NPNR_ASSERT(type_idx != -1);
|
||||
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.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);
|
||||
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);
|
||||
NPNR_ASSERT(dly_idx != -1);
|
||||
clock = IdString(ct.prop_delays[dly_idx].from_port);
|
||||
delay.min_delay = ct.prop_delays[dly_idx].min_delay;
|
||||
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
|
||||
delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
|
||||
}
|
||||
|
||||
TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const
|
||||
{
|
||||
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));
|
||||
return (sh_idx != -1) ? TMG_REGISTER_INPUT : TMG_COMB_INPUT;
|
||||
} else {
|
||||
DelayInfo dly;
|
||||
DelayQuad dly;
|
||||
// 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;
|
||||
}
|
||||
|
37
nexus/arch.h
37
nexus/arch.h
@ -1042,13 +1042,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
|
||||
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const override;
|
||||
|
||||
DelayInfo getWireDelay(WireId wire) const override
|
||||
{
|
||||
DelayInfo delay;
|
||||
delay.min_delay = 0;
|
||||
delay.max_delay = 0;
|
||||
return delay;
|
||||
}
|
||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||
|
||||
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); }
|
||||
|
||||
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];
|
||||
delay.min_delay = std::max(0, cls.min_delay);
|
||||
delay.max_delay = std::max(0, cls.max_delay);
|
||||
return delay;
|
||||
return DelayQuad(cls.min_delay, cls.max_delay);
|
||||
}
|
||||
|
||||
UpDownhillPipRange getPipsDownhill(WireId wire) const override
|
||||
@ -1179,13 +1170,7 @@ struct Arch : BaseArch<ArchRanges>
|
||||
delay_t getRipupDelayPenalty() const override { return 120; }
|
||||
delay_t getWireRipupDelayPenalty(WireId wire) const;
|
||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||
DelayInfo getDelayFromNS(float ns) const override
|
||||
{
|
||||
DelayInfo del;
|
||||
del.min_delay = delay_t(ns * 1000);
|
||||
del.max_delay = delay_t(ns * 1000);
|
||||
return del;
|
||||
}
|
||||
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) 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
|
||||
// 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
|
||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||
// 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
|
||||
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
|
||||
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
|
||||
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup,
|
||||
DelayInfo &hold) const;
|
||||
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
|
||||
DelayPair &hold) const;
|
||||
// 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,
|
||||
DelayInfo &hold) const;
|
||||
void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
|
||||
DelayPair &hold) const;
|
||||
// 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
|
||||
TimingPortClass lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const;
|
||||
// -------------------------------------------------
|
||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
|
@ -1862,9 +1862,12 @@ struct NexusPacker
|
||||
return;
|
||||
}
|
||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio);
|
||||
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio);
|
||||
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio);
|
||||
to->clkconstr->low =
|
||||
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.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),
|
||||
to->name.c_str(ctx));
|
||||
changed_nets.insert(to->name);
|
||||
|
Loading…
Reference in New Issue
Block a user