aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-02-19 10:39:57 +0000
committergatecat <gatecat@ds0.me>2021-02-19 11:31:33 +0000
commit7922b3bfc4ef93b8f67194c05e1a236b4c83c3da (patch)
treeb2b21259e030edd0adc7cc944322e3e9186d3a71 /common
parent8376db94a7519406444988be3628a4dadfb8d742 (diff)
downloadnextpnr-7922b3bfc4ef93b8f67194c05e1a236b4c83c3da.tar.gz
nextpnr-7922b3bfc4ef93b8f67194c05e1a236b4c83c3da.tar.bz2
nextpnr-7922b3bfc4ef93b8f67194c05e1a236b4c83c3da.zip
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>
Diffstat (limited to 'common')
-rw-r--r--common/arch_pybindings_shared.h2
-rw-r--r--common/nextpnr.cc6
-rw-r--r--common/nextpnr.h23
-rw-r--r--common/sdf.cc20
-rw-r--r--common/timing.cc18
-rw-r--r--common/timing_opt.cc4
6 files changed, 38 insertions, 35 deletions
diff --git a/common/arch_pybindings_shared.h b/common/arch_pybindings_shared.h
index 1cd70c99..81469df3 100644
--- a/common/arch_pybindings_shared.h
+++ b/common/arch_pybindings_shared.h
@@ -103,7 +103,7 @@ fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWir
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
-fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
+fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index 11acf991..9a73affc 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -656,9 +656,9 @@ void Context::check() const
void BaseCtx::addClock(IdString net, float freq)
{
std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
- cc->period = getCtx()->getDelayFromNS(1000 / freq);
- cc->high = getCtx()->getDelayFromNS(500 / freq);
- cc->low = getCtx()->getDelayFromNS(500 / freq);
+ cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq));
+ cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq));
+ cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq));
if (!net_aliases.count(net)) {
log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this));
} else {
diff --git a/common/nextpnr.h b/common/nextpnr.h
index 0a501910..c2fe5192 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -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;
}
diff --git a/common/sdf.cc b/common/sdf.cc
index b9606907..5c3d0a5a 100644
--- a/common/sdf.cc
+++ b/common/sdf.cc
@@ -231,19 +231,19 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
wr.program = "nextpnr";
const double delay_scale = 1000;
- // Convert from DelayInfo to SDF-friendly RiseFallDelay
- auto convert_delay = [&](const DelayInfo &dly) {
+ // Convert from DelayQuad to SDF-friendly RiseFallDelay
+ auto convert_delay = [&](const DelayQuad &dly) {
RiseFallDelay rf;
- rf.rise.min = getDelayNS(dly.minRaiseDelay()) * delay_scale;
- rf.rise.typ = getDelayNS((dly.minRaiseDelay() + dly.maxRaiseDelay()) / 2) * delay_scale; // fixme: typ delays?
- rf.rise.max = getDelayNS(dly.maxRaiseDelay()) * delay_scale;
+ rf.rise.min = getDelayNS(dly.minRiseDelay()) * delay_scale;
+ rf.rise.typ = getDelayNS((dly.minRiseDelay() + dly.maxRiseDelay()) / 2) * delay_scale; // fixme: typ delays?
+ rf.rise.max = getDelayNS(dly.maxRiseDelay()) * delay_scale;
rf.fall.min = getDelayNS(dly.minFallDelay()) * delay_scale;
rf.fall.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays?
rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale;
return rf;
};
- auto convert_setuphold = [&](const DelayInfo &setup, const DelayInfo &hold) {
+ auto convert_setuphold = [&](const DelayPair &setup, const DelayPair &hold) {
RiseFallDelay rf;
rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale;
rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays?
@@ -273,7 +273,7 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
continue;
if (other.second.type == PORT_OUT)
continue;
- DelayInfo dly;
+ DelayQuad dly;
if (!getCellDelay(ci, other.first, port.first, dly))
continue;
IOPath iop;
@@ -323,12 +323,12 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
ic.from.port = ni->driver.port.str(this);
ic.to.cell = usr.cell->name.str(this);
ic.to.port = usr.port.str(this);
- // FIXME: min/max routing delay - or at least constructing DelayInfo here
- ic.delay = convert_delay(getDelayFromNS(getDelayNS(getNetinfoRouteDelay(ni, usr))));
+ // FIXME: min/max routing delay
+ ic.delay = convert_delay(DelayQuad(getNetinfoRouteDelay(ni, usr)));
wr.conn.push_back(ic);
}
}
wr.write(out);
}
-NEXTPNR_NAMESPACE_END \ No newline at end of file
+NEXTPNR_NAMESPACE_END
diff --git a/common/timing.cc b/common/timing.cc
index a741c6ee..0c62b1a0 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -121,7 +121,7 @@ struct Timing
delay_t walk_paths()
{
- const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq")).maxDelay();
+ const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq"));
// First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
@@ -188,7 +188,7 @@ struct Timing
// Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and
// the current output port, increment fanin counter
for (auto i : input_ports) {
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
NetInfo *i_net = cell.second->ports[i].net;
if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name))
continue;
@@ -238,7 +238,7 @@ struct Timing
if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE ||
portClass == TMG_GEN_CLOCK)
continue;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path)
continue;
@@ -309,7 +309,7 @@ struct Timing
for (auto port : usr.cell->ports) {
if (port.second.type != PORT_OUT || !port.second.net)
continue;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
// Look up delay through this path
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path)
@@ -421,7 +421,7 @@ struct Timing
for (const auto &port : usr.cell->ports) {
if (port.second.type != PORT_OUT || !port.second.net)
continue;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
if (!is_path)
continue;
@@ -452,7 +452,7 @@ struct Timing
for (const auto &port : crit_net->driver.cell->ports) {
if (port.second.type != PORT_IN || !port.second.net)
continue;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
bool is_path =
ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay);
if (!is_path)
@@ -563,7 +563,7 @@ struct Timing
for (const auto &port : drv.cell->ports) {
if (port.second.type != PORT_IN || !port.second.net)
continue;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay);
if (!is_path)
continue;
@@ -843,14 +843,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
auto net = port.net;
auto &driver = net->driver;
auto driver_cell = driver.cell;
- DelayInfo comb_delay;
+ DelayQuad comb_delay;
if (clock_start != -1) {
auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
comb_delay = clockInfo.clockToQ;
clock_start = -1;
} else if (last_port == driver.port) {
// Case where we start with a STARTPOINT etc
- comb_delay = ctx->getDelayFromNS(0);
+ comb_delay = DelayQuad(0);
} else {
ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
}
diff --git a/common/timing_opt.cc b/common/timing_opt.cc
index 9c601e48..28b7f2cf 100644
--- a/common/timing_opt.cc
+++ b/common/timing_opt.cc
@@ -328,7 +328,7 @@ class TimingOptimiser
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
continue;
int ccount;
- DelayInfo combDelay;
+ DelayQuad combDelay;
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
if (tpclass != TMG_COMB_INPUT)
continue;
@@ -367,7 +367,7 @@ class TimingOptimiser
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
continue;
int ccount;
- DelayInfo combDelay;
+ DelayQuad combDelay;
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
continue;