aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/arch_api.h2
-rw-r--r--common/arch_pybindings_shared.h4
-rw-r--r--common/command.cc8
-rw-r--r--common/context.cc23
-rw-r--r--common/context.h2
-rw-r--r--common/hashlib.h7
-rw-r--r--common/nextpnr_namespaces.h2
-rw-r--r--common/place_common.cc2
-rw-r--r--common/placer1.cc4
-rw-r--r--common/pybindings.cc5
-rw-r--r--common/pywrappers.h17
-rw-r--r--common/router1.cc133
-rw-r--r--common/router2.cc4
-rw-r--r--common/sso_array.h20
-rw-r--r--common/timing.cc2
-rw-r--r--common/timing_opt.cc8
16 files changed, 202 insertions, 41 deletions
diff --git a/common/arch_api.h b/common/arch_api.h
index e49d26c1..14a30652 100644
--- a/common/arch_api.h
+++ b/common/arch_api.h
@@ -110,7 +110,7 @@ template <typename R> struct ArchAPI : BaseCtx
virtual typename R::GroupPipsRangeT getGroupPips(GroupId group) const = 0;
virtual typename R::GroupGroupsRangeT getGroupGroups(GroupId group) const = 0;
// Delay Methods
- virtual delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const = 0;
+ virtual delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const = 0;
virtual delay_t getDelayEpsilon() const = 0;
virtual delay_t getRipupDelayPenalty() const = 0;
virtual float getDelayNS(delay_t v) const = 0;
diff --git a/common/arch_pybindings_shared.h b/common/arch_pybindings_shared.h
index f44aa70e..b3dc0506 100644
--- a/common/arch_pybindings_shared.h
+++ b/common/arch_pybindings_shared.h
@@ -48,6 +48,8 @@ fn_wrapper_2a_v<Context, decltype(&Context::copyBelPorts), &Context::copyBelPort
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<IdString>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
+fn_wrapper_1a<Context, decltype(&Context::getBelLocation), &Context::getBelLocation, pass_through<Loc>,
+ conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelLocation");
fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail");
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
@@ -92,6 +94,8 @@ fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips, wrap_cont
"getPips");
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
+fn_wrapper_1a<Context, decltype(&Context::getPipLocation), &Context::getPipLocation, pass_through<Loc>,
+ conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipLocation");
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>, addr_and_unwrap<NetInfo>,
pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
diff --git a/common/command.cc b/common/command.cc
index 5a13fb55..d4279a58 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -176,7 +176,9 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("router2-heatmap", po::value<std::string>(),
"prefix for router2 resource congestion heatmaps");
- general.add_options()("router2-tmg-ripup", "enable experimental timing-driven ripup in router2");
+ general.add_options()("tmg-ripup", "enable experimental timing-driven ripup in router");
+ general.add_options()("router2-tmg-ripup",
+ "enable experimental timing-driven ripup in router (deprecated; use --tmg-ripup instead)");
general.add_options()("report", po::value<std::string>(),
"write timing and utilization report in JSON format to file");
@@ -298,8 +300,8 @@ void CommandHandler::setupContext(Context *ctx)
ctx->settings[ctx->id("placerHeap/timingWeight")] = std::to_string(vm["placer-heap-timingweight"].as<int>());
if (vm.count("router2-heatmap"))
ctx->settings[ctx->id("router2/heatmap")] = vm["router2-heatmap"].as<std::string>();
- if (vm.count("router2-tmg-ripup"))
- ctx->settings[ctx->id("router2/tmg_ripup")] = true;
+ if (vm.count("tmg-ripup") || vm.count("router2-tmg-ripup"))
+ ctx->settings[ctx->id("router/tmg_ripup")] = true;
// Setting default values
if (ctx->settings.find(ctx->id("target_freq")) == ctx->settings.end())
diff --git a/common/context.cc b/common/context.cc
index 6bba5cbe..faddf825 100644
--- a/common/context.cc
+++ b/common/context.cc
@@ -90,6 +90,25 @@ WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink,
return WireId();
}
+delay_t Context::predictArcDelay(const NetInfo *net_info, const PortRef &sink) const
+{
+ if (net_info->driver.cell == nullptr || net_info->driver.cell->bel == BelId() || sink.cell->bel == BelId())
+ return 0;
+ IdString driver_pin, sink_pin;
+ // Pick the first pin for a prediction; assume all will be similar enouhg
+ for (auto pin : getBelPinsForCellPin(net_info->driver.cell, net_info->driver.port)) {
+ driver_pin = pin;
+ break;
+ }
+ for (auto pin : getBelPinsForCellPin(sink.cell, sink.port)) {
+ sink_pin = pin;
+ break;
+ }
+ if (driver_pin == IdString() || sink_pin == IdString())
+ return 0;
+ return predictDelay(net_info->driver.cell->bel, driver_pin, sink.cell->bel, sink_pin);
+}
+
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
{
#ifdef ARCH_ECP5
@@ -98,7 +117,7 @@ delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &us
#endif
if (net_info->wires.empty())
- return predictDelay(net_info, user_info);
+ return predictArcDelay(net_info, user_info);
WireId src_wire = getNetinfoSourceWire(net_info);
if (src_wire == WireId())
@@ -128,7 +147,7 @@ delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &us
if (cursor == src_wire)
max_delay = std::max(max_delay, delay + getWireDelay(src_wire).maxDelay()); // routed
else
- max_delay = std::max(max_delay, predictDelay(net_info, user_info)); // unrouted
+ max_delay = std::max(max_delay, predictArcDelay(net_info, user_info)); // unrouted
}
return max_delay;
}
diff --git a/common/context.h b/common/context.h
index 6adbbdb5..cb8fd257 100644
--- a/common/context.h
+++ b/common/context.h
@@ -51,6 +51,8 @@ struct Context : Arch, DeterministicRNG
// --------------------------------------------------------------
+ delay_t predictArcDelay(const NetInfo *net_info, const PortRef &sink) const;
+
WireId getNetinfoSourceWire(const NetInfo *net_info) const;
SSOArray<WireId, 2> getNetinfoSinkWires(const NetInfo *net_info, const PortRef &sink) const;
size_t getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const;
diff --git a/common/hashlib.h b/common/hashlib.h
index b71f0129..70de8c91 100644
--- a/common/hashlib.h
+++ b/common/hashlib.h
@@ -26,8 +26,11 @@ NEXTPNR_NAMESPACE_BEGIN
const int hashtable_size_trigger = 2;
const int hashtable_size_factor = 3;
-// The XOR version of DJB2
-inline unsigned int mkhash(unsigned int a, unsigned int b) { return ((a << 5) + a) ^ b; }
+// Cantor pairing function for two non-negative integers
+// https://en.wikipedia.org/wiki/Pairing_function
+inline unsigned int mkhash(unsigned int a, unsigned int b) {
+ return (a*a + 3*a + 2*a*b + b + b*b) / 2;
+}
// traditionally 5381 is used as starting value for the djb2 hash
const unsigned int mkhash_init = 5381;
diff --git a/common/nextpnr_namespaces.h b/common/nextpnr_namespaces.h
index 6fb0aa77..b758d7c5 100644
--- a/common/nextpnr_namespaces.h
+++ b/common/nextpnr_namespaces.h
@@ -33,6 +33,8 @@
#define USING_NEXTPNR_NAMESPACE
#endif
+#define NPNR_UNUSED(x) ((void)x)
+
#if defined(__GNUC__) || defined(__clang__)
#define NPNR_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#define NPNR_NORETURN __attribute__((noreturn))
diff --git a/common/place_common.cc b/common/place_common.cc
index bcfa3633..e03fca55 100644
--- a/common/place_common.cc
+++ b/common/place_common.cc
@@ -50,7 +50,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
if (load_cell->bel == BelId())
continue;
if (timing_driven) {
- delay_t net_delay = ctx->predictDelay(net, load);
+ delay_t net_delay = ctx->predictArcDelay(net, load);
auto slack = load.budget - net_delay;
if (slack < 0)
negative_slack += slack;
diff --git a/common/placer1.cc b/common/placer1.cc
index 4db1c951..6de035b4 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -866,11 +866,11 @@ class SAPlacer
if (ctx->getPortTimingClass(net->driver.cell, net->driver.port, cc) == TMG_IGNORE)
return 0;
if (cfg.budgetBased) {
- double delay = ctx->getDelayNS(ctx->predictDelay(net, net->users.at(user)));
+ double delay = ctx->getDelayNS(ctx->predictArcDelay(net, net->users.at(user)));
return std::min(10.0, std::exp(delay - ctx->getDelayNS(net->users.at(user).budget) / 10));
} else {
float crit = tmg.get_criticality(CellPortKey(net->users.at(user)));
- double delay = ctx->getDelayNS(ctx->predictDelay(net, net->users.at(user)));
+ double delay = ctx->getDelayNS(ctx->predictArcDelay(net, net->users.at(user)));
return delay * std::pow(crit, crit_exp);
}
}
diff --git a/common/pybindings.cc b/common/pybindings.cc
index f9ee9eb7..eef460ce 100644
--- a/common/pybindings.cc
+++ b/common/pybindings.cc
@@ -83,6 +83,8 @@ template <> struct string_converter<Property>
} // namespace PythonConversion
+std::string loc_repr_py(Loc loc) { return stringf("Loc(%d, %d, %d)", loc.x, loc.y, loc.z); }
+
PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
{
py::register_exception_translator([](std::exception_ptr p) {
@@ -175,7 +177,8 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
.def(py::init<int, int, int>())
.def_readwrite("x", &Loc::x)
.def_readwrite("y", &Loc::y)
- .def_readwrite("z", &Loc::z);
+ .def_readwrite("z", &Loc::z)
+ .def("__repr__", loc_repr_py);
auto ci_cls = py::class_<ContextualWrapper<CellInfo &>>(m, "CellInfo");
readwrite_wrapper<CellInfo &, decltype(&CellInfo::name), &CellInfo::name, conv_to_str<IdString>,
diff --git a/common/pywrappers.h b/common/pywrappers.h
index 66dec6fb..60ef65be 100644
--- a/common/pywrappers.h
+++ b/common/pywrappers.h
@@ -257,7 +257,7 @@ template <typename Class, typename FuncT, FuncT fn, typename arg1_conv> struct f
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1));
+ (base.*fn)(arg1_conv()(ctx, arg1));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
@@ -280,7 +280,7 @@ template <typename Class, typename FuncT, FuncT fn, typename arg1_conv, typename
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2));
+ (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
@@ -304,7 +304,7 @@ struct fn_wrapper_3a_v
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3));
+ (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
@@ -331,8 +331,7 @@ struct fn_wrapper_4a_v
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3),
- arg4_conv()(ctx, arg4));
+ (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3), arg4_conv()(ctx, arg4));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
@@ -360,8 +359,8 @@ struct fn_wrapper_5a_v
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3),
- arg4_conv()(ctx, arg4), arg5_conv()(ctx, arg5));
+ (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3), arg4_conv()(ctx, arg4),
+ arg5_conv()(ctx, arg5));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
@@ -390,8 +389,8 @@ struct fn_wrapper_6a_v
{
Context *ctx = get_ctx<Class>(cls);
Class &base = get_base<Class>(cls);
- return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3),
- arg4_conv()(ctx, arg4), arg5_conv()(ctx, arg5), arg6_conv()(ctx, arg6));
+ (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3), arg4_conv()(ctx, arg4),
+ arg5_conv()(ctx, arg5), arg6_conv()(ctx, arg6));
}
template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); }
diff --git a/common/router1.cc b/common/router1.cc
index 0ff2bedd..f387aee1 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -117,14 +117,24 @@ struct Router1
int arcs_without_ripup = 0;
bool ripup_flag;
- Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) {}
+ TimingAnalyser tmg;
+
+ bool timing_driven = true;
+
+ Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg), tmg(ctx)
+ {
+ timing_driven = ctx->setting<bool>("timing_driven");
+ tmg.setup();
+ tmg.run();
+ }
void arc_queue_insert(const arc_key &arc, WireId src_wire, WireId dst_wire)
{
if (queued_arcs.count(arc))
return;
- delay_t pri = ctx->estimateDelay(src_wire, dst_wire) - arc.net_info->users[arc.user_idx].budget;
+ delay_t pri = ctx->estimateDelay(src_wire, dst_wire) *
+ (100 * tmg.get_criticality(CellPortKey(arc.net_info->users.at(arc.user_idx))));
arc_entry entry;
entry.arc = arc;
@@ -459,6 +469,8 @@ struct Router1
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], arc.phys_idx);
ripup_flag = false;
+ float crit = tmg.get_criticality(CellPortKey(net_info->users.at(user_idx)));
+
if (ctx->debug) {
log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info),
int(net_info->users.size()));
@@ -536,6 +548,7 @@ struct Router1
delay_t next_delay = qw.delay + ctx->getPipDelay(pip).maxDelay();
delay_t next_penalty = qw.penalty;
delay_t next_bonus = qw.bonus;
+ delay_t penalty_delta = 0;
WireId next_wire = ctx->getPipDstWire(pip);
next_delay += ctx->getWireDelay(next_wire).maxDelay();
@@ -544,7 +557,7 @@ struct Router1
NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr;
if (net_info->wires.count(next_wire) && net_info->wires.at(next_wire).pip == pip) {
- next_bonus += cfg.reuseBonus;
+ next_bonus += cfg.reuseBonus * (1.0 - crit);
} else {
if (!ctx->checkWireAvail(next_wire)) {
if (!ripup)
@@ -609,34 +622,36 @@ struct Router1
if (conflictWireWire != WireId()) {
auto scores_it = wireScores.find(conflictWireWire);
if (scores_it != wireScores.end())
- next_penalty += scores_it->second * cfg.wireRipupPenalty;
- next_penalty += cfg.wireRipupPenalty;
+ penalty_delta += scores_it->second * cfg.wireRipupPenalty;
+ penalty_delta += cfg.wireRipupPenalty;
}
if (conflictPipWire != WireId()) {
auto scores_it = wireScores.find(conflictPipWire);
if (scores_it != wireScores.end())
- next_penalty += scores_it->second * cfg.wireRipupPenalty;
- next_penalty += cfg.wireRipupPenalty;
+ penalty_delta += scores_it->second * cfg.wireRipupPenalty;
+ penalty_delta += cfg.wireRipupPenalty;
}
if (conflictWireNet != nullptr) {
auto scores_it = netScores.find(conflictWireNet);
if (scores_it != netScores.end())
- next_penalty += scores_it->second * cfg.netRipupPenalty;
- next_penalty += cfg.netRipupPenalty;
- next_penalty += conflictWireNet->wires.size() * cfg.wireRipupPenalty;
+ penalty_delta += scores_it->second * cfg.netRipupPenalty;
+ penalty_delta += cfg.netRipupPenalty;
+ penalty_delta += conflictWireNet->wires.size() * cfg.wireRipupPenalty;
}
if (conflictPipNet != nullptr) {
auto scores_it = netScores.find(conflictPipNet);
if (scores_it != netScores.end())
- next_penalty += scores_it->second * cfg.netRipupPenalty;
- next_penalty += cfg.netRipupPenalty;
- next_penalty += conflictPipNet->wires.size() * cfg.wireRipupPenalty;
+ penalty_delta += scores_it->second * cfg.netRipupPenalty;
+ penalty_delta += cfg.netRipupPenalty;
+ penalty_delta += conflictPipNet->wires.size() * cfg.wireRipupPenalty;
}
}
+ next_penalty += penalty_delta * (timing_driven ? std::max(0.05, (1.0 - crit)) : 1);
+
delay_t next_score = next_delay + next_penalty;
NPNR_ASSERT(next_score >= 0);
@@ -778,6 +793,53 @@ struct Router1
return true;
}
+
+ delay_t find_slack_thresh()
+ {
+ // If more than 5% of arcs have negative slack; use the 5% threshold as a ripup criteria
+ int arc_count = 0;
+ int failed_count = 0;
+ delay_t default_thresh = ctx->getDelayEpsilon();
+
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
+ if (skip_net(ni))
+ continue;
+ for (size_t i = 0; i < ni->users.size(); i++) {
+ auto &usr = ni->users.at(i);
+ ++arc_count;
+ delay_t slack = tmg.get_setup_slack(CellPortKey(usr));
+ if (slack == std::numeric_limits<delay_t>::min())
+ continue;
+ if (slack < default_thresh)
+ ++failed_count;
+ }
+ }
+
+ if (arc_count < 50 || (failed_count < (0.05 * arc_count))) {
+ return default_thresh;
+ }
+
+ std::vector<delay_t> slacks;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
+ if (skip_net(ni))
+ continue;
+ for (size_t i = 0; i < ni->users.size(); i++) {
+ auto &usr = ni->users.at(i);
+ delay_t slack = tmg.get_setup_slack(CellPortKey(usr));
+ if (slack == std::numeric_limits<delay_t>::min())
+ continue;
+ slacks.push_back(slack);
+ }
+ }
+ std::sort(slacks.begin(), slacks.end());
+ delay_t thresh = slacks.at(int(slacks.size() * 0.05));
+ log_warning("%.f%% of arcs have failing slack; using %.2fns as ripup threshold. Consider a reduced Fmax "
+ "constraint.\n",
+ (100.0 * failed_count) / arc_count, ctx->getDelayNS(thresh));
+ return thresh;
+ }
};
} // namespace
@@ -819,6 +881,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
int iter_cnt = 0;
int last_arcs_with_ripup = 0;
int last_arcs_without_ripup = 0;
+ int timing_fail_count = 0;
+ bool timing_ripup = ctx->setting<bool>("router/tmg_ripup", false);
+ delay_t ripup_slack = 0;
log_info(" | (re-)routed arcs | delta | remaining| time spent |\n");
log_info(" IterCnt | w/ripup wo/ripup | w/r wo/r | arcs| batch(sec) total(sec)|\n");
@@ -854,6 +919,48 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
#endif
return false;
}
+ // Timing driven ripup
+ if (timing_ripup && router.arc_queue.empty() && timing_fail_count < 50) {
+ ++timing_fail_count;
+ router.tmg.run();
+ delay_t wns = 0, tns = 0;
+ if (timing_fail_count == 1)
+ ripup_slack = router.find_slack_thresh();
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
+ if (router.skip_net(ni))
+ continue;
+ bool is_locked = false;
+ for (auto &wire : ni->wires) {
+ if (wire.second.strength > STRENGTH_STRONG)
+ is_locked = true;
+ }
+ if (is_locked)
+ continue;
+ for (size_t i = 0; i < ni->users.size(); i++) {
+ auto &usr = ni->users.at(i);
+ delay_t slack = router.tmg.get_setup_slack(CellPortKey(usr));
+ if (slack == std::numeric_limits<delay_t>::min())
+ continue;
+ if (slack < 0) {
+ wns = std::min(wns, slack);
+ tns += slack;
+ }
+ if (slack <= ripup_slack) {
+ for (WireId w : ctx->getNetinfoSinkWires(ni, usr)) {
+ if (ctx->checkWireAvail(w))
+ continue;
+ router.ripup_wire(w);
+ }
+ }
+ }
+ }
+ log_info(" %d arcs ripped up due to negative slack WNS=%.02fns TNS=%.02fns.\n",
+ int(router.arc_queue.size()), ctx->getDelayNS(wns), ctx->getDelayNS(tns));
+ iter_cnt = 0;
+ router.wireScores.clear();
+ router.netScores.clear();
+ }
}
auto rend = std::chrono::high_resolution_clock::now();
log_info("%10d | %8d %10d | %4d %5d | %9d| %10.02f %10.02f|\n", iter_cnt, router.arcs_with_ripup,
diff --git a/common/router2.cc b/common/router2.cc
index d713cce2..c76e1f61 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -1373,8 +1373,8 @@ struct Router2
route_queue.push_back(i);
timing_driven = ctx->setting<bool>("timing_driven");
- if (ctx->settings.count(ctx->id("router2/tmg_ripup")))
- timing_driven_ripup = timing_driven && ctx->setting<bool>("router2/tmg_ripup");
+ if (ctx->settings.count(ctx->id("router/tmg_ripup")))
+ timing_driven_ripup = timing_driven && ctx->setting<bool>("router/tmg_ripup");
else
timing_driven_ripup = false;
log_info("Running main router loop...\n");
diff --git a/common/sso_array.h b/common/sso_array.h
index 1fae6c57..80e7d1c1 100644
--- a/common/sso_array.h
+++ b/common/sso_array.h
@@ -70,6 +70,26 @@ template <typename T, std::size_t N> class SSOArray
std::copy(other.begin(), other.end(), begin());
}
+ SSOArray(SSOArray &&other) : m_size(other.size())
+ {
+ if (is_heap())
+ data_heap = other.data_heap;
+ else
+ std::copy(other.begin(), other.end(), begin());
+ other.m_size = 0;
+ }
+ SSOArray &operator=(const SSOArray &other)
+ {
+ if (&other == this)
+ return *this;
+ if (is_heap())
+ delete[] data_heap;
+ m_size = other.m_size;
+ alloc();
+ std::copy(other.begin(), other.end(), begin());
+ return *this;
+ }
+
template <typename Tother> SSOArray(const Tother &other) : m_size(other.size())
{
alloc();
diff --git a/common/timing.cc b/common/timing.cc
index e305d82d..f30d4fc5 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -1378,7 +1378,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
auto driver_wire = ctx->getNetinfoSourceWire(net);
auto sink_wire = ctx->getNetinfoSinkWire(net, sink_ref, 0);
log_info(" prediction: %f ns estimate: %f ns\n",
- ctx->getDelayNS(ctx->predictDelay(net, sink_ref)),
+ ctx->getDelayNS(ctx->predictArcDelay(net, sink_ref)),
ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire)));
auto cursor = sink_wire;
delay_t delay;
diff --git a/common/timing_opt.cc b/common/timing_opt.cc
index 6dd93d67..a73a70cf 100644
--- a/common/timing_opt.cc
+++ b/common/timing_opt.cc
@@ -99,7 +99,7 @@ class TimingOptimiser
continue;
for (auto user : net->users) {
if (user.cell == cell && user.port == port.first) {
- if (ctx->predictDelay(net, user) >
+ if (ctx->predictArcDelay(net, user) >
1.1 * max_net_delay.at(std::make_pair(cell->name, port.first)))
return false;
}
@@ -111,7 +111,7 @@ class TimingOptimiser
BelId dstBel = user.cell->bel;
if (dstBel == BelId())
continue;
- if (ctx->predictDelay(net, user) >
+ if (ctx->predictArcDelay(net, user) >
1.1 * max_net_delay.at(std::make_pair(user.cell->name, user.port))) {
return false;
@@ -413,7 +413,7 @@ class TimingOptimiser
for (size_t j = 0; j < pn->users.size(); j++) {
auto &usr = pn->users.at(j);
if (usr.cell == path.at(i)->cell && usr.port == path.at(i)->port) {
- original_delay += ctx->predictDelay(pn, usr);
+ original_delay += ctx->predictArcDelay(pn, usr);
break;
}
}
@@ -497,7 +497,7 @@ class TimingOptimiser
for (size_t j = 0; j < pn->users.size(); j++) {
auto &usr = pn->users.at(j);
if (usr.cell == path.at(i)->cell && usr.port == path.at(i)->port) {
- total_delay += ctx->predictDelay(pn, usr);
+ total_delay += ctx->predictArcDelay(pn, usr);
break;
}
}