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");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||||
|
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||||
|
@ -656,9 +656,9 @@ void Context::check() const
|
|||||||
void BaseCtx::addClock(IdString net, float freq)
|
void BaseCtx::addClock(IdString net, float freq)
|
||||||
{
|
{
|
||||||
std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
|
std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
|
||||||
cc->period = getCtx()->getDelayFromNS(1000 / freq);
|
cc->period = DelayPair(getCtx()->getDelayFromNS(1000 / freq));
|
||||||
cc->high = getCtx()->getDelayFromNS(500 / freq);
|
cc->high = DelayPair(getCtx()->getDelayFromNS(500 / freq));
|
||||||
cc->low = getCtx()->getDelayFromNS(500 / freq);
|
cc->low = DelayPair(getCtx()->getDelayFromNS(500 / freq));
|
||||||
if (!net_aliases.count(net)) {
|
if (!net_aliases.count(net)) {
|
||||||
log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this));
|
log_warning("net '%s' does not exist in design, ignoring clock constraint\n", net.c_str(this));
|
||||||
} else {
|
} else {
|
||||||
|
@ -575,6 +575,7 @@ struct DelayPair
|
|||||||
struct DelayQuad
|
struct DelayQuad
|
||||||
{
|
{
|
||||||
DelayPair rise, fall;
|
DelayPair rise, fall;
|
||||||
|
DelayQuad(){};
|
||||||
explicit DelayQuad(delay_t delay) : rise(delay), fall(delay){};
|
explicit DelayQuad(delay_t delay) : rise(delay), fall(delay){};
|
||||||
DelayQuad(delay_t min_delay, delay_t max_delay) : rise(min_delay, max_delay), fall(min_delay, max_delay){};
|
DelayQuad(delay_t min_delay, delay_t max_delay) : rise(min_delay, max_delay), fall(min_delay, max_delay){};
|
||||||
DelayQuad(DelayPair rise, DelayPair fall) : rise(rise), fall(fall){};
|
DelayQuad(DelayPair rise, DelayPair fall) : rise(rise), fall(fall){};
|
||||||
@ -588,6 +589,8 @@ struct DelayQuad
|
|||||||
delay_t minDelay() const { return std::min<delay_t>(rise.minDelay(), fall.minDelay()); };
|
delay_t minDelay() const { return std::min<delay_t>(rise.minDelay(), fall.minDelay()); };
|
||||||
delay_t maxDelay() const { return std::max<delay_t>(rise.maxDelay(), fall.maxDelay()); };
|
delay_t maxDelay() const { return std::max<delay_t>(rise.maxDelay(), fall.maxDelay()); };
|
||||||
|
|
||||||
|
DelayPair delayPair() const { return DelayPair(minDelay(), maxDelay()); };
|
||||||
|
|
||||||
DelayQuad operator+(const DelayQuad &other) const { return {rise + other.rise, fall + other.fall}; }
|
DelayQuad operator+(const DelayQuad &other) const { return {rise + other.rise, fall + other.fall}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -686,15 +689,15 @@ struct TimingClockingInfo
|
|||||||
{
|
{
|
||||||
IdString clock_port; // Port name of clock domain
|
IdString clock_port; // Port name of clock domain
|
||||||
ClockEdge edge;
|
ClockEdge edge;
|
||||||
DelayInfo setup, hold; // Input timing checks
|
DelayPair setup, hold; // Input timing checks
|
||||||
DelayInfo clockToQ; // Output clock-to-Q time
|
DelayQuad clockToQ; // Output clock-to-Q time
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClockConstraint
|
struct ClockConstraint
|
||||||
{
|
{
|
||||||
DelayInfo high;
|
DelayPair high;
|
||||||
DelayInfo low;
|
DelayPair low;
|
||||||
DelayInfo period;
|
DelayPair period;
|
||||||
|
|
||||||
TimingConstrObjectId domain_tmg_id;
|
TimingConstrObjectId domain_tmg_id;
|
||||||
};
|
};
|
||||||
@ -1152,7 +1155,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual NetInfo *getBoundWireNet(WireId wire) const = 0;
|
virtual NetInfo *getBoundWireNet(WireId wire) const = 0;
|
||||||
virtual WireId getConflictingWireWire(WireId wire) const = 0;
|
virtual WireId getConflictingWireWire(WireId wire) const = 0;
|
||||||
virtual NetInfo *getConflictingWireNet(WireId wire) const = 0;
|
virtual NetInfo *getConflictingWireNet(WireId wire) const = 0;
|
||||||
virtual DelayInfo getWireDelay(WireId wire) const = 0;
|
virtual DelayQuad getWireDelay(WireId wire) const = 0;
|
||||||
// Pip methods
|
// Pip methods
|
||||||
virtual typename R::AllPipsRangeT getPips() const = 0;
|
virtual typename R::AllPipsRangeT getPips() const = 0;
|
||||||
virtual PipId getPipByName(IdStringList name) const = 0;
|
virtual PipId getPipByName(IdStringList name) const = 0;
|
||||||
@ -1168,7 +1171,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual NetInfo *getConflictingPipNet(PipId pip) const = 0;
|
virtual NetInfo *getConflictingPipNet(PipId pip) const = 0;
|
||||||
virtual WireId getPipSrcWire(PipId pip) const = 0;
|
virtual WireId getPipSrcWire(PipId pip) const = 0;
|
||||||
virtual WireId getPipDstWire(PipId pip) const = 0;
|
virtual WireId getPipDstWire(PipId pip) const = 0;
|
||||||
virtual DelayInfo getPipDelay(PipId pip) const = 0;
|
virtual DelayQuad getPipDelay(PipId pip) const = 0;
|
||||||
virtual Loc getPipLocation(PipId pip) const = 0;
|
virtual Loc getPipLocation(PipId pip) const = 0;
|
||||||
// Group methods
|
// Group methods
|
||||||
virtual GroupId getGroupByName(IdStringList name) const = 0;
|
virtual GroupId getGroupByName(IdStringList name) const = 0;
|
||||||
@ -1183,7 +1186,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual delay_t getDelayEpsilon() const = 0;
|
virtual delay_t getDelayEpsilon() const = 0;
|
||||||
virtual delay_t getRipupDelayPenalty() const = 0;
|
virtual delay_t getRipupDelayPenalty() const = 0;
|
||||||
virtual float getDelayNS(delay_t v) const = 0;
|
virtual float getDelayNS(delay_t v) const = 0;
|
||||||
virtual DelayInfo getDelayFromNS(float ns) const = 0;
|
virtual delay_t getDelayFromNS(float ns) const = 0;
|
||||||
virtual uint32_t getDelayChecksum(delay_t v) const = 0;
|
virtual uint32_t getDelayChecksum(delay_t v) const = 0;
|
||||||
virtual bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const = 0;
|
virtual bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const = 0;
|
||||||
virtual delay_t estimateDelay(WireId src, WireId dst) const = 0;
|
virtual delay_t estimateDelay(WireId src, WireId dst) const = 0;
|
||||||
@ -1195,7 +1198,7 @@ template <typename R> struct ArchAPI : BaseCtx
|
|||||||
virtual DecalXY getPipDecal(PipId pip) const = 0;
|
virtual DecalXY getPipDecal(PipId pip) const = 0;
|
||||||
virtual DecalXY getGroupDecal(GroupId group) const = 0;
|
virtual DecalXY getGroupDecal(GroupId group) const = 0;
|
||||||
// Cell timing methods
|
// Cell timing methods
|
||||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const = 0;
|
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const = 0;
|
||||||
virtual TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const = 0;
|
virtual TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const = 0;
|
||||||
virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0;
|
virtual TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const = 0;
|
||||||
// Placement validity checks
|
// Placement validity checks
|
||||||
@ -1426,7 +1429,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
|||||||
virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); }
|
virtual DecalXY getGroupDecal(GroupId group) const override { return DecalXY(); }
|
||||||
|
|
||||||
// Cell timing methods
|
// Cell timing methods
|
||||||
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override
|
virtual bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -231,19 +231,19 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
|||||||
wr.program = "nextpnr";
|
wr.program = "nextpnr";
|
||||||
|
|
||||||
const double delay_scale = 1000;
|
const double delay_scale = 1000;
|
||||||
// Convert from DelayInfo to SDF-friendly RiseFallDelay
|
// Convert from DelayQuad to SDF-friendly RiseFallDelay
|
||||||
auto convert_delay = [&](const DelayInfo &dly) {
|
auto convert_delay = [&](const DelayQuad &dly) {
|
||||||
RiseFallDelay rf;
|
RiseFallDelay rf;
|
||||||
rf.rise.min = getDelayNS(dly.minRaiseDelay()) * delay_scale;
|
rf.rise.min = getDelayNS(dly.minRiseDelay()) * delay_scale;
|
||||||
rf.rise.typ = getDelayNS((dly.minRaiseDelay() + dly.maxRaiseDelay()) / 2) * delay_scale; // fixme: typ delays?
|
rf.rise.typ = getDelayNS((dly.minRiseDelay() + dly.maxRiseDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||||
rf.rise.max = getDelayNS(dly.maxRaiseDelay()) * delay_scale;
|
rf.rise.max = getDelayNS(dly.maxRiseDelay()) * delay_scale;
|
||||||
rf.fall.min = getDelayNS(dly.minFallDelay()) * delay_scale;
|
rf.fall.min = getDelayNS(dly.minFallDelay()) * delay_scale;
|
||||||
rf.fall.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays?
|
rf.fall.typ = getDelayNS((dly.minFallDelay() + dly.maxFallDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||||
rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale;
|
rf.fall.max = getDelayNS(dly.maxFallDelay()) * delay_scale;
|
||||||
return rf;
|
return rf;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto convert_setuphold = [&](const DelayInfo &setup, const DelayInfo &hold) {
|
auto convert_setuphold = [&](const DelayPair &setup, const DelayPair &hold) {
|
||||||
RiseFallDelay rf;
|
RiseFallDelay rf;
|
||||||
rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale;
|
rf.rise.min = getDelayNS(setup.minDelay()) * delay_scale;
|
||||||
rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays?
|
rf.rise.typ = getDelayNS((setup.minDelay() + setup.maxDelay()) / 2) * delay_scale; // fixme: typ delays?
|
||||||
@ -273,7 +273,7 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
|||||||
continue;
|
continue;
|
||||||
if (other.second.type == PORT_OUT)
|
if (other.second.type == PORT_OUT)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo dly;
|
DelayQuad dly;
|
||||||
if (!getCellDelay(ci, other.first, port.first, dly))
|
if (!getCellDelay(ci, other.first, port.first, dly))
|
||||||
continue;
|
continue;
|
||||||
IOPath iop;
|
IOPath iop;
|
||||||
@ -323,8 +323,8 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
|
|||||||
ic.from.port = ni->driver.port.str(this);
|
ic.from.port = ni->driver.port.str(this);
|
||||||
ic.to.cell = usr.cell->name.str(this);
|
ic.to.cell = usr.cell->name.str(this);
|
||||||
ic.to.port = usr.port.str(this);
|
ic.to.port = usr.port.str(this);
|
||||||
// FIXME: min/max routing delay - or at least constructing DelayInfo here
|
// FIXME: min/max routing delay
|
||||||
ic.delay = convert_delay(getDelayFromNS(getDelayNS(getNetinfoRouteDelay(ni, usr))));
|
ic.delay = convert_delay(DelayQuad(getNetinfoRouteDelay(ni, usr)));
|
||||||
wr.conn.push_back(ic);
|
wr.conn.push_back(ic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ struct Timing
|
|||||||
|
|
||||||
delay_t walk_paths()
|
delay_t walk_paths()
|
||||||
{
|
{
|
||||||
const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq")).maxDelay();
|
const auto clk_period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq"));
|
||||||
|
|
||||||
// First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph
|
// First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph
|
||||||
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
|
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
|
||||||
@ -188,7 +188,7 @@ struct Timing
|
|||||||
// Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and
|
// Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and
|
||||||
// the current output port, increment fanin counter
|
// the current output port, increment fanin counter
|
||||||
for (auto i : input_ports) {
|
for (auto i : input_ports) {
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
NetInfo *i_net = cell.second->ports[i].net;
|
NetInfo *i_net = cell.second->ports[i].net;
|
||||||
if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name))
|
if (i_net->driver.cell == nullptr && !ooc_port_nets.count(i_net->name))
|
||||||
continue;
|
continue;
|
||||||
@ -238,7 +238,7 @@ struct Timing
|
|||||||
if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE ||
|
if (portClass == TMG_REGISTER_OUTPUT || portClass == TMG_STARTPOINT || portClass == TMG_IGNORE ||
|
||||||
portClass == TMG_GEN_CLOCK)
|
portClass == TMG_GEN_CLOCK)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||||
if (!is_path)
|
if (!is_path)
|
||||||
continue;
|
continue;
|
||||||
@ -309,7 +309,7 @@ struct Timing
|
|||||||
for (auto port : usr.cell->ports) {
|
for (auto port : usr.cell->ports) {
|
||||||
if (port.second.type != PORT_OUT || !port.second.net)
|
if (port.second.type != PORT_OUT || !port.second.net)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
// Look up delay through this path
|
// Look up delay through this path
|
||||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||||
if (!is_path)
|
if (!is_path)
|
||||||
@ -421,7 +421,7 @@ struct Timing
|
|||||||
for (const auto &port : usr.cell->ports) {
|
for (const auto &port : usr.cell->ports) {
|
||||||
if (port.second.type != PORT_OUT || !port.second.net)
|
if (port.second.type != PORT_OUT || !port.second.net)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||||
if (!is_path)
|
if (!is_path)
|
||||||
continue;
|
continue;
|
||||||
@ -452,7 +452,7 @@ struct Timing
|
|||||||
for (const auto &port : crit_net->driver.cell->ports) {
|
for (const auto &port : crit_net->driver.cell->ports) {
|
||||||
if (port.second.type != PORT_IN || !port.second.net)
|
if (port.second.type != PORT_IN || !port.second.net)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
bool is_path =
|
bool is_path =
|
||||||
ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay);
|
ctx->getCellDelay(crit_net->driver.cell, port.first, crit_net->driver.port, comb_delay);
|
||||||
if (!is_path)
|
if (!is_path)
|
||||||
@ -563,7 +563,7 @@ struct Timing
|
|||||||
for (const auto &port : drv.cell->ports) {
|
for (const auto &port : drv.cell->ports) {
|
||||||
if (port.second.type != PORT_IN || !port.second.net)
|
if (port.second.type != PORT_IN || !port.second.net)
|
||||||
continue;
|
continue;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay);
|
bool is_path = ctx->getCellDelay(drv.cell, port.first, drv.port, comb_delay);
|
||||||
if (!is_path)
|
if (!is_path)
|
||||||
continue;
|
continue;
|
||||||
@ -843,14 +843,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
|
|||||||
auto net = port.net;
|
auto net = port.net;
|
||||||
auto &driver = net->driver;
|
auto &driver = net->driver;
|
||||||
auto driver_cell = driver.cell;
|
auto driver_cell = driver.cell;
|
||||||
DelayInfo comb_delay;
|
DelayQuad comb_delay;
|
||||||
if (clock_start != -1) {
|
if (clock_start != -1) {
|
||||||
auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
|
auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
|
||||||
comb_delay = clockInfo.clockToQ;
|
comb_delay = clockInfo.clockToQ;
|
||||||
clock_start = -1;
|
clock_start = -1;
|
||||||
} else if (last_port == driver.port) {
|
} else if (last_port == driver.port) {
|
||||||
// Case where we start with a STARTPOINT etc
|
// Case where we start with a STARTPOINT etc
|
||||||
comb_delay = ctx->getDelayFromNS(0);
|
comb_delay = DelayQuad(0);
|
||||||
} else {
|
} else {
|
||||||
ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
|
ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ class TimingOptimiser
|
|||||||
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
||||||
continue;
|
continue;
|
||||||
int ccount;
|
int ccount;
|
||||||
DelayInfo combDelay;
|
DelayQuad combDelay;
|
||||||
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
||||||
if (tpclass != TMG_COMB_INPUT)
|
if (tpclass != TMG_COMB_INPUT)
|
||||||
continue;
|
continue;
|
||||||
@ -367,7 +367,7 @@ class TimingOptimiser
|
|||||||
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
if (!net_crit.count(pn->name) || net_crit.at(pn->name).criticality.empty())
|
||||||
continue;
|
continue;
|
||||||
int ccount;
|
int ccount;
|
||||||
DelayInfo combDelay;
|
DelayQuad combDelay;
|
||||||
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
|
||||||
if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
|
if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
|
||||||
continue;
|
continue;
|
||||||
|
@ -43,21 +43,6 @@ With the exception of `ArchNetInfo` and `ArchCellInfo`, the following types shou
|
|||||||
|
|
||||||
A scalar type that is used to represent delays. May be an integer or float type.
|
A scalar type that is used to represent delays. May be an integer or float type.
|
||||||
|
|
||||||
### DelayInfo
|
|
||||||
|
|
||||||
A struct representing the delay across a timing arc. Must provide a `+` operator for getting the combined delay of two arcs, and the following methods to access concrete timings:
|
|
||||||
|
|
||||||
```
|
|
||||||
delay_t minRaiseDelay() const { return delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return delay; }
|
|
||||||
delay_t maxFallDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return delay; }
|
|
||||||
delay_t maxDelay() const { return delay; }
|
|
||||||
```
|
|
||||||
|
|
||||||
### BelId
|
### BelId
|
||||||
|
|
||||||
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`.
|
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`.
|
||||||
@ -332,7 +317,7 @@ will make the given wire available.
|
|||||||
|
|
||||||
*BaseArch default: returns `getBoundWireNet(wire)`*
|
*BaseArch default: returns `getBoundWireNet(wire)`*
|
||||||
|
|
||||||
### DelayInfo getWireDelay(WireId wire) const
|
### DelayQuad getWireDelay(WireId wire) const
|
||||||
|
|
||||||
Get the delay for a wire.
|
Get the delay for a wire.
|
||||||
|
|
||||||
@ -448,7 +433,7 @@ Get the destination wire for a pip.
|
|||||||
Bi-directional switches (transfer gates) are modeled using two
|
Bi-directional switches (transfer gates) are modeled using two
|
||||||
anti-parallel pips.
|
anti-parallel pips.
|
||||||
|
|
||||||
### DelayInfo getPipDelay(PipId pip) const
|
### DelayQuad getPipDelay(PipId pip) const
|
||||||
|
|
||||||
Get the delay for a pip.
|
Get the delay for a pip.
|
||||||
|
|
||||||
@ -541,9 +526,9 @@ actual penalty used is a multiple of this value (i.e. a weighted version of this
|
|||||||
|
|
||||||
Convert an `delay_t` to an actual real-world delay in nanoseconds.
|
Convert an `delay_t` to an actual real-world delay in nanoseconds.
|
||||||
|
|
||||||
### DelayInfo getDelayFromNS(float v) const
|
### delay_t getDelayFromNS(float v) const
|
||||||
|
|
||||||
Convert a real-world delay in nanoseconds to a DelayInfo with equal min/max rising/falling values.
|
Convert a real-world delay in nanoseconds to a `delay_t`.
|
||||||
|
|
||||||
### uint32\_t getDelayChecksum(delay\_t v) const
|
### uint32\_t getDelayChecksum(delay\_t v) const
|
||||||
|
|
||||||
@ -609,7 +594,7 @@ Return the decal and X/Y position for the graphics representing a group.
|
|||||||
Cell Delay Methods
|
Cell Delay Methods
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
### bool getCellDelay(const CellInfo \*cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
### bool getCellDelay(const CellInfo \*cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
|
|
||||||
Returns the delay for the specified path through a cell in the `&delay` argument. The method returns
|
Returns the delay for the specified path through a cell in the `&delay` argument. The method returns
|
||||||
false if there is no timing relationship from `fromPort` to `toPort`.
|
false if there is no timing relationship from `fromPort` to `toPort`.
|
||||||
|
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});
|
auto fnd_dk = celldelay_cache.find({tctype, from, to});
|
||||||
if (fnd_dk != celldelay_cache.end()) {
|
if (fnd_dk != celldelay_cache.end()) {
|
||||||
@ -732,21 +732,20 @@ bool Arch::get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, De
|
|||||||
if (tc.cell_type == tctype.index) {
|
if (tc.cell_type == tctype.index) {
|
||||||
for (auto &dly : tc.prop_delays) {
|
for (auto &dly : tc.prop_delays) {
|
||||||
if (dly.from_port == from.index && dly.to_port == to.index) {
|
if (dly.from_port == from.index && dly.to_port == to.index) {
|
||||||
delay.max_delay = dly.max_delay;
|
delay = DelayQuad(dly.min_delay, dly.max_delay);
|
||||||
delay.min_delay = dly.min_delay;
|
|
||||||
celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay);
|
celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayInfo());
|
celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayQuad());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NPNR_ASSERT_FALSE("failed to find timing cell in db");
|
NPNR_ASSERT_FALSE("failed to find timing cell in db");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayInfo &setup,
|
void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup,
|
||||||
DelayInfo &hold) const
|
DelayPair &hold) const
|
||||||
{
|
{
|
||||||
for (auto &tc : speed_grade->cell_timings) {
|
for (auto &tc : speed_grade->cell_timings) {
|
||||||
if (tc.cell_type == tctype.index) {
|
if (tc.cell_type == tctype.index) {
|
||||||
@ -764,7 +763,7 @@ void Arch::get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString p
|
|||||||
NPNR_ASSERT_FALSE("failed to find timing cell in db");
|
NPNR_ASSERT_FALSE("failed to find timing cell in db");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
// Data for -8 grade
|
// Data for -8 grade
|
||||||
if (cell->type == id_TRELLIS_SLICE) {
|
if (cell->type == id_TRELLIS_SLICE) {
|
||||||
@ -779,15 +778,13 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
|
|||||||
(fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) ||
|
(fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) ||
|
||||||
(fromPort == id_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) ||
|
(fromPort == id_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) ||
|
||||||
(fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) {
|
(fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) {
|
||||||
delay.min_delay = 0;
|
delay = DelayQuad(0);
|
||||||
delay.max_delay = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (cell->type == id_DCCA) {
|
} else if (cell->type == id_DCCA) {
|
||||||
if (fromPort == id_CLKI && toPort == id_CLKO) {
|
if (fromPort == id_CLKI && toPort == id_CLKO) {
|
||||||
delay.min_delay = 0;
|
delay = DelayQuad(0);
|
||||||
delay.max_delay = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -987,9 +984,9 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
|
|||||||
TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
|
TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
|
||||||
{
|
{
|
||||||
TimingClockingInfo info;
|
TimingClockingInfo info;
|
||||||
info.setup = getDelayFromNS(0);
|
info.setup = DelayPair(0);
|
||||||
info.hold = getDelayFromNS(0);
|
info.hold = DelayPair(0);
|
||||||
info.clockToQ = getDelayFromNS(0);
|
info.clockToQ = DelayQuad(0);
|
||||||
if (cell->type == id_TRELLIS_SLICE) {
|
if (cell->type == id_TRELLIS_SLICE) {
|
||||||
int sd0 = cell->sliceInfo.sd0, sd1 = cell->sliceInfo.sd1;
|
int sd0 = cell->sliceInfo.sd0, sd1 = cell->sliceInfo.sd1;
|
||||||
if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 ||
|
if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 ||
|
||||||
@ -1058,26 +1055,26 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
else if (prefix == "CH1_FF_RX")
|
else if (prefix == "CH1_FF_RX")
|
||||||
info.clock_port = id_CH1_FF_RXI_CLK;
|
info.clock_port = id_CH1_FF_RXI_CLK;
|
||||||
if (cell->ports.at(port).type == PORT_OUT) {
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
info.clockToQ = getDelayFromNS(0.7);
|
info.clockToQ = DelayQuad(getDelayFromNS(0.7));
|
||||||
} else {
|
} else {
|
||||||
info.setup = getDelayFromNS(1);
|
info.setup = DelayPair(getDelayFromNS(1));
|
||||||
info.hold = getDelayFromNS(0);
|
info.hold = DelayPair(getDelayFromNS(0));
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) {
|
} else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) {
|
||||||
info.clock_port = id_CLK;
|
info.clock_port = id_CLK;
|
||||||
if (cell->ports.at(port).type == PORT_OUT) {
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
info.clockToQ = getDelayFromNS(0.5);
|
info.clockToQ = DelayQuad(getDelayFromNS(0.5));
|
||||||
} else {
|
} else {
|
||||||
info.setup = getDelayFromNS(0.1);
|
info.setup = DelayPair(getDelayFromNS(0.1));
|
||||||
info.hold = getDelayFromNS(0);
|
info.hold = DelayPair(getDelayFromNS(0));
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_DQSBUFM) {
|
} else if (cell->type == id_DQSBUFM) {
|
||||||
info.clock_port = id_SCLK;
|
info.clock_port = id_SCLK;
|
||||||
if (port == id_DATAVALID) {
|
if (port == id_DATAVALID) {
|
||||||
info.clockToQ = getDelayFromNS(0.2);
|
info.clockToQ = DelayQuad(getDelayFromNS(0.2));
|
||||||
} else if (port == id_READ0 || port == id_READ1) {
|
} else if (port == id_READ0 || port == id_READ1) {
|
||||||
info.setup = getDelayFromNS(0.5);
|
info.setup = DelayPair(getDelayFromNS(0.5));
|
||||||
info.hold = getDelayFromNS(-0.4);
|
info.hold = DelayPair(getDelayFromNS(-0.4));
|
||||||
} else {
|
} else {
|
||||||
NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
|
NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
|
||||||
}
|
}
|
||||||
|
35
ecp5/arch.h
35
ecp5/arch.h
@ -643,13 +643,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
BaseArch::unbindWire(wire);
|
BaseArch::unbindWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getWireDelay(WireId wire) const override
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
{
|
|
||||||
DelayInfo delay;
|
|
||||||
delay.min_delay = 0;
|
|
||||||
delay.max_delay = 0;
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
WireRange getWires() const override
|
WireRange getWires() const override
|
||||||
{
|
{
|
||||||
@ -729,21 +723,20 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getPipDelay(PipId pip) const override
|
DelayQuad getPipDelay(PipId pip) const override
|
||||||
{
|
{
|
||||||
DelayInfo delay;
|
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
int fanout = 0;
|
int fanout = 0;
|
||||||
auto fnd_fanout = wire_fanout.find(getPipSrcWire(pip));
|
auto fnd_fanout = wire_fanout.find(getPipSrcWire(pip));
|
||||||
if (fnd_fanout != wire_fanout.end())
|
if (fnd_fanout != wire_fanout.end())
|
||||||
fanout = fnd_fanout->second;
|
fanout = fnd_fanout->second;
|
||||||
delay.min_delay =
|
delay_t min_dly =
|
||||||
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay +
|
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_base_delay +
|
||||||
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder;
|
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].min_fanout_adder;
|
||||||
delay.max_delay =
|
delay_t max_dly =
|
||||||
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay +
|
speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_base_delay +
|
||||||
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder;
|
fanout * speed_grade->pip_classes[loc_info(pip)->pip_data[pip.index].timing_class].max_fanout_adder;
|
||||||
return delay;
|
return DelayQuad(min_dly, max_dly);
|
||||||
}
|
}
|
||||||
|
|
||||||
PipRange getPipsDownhill(WireId wire) const override
|
PipRange getPipsDownhill(WireId wire) const override
|
||||||
@ -821,13 +814,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
delay_t getDelayEpsilon() const override { return 20; }
|
delay_t getDelayEpsilon() const override { return 20; }
|
||||||
delay_t getRipupDelayPenalty() const override;
|
delay_t getRipupDelayPenalty() const override;
|
||||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.min_delay = delay_t(ns * 1000);
|
|
||||||
del.max_delay = delay_t(ns * 1000);
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
|
|
||||||
@ -850,7 +837,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// Get the delay through a cell from one port to another, returning false
|
// Get the delay through a cell from one port to another, returning false
|
||||||
// if no path exists
|
// if no path exists
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
@ -858,9 +845,9 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Return true if a port is a net
|
// Return true if a port is a net
|
||||||
bool is_global_net(const NetInfo *net) const;
|
bool is_global_net(const NetInfo *net) const;
|
||||||
|
|
||||||
bool get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayInfo &delay) const;
|
bool get_delay_from_tmg_db(IdString tctype, IdString from, IdString to, DelayQuad &delay) const;
|
||||||
void get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayInfo &setup,
|
void get_setuphold_from_tmg_db(IdString tctype, IdString clock, IdString port, DelayPair &setup,
|
||||||
DelayInfo &hold) const;
|
DelayPair &hold) const;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// Placement validity checks
|
// Placement validity checks
|
||||||
@ -929,7 +916,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides;
|
std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides;
|
||||||
void setup_wire_locations();
|
void setup_wire_locations();
|
||||||
|
|
||||||
mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache;
|
mutable std::unordered_map<DelayKey, std::pair<bool, DelayQuad>> celldelay_cache;
|
||||||
|
|
||||||
static const std::string defaultPlacer;
|
static const std::string defaultPlacer;
|
||||||
static const std::vector<std::string> availablePlacers;
|
static const std::vector<std::string> availablePlacers;
|
||||||
|
@ -28,28 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef int delay_t;
|
typedef int delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t min_delay = 0, max_delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return min_delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return min_delay; }
|
|
||||||
delay_t maxFallDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return min_delay; }
|
|
||||||
delay_t maxDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.min_delay = this->min_delay + other.min_delay;
|
|
||||||
ret.max_delay = this->max_delay + other.max_delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
// https://bugreports.qt.io/browse/QTBUG-80789
|
// https://bugreports.qt.io/browse/QTBUG-80789
|
||||||
|
34
ecp5/pack.cc
34
ecp5/pack.cc
@ -2851,7 +2851,7 @@ class Ecp5Packer
|
|||||||
NetInfo *from = ci->ports.at(port).net;
|
NetInfo *from = ci->ports.at(port).net;
|
||||||
if (from == nullptr || from->clkconstr == nullptr)
|
if (from == nullptr || from->clkconstr == nullptr)
|
||||||
return false;
|
return false;
|
||||||
period = from->clkconstr->period.min_delay;
|
period = from->clkconstr->period.minDelay();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2862,7 +2862,7 @@ class Ecp5Packer
|
|||||||
if (to == nullptr)
|
if (to == nullptr)
|
||||||
return;
|
return;
|
||||||
if (to->clkconstr != nullptr) {
|
if (to->clkconstr != nullptr) {
|
||||||
if (!equals_epsilon(to->clkconstr->period.min_delay, period) && user_constrained.count(to->name))
|
if (!equals_epsilon(to->clkconstr->period.minDelay(), period) && user_constrained.count(to->name))
|
||||||
log_warning(
|
log_warning(
|
||||||
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
||||||
"%.1f MHz.\n",
|
"%.1f MHz.\n",
|
||||||
@ -2870,13 +2870,10 @@ class Ecp5Packer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||||
to->clkconstr->low.min_delay = period / 2;
|
to->clkconstr->low = DelayPair(period / 2);
|
||||||
to->clkconstr->low.max_delay = period / 2;
|
to->clkconstr->high = DelayPair(period / 2);
|
||||||
to->clkconstr->high.min_delay = period / 2;
|
to->clkconstr->period = DelayPair(period);
|
||||||
to->clkconstr->high.max_delay = period / 2;
|
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.minDelay()),
|
||||||
to->clkconstr->period.min_delay = period;
|
|
||||||
to->clkconstr->period.max_delay = period;
|
|
||||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
|
|
||||||
to->name.c_str(ctx));
|
to->name.c_str(ctx));
|
||||||
changed_nets.insert(to->name);
|
changed_nets.insert(to->name);
|
||||||
};
|
};
|
||||||
@ -2888,21 +2885,24 @@ class Ecp5Packer
|
|||||||
if (from == nullptr || from->clkconstr == nullptr || to == nullptr)
|
if (from == nullptr || from->clkconstr == nullptr || to == nullptr)
|
||||||
return;
|
return;
|
||||||
if (to->clkconstr != nullptr) {
|
if (to->clkconstr != nullptr) {
|
||||||
if (!equals_epsilon(to->clkconstr->period.min_delay,
|
if (!equals_epsilon(to->clkconstr->period.minDelay(),
|
||||||
delay_t(from->clkconstr->period.min_delay / ratio)) &&
|
delay_t(from->clkconstr->period.minDelay() / ratio)) &&
|
||||||
user_constrained.count(to->name))
|
user_constrained.count(to->name))
|
||||||
log_warning(
|
log_warning(
|
||||||
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
||||||
"%.1f MHz.\n",
|
"%.1f MHz.\n",
|
||||||
MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx),
|
MHz(to->clkconstr->period.minDelay()), to->name.c_str(ctx),
|
||||||
MHz(delay_t(from->clkconstr->period.min_delay / ratio)));
|
MHz(delay_t(from->clkconstr->period.minDelay() / ratio)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||||
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio);
|
to->clkconstr->low =
|
||||||
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio);
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio));
|
||||||
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio);
|
to->clkconstr->high =
|
||||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio));
|
||||||
|
to->clkconstr->period =
|
||||||
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio));
|
||||||
|
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.minDelay()),
|
||||||
to->name.c_str(ctx));
|
to->name.c_str(ctx));
|
||||||
changed_nets.insert(to->name);
|
changed_nets.insert(to->name);
|
||||||
};
|
};
|
||||||
|
@ -686,7 +686,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
// FIXME: Implement when adding timing-driven place and route.
|
// FIXME: Implement when adding timing-driven place and route.
|
||||||
return false;
|
return false;
|
||||||
|
@ -1127,12 +1127,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
return w2n == wire_to_net.end() ? nullptr : w2n->second;
|
return w2n == wire_to_net.end() ? nullptr : w2n->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getWireDelay(WireId wire) const override
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
{
|
|
||||||
DelayInfo delay;
|
|
||||||
delay.delay = 0;
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
TileWireRange get_tile_wire_range(WireId wire) const
|
TileWireRange get_tile_wire_range(WireId wire) const
|
||||||
{
|
{
|
||||||
@ -1279,7 +1274,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].dst_index);
|
return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].dst_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getPipDelay(PipId pip) const override { return DelayInfo(); }
|
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
||||||
|
|
||||||
DownhillPipRange getPipsDownhill(WireId wire) const override
|
DownhillPipRange getPipsDownhill(WireId wire) const override
|
||||||
{
|
{
|
||||||
@ -1333,12 +1328,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
delay_t getDelayEpsilon() const override { return 20; }
|
delay_t getDelayEpsilon() const override { return 20; }
|
||||||
delay_t getRipupDelayPenalty() const override { return 120; }
|
delay_t getRipupDelayPenalty() const override { return 120; }
|
||||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.delay = delay_t(ns * 1000);
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
|
|
||||||
@ -1363,7 +1353,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
|
|
||||||
// Get the delay through a cell from one port to another, returning false
|
// Get the delay through a cell from one port to another, returning false
|
||||||
// if no path exists. This only considers combinational delays, as required by the Arch API
|
// if no path exists. This only considers combinational delays, as required by the Arch API
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
|
@ -28,27 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef int delay_t;
|
typedef int delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return delay; }
|
|
||||||
delay_t maxFallDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return delay; }
|
|
||||||
delay_t maxDelay() const { return delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.delay = this->delay + other.delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
struct BelId
|
struct BelId
|
||||||
|
@ -64,8 +64,7 @@ void Arch::addWire(IdStringList name, IdString type, int x, int y)
|
|||||||
wire_ids.push_back(name);
|
wire_ids.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay,
|
void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc)
|
||||||
Loc loc)
|
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pips.count(name) == 0);
|
NPNR_ASSERT(pips.count(name) == 0);
|
||||||
PipInfo &pi = pips[name];
|
PipInfo &pi = pips[name];
|
||||||
@ -219,32 +218,32 @@ void Arch::setDelayScaling(double scale, double offset)
|
|||||||
|
|
||||||
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
|
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
|
||||||
|
|
||||||
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay)
|
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, delay_t delay)
|
||||||
{
|
{
|
||||||
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
|
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
|
||||||
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
|
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
|
||||||
if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE)
|
if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE)
|
||||||
cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT;
|
cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT;
|
||||||
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay;
|
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = DelayQuad(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold)
|
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, delay_t setup, delay_t hold)
|
||||||
{
|
{
|
||||||
TimingClockingInfo ci;
|
TimingClockingInfo ci;
|
||||||
ci.clock_port = clock;
|
ci.clock_port = clock;
|
||||||
ci.edge = RISING_EDGE;
|
ci.edge = RISING_EDGE;
|
||||||
ci.setup = setup;
|
ci.setup = DelayPair(setup);
|
||||||
ci.hold = hold;
|
ci.hold = DelayPair(hold);
|
||||||
cellTiming[cell].clockingInfo[port].push_back(ci);
|
cellTiming[cell].clockingInfo[port].push_back(ci);
|
||||||
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
|
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq)
|
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, delay_t clktoq)
|
||||||
{
|
{
|
||||||
TimingClockingInfo ci;
|
TimingClockingInfo ci;
|
||||||
ci.clock_port = clock;
|
ci.clock_port = clock;
|
||||||
ci.edge = RISING_EDGE;
|
ci.edge = RISING_EDGE;
|
||||||
ci.clockToQ = clktoq;
|
ci.clockToQ = DelayQuad(clktoq);
|
||||||
cellTiming[cell].clockingInfo[port].push_back(ci);
|
cellTiming[cell].clockingInfo[port].push_back(ci);
|
||||||
cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT;
|
cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT;
|
||||||
}
|
}
|
||||||
@ -465,7 +464,7 @@ WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
|
|||||||
|
|
||||||
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
|
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
|
||||||
|
|
||||||
DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; }
|
DelayQuad Arch::getPipDelay(PipId pip) const { return DelayQuad(pips.at(pip).delay); }
|
||||||
|
|
||||||
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
|
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
|
||||||
|
|
||||||
@ -615,7 +614,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decal
|
|||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
if (!cellTiming.count(cell->name))
|
if (!cellTiming.count(cell->name))
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,7 +41,7 @@ struct PipInfo
|
|||||||
std::map<IdString, std::string> attrs;
|
std::map<IdString, std::string> attrs;
|
||||||
NetInfo *bound_net;
|
NetInfo *bound_net;
|
||||||
WireId srcWire, dstWire;
|
WireId srcWire, dstWire;
|
||||||
DelayInfo delay;
|
delay_t delay;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
Loc loc;
|
Loc loc;
|
||||||
};
|
};
|
||||||
@ -113,7 +113,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
struct CellTiming
|
struct CellTiming
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, TimingPortClass> portClasses;
|
std::unordered_map<IdString, TimingPortClass> portClasses;
|
||||||
std::unordered_map<CellDelayKey, DelayInfo> combDelays;
|
std::unordered_map<CellDelayKey, DelayQuad> combDelays;
|
||||||
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
std::unordered_map<IdString, CellTiming> cellTiming;
|
||||||
|
|
||||||
void addWire(IdStringList name, IdString type, int x, int y);
|
void addWire(IdStringList name, IdString type, int x, int y);
|
||||||
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, DelayInfo delay, Loc loc);
|
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc);
|
||||||
|
|
||||||
void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
|
void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
|
||||||
void addBelInput(IdStringList bel, IdString name, IdStringList wire);
|
void addBelInput(IdStringList bel, IdString name, IdStringList wire);
|
||||||
@ -203,9 +203,9 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
void setDelayScaling(double scale, double offset);
|
void setDelayScaling(double scale, double offset);
|
||||||
|
|
||||||
void addCellTimingClock(IdString cell, IdString port);
|
void addCellTimingClock(IdString cell, IdString port);
|
||||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay);
|
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, delay_t delay);
|
||||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold);
|
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, delay_t setup, delay_t hold);
|
||||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq);
|
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, delay_t clktoq);
|
||||||
|
|
||||||
void clearCellBelPinMap(IdString cell, IdString cell_pin);
|
void clearCellBelPinMap(IdString cell, IdString cell_pin);
|
||||||
void addCellBelPinMapping(IdString cell, IdString cell_pin, IdString bel_pin);
|
void addCellBelPinMapping(IdString cell, IdString cell_pin, IdString bel_pin);
|
||||||
@ -260,7 +260,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
NetInfo *getBoundWireNet(WireId wire) const override;
|
NetInfo *getBoundWireNet(WireId wire) const override;
|
||||||
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
||||||
NetInfo *getConflictingWireNet(WireId wire) const override;
|
NetInfo *getConflictingWireNet(WireId wire) const override;
|
||||||
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); }
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
const std::vector<WireId> &getWires() const override;
|
const std::vector<WireId> &getWires() const override;
|
||||||
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
|
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
Loc getPipLocation(PipId pip) const override;
|
Loc getPipLocation(PipId pip) const override;
|
||||||
WireId getPipSrcWire(PipId pip) const override;
|
WireId getPipSrcWire(PipId pip) const override;
|
||||||
WireId getPipDstWire(PipId pip) const override;
|
WireId getPipDstWire(PipId pip) const override;
|
||||||
DelayInfo getPipDelay(PipId pip) const override;
|
DelayQuad getPipDelay(PipId pip) const override;
|
||||||
const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
|
const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
|
||||||
const std::vector<PipId> &getPipsUphill(WireId wire) const override;
|
const std::vector<PipId> &getPipsUphill(WireId wire) const override;
|
||||||
|
|
||||||
@ -297,12 +297,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
||||||
float getDelayNS(delay_t v) const override { return v; }
|
float getDelayNS(delay_t v) const override { return v; }
|
||||||
|
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.delay = ns;
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
@ -350,7 +345,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
DecalXY getPipDecal(PipId pip) const override;
|
DecalXY getPipDecal(PipId pip) const override;
|
||||||
DecalXY getGroupDecal(GroupId group) const override;
|
DecalXY getGroupDecal(GroupId group) const override;
|
||||||
|
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
|
@ -60,8 +60,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
|
|
||||||
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||||
|
|
||||||
py::class_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
||||||
@ -126,10 +124,10 @@ void arch_wrap_python(py::module &m)
|
|||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<DelayInfo>,
|
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
|
||||||
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
||||||
|
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||||
@ -159,7 +157,7 @@ void arch_wrap_python(py::module &m)
|
|||||||
"y"_a);
|
"y"_a);
|
||||||
fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdStringList>,
|
fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdStringList>,
|
||||||
conv_from_str<IdString>, conv_from_str<IdStringList>, conv_from_str<IdStringList>,
|
conv_from_str<IdString>, conv_from_str<IdStringList>, conv_from_str<IdStringList>,
|
||||||
pass_through<DelayInfo>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
|
pass_through<delay_t>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
|
||||||
"srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a);
|
"srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a);
|
||||||
|
|
||||||
fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
|
fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
|
||||||
@ -215,16 +213,16 @@ void arch_wrap_python(py::module &m)
|
|||||||
"port"_a);
|
"port"_a);
|
||||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay,
|
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingDelay), &Context::addCellTimingDelay,
|
||||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a,
|
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingDelay", "cell"_a, "fromPort"_a, "toPort"_a,
|
||||||
"toPort"_a, "delay"_a);
|
"delay"_a);
|
||||||
fn_wrapper_5a_v<Context, decltype(&Context::addCellTimingSetupHold), &Context::addCellTimingSetupHold,
|
fn_wrapper_5a_v<Context, decltype(&Context::addCellTimingSetupHold), &Context::addCellTimingSetupHold,
|
||||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<DelayInfo>,
|
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>, pass_through<delay_t>,
|
||||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a,
|
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingSetupHold", "cell"_a, "port"_a, "clock"_a,
|
||||||
"setup"_a, "hold"_a);
|
"setup"_a, "hold"_a);
|
||||||
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut,
|
fn_wrapper_4a_v<Context, decltype(&Context::addCellTimingClockToOut), &Context::addCellTimingClockToOut,
|
||||||
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
conv_from_str<IdString>, conv_from_str<IdString>, conv_from_str<IdString>,
|
||||||
pass_through<DelayInfo>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a,
|
pass_through<delay_t>>::def_wrap(ctx_cls, "addCellTimingClockToOut", "cell"_a, "port"_a, "clock"_a,
|
||||||
"clock"_a, "clktoq"_a);
|
"clktoq"_a);
|
||||||
|
|
||||||
fn_wrapper_2a_v<Context, decltype(&Context::clearCellBelPinMap), &Context::clearCellBelPinMap,
|
fn_wrapper_2a_v<Context, decltype(&Context::clearCellBelPinMap), &Context::clearCellBelPinMap,
|
||||||
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "clearCellBelPinMap", "cell"_a,
|
conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "clearCellBelPinMap", "cell"_a,
|
||||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef float delay_t;
|
typedef float delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return delay; }
|
|
||||||
delay_t maxFallDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return delay; }
|
|
||||||
delay_t maxDelay() const { return delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.delay = this->delay + other.delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef IdStringList BelId;
|
typedef IdStringList BelId;
|
||||||
typedef IdStringList WireId;
|
typedef IdStringList WireId;
|
||||||
typedef IdStringList PipId;
|
typedef IdStringList PipId;
|
||||||
|
@ -68,7 +68,7 @@ void Arch::addWire(IdString name, IdString type, int x, int y)
|
|||||||
wire_ids.push_back(name);
|
wire_ids.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc)
|
void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pips.count(name) == 0);
|
NPNR_ASSERT(pips.count(name) == 0);
|
||||||
PipInfo &pi = pips[name];
|
PipInfo &pi = pips[name];
|
||||||
@ -226,7 +226,7 @@ void Arch::setDelayScaling(double scale, double offset)
|
|||||||
|
|
||||||
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
|
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
|
||||||
|
|
||||||
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay)
|
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay)
|
||||||
{
|
{
|
||||||
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
|
if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
|
||||||
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
|
cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
|
||||||
@ -235,7 +235,7 @@ void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort,
|
|||||||
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay;
|
cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold)
|
void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold)
|
||||||
{
|
{
|
||||||
TimingClockingInfo ci;
|
TimingClockingInfo ci;
|
||||||
ci.clock_port = clock;
|
ci.clock_port = clock;
|
||||||
@ -246,7 +246,7 @@ void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock,
|
|||||||
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
|
cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq)
|
void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq)
|
||||||
{
|
{
|
||||||
TimingClockingInfo ci;
|
TimingClockingInfo ci;
|
||||||
ci.clock_port = clock;
|
ci.clock_port = clock;
|
||||||
@ -340,27 +340,24 @@ template <class T, class C> const T *genericLookup(const T *first, int len, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo delayLookup(const TimingPOD *first, int len, IdString name)
|
DelayQuad delayLookup(const TimingPOD *first, int len, IdString name)
|
||||||
{
|
{
|
||||||
TimingPOD needle;
|
TimingPOD needle;
|
||||||
needle.name_id = name.index;
|
needle.name_id = name.index;
|
||||||
const TimingPOD *timing = genericLookup(first, len, needle, timingCompare);
|
const TimingPOD *timing = genericLookup(first, len, needle, timingCompare);
|
||||||
DelayInfo info;
|
DelayQuad delay;
|
||||||
if (timing != nullptr) {
|
if (timing != nullptr) {
|
||||||
info.maxFall = std::max(timing->ff, timing->rf) / 1000;
|
delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000;
|
||||||
info.minFall = std::min(timing->ff, timing->rf) / 1000;
|
delay.fall.min_delay = std::min(timing->ff, timing->rf) / 1000;
|
||||||
info.maxRaise = std::max(timing->rr, timing->fr) / 1000;
|
delay.rise.max_delay = std::max(timing->rr, timing->fr) / 1000;
|
||||||
info.minRaise = std::min(timing->rr, timing->fr) / 1000;
|
delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000;
|
||||||
} else {
|
} else {
|
||||||
info.maxFall = 0;
|
delay = DelayQuad(0);
|
||||||
info.minFall = 0;
|
|
||||||
info.maxRaise = 0;
|
|
||||||
info.minRaise = 0;
|
|
||||||
}
|
}
|
||||||
return info;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo Arch::getWireTypeDelay(IdString wire)
|
DelayQuad Arch::getWireTypeDelay(IdString wire)
|
||||||
{
|
{
|
||||||
IdString len;
|
IdString len;
|
||||||
IdString glbsrc;
|
IdString glbsrc;
|
||||||
@ -480,12 +477,7 @@ DelayInfo Arch::getWireTypeDelay(IdString wire)
|
|||||||
} else if (glbsrc != IdString()) {
|
} else if (glbsrc != IdString()) {
|
||||||
return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc);
|
return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc);
|
||||||
} else {
|
} else {
|
||||||
DelayInfo info;
|
return DelayQuad(0);
|
||||||
info.maxFall = 0;
|
|
||||||
info.minFall = 0;
|
|
||||||
info.maxRaise = 0;
|
|
||||||
info.minRaise = 0;
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,7 +712,7 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
|
|
||||||
snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this));
|
snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this));
|
||||||
IdString pipname = id(buf);
|
IdString pipname = id(buf);
|
||||||
DelayInfo delay = getWireTypeDelay(destid);
|
DelayQuad delay = getWireTypeDelay(destid);
|
||||||
// local alias
|
// local alias
|
||||||
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
|
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
|
||||||
// std::cout << "srcid " << srcid.str(this) << std::endl;
|
// std::cout << "srcid " << srcid.str(this) << std::endl;
|
||||||
@ -934,7 +926,7 @@ WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
|
|||||||
|
|
||||||
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
|
WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
|
||||||
|
|
||||||
DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; }
|
DelayQuad Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; }
|
||||||
|
|
||||||
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
|
const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
|
||||||
|
|
||||||
@ -1067,7 +1059,7 @@ bool Arch::route()
|
|||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
if (!cellTiming.count(cell->name))
|
if (!cellTiming.count(cell->name))
|
||||||
return false;
|
return false;
|
||||||
@ -1145,19 +1137,17 @@ void Arch::assignArchInfo()
|
|||||||
addCellTimingClock(cname, id_CLK);
|
addCellTimingClock(cname, id_CLK);
|
||||||
IdString ports[4] = {id_A, id_B, id_C, id_D};
|
IdString ports[4] = {id_A, id_B, id_C, id_D};
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
DelayInfo setup = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos);
|
DelayPair setup =
|
||||||
DelayInfo hold = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos);
|
delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos).delayPair();
|
||||||
// DelayInfo setup = getDelayFromNS(0.1);
|
DelayPair hold =
|
||||||
// DelayInfo hold = getDelayFromNS(0.1);
|
delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos).delayPair();
|
||||||
addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold);
|
addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold);
|
||||||
}
|
}
|
||||||
DelayInfo clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos);
|
DelayQuad clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos);
|
||||||
// DelayInfo clkout = getDelayFromNS(0.1);
|
|
||||||
addCellTimingClockToOut(cname, id_Q, id_CLK, clkout);
|
addCellTimingClockToOut(cname, id_Q, id_CLK, clkout);
|
||||||
IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f};
|
IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f};
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
DelayInfo delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
|
DelayQuad delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]);
|
||||||
// DelayInfo delay = getDelayFromNS(0.1);
|
|
||||||
addCellTimingDelay(cname, ports[i], id_F, delay);
|
addCellTimingDelay(cname, ports[i], id_F, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
gowin/arch.h
30
gowin/arch.h
@ -170,7 +170,7 @@ struct PipInfo
|
|||||||
std::map<IdString, std::string> attrs;
|
std::map<IdString, std::string> attrs;
|
||||||
NetInfo *bound_net;
|
NetInfo *bound_net;
|
||||||
WireId srcWire, dstWire;
|
WireId srcWire, dstWire;
|
||||||
DelayInfo delay;
|
DelayQuad delay;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
Loc loc;
|
Loc loc;
|
||||||
};
|
};
|
||||||
@ -239,7 +239,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
struct CellTiming
|
struct CellTiming
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, TimingPortClass> portClasses;
|
std::unordered_map<IdString, TimingPortClass> portClasses;
|
||||||
std::unordered_map<CellDelayKey, DelayInfo> combDelays;
|
std::unordered_map<CellDelayKey, DelayQuad> combDelays;
|
||||||
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
std::unordered_map<IdString, CellTiming> cellTiming;
|
||||||
|
|
||||||
void addWire(IdString name, IdString type, int x, int y);
|
void addWire(IdString name, IdString type, int x, int y);
|
||||||
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc);
|
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
|
||||||
|
|
||||||
void addBel(IdString name, IdString type, Loc loc, bool gb);
|
void addBel(IdString name, IdString type, Loc loc, bool gb);
|
||||||
void addBelInput(IdString bel, IdString name, IdString wire);
|
void addBelInput(IdString bel, IdString name, IdString wire);
|
||||||
@ -327,12 +327,12 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
void setDelayScaling(double scale, double offset);
|
void setDelayScaling(double scale, double offset);
|
||||||
|
|
||||||
void addCellTimingClock(IdString cell, IdString port);
|
void addCellTimingClock(IdString cell, IdString port);
|
||||||
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay);
|
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay);
|
||||||
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold);
|
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold);
|
||||||
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq);
|
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq);
|
||||||
|
|
||||||
IdString wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString &wire);
|
IdString wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString &wire);
|
||||||
DelayInfo getWireTypeDelay(IdString wire);
|
DelayQuad getWireTypeDelay(IdString wire);
|
||||||
void read_cst(std::istream &in);
|
void read_cst(std::istream &in);
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
@ -384,7 +384,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
NetInfo *getBoundWireNet(WireId wire) const override;
|
NetInfo *getBoundWireNet(WireId wire) const override;
|
||||||
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
WireId getConflictingWireWire(WireId wire) const override { return wire; }
|
||||||
NetInfo *getConflictingWireNet(WireId wire) const override;
|
NetInfo *getConflictingWireNet(WireId wire) const override;
|
||||||
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); }
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
const std::vector<WireId> &getWires() const override;
|
const std::vector<WireId> &getWires() const override;
|
||||||
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
|
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
Loc getPipLocation(PipId pip) const override;
|
Loc getPipLocation(PipId pip) const override;
|
||||||
WireId getPipSrcWire(PipId pip) const override;
|
WireId getPipSrcWire(PipId pip) const override;
|
||||||
WireId getPipDstWire(PipId pip) const override;
|
WireId getPipDstWire(PipId pip) const override;
|
||||||
DelayInfo getPipDelay(PipId pip) const override;
|
DelayQuad getPipDelay(PipId pip) const override;
|
||||||
const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
|
const std::vector<PipId> &getPipsDownhill(WireId wire) const override;
|
||||||
const std::vector<PipId> &getPipsUphill(WireId wire) const override;
|
const std::vector<PipId> &getPipsUphill(WireId wire) const override;
|
||||||
|
|
||||||
@ -420,15 +420,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
delay_t getRipupDelayPenalty() const override { return 0.4; }
|
delay_t getRipupDelayPenalty() const override { return 0.4; }
|
||||||
float getDelayNS(delay_t v) const override { return v; }
|
float getDelayNS(delay_t v) const override { return v; }
|
||||||
|
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.maxRaise = ns;
|
|
||||||
del.maxFall = ns;
|
|
||||||
del.minRaise = ns;
|
|
||||||
del.minFall = ns;
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
uint32_t getDelayChecksum(delay_t v) const override { return 0; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
@ -439,7 +431,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
bool place() override;
|
bool place() override;
|
||||||
bool route() override;
|
bool route() override;
|
||||||
|
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
|
@ -59,8 +59,6 @@ void arch_wrap_python(py::module &m)
|
|||||||
|
|
||||||
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
py::class_<BelPin>(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||||
|
|
||||||
py::class_<DelayInfo>(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay);
|
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
||||||
@ -125,10 +123,10 @@ void arch_wrap_python(py::module &m)
|
|||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayQuad>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay");
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<DelayInfo>,
|
fn_wrapper_1a<Context, decltype(&Context::getDelayFromNS), &Context::getDelayFromNS, pass_through<delay_t>,
|
||||||
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
pass_through<double>>::def_wrap(ctx_cls, "getDelayFromNS");
|
||||||
|
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap(
|
||||||
|
@ -26,33 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef float delay_t;
|
typedef float delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t minRaise = 0;
|
|
||||||
delay_t minFall = 0;
|
|
||||||
delay_t maxRaise = 0;
|
|
||||||
delay_t maxFall = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return minRaise; }
|
|
||||||
delay_t maxRaiseDelay() const { return maxRaise; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return minFall; }
|
|
||||||
delay_t maxFallDelay() const { return maxFall; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return std::min(minFall, minRaise); }
|
|
||||||
delay_t maxDelay() const { return std::max(maxFall, maxRaise); }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.minRaise = this->minRaise + other.minRaise;
|
|
||||||
ret.maxRaise = this->maxRaise + other.maxRaise;
|
|
||||||
ret.minFall = this->minFall + other.minFall;
|
|
||||||
ret.maxFall = this->maxFall + other.maxFall;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef Q_MOC_RUN
|
#ifndef Q_MOC_RUN
|
||||||
enum ConstIds
|
enum ConstIds
|
||||||
{
|
{
|
||||||
|
@ -652,11 +652,11 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
|
|||||||
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
|
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo delay = ctx->getWireDelay(wire);
|
DelayQuad delay = ctx->getWireDelay(wire);
|
||||||
|
|
||||||
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
||||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay());
|
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay());
|
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
|
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
|
||||||
|
|
||||||
@ -721,11 +721,11 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
|
|||||||
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
|
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo delay = ctx->getPipDelay(pip);
|
DelayQuad delay = ctx->getPipDelay(pip);
|
||||||
|
|
||||||
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
||||||
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRaiseDelay());
|
addProperty(delayItem, QVariant::Double, "Min Raise", delay.minRiseDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRaiseDelay());
|
addProperty(delayItem, QVariant::Double, "Max Raise", delay.maxRiseDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
|
||||||
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
|
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
|
||||||
} else if (type == ElementType::NET) {
|
} else if (type == ElementType::NET) {
|
||||||
|
@ -921,7 +921,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) {
|
if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) {
|
||||||
if (toPort == id_O)
|
if (toPort == id_O)
|
||||||
@ -932,16 +932,16 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
|
|||||||
return get_cell_delay_internal(cell, fromPort, toPort, delay);
|
return get_cell_delay_internal(cell, fromPort, toPort, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
for (auto &tc : chip_info->cell_timing) {
|
for (auto &tc : chip_info->cell_timing) {
|
||||||
if (tc.type == cell->type.index) {
|
if (tc.type == cell->type.index) {
|
||||||
for (auto &path : tc.path_delays) {
|
for (auto &path : tc.path_delays) {
|
||||||
if (path.from_port == fromPort.index && path.to_port == toPort.index) {
|
if (path.from_port == fromPort.index && path.to_port == toPort.index) {
|
||||||
if (fast_part)
|
if (fast_part)
|
||||||
delay.delay = path.fast_delay;
|
delay = DelayQuad(path.fast_delay);
|
||||||
else
|
else
|
||||||
delay.delay = path.slow_delay;
|
delay = DelayQuad(path.slow_delay);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1088,22 +1088,22 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
NPNR_ASSERT(has_clktoq);
|
NPNR_ASSERT(has_clktoq);
|
||||||
} else {
|
} else {
|
||||||
if (port == id_I0 || port == id_I1 || port == id_I2 || port == id_I3) {
|
if (port == id_I0 || port == id_I1 || port == id_I2 || port == id_I3) {
|
||||||
DelayInfo dlut;
|
DelayQuad dlut;
|
||||||
bool has_ld = get_cell_delay_internal(cell, port, id_O, dlut);
|
bool has_ld = get_cell_delay_internal(cell, port, id_O, dlut);
|
||||||
NPNR_ASSERT(has_ld);
|
NPNR_ASSERT(has_ld);
|
||||||
if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K || args.type == ArchArgs::LP8K ||
|
if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K || args.type == ArchArgs::LP8K ||
|
||||||
args.type == ArchArgs::LP384) {
|
args.type == ArchArgs::LP384) {
|
||||||
info.setup.delay = 30 + dlut.delay;
|
info.setup = DelayPair(30 + dlut.maxDelay());
|
||||||
} else if (args.type == ArchArgs::UP3K || args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K ||
|
} else if (args.type == ArchArgs::UP3K || args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K ||
|
||||||
args.type == ArchArgs::U1K || args.type == ArchArgs::U2K) { // XXX verify u4k
|
args.type == ArchArgs::U1K || args.type == ArchArgs::U2K) { // XXX verify u4k
|
||||||
info.setup.delay = dlut.delay - 50;
|
info.setup = DelayPair(dlut.maxDelay() - 50);
|
||||||
} else {
|
} else {
|
||||||
info.setup.delay = 20 + dlut.delay;
|
info.setup = DelayPair(20 + dlut.maxDelay());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info.setup.delay = 100;
|
info.setup = DelayPair(100);
|
||||||
}
|
}
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_ICESTORM_RAM) {
|
} else if (cell->type == id_ICESTORM_RAM) {
|
||||||
if (port.str(this)[0] == 'R') {
|
if (port.str(this)[0] == 'R') {
|
||||||
@ -1117,8 +1117,8 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
|
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
|
||||||
NPNR_ASSERT(has_clktoq);
|
NPNR_ASSERT(has_clktoq);
|
||||||
} else {
|
} else {
|
||||||
info.setup.delay = 100;
|
info.setup = DelayPair(100);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_SB_IO) {
|
} else if (cell->type == id_SB_IO) {
|
||||||
delay_t io_setup = 80, io_clktoq = 140;
|
delay_t io_setup = 80, io_clktoq = 140;
|
||||||
@ -1133,26 +1133,26 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
if (port == id_CLOCK_ENABLE) {
|
if (port == id_CLOCK_ENABLE) {
|
||||||
info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK;
|
info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK;
|
||||||
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
||||||
info.setup.delay = io_setup;
|
info.setup = DelayPair(io_setup);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
} else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) {
|
} else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) {
|
||||||
info.clock_port = id_OUTPUT_CLK;
|
info.clock_port = id_OUTPUT_CLK;
|
||||||
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
||||||
info.setup.delay = io_setup;
|
info.setup = DelayPair(io_setup);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
} else if (port == id_D_OUT_1) {
|
} else if (port == id_D_OUT_1) {
|
||||||
info.clock_port = id_OUTPUT_CLK;
|
info.clock_port = id_OUTPUT_CLK;
|
||||||
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
||||||
info.setup.delay = io_setup;
|
info.setup = DelayPair(io_setup);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
} else if (port == id_D_IN_0) {
|
} else if (port == id_D_IN_0) {
|
||||||
info.clock_port = id_INPUT_CLK;
|
info.clock_port = id_INPUT_CLK;
|
||||||
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE;
|
||||||
info.clockToQ.delay = io_clktoq;
|
info.clockToQ = DelayQuad(io_clktoq);
|
||||||
} else if (port == id_D_IN_1) {
|
} else if (port == id_D_IN_1) {
|
||||||
info.clock_port = id_INPUT_CLK;
|
info.clock_port = id_INPUT_CLK;
|
||||||
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE;
|
||||||
info.clockToQ.delay = io_clktoq;
|
info.clockToQ = DelayQuad(io_clktoq);
|
||||||
} else {
|
} else {
|
||||||
NPNR_ASSERT_FALSE("no clock data for IO cell port");
|
NPNR_ASSERT_FALSE("no clock data for IO cell port");
|
||||||
}
|
}
|
||||||
@ -1162,21 +1162,21 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
if (cell->ports.at(port).type == PORT_OUT) {
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
|
bool has_clktoq = get_cell_delay_internal(cell, info.clock_port, port, info.clockToQ);
|
||||||
if (!has_clktoq)
|
if (!has_clktoq)
|
||||||
info.clockToQ.delay = 100;
|
info.clockToQ = DelayQuad(100);
|
||||||
} else {
|
} else {
|
||||||
info.setup.delay = 100;
|
info.setup = DelayPair(100);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
}
|
}
|
||||||
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
|
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
|
||||||
info.clock_port = this->id("SBCLKI");
|
info.clock_port = this->id("SBCLKI");
|
||||||
info.edge = RISING_EDGE;
|
info.edge = RISING_EDGE;
|
||||||
if (cell->ports.at(port).type == PORT_OUT) {
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
/* Dummy number */
|
/* Dummy number */
|
||||||
info.clockToQ.delay = 1500;
|
info.clockToQ = DelayQuad(1500);
|
||||||
} else {
|
} else {
|
||||||
/* Dummy number */
|
/* Dummy number */
|
||||||
info.setup.delay = 1500;
|
info.setup = DelayPair(1500);
|
||||||
info.hold.delay = 0;
|
info.hold = DelayPair(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
||||||
|
27
ice40/arch.h
27
ice40/arch.h
@ -578,15 +578,13 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return wire_to_net[wire.index];
|
return wire_to_net[wire.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getWireDelay(WireId wire) const override
|
DelayQuad getWireDelay(WireId wire) const override
|
||||||
{
|
{
|
||||||
DelayInfo delay;
|
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
if (fast_part)
|
if (fast_part)
|
||||||
delay.delay = chip_info->wire_data[wire.index].fast_delay;
|
return DelayQuad(chip_info->wire_data[wire.index].fast_delay);
|
||||||
else
|
else
|
||||||
delay.delay = chip_info->wire_data[wire.index].slow_delay;
|
return DelayQuad(chip_info->wire_data[wire.index].slow_delay);
|
||||||
return delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BelPinRange getWireBelPins(WireId wire) const override
|
BelPinRange getWireBelPins(WireId wire) const override
|
||||||
@ -739,15 +737,13 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getPipDelay(PipId pip) const override
|
DelayQuad getPipDelay(PipId pip) const override
|
||||||
{
|
{
|
||||||
DelayInfo delay;
|
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
if (fast_part)
|
if (fast_part)
|
||||||
delay.delay = chip_info->pip_data[pip.index].fast_delay;
|
return DelayQuad(chip_info->pip_data[pip.index].fast_delay);
|
||||||
else
|
else
|
||||||
delay.delay = chip_info->pip_data[pip.index].slow_delay;
|
return DelayQuad(chip_info->pip_data[pip.index].slow_delay);
|
||||||
return delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PipRange getPipsDownhill(WireId wire) const override
|
PipRange getPipsDownhill(WireId wire) const override
|
||||||
@ -788,12 +784,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
delay_t getDelayEpsilon() const override { return 20; }
|
delay_t getDelayEpsilon() const override { return 20; }
|
||||||
delay_t getRipupDelayPenalty() const override { return 200; }
|
delay_t getRipupDelayPenalty() const override { return 200; }
|
||||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.delay = delay_t(ns * 1000);
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
|
|
||||||
@ -818,10 +809,10 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// Get the delay through a cell from one port to another, returning false
|
// Get the delay through a cell from one port to another, returning false
|
||||||
// if no path exists. This only considers combinational delays, as required by the Arch API
|
// if no path exists. This only considers combinational delays, as required by the Arch API
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
|
||||||
// get_cell_delay_internal is similar to the above, but without false path checks and including clock to out delays
|
// get_cell_delay_internal is similar to the above, but without false path checks and including clock to out delays
|
||||||
// for internal arch use only
|
// for internal arch use only
|
||||||
bool get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
|
bool get_cell_delay_internal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef int delay_t;
|
typedef int delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return delay; }
|
|
||||||
delay_t maxFallDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return delay; }
|
|
||||||
delay_t maxDelay() const { return delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.delay = this->delay + other.delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
// https://bugreports.qt.io/browse/QTBUG-80789
|
// https://bugreports.qt.io/browse/QTBUG-80789
|
||||||
|
@ -1085,17 +1085,17 @@ void set_period(Context *ctx, CellInfo *ci, IdString port, delay_t period)
|
|||||||
if (to == nullptr)
|
if (to == nullptr)
|
||||||
return;
|
return;
|
||||||
if (to->clkconstr != nullptr) {
|
if (to->clkconstr != nullptr) {
|
||||||
if (!equals_epsilon(to->clkconstr->period.delay, period))
|
if (!equals_epsilon(to->clkconstr->period.maxDelay(), period))
|
||||||
log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
|
||||||
"%.1f MHz.\n",
|
"%.1f MHz.\n",
|
||||||
MHz(ctx, to->clkconstr->period.delay), to->name.c_str(ctx), MHz(ctx, period));
|
MHz(ctx, to->clkconstr->period.maxDelay()), to->name.c_str(ctx), MHz(ctx, period));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||||
to->clkconstr->low.delay = period / 2;
|
to->clkconstr->low = DelayPair(period / 2);
|
||||||
to->clkconstr->high.delay = period / 2;
|
to->clkconstr->high = DelayPair(period / 2);
|
||||||
to->clkconstr->period.delay = period;
|
to->clkconstr->period = DelayPair(period);
|
||||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.delay),
|
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(ctx, to->clkconstr->period.maxDelay()),
|
||||||
to->name.c_str(ctx));
|
to->name.c_str(ctx));
|
||||||
};
|
};
|
||||||
bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period)
|
bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period)
|
||||||
@ -1105,7 +1105,7 @@ bool get_period(Context *ctx, CellInfo *ci, IdString port, delay_t &period)
|
|||||||
NetInfo *from = ci->ports.at(port).net;
|
NetInfo *from = ci->ports.at(port).net;
|
||||||
if (from == nullptr || from->clkconstr == nullptr)
|
if (from == nullptr || from->clkconstr == nullptr)
|
||||||
return false;
|
return false;
|
||||||
period = from->clkconstr->period.delay;
|
period = from->clkconstr->period.maxDelay();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -509,7 +509,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return IdStringList(ids);
|
return IdStringList(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); }
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
|
|
||||||
WireRange getWires() const override
|
WireRange getWires() const override
|
||||||
{
|
{
|
||||||
@ -582,14 +582,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayInfo getPipDelay(PipId pip) const override
|
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
||||||
{
|
|
||||||
DelayInfo delay;
|
|
||||||
|
|
||||||
delay.delay = 0.01;
|
|
||||||
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
PipRange getPipsDownhill(WireId wire) const override
|
PipRange getPipsDownhill(WireId wire) const override
|
||||||
{
|
{
|
||||||
@ -633,12 +626,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
delay_t getRipupDelayPenalty() const override { return 0.015; }
|
||||||
float getDelayNS(delay_t v) const override { return v; }
|
float getDelayNS(delay_t v) const override { return v; }
|
||||||
|
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return ns; }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.delay = ns;
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||||
|
|
||||||
|
@ -26,27 +26,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef float delay_t;
|
typedef float delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return delay; }
|
|
||||||
delay_t maxFallDelay() const { return delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return delay; }
|
|
||||||
delay_t maxDelay() const { return delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.delay = this->delay + other.delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ConstIds
|
enum ConstIds
|
||||||
{
|
{
|
||||||
ID_NONE
|
ID_NONE
|
||||||
|
@ -432,7 +432,7 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
auto lookup_port = [&](IdString p) {
|
auto lookup_port = [&](IdString p) {
|
||||||
auto fnd = cell->tmg_portmap.find(p);
|
auto fnd = cell->tmg_portmap.find(p);
|
||||||
@ -443,8 +443,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
|
|||||||
bool result = lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay);
|
bool result = lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay);
|
||||||
// Because CCU2 = 2x OXIDE_COMB
|
// Because CCU2 = 2x OXIDE_COMB
|
||||||
if (result && fromPort == id_FCI && toPort == id_FCO) {
|
if (result && fromPort == id_FCI && toPort == id_FCO) {
|
||||||
delay.min_delay /= 2;
|
delay = DelayQuad(delay.minDelay() / 2, delay.maxDelay() / 2);
|
||||||
delay.max_delay /= 2;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
@ -870,7 +869,7 @@ int Arch::get_cell_timing_idx(IdString cell_type, IdString cell_variant) const
|
|||||||
std::make_pair(cell_type.index, cell_variant.index));
|
std::make_pair(cell_type.index, cell_variant.index));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const
|
bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(type_idx != -1);
|
NPNR_ASSERT(type_idx != -1);
|
||||||
const auto &ct = speed_grade->cell_types[type_idx];
|
const auto &ct = speed_grade->cell_types[type_idx];
|
||||||
@ -880,13 +879,12 @@ bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port,
|
|||||||
std::make_pair(to_port.index, from_port.index));
|
std::make_pair(to_port.index, from_port.index));
|
||||||
if (dly_idx == -1)
|
if (dly_idx == -1)
|
||||||
return false;
|
return false;
|
||||||
delay.min_delay = ct.prop_delays[dly_idx].min_delay;
|
delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
|
||||||
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup,
|
void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
|
||||||
DelayInfo &hold) const
|
DelayPair &hold) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(type_idx != -1);
|
NPNR_ASSERT(type_idx != -1);
|
||||||
const auto &ct = speed_grade->cell_types[type_idx];
|
const auto &ct = speed_grade->cell_types[type_idx];
|
||||||
@ -901,8 +899,8 @@ void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString cloc
|
|||||||
hold.max_delay = ct.setup_holds[dly_idx].max_hold;
|
hold.max_delay = ct.setup_holds[dly_idx].max_hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup,
|
void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
|
||||||
DelayInfo &hold) const
|
DelayPair &hold) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(type_idx != -1);
|
NPNR_ASSERT(type_idx != -1);
|
||||||
const auto &ct = speed_grade->cell_types[type_idx];
|
const auto &ct = speed_grade->cell_types[type_idx];
|
||||||
@ -916,7 +914,7 @@ void Arch::lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdStrin
|
|||||||
hold.min_delay = ct.setup_holds[dly_idx].min_hold;
|
hold.min_delay = ct.setup_holds[dly_idx].min_hold;
|
||||||
hold.max_delay = ct.setup_holds[dly_idx].max_hold;
|
hold.max_delay = ct.setup_holds[dly_idx].max_hold;
|
||||||
}
|
}
|
||||||
void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayInfo &delay) const
|
void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayQuad &delay) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(type_idx != -1);
|
NPNR_ASSERT(type_idx != -1);
|
||||||
const auto &ct = speed_grade->cell_types[type_idx];
|
const auto &ct = speed_grade->cell_types[type_idx];
|
||||||
@ -925,9 +923,9 @@ void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock
|
|||||||
to_port.index);
|
to_port.index);
|
||||||
NPNR_ASSERT(dly_idx != -1);
|
NPNR_ASSERT(dly_idx != -1);
|
||||||
clock = IdString(ct.prop_delays[dly_idx].from_port);
|
clock = IdString(ct.prop_delays[dly_idx].from_port);
|
||||||
delay.min_delay = ct.prop_delays[dly_idx].min_delay;
|
delay = DelayQuad(ct.prop_delays[dly_idx].min_delay, ct.prop_delays[dly_idx].max_delay);
|
||||||
delay.max_delay = ct.prop_delays[dly_idx].max_delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const
|
TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const
|
||||||
{
|
{
|
||||||
if (dir == PORT_IN) {
|
if (dir == PORT_IN) {
|
||||||
@ -940,7 +938,7 @@ TimingPortClass Arch::lookup_port_type(int type_idx, IdString port, PortType dir
|
|||||||
std::make_pair(port.index, clock.index));
|
std::make_pair(port.index, clock.index));
|
||||||
return (sh_idx != -1) ? TMG_REGISTER_INPUT : TMG_COMB_INPUT;
|
return (sh_idx != -1) ? TMG_REGISTER_INPUT : TMG_COMB_INPUT;
|
||||||
} else {
|
} else {
|
||||||
DelayInfo dly;
|
DelayQuad dly;
|
||||||
// If a clock-to-out entry exists, then this is a register output
|
// If a clock-to-out entry exists, then this is a register output
|
||||||
return lookup_cell_delay(type_idx, clock, port, dly) ? TMG_REGISTER_OUTPUT : TMG_COMB_OUTPUT;
|
return lookup_cell_delay(type_idx, clock, port, dly) ? TMG_REGISTER_OUTPUT : TMG_COMB_OUTPUT;
|
||||||
}
|
}
|
||||||
|
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;
|
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const override;
|
||||||
|
|
||||||
DelayInfo getWireDelay(WireId wire) const override
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
{
|
|
||||||
DelayInfo delay;
|
|
||||||
delay.min_delay = 0;
|
|
||||||
delay.max_delay = 0;
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
BelPinRange getWireBelPins(WireId wire) const override
|
BelPinRange getWireBelPins(WireId wire) const override
|
||||||
{
|
{
|
||||||
@ -1120,13 +1114,10 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
WireId getPipDstWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).to_wire); }
|
WireId getPipDstWire(PipId pip) const override { return canonical_wire(pip.tile, pip_data(pip).to_wire); }
|
||||||
|
|
||||||
DelayInfo getPipDelay(PipId pip) const override
|
DelayQuad getPipDelay(PipId pip) const override
|
||||||
{
|
{
|
||||||
DelayInfo delay;
|
|
||||||
auto &cls = speed_grade->pip_classes[pip_data(pip).timing_class];
|
auto &cls = speed_grade->pip_classes[pip_data(pip).timing_class];
|
||||||
delay.min_delay = std::max(0, cls.min_delay);
|
return DelayQuad(cls.min_delay, cls.max_delay);
|
||||||
delay.max_delay = std::max(0, cls.max_delay);
|
|
||||||
return delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpDownhillPipRange getPipsDownhill(WireId wire) const override
|
UpDownhillPipRange getPipsDownhill(WireId wire) const override
|
||||||
@ -1179,13 +1170,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
delay_t getRipupDelayPenalty() const override { return 120; }
|
delay_t getRipupDelayPenalty() const override { return 120; }
|
||||||
delay_t getWireRipupDelayPenalty(WireId wire) const;
|
delay_t getWireRipupDelayPenalty(WireId wire) const;
|
||||||
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
float getDelayNS(delay_t v) const override { return v * 0.001; }
|
||||||
DelayInfo getDelayFromNS(float ns) const override
|
delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); }
|
||||||
{
|
|
||||||
DelayInfo del;
|
|
||||||
del.min_delay = delay_t(ns * 1000);
|
|
||||||
del.max_delay = delay_t(ns * 1000);
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
uint32_t getDelayChecksum(delay_t v) const override { return v; }
|
||||||
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override;
|
||||||
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override;
|
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override;
|
||||||
@ -1198,7 +1183,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// Get the delay through a cell from one port to another, returning false
|
// Get the delay through a cell from one port to another, returning false
|
||||||
// if no path exists. This only considers combinational delays, as required by the Arch API
|
// if no path exists. This only considers combinational delays, as required by the Arch API
|
||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const override;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
|
||||||
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
|
||||||
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;
|
||||||
// Get the TimingClockingInfo of a port
|
// Get the TimingClockingInfo of a port
|
||||||
@ -1385,15 +1370,15 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Given cell type and variant, get the index inside the speed grade timing data
|
// Given cell type and variant, get the index inside the speed grade timing data
|
||||||
int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const;
|
int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const;
|
||||||
// Return true and set delay if a comb path exists in a given cell timing index
|
// Return true and set delay if a comb path exists in a given cell timing index
|
||||||
bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const;
|
bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayQuad &delay) const;
|
||||||
// Get setup and hold time for a given cell timing index and signal/clock pair
|
// Get setup and hold time for a given cell timing index and signal/clock pair
|
||||||
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup,
|
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayPair &setup,
|
||||||
DelayInfo &hold) const;
|
DelayPair &hold) const;
|
||||||
// Get setup and hold time and associated clock for a given cell timing index and signal
|
// Get setup and hold time and associated clock for a given cell timing index and signal
|
||||||
void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup,
|
void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayPair &setup,
|
||||||
DelayInfo &hold) const;
|
DelayPair &hold) const;
|
||||||
// Similar to lookup_cell_delay but only needs the 'to' signal, intended for clk->out delays
|
// Similar to lookup_cell_delay but only needs the 'to' signal, intended for clk->out delays
|
||||||
void lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayInfo &delay) const;
|
void lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayQuad &delay) const;
|
||||||
// Attempt to look up port type based on database
|
// Attempt to look up port type based on database
|
||||||
TimingPortClass lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const;
|
TimingPortClass lookup_port_type(int type_idx, IdString port, PortType dir, IdString clock) const;
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
@ -25,27 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef int delay_t;
|
typedef int delay_t;
|
||||||
|
|
||||||
struct DelayInfo
|
|
||||||
{
|
|
||||||
delay_t min_delay = 0, max_delay = 0;
|
|
||||||
|
|
||||||
delay_t minRaiseDelay() const { return min_delay; }
|
|
||||||
delay_t maxRaiseDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
delay_t minFallDelay() const { return min_delay; }
|
|
||||||
delay_t maxFallDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
delay_t minDelay() const { return min_delay; }
|
|
||||||
delay_t maxDelay() const { return max_delay; }
|
|
||||||
|
|
||||||
DelayInfo operator+(const DelayInfo &other) const
|
|
||||||
{
|
|
||||||
DelayInfo ret;
|
|
||||||
ret.min_delay = this->min_delay + other.min_delay;
|
|
||||||
ret.max_delay = this->max_delay + other.max_delay;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// https://bugreports.qt.io/browse/QTBUG-80789
|
// https://bugreports.qt.io/browse/QTBUG-80789
|
||||||
|
|
||||||
#ifndef Q_MOC_RUN
|
#ifndef Q_MOC_RUN
|
||||||
|
@ -1862,9 +1862,12 @@ struct NexusPacker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||||
to->clkconstr->low = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio);
|
to->clkconstr->low =
|
||||||
to->clkconstr->high = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio);
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->low.min_delay) / ratio));
|
||||||
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio);
|
to->clkconstr->high =
|
||||||
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->high.min_delay) / ratio));
|
||||||
|
to->clkconstr->period =
|
||||||
|
DelayPair(ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio));
|
||||||
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
|
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
|
||||||
to->name.c_str(ctx));
|
to->name.c_str(ctx));
|
||||||
changed_nets.insert(to->name);
|
changed_nets.insert(to->name);
|
||||||
|
Loading…
Reference in New Issue
Block a user