aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/pybindings.cc26
-rw-r--r--common/pycontainers.h59
-rw-r--r--common/router1.cc7
-rw-r--r--common/timing.cc18
4 files changed, 105 insertions, 5 deletions
diff --git a/common/pybindings.cc b/common/pybindings.cc
index 061dfc47..6cae889d 100644
--- a/common/pybindings.cc
+++ b/common/pybindings.cc
@@ -68,6 +68,19 @@ void translate_assertfail(const assertion_failure &e)
PyErr_SetString(PyExc_AssertionError, e.what());
}
+namespace PythonConversion {
+template <> struct string_converter<PortRef &>
+{
+ inline PortRef from_str(Context *ctx, std::string name) { NPNR_ASSERT_FALSE("PortRef from_str not implemented"); }
+
+ inline std::string to_str(Context *ctx, const PortRef &pr)
+ {
+ return pr.cell->name.str(ctx) + "." + pr.port.str(ctx);
+ }
+};
+
+} // namespace PythonConversion
+
BOOST_PYTHON_MODULE(MODULE_NAME)
{
register_exception_translator<assertion_failure>(&translate_assertfail);
@@ -120,7 +133,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
readwrite_wrapper<PortInfo &, decltype(&PortInfo::type), &PortInfo::type, pass_through<PortType>,
pass_through<PortType>>::def_wrap(pi_cls, "type");
- typedef std::vector<PortRef> PortVector;
+ typedef std::vector<PortRef> PortRefVector;
typedef std::unordered_map<WireId, PipMap> WireMap;
auto ni_cls = class_<ContextualWrapper<NetInfo &>>("NetInfo", no_init);
@@ -128,7 +141,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
conv_from_str<IdString>>::def_wrap(ni_cls, "name");
readwrite_wrapper<NetInfo &, decltype(&NetInfo::driver), &NetInfo::driver, wrap_context<PortRef &>,
unwrap_context<PortRef &>>::def_wrap(ni_cls, "driver");
- readonly_wrapper<NetInfo &, decltype(&NetInfo::users), &NetInfo::users, wrap_context<PortVector &>>::def_wrap(
+ readonly_wrapper<NetInfo &, decltype(&NetInfo::users), &NetInfo::users, wrap_context<PortRefVector &>>::def_wrap(
ni_cls, "users");
readonly_wrapper<NetInfo &, decltype(&NetInfo::wires), &NetInfo::wires, wrap_context<WireMap &>>::def_wrap(ni_cls,
"wires");
@@ -141,12 +154,21 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
readwrite_wrapper<PortRef &, decltype(&PortRef::budget), &PortRef::budget, pass_through<delay_t>,
pass_through<delay_t>>::def_wrap(pr_cls, "budget");
+ auto pm_cls = class_<ContextualWrapper<PipMap &>>("PipMap", no_init);
+ readwrite_wrapper<PipMap &, decltype(&PipMap::pip), &PipMap::pip, conv_to_str<PipId>,
+ conv_from_str<PipId>>::def_wrap(pm_cls, "pip");
+ readwrite_wrapper<PipMap &, decltype(&PipMap::strength), &PipMap::strength, pass_through<PlaceStrength>,
+ pass_through<PlaceStrength>>::def_wrap(pm_cls, "strength");
+
def("parse_json", parse_json_shim);
def("load_design", load_design_shim, return_value_policy<manage_new_object>());
WRAP_MAP(AttrMap, pass_through<std::string>, "AttrMap");
WRAP_MAP(PortMap, wrap_context<PortInfo &>, "PortMap");
WRAP_MAP(PinMap, conv_to_str<IdString>, "PinMap");
+ WRAP_MAP(WireMap, wrap_context<PipMap &>, "WireMap");
+
+ WRAP_VECTOR(PortRefVector, wrap_context<PortRef &>);
arch_wrap_python();
}
diff --git a/common/pycontainers.h b/common/pycontainers.h
index 094706f7..70f69c51 100644
--- a/common/pycontainers.h
+++ b/common/pycontainers.h
@@ -119,9 +119,66 @@ struct range_wrapper
range_wrapper<t##Range, return_value_policy<return_by_value>, conv>().wrap(#t "Range", #t "Iterator")
/*
+A wrapper for a vector or similar structure. With support for conversion
+*/
+
+template <typename T, typename P = return_value_policy<return_by_value>,
+ typename value_conv = PythonConversion::pass_through<T>>
+struct vector_wrapper
+{
+ typedef decltype(std::declval<T>().begin()) iterator_t;
+ typedef decltype(*(std::declval<iterator_t>())) value_t;
+ typedef typename PythonConversion::ContextualWrapper<T &> wrapped_vector;
+ typedef typename PythonConversion::ContextualWrapper<std::pair<iterator_t, iterator_t>> wrapped_pair;
+ using return_t = typename value_conv::ret_type;
+ static wrapped_pair iter(wrapped_vector &range)
+ {
+ return wrapped_pair(range.ctx, std::make_pair(range.base.begin(), range.base.end()));
+ }
+
+ static std::string repr(wrapped_vector &range)
+ {
+ PythonConversion::string_converter<value_t> conv;
+ bool first = true;
+ std::stringstream ss;
+ ss << "[";
+ for (const auto &item : range.base) {
+ if (!first)
+ ss << ", ";
+ ss << "'" << conv.to_str(range.ctx, item) << "'";
+ first = false;
+ }
+ ss << "]";
+ return ss.str();
+ }
+
+ static int len(wrapped_vector &range) { return range.base.size(); }
+
+ static return_t getitem(wrapped_vector &range, int i)
+ {
+ return value_conv()(range.ctx, boost::ref(range.base.at(i)));
+ }
+
+ static void wrap(const char *range_name, const char *iter_name)
+ {
+ class_<wrapped_vector>(range_name, no_init)
+ .def("__iter__", iter)
+ .def("__repr__", repr)
+ .def("__len__", len)
+ .def("__getitem__", getitem);
+
+ iterator_wrapper<iterator_t, P, value_conv>().wrap(iter_name);
+ }
+
+ typedef iterator_wrapper<iterator_t, P, value_conv> iter_wrap;
+};
+
+#define WRAP_VECTOR(t, conv) vector_wrapper<t, return_value_policy<return_by_value>, conv>().wrap(#t, #t "Iterator")
+
+/*
Wrapper for a pair, allows accessing either using C++-style members (.first and
.second) or as a Python iterable and indexable object
- */
+*/
template <typename T1, typename T2> struct pair_wrapper
{
typedef std::pair<T1, T2> T;
diff --git a/common/router1.cc b/common/router1.cc
index 8d19797b..cbc0df90 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -871,7 +871,12 @@ bool Context::checkRoutedDesign() const
}
auto src_wire = ctx->getNetinfoSourceWire(net_info);
- log_assert(src_wire != WireId());
+ if (src_wire == WireId()) {
+ log_assert(net_info->driver.cell == nullptr);
+ if (ctx->debug)
+ log(" undriven and unrouted\n");
+ continue;
+ }
if (net_info->wires.count(src_wire) == 0) {
if (ctx->debug)
diff --git a/common/timing.cc b/common/timing.cc
index 8bbf2bca..242d56d9 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -593,7 +593,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
if (print_path) {
auto print_path_report = [ctx](ClockPair &clocks, PortRefVector &crit_path) {
- delay_t total = 0;
+ delay_t total = 0, logic_total = 0, route_total = 0;
auto &front = crit_path.front();
auto &front_port = front->cell->ports.at(front->port);
auto &front_driver = front_port.net->driver;
@@ -608,6 +608,9 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
if (clknet != nullptr && clknet->name == clocks.start.clock &&
clockInfo.edge == clocks.start.edge) {
last_port = clockInfo.clock_port;
+ total += clockInfo.clockToQ.maxDelay();
+ logic_total += clockInfo.clockToQ.maxDelay();
+ break;
}
}
}
@@ -627,10 +630,12 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
ctx->getCellDelay(sink_cell, last_port, driver.port, comb_delay);
}
total += comb_delay.maxDelay();
+ logic_total += comb_delay.maxDelay();
log_info("%4.1f %4.1f Source %s.%s\n", ctx->getDelayNS(comb_delay.maxDelay()), ctx->getDelayNS(total),
driver_cell->name.c_str(ctx), driver.port.c_str(ctx));
auto net_delay = ctx->getNetinfoRouteDelay(net, *sink);
total += net_delay;
+ route_total += net_delay;
auto driver_loc = ctx->getBelLocation(driver_cell->bel);
auto sink_loc = ctx->getBelLocation(sink_cell->bel);
log_info("%4.1f %4.1f Net %s budget %f ns (%d,%d) -> (%d,%d)\n", ctx->getDelayNS(net_delay),
@@ -658,6 +663,17 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
}
last_port = sink->port;
}
+ int clockCount = 0;
+ auto sinkClass = ctx->getPortTimingClass(crit_path.back()->cell, crit_path.back()->port, clockCount);
+ if (sinkClass == TMG_REGISTER_INPUT && clockCount > 0) {
+ auto sinkClockInfo = ctx->getPortClockingInfo(crit_path.back()->cell, crit_path.back()->port, 0);
+ delay_t setup = sinkClockInfo.setup.maxDelay();
+ total += setup;
+ logic_total += setup;
+ log_info("%4.1f %4.1f Setup %s.%s\n", ctx->getDelayNS(setup), ctx->getDelayNS(total),
+ crit_path.back()->cell->name.c_str(ctx), crit_path.back()->port.c_str(ctx));
+ }
+ log_info("%.1f ns logic, %.1f ns routing\n", ctx->getDelayNS(logic_total), ctx->getDelayNS(route_total));
};
for (auto &clock : clock_reports) {