diff options
Diffstat (limited to 'common/report.cc')
-rw-r--r-- | common/report.cc | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/common/report.cc b/common/report.cc index 4b3b2418..a595777a 100644 --- a/common/report.cc +++ b/common/report.cc @@ -40,6 +40,127 @@ dict<IdString, std::pair<int, int>> get_utilization(const Context *ctx) return result; } } // namespace + +static std::string clock_event_name (const Context* ctx, const ClockEvent& e) { + std::string value; + if (e.clock == ctx->id("$async$")) + value = std::string("<async>"); + else + value = (e.edge == FALLING_EDGE ? std::string("negedge ") : + std::string("posedge ")) + e.clock.str(ctx); + return value; +}; + +static Json::array report_critical_paths (const Context* ctx) { + + auto report_critical_path = [ctx](const CriticalPath& report) { + Json::array pathJson; + + for (const auto& segment : report.segments) { + + const auto& driver = ctx->cells.at(segment.from.first); + const auto& sink = ctx->cells.at(segment.to.first); + + auto fromLoc = ctx->getBelLocation(driver->bel); + auto toLoc = ctx->getBelLocation(sink->bel); + + auto fromJson = Json::object({ + {"cell", segment.from.first.c_str(ctx)}, + {"port", segment.from.second.c_str(ctx)}, + {"loc", Json::array({fromLoc.x, fromLoc.y})} + }); + + auto toJson = Json::object({ + {"cell", segment.to.first.c_str(ctx)}, + {"port", segment.to.second.c_str(ctx)}, + {"loc", Json::array({toLoc.x, toLoc.y})} + }); + + auto segmentJson = Json::object({ + {"delay", ctx->getDelayNS(segment.delay)}, + {"from", fromJson}, + {"to", toJson}, + }); + + if (segment.type == CriticalPath::Segment::Type::LOGIC) { + segmentJson["type"] = "logic"; + } + else if (segment.type == CriticalPath::Segment::Type::ROUTING) { + segmentJson["type"] = "routing"; + segmentJson["net"] = segment.net.c_str(ctx); + segmentJson["budget"] = ctx->getDelayNS(segment.budget); + } + + pathJson.push_back(segmentJson); + } + + return pathJson; + }; + + auto critPathsJson = Json::array(); + + // Critical paths + for (auto &report : ctx->timing_result.clock_paths) { + + critPathsJson.push_back(Json::object({ + {"from", clock_event_name(ctx, report.second.clock_pair.start)}, + {"to", clock_event_name(ctx, report.second.clock_pair.end)}, + {"path", report_critical_path(report.second)} + })); + } + + // Cross-domain paths + for (auto &report : ctx->timing_result.xclock_paths) { + critPathsJson.push_back(Json::object({ + {"from", clock_event_name(ctx, report.clock_pair.start)}, + {"to", clock_event_name(ctx, report.clock_pair.end)}, + {"path", report_critical_path(report)} + })); + } + + return critPathsJson; +} + +static Json::array report_detailed_net_timings (const Context* ctx) { + auto detailedNetTimingsJson = Json::array(); + + // Detailed per-net timing analysis + for (const auto& it : ctx->timing_result.detailed_net_timings) { + + const NetInfo* net = ctx->nets.at(it.first).get(); + ClockEvent start = it.second[0].clock_pair.start; + + Json::array endpointsJson; + for (const auto& sink_timing : it.second) { + + // FIXME: Is it possible that there are multiple different start + // events for a single net? It has a single driver + NPNR_ASSERT(sink_timing.clock_pair.start == start); + + auto endpointJson = Json::object({ + {"cell", sink_timing.cell_port.first.c_str(ctx)}, + {"port", sink_timing.cell_port.second.c_str(ctx)}, + {"event", clock_event_name(ctx, sink_timing.clock_pair.end)}, + {"delay", ctx->getDelayNS(sink_timing.delay)}, + {"budget", ctx->getDelayNS(sink_timing.budget)} + }); + endpointsJson.push_back(endpointJson); + } + + auto netTimingJson = Json::object({ + {"net", net->name.c_str(ctx)}, + {"driver", net->driver.cell->name.c_str(ctx)}, + {"port", net->driver.port.c_str(ctx)}, + {"event", clock_event_name(ctx, start)}, + {"endpoints", endpointsJson} + }); + + detailedNetTimingsJson.push_back(netTimingJson); + } + + return detailedNetTimingsJson; +} + void Context::writeReport(std::ostream &out) const { auto util = get_utilization(this); @@ -60,6 +181,8 @@ void Context::writeReport(std::ostream &out) const out << Json(Json::object{ {"utilization", util_json}, {"fmax", fmax_json}, + {"critical_paths", report_critical_paths(this)}, + {"detailed_net_timings", report_detailed_net_timings(this)} }) .dump() << std::endl; |