Files
OpenSTA/search/ReportPath.cc
T

3653 lines
114 KiB
C++
Raw Normal View History

2018-09-28 08:54:21 -07:00
// OpenSTA, Static Timing Analyzer
2026-03-10 13:21:17 -07:00
// Copyright (c) 2026, Parallax Software, Inc.
2018-09-28 08:54:21 -07:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2022-01-04 10:17:08 -07:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2018-09-28 08:54:21 -07:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
2022-01-04 10:17:08 -07:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2025-01-21 18:54:33 -07:00
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
2018-09-28 08:54:21 -07:00
2026-04-13 14:58:16 -07:00
#include "ReportPath.hh"
#include <algorithm> // reverse
2026-03-02 12:13:13 -08:00
#include <string>
2026-03-28 19:13:35 -07:00
#include <string_view>
2026-04-13 14:58:16 -07:00
#include "ArcDelayCalc.hh"
#include "CheckMaxSkews.hh"
#include "CheckMinPeriods.hh"
#include "CheckMinPulseWidths.hh"
#include "ClkInfo.hh"
2026-01-03 16:59:35 -08:00
#include "ContainerHelpers.hh"
2020-04-05 14:53:44 -07:00
#include "Error.hh"
2026-04-13 14:58:16 -07:00
#include "ExceptionPath.hh"
#include "Format.hh"
2020-04-05 14:53:44 -07:00
#include "Fuzzy.hh"
2026-04-13 14:58:16 -07:00
#include "Genclks.hh"
2020-04-05 14:53:44 -07:00
#include "Graph.hh"
2026-04-13 14:58:16 -07:00
#include "GraphDelayCalc.hh"
2020-04-05 14:53:44 -07:00
#include "InputDrive.hh"
2026-04-13 14:58:16 -07:00
#include "Latches.hh"
#include "Liberty.hh"
#include "Mode.hh"
#include "Network.hh"
2020-04-05 14:53:44 -07:00
#include "Parasitics.hh"
2025-03-26 18:21:03 -07:00
#include "Path.hh"
2020-04-05 14:53:44 -07:00
#include "PathExpanded.hh"
2026-04-13 14:58:16 -07:00
#include "PathGroup.hh"
#include "PortDelay.hh"
#include "PortDirection.hh"
#include "Report.hh"
2026-01-03 16:59:35 -08:00
#include "Scene.hh"
2026-04-13 14:58:16 -07:00
#include "Sdc.hh"
#include "Search.hh"
#include "StringUtil.hh"
#include "Tag.hh"
#include "TimingArc.hh"
#include "TimingRole.hh"
#include "Transition.hh"
#include "Units.hh"
2025-04-09 16:35:15 -07:00
#include "Variables.hh"
2018-09-28 08:54:21 -07:00
namespace sta {
static void
hierPinsAbove(const Net *net,
const Network *network,
PinSeq &pins_above);
static void
hierPinsAbove(const Pin *pin,
const Network *network,
PinSeq &pins_above);
static PinSeq
hierPinsThruEdge(const Edge *edge,
const Network *network,
const Graph *graph);
2026-03-28 19:13:35 -07:00
ReportField::ReportField(std::string_view name,
2026-05-12 11:24:24 -07:00
std::string_view name_abrev,
2026-03-28 19:13:35 -07:00
std::string_view title,
size_t width,
2026-01-03 16:59:35 -08:00
bool left_justify,
Unit *unit,
2026-05-12 11:24:24 -07:00
ReportFieldGetValue get_value) :
2018-09-28 08:54:21 -07:00
name_(name),
2026-05-12 11:24:24 -07:00
name_abrev_(name_abrev),
2026-03-28 19:13:35 -07:00
title_(title),
2018-09-28 08:54:21 -07:00
left_justify_(left_justify),
unit_(unit),
2026-05-12 11:24:24 -07:00
get_value_(get_value)
2018-09-28 08:54:21 -07:00
{
setWidth(width);
}
void
2026-03-28 19:13:35 -07:00
ReportField::setProperties(std::string_view title,
size_t width,
2026-01-03 16:59:35 -08:00
bool left_justify)
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
title_ = std::string(title);
2018-09-28 08:54:21 -07:00
left_justify_ = left_justify;
setWidth(width);
}
void
2026-03-28 19:13:35 -07:00
ReportField::setWidth(size_t width)
2018-09-28 08:54:21 -07:00
{
width_ = width;
2026-03-28 19:13:35 -07:00
blank_.assign(width_, ' ');
2018-09-28 08:54:21 -07:00
}
void
ReportField::setEnabled(bool enabled)
{
enabled_ = enabled;
}
2026-05-12 11:24:24 -07:00
std::string
ReportField::value(const Path *path,
const StaState *sta) const
{
return get_value_(path, sta);
}
2018-09-28 08:54:21 -07:00
////////////////////////////////////////////////////////////////
ReportPath::ReportPath(StaState *sta) :
2026-04-13 14:58:16 -07:00
StaState(sta)
2018-09-28 08:54:21 -07:00
{
makeFields();
2026-05-12 11:24:24 -07:00
setReportFields({"incr", "total", "edge", "description"});
2026-03-13 14:06:35 -07:00
setDigits(2);
2018-09-28 08:54:21 -07:00
}
ReportPath::~ReportPath()
{
2026-05-12 11:24:24 -07:00
deleteContents(fields_);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::makeFields()
{
2026-03-13 14:06:35 -07:00
// The order corresponds to the default field order.
2026-05-12 11:24:24 -07:00
field_fanout_ = makeField("fanout", "fanout", "Fanout", 6, false, nullptr);
field_capacitance_ = makeField("capacitance", "cap", "Cap", 6, false,
units_->capacitanceUnit());
field_slew_ = makeField("slew", "slew", "Slew", 6, false, units_->timeUnit());
field_incr_ = makeField("incr", "incr", "Delay", 6, false, units_->timeUnit());
field_variation_ = makeField("variation", "var", "Variation", 6, false,
units_->timeUnit());
field_total_ = makeField("total", "total", "Time", 6, false, units_->timeUnit());
field_edge_ = makeField("edge", "edge", "", 1, false, nullptr);
field_case_ = makeField("case", "case", "case", 11, false, nullptr);
field_description_ = makeField("description", "desc", "Description", 36, true, nullptr);
field_src_attr_ = makeField("src_attr", "src", "Src Attr", 40, true, nullptr);
}
ReportField *
ReportPath::makeField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit)
{
return makeField(name, name_abrev, title, width, left_justify, unit, nullptr);
2018-09-28 08:54:21 -07:00
}
ReportField *
2026-03-28 19:13:35 -07:00
ReportPath::makeField(std::string_view name,
2026-05-12 11:24:24 -07:00
std::string_view name_abrev,
2026-03-28 19:13:35 -07:00
std::string_view title,
2026-05-12 11:24:24 -07:00
size_t width,
2026-01-03 16:59:35 -08:00
bool left_justify,
Unit *unit,
2026-05-12 11:24:24 -07:00
ReportFieldGetValue get_value)
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
ReportField *field = new ReportField(name, name_abrev, title, width, left_justify,
unit, get_value);
2019-02-16 12:07:59 -08:00
fields_.push_back(field);
2026-05-12 11:24:24 -07:00
field_map_[std::string(name)] = field;
2018-09-28 08:54:21 -07:00
return field;
}
ReportField *
2026-05-12 11:24:24 -07:00
ReportPath::findField(std::string_view name)
{
return findKey(field_map_, std::string(name));
}
ReportField *
ReportPath::findFieldAbrev(std::string_view name)
2018-09-28 08:54:21 -07:00
{
2025-02-01 14:53:28 -08:00
for (ReportField *field : fields_) {
2026-05-12 11:24:24 -07:00
const std::string &name_abrev = field->nameAbrev();
if (name.substr(0, name_abrev.size()) == name_abrev)
2019-12-24 08:53:45 -08:00
return field;
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
void
2026-03-08 15:51:50 -07:00
ReportPath::setReportFieldOrder(const StringSeq &field_names)
2018-09-28 08:54:21 -07:00
{
// Disable all fields.
2026-01-03 16:59:35 -08:00
for (ReportField *field : fields_)
2018-09-28 08:54:21 -07:00
field->setEnabled(false);
2019-02-16 12:07:59 -08:00
ReportFieldSeq next_fields;
2026-03-08 15:19:27 -07:00
for (const std::string &field_name : field_names) {
2026-03-28 19:13:35 -07:00
ReportField *field = findField(field_name);
2022-01-15 12:51:05 -07:00
if (field) {
next_fields.push_back(field);
field->setEnabled(true);
}
2018-09-28 08:54:21 -07:00
}
// Push remaining disabled fields on the end.
2025-02-01 14:53:28 -08:00
for (ReportField *field : fields_) {
2018-09-28 08:54:21 -07:00
if (!field->enabled())
2019-02-16 12:07:59 -08:00
next_fields.push_back(field);
}
2026-05-12 11:24:24 -07:00
fields_ = next_fields;
2018-09-28 08:54:21 -07:00
}
void
2026-05-12 11:24:24 -07:00
ReportPath::setReportFields(const StringSeq &fields)
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
for (ReportField *field : fields_)
field->setEnabled(false);
field_incr_->setEnabled(true);
field_total_->setEnabled(true);
field_description_->setEnabled(true);
field_edge_->setEnabled(true);
// These are not real fields; they are flags.
report_input_pin_ = false;
report_hier_pins_ = false;
report_net_ = false;
for (const std::string &field_name : fields) {
if (field_name == "input_pin")
report_input_pin_ = true;
else if (field_name == "hierarchical_pin")
report_hier_pins_ = true;
else if (field_name == "net")
report_net_ = true;
else {
ReportField *field = findField(field_name);
if (field)
field->setEnabled(true);
else
report_->warn(2720, "unknown path reporting field {}.", field_name);
}
}
2018-09-28 08:54:21 -07:00
}
void
ReportPath::setPathFormat(ReportPathFormat format)
{
format_ = format;
}
void
ReportPath::setNoSplit(bool no_split)
{
no_split_ = no_split;
}
void
ReportPath::setDigits(int digits)
{
digits_ = digits;
2026-03-15 14:35:24 -07:00
minus_zero_ = sta::formatRuntime("-{:.{}f}", 0.0, digits_);
plus_zero_ = sta::formatRuntime("{:.{}f}", 0.0, digits_);
2018-09-28 08:54:21 -07:00
2026-03-13 14:06:35 -07:00
// Numeric field width expands with digits.
int field_width = digits + field_width_extra_;
field_capacitance_->setWidth(field_width);
field_slew_->setWidth(field_width);
field_variation_->setWidth(field_width);
field_incr_->setWidth(field_width);
field_total_->setWidth(field_width);
2019-12-24 08:53:45 -08:00
}
2018-09-28 08:54:21 -07:00
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathEnd(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2024-09-16 17:04:31 -07:00
reportPathEnd(end, nullptr, true);
2018-12-20 22:41:54 -08:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathEnd(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathEnd *prev_end,
2025-02-01 14:53:28 -08:00
bool last) const
2018-12-20 22:41:54 -08:00
{
2018-09-28 08:54:21 -07:00
switch (format_) {
2019-03-12 17:25:53 -07:00
case ReportPathFormat::full:
case ReportPathFormat::full_clock:
case ReportPathFormat::full_clock_expanded:
2020-12-28 19:51:34 -08:00
end->reportFull(this);
reportBlankLine();
reportBlankLine();
2018-09-28 08:54:21 -07:00
break;
2019-03-12 17:25:53 -07:00
case ReportPathFormat::shorter:
2020-12-28 19:51:34 -08:00
end->reportShort(this);
reportBlankLine();
reportBlankLine();
2018-09-28 08:54:21 -07:00
break;
2019-03-12 17:25:53 -07:00
case ReportPathFormat::endpoint:
2018-12-20 22:41:54 -08:00
reportEndpointHeader(end, prev_end);
2020-12-28 19:51:34 -08:00
reportEndLine(end);
2018-09-28 08:54:21 -07:00
break;
2019-03-12 17:25:53 -07:00
case ReportPathFormat::summary:
2020-12-28 18:04:49 -08:00
reportSummaryLine(end);
2018-09-28 08:54:21 -07:00
break;
2019-03-12 17:25:53 -07:00
case ReportPathFormat::slack_only:
2020-12-28 18:04:49 -08:00
reportSlackOnly(end);
2018-09-28 08:54:21 -07:00
break;
2024-09-16 17:04:31 -07:00
case ReportPathFormat::json:
reportJson(end, last);
2018-09-28 08:54:21 -07:00
break;
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathEnds(const PathEndSeq *ends) const
2018-09-28 08:54:21 -07:00
{
2018-12-20 22:41:54 -08:00
reportPathEndHeader();
2025-01-16 15:32:53 -08:00
if (ends && !ends->empty()) {
2026-01-03 16:59:35 -08:00
const PathEnd *prev_end = nullptr;
for (size_t i = 0; i < ends->size(); i++) {
const PathEnd *end = (*ends)[i];
reportPathEnd(end, prev_end, i == ends->size() - 1);
prev_end = end;
}
2018-09-28 08:54:21 -07:00
}
2025-01-16 15:32:53 -08:00
else {
if (format_ != ReportPathFormat::json)
2026-03-15 14:35:24 -07:00
report_->report("No paths found.");
2025-01-16 15:32:53 -08:00
}
2018-12-20 22:41:54 -08:00
reportPathEndFooter();
2018-09-28 08:54:21 -07:00
}
2024-09-16 17:04:31 -07:00
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathEndHeader() const
2024-09-16 17:04:31 -07:00
{
switch (format_) {
case ReportPathFormat::full:
case ReportPathFormat::full_clock:
case ReportPathFormat::full_clock_expanded:
case ReportPathFormat::shorter:
case ReportPathFormat::endpoint:
break;
case ReportPathFormat::summary:
reportSummaryHeader();
break;
case ReportPathFormat::slack_only:
reportSlackOnlyHeader();
break;
case ReportPathFormat::json:
reportJsonHeader();
break;
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathEndFooter() const
2024-09-16 17:04:31 -07:00
{
switch (format_) {
case ReportPathFormat::full:
case ReportPathFormat::full_clock:
case ReportPathFormat::full_clock_expanded:
case ReportPathFormat::shorter:
break;
case ReportPathFormat::endpoint:
case ReportPathFormat::summary:
case ReportPathFormat::slack_only:
reportBlankLine();
break;
case ReportPathFormat::json:
reportJsonFooter();
break;
}
}
2018-09-28 08:54:21 -07:00
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpointHeader(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathEnd *prev_end) const
2018-09-28 08:54:21 -07:00
{
2019-03-12 17:25:53 -07:00
PathGroup *prev_group = nullptr;
2018-12-20 22:41:54 -08:00
if (prev_end)
prev_group = prev_end->pathGroup();
PathGroup *group = end->pathGroup();
2022-01-15 12:51:05 -07:00
if (group && group != prev_group) {
2018-12-20 22:41:54 -08:00
if (prev_group)
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-12-20 22:41:54 -08:00
const char *setup_hold = (end->minMax(this) == MinMax::min())
? "min_delay/hold"
: "max_delay/setup";
2026-03-15 14:35:24 -07:00
report_->report("{} group {}", setup_hold, group->name());
2020-12-28 19:51:34 -08:00
reportBlankLine();
2020-12-28 18:04:49 -08:00
reportEndHeader();
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndUnconstrained *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndUnconstrained *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportUnclockedEndpoint(end, "internal pin");
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndUnconstrained *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportBlankLine();
2018-09-28 08:54:21 -07:00
2020-12-28 19:51:34 -08:00
reportPath(end, expanded);
2018-11-26 09:15:52 -08:00
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
2026-01-03 16:59:35 -08:00
end->pathEarlyLate(this));
2020-12-28 19:51:34 -08:00
reportDashLine();
2026-03-15 14:35:24 -07:00
report_->report("(Path is unconstrained)");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndCheck *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportEndpoint(end);
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportSrcPathArrival(end, expanded);
reportTgtClk(end);
reportRequired(end, checkRoleString(end));
reportSlack(end);
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::checkRoleString(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
return sta::format("library {} time",
end->checkRole(this)->to_string());
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndCheck *end) const
2018-09-28 08:54:21 -07:00
{
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-28 19:13:35 -07:00
std::string inst_name = cmd_network_->pathName(inst);
2026-03-02 12:13:13 -08:00
std::string clk_name = tgtClkName(end);
2026-03-28 19:13:35 -07:00
std::string_view rise_fall = asRisingFalling(end->targetClkEndTrans(this));
2018-09-28 08:54:21 -07:00
const TimingRole *check_role = end->checkRole(this);
const TimingRole *check_generic_role = check_role->genericRole();
if (check_role == TimingRole::recovery()
|| check_role == TimingRole::removal()) {
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} check against {}-edge clock {}",
check_role->to_string(),
rise_fall,
clk_name);
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
else if (check_generic_role == TimingRole::setup()
2026-01-03 16:59:35 -08:00
|| check_generic_role == TimingRole::hold()) {
2018-09-28 08:54:21 -07:00
LibertyCell *cell = network_->libertyCell(inst);
if (cell->isClockGate()) {
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clock gating-check end-point clocked by {}",
rise_fall, clk_name);
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
else {
2026-03-28 19:13:35 -07:00
std::string_view reg_desc = clkRegLatchDesc(end);
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name);
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
}
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndLatchCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndLatchCheck *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportEndpoint(end);
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndLatchCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportBlankLine();
2018-09-28 08:54:21 -07:00
PathDelay *path_delay = end->pathDelay();
bool ignore_clk_latency = path_delay && path_delay->ignoreClkLatency();
if (ignore_clk_latency) {
// Based on reportSrcPath.
2020-12-28 19:51:34 -08:00
reportPathHeader();
2025-08-18 13:27:30 -07:00
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportSrcPath(end, expanded);
reportLine("data arrival time", end->dataArrivalTimeOffset(this), early_late);
reportBlankLine();
2018-09-28 08:54:21 -07:00
Required req_time;
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
end->latchRequired(this, req_time, borrow, adjusted_data_arrival,
2026-01-03 16:59:35 -08:00
time_given_to_startpoint);
2018-09-28 08:54:21 -07:00
// Adjust required to requiredTimeOffset.
2026-03-13 14:06:35 -07:00
req_time = delaySum(req_time, end->sourceClkOffset(this), this);
2018-09-28 08:54:21 -07:00
if (path_delay) {
float delay = path_delay->delay();
2020-12-28 19:51:34 -08:00
reportLine("max_delay", delay, delay, early_late);
2018-09-28 08:54:21 -07:00
if (!ignore_clk_latency) {
if (reportClkPath()
2026-01-03 16:59:35 -08:00
&& isPropagated(end->targetClkPath()))
reportTgtClk(end, delay);
2018-11-26 09:15:52 -08:00
else {
2026-01-03 16:59:35 -08:00
Delay delay1(delay);
reportCommonClkPessimism(end, delay1);
2018-11-26 09:15:52 -08:00
}
2018-09-28 08:54:21 -07:00
}
}
else
2020-12-28 19:51:34 -08:00
reportTgtClk(end);
2018-09-28 08:54:21 -07:00
2020-07-11 17:43:30 -07:00
if (delayGreaterEqual(borrow, 0.0, this))
2020-12-28 19:51:34 -08:00
reportLine("time borrowed from endpoint", borrow, req_time, early_late);
2018-09-28 08:54:21 -07:00
else
2020-12-28 19:51:34 -08:00
reportLine("time given to endpoint", borrow, req_time, early_late);
reportLine("data required time", req_time, early_late);
reportDashLine();
reportSlack(end);
2018-09-28 08:54:21 -07:00
if (end->checkGenericRole(this) == TimingRole::setup()
&& !ignore_clk_latency) {
2020-12-28 19:51:34 -08:00
reportBlankLine();
reportBorrowing(end, borrow, time_given_to_startpoint);
2018-09-28 08:54:21 -07:00
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndLatchCheck *end) const
2018-09-28 08:54:21 -07:00
{
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-02 12:13:13 -08:00
std::string clk_name = tgtClkName(end);
2026-03-28 19:13:35 -07:00
std::string_view reg_desc = latchDesc(end);
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name);
2026-03-28 19:13:35 -07:00
std::string inst_name = cmd_network_->pathName(inst);
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::latchDesc(const PathEndLatchCheck *end) const
2018-09-28 08:54:21 -07:00
{
TimingArc *check_arc = end->checkArc();
2024-07-07 17:56:55 -07:00
const RiseFall *en_rf = check_arc->fromEdge()->asRiseFall()->opposite();
return latchDesc(en_rf);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportBorrowing(const PathEndLatchCheck *end,
2026-01-03 16:59:35 -08:00
Arrival &borrow,
Arrival &time_given_to_startpoint) const
2018-09-28 08:54:21 -07:00
{
Delay open_latency, latency_diff, max_borrow;
2018-12-11 10:47:04 -08:00
float nom_pulse_width, open_uncertainty;
Crpr open_crpr, crpr_diff;
2018-09-28 08:54:21 -07:00
bool borrow_limit_exists;
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = EarlyLate::late();
2018-09-28 08:54:21 -07:00
end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff,
2026-01-03 16:59:35 -08:00
open_uncertainty, open_crpr, crpr_diff,
max_borrow, borrow_limit_exists);
2026-03-15 14:35:24 -07:00
report_->report("Time Borrowing Information");
2020-12-28 19:51:34 -08:00
reportDashLineTotal();
2018-09-28 08:54:21 -07:00
if (borrow_limit_exists)
2020-12-28 19:51:34 -08:00
reportLineTotal("user max time borrow", max_borrow, early_late);
2018-09-28 08:54:21 -07:00
else {
2026-03-02 12:13:13 -08:00
std::string tgt_clk_name = tgtClkName(end);
2018-09-28 08:54:21 -07:00
Arrival tgt_clk_width = end->targetClkWidth(this);
const Path *tgt_clk_path = end->targetClkPath();
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
2026-03-15 14:35:24 -07:00
std::string width_msg = sta::format("{} nominal pulse width", tgt_clk_name);
2026-03-28 19:13:35 -07:00
reportLineTotal(width_msg, nom_pulse_width, early_late);
2026-03-13 14:06:35 -07:00
if (!delayZero(latency_diff, this))
2026-01-03 16:59:35 -08:00
reportLineTotalMinus("clock latency difference", latency_diff, early_late);
2018-09-28 08:54:21 -07:00
}
else {
2026-03-28 19:13:35 -07:00
std::string width_msg = sta::format("{} pulse width", tgt_clk_name);
reportLineTotal(width_msg, tgt_clk_width, early_late);
2018-09-28 08:54:21 -07:00
}
ArcDelay margin = end->margin(this);
2020-12-28 19:51:34 -08:00
reportLineTotalMinus("library setup time", margin, early_late);
reportDashLineTotal();
2026-03-13 14:06:35 -07:00
if (!delayZero(crpr_diff, this))
2020-12-28 19:51:34 -08:00
reportLineTotalMinus("CRPR difference", crpr_diff, early_late);
reportLineTotal("max time borrow", max_borrow, early_late);
2018-09-28 08:54:21 -07:00
}
2020-07-11 17:43:30 -07:00
if (delayGreater(borrow, delay_zero, this)
2018-09-28 08:54:21 -07:00
&& (!fuzzyZero(open_uncertainty)
2026-03-13 14:06:35 -07:00
|| !delayZero(open_crpr, this))) {
2020-12-28 19:51:34 -08:00
reportDashLineTotal();
reportLineTotal("actual time borrow", borrow, early_late);
2018-09-28 08:54:21 -07:00
if (!fuzzyZero(open_uncertainty))
2020-12-28 19:51:34 -08:00
reportLineTotal("open edge uncertainty", open_uncertainty, early_late);
2026-03-13 14:06:35 -07:00
if (!delayZero(open_crpr, this))
2020-12-28 19:51:34 -08:00
reportLineTotal("open edge CRPR", open_crpr, early_late);
reportDashLineTotal();
reportLineTotal("time given to startpoint", time_given_to_startpoint, early_late);
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportLineTotal("actual time borrow", borrow, early_late);
reportDashLineTotal();
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndPathDelay *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndPathDelay *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
2018-09-28 08:54:21 -07:00
if (end->targetClk(this))
2020-12-28 19:51:34 -08:00
reportEndpoint(end);
2018-09-28 08:54:21 -07:00
else
2020-12-28 19:51:34 -08:00
reportUnclockedEndpoint(end, "internal path endpoint");
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndPathDelay *end) const
2018-09-28 08:54:21 -07:00
{
if (end->hasOutputDelay())
2020-12-28 19:51:34 -08:00
reportEndpointOutputDelay(end);
else {
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clocked by {}",
clkRegLatchDesc(end),
tgtClkName(end));
2026-03-28 19:13:35 -07:00
reportEndpoint(cmd_network_->pathName(inst), reason);
}
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndPathDelay *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
2018-09-28 08:54:21 -07:00
// Based on reportSrcPathArrival.
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
PathDelay *path_delay = end->pathDelay();
if (end->ignoreClkLatency(this)) {
2018-09-28 08:54:21 -07:00
// Based on reportSrcPath.
2020-12-28 19:51:34 -08:00
reportPathHeader();
2025-08-18 13:27:30 -07:00
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportSrcPath(end, expanded);
reportLine("data arrival time", end->dataArrivalTimeOffset(this), early_late);
reportBlankLine();
2018-09-28 08:54:21 -07:00
ArcDelay margin = end->margin(this);
2025-03-30 15:27:53 -07:00
const MinMax *min_max = path_delay->minMax()->asMinMax();
2018-09-28 08:54:21 -07:00
if (min_max == MinMax::max())
2026-03-13 14:06:35 -07:00
margin = delayDiff(delay_zero, margin, this);
2018-09-28 08:54:21 -07:00
2026-03-02 12:13:13 -08:00
std::string delay_msg = min_max->to_string() + "_delay";
2018-09-28 08:54:21 -07:00
float delay = path_delay->delay();
2026-03-28 19:13:35 -07:00
reportLine(delay_msg, delay, delay, early_late);
2018-09-28 08:54:21 -07:00
if (!path_delay->ignoreClkLatency()) {
2023-01-19 11:23:45 -07:00
const Clock *tgt_clk = end->targetClk(this);
if (tgt_clk) {
const Path *tgt_clk_path = end->targetClkPath();
2018-09-28 08:54:21 -07:00
if (reportClkPath()
2026-01-03 16:59:35 -08:00
&& isPropagated(tgt_clk_path, tgt_clk))
reportTgtClk(end, delay, 0.0, true);
2018-09-28 08:54:21 -07:00
else {
2026-01-03 16:59:35 -08:00
Arrival tgt_clk_delay = end->targetClkDelay(this);
2026-03-13 14:06:35 -07:00
Arrival tgt_clk_arrival = delaySum(tgt_clk_delay, delay, this);
if (!delayZero(tgt_clk_delay, this))
2026-01-03 16:59:35 -08:00
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
tgt_clk_delay, tgt_clk_arrival, early_late);
reportClkUncertainty(end, tgt_clk_arrival);
reportCommonClkPessimism(end, tgt_clk_arrival);
2018-09-28 08:54:21 -07:00
}
}
}
2019-01-16 15:37:31 -08:00
if (end->pathDelayMarginIsExternal())
2020-12-28 19:51:34 -08:00
reportRequired(end, "output external delay");
2019-01-16 15:37:31 -08:00
else
2020-12-28 19:51:34 -08:00
reportRequired(end, checkRoleString(end));
reportSlack(end);
2018-09-28 08:54:21 -07:00
}
bool
2025-02-01 14:53:28 -08:00
ReportPath::isPropagated(const Path *clk_path) const
2018-09-28 08:54:21 -07:00
{
return clk_path->clkInfo(search_)->isPropagated();
}
bool
ReportPath::isPropagated(const Path *clk_path,
2026-01-03 16:59:35 -08:00
const Clock *clk) const
2018-09-28 08:54:21 -07:00
{
if (clk_path)
return clk_path->clkInfo(search_)->isPropagated();
else
return clk->isPropagated();
}
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::clkNetworkDelayIdealProp(bool is_prop) const
2018-09-28 08:54:21 -07:00
{
if (is_prop)
return "clock network delay (propagated)";
else
return "clock network delay (ideal)";
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndOutputDelay *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndOutputDelay *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportEndpoint(end);
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndOutputDelay *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportSrcPathArrival(end, expanded);
reportTgtClk(end);
reportRequired(end, "output external delay");
reportSlack(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndOutputDelay *end) const
{
2020-12-28 19:51:34 -08:00
reportEndpointOutputDelay(end);
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end) const
2018-09-28 08:54:21 -07:00
{
Vertex *vertex = end->vertex(this);
Pin *pin = vertex->pin();
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(pin);
2023-01-19 11:23:45 -07:00
const Clock *tgt_clk = end->targetClk(this);
2018-09-28 08:54:21 -07:00
if (network_->isTopLevelPort(pin)) {
// Pin direction is "output" even for bidirects.
if (tgt_clk) {
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("output port clocked by {}",
tgtClkName(end));
2020-12-28 19:51:34 -08:00
reportEndpoint(pin_name, reason);
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportEndpoint(pin_name, "output port");
2018-09-28 08:54:21 -07:00
}
else {
if (tgt_clk) {
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("internal path endpoint clocked by {}",
tgtClkName(end));
2020-12-28 19:51:34 -08:00
reportEndpoint(pin_name, reason);
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportEndpoint(pin_name, "internal path endpoint");
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndGatedClock *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndGatedClock *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportEndpoint(end);
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndGatedClock *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportSrcPathArrival(end, expanded);
reportTgtClk(end);
reportRequired(end, checkRoleReason(end));
reportSlack(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndGatedClock *end) const
2018-09-28 08:54:21 -07:00
{
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-28 19:13:35 -07:00
const std::string inst_name = cmd_network_->pathName(inst);
2019-11-11 15:30:19 -07:00
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
2026-03-15 14:35:24 -07:00
const RiseFall *clk_rf = (end->minMax(this) == MinMax::max())
? clk_end_rf
: clk_end_rf->opposite();
2018-09-28 08:54:21 -07:00
// Note that target clock transition is ignored.
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clock gating-check end-point clocked by {}",
asRisingFalling(clk_rf),
tgtClkName(end));
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportShort(const PathEndDataCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportShort(const PathEndDataCheck *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartpoint(end, expanded);
reportEndpoint(end);
reportGroup(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportFull(const PathEndDataCheck *end) const
2018-09-28 08:54:21 -07:00
{
PathExpanded expanded(end->path(), this);
2020-12-28 19:51:34 -08:00
reportShort(end, expanded);
reportSrcPathArrival(end, expanded);
2018-09-28 08:54:21 -07:00
// Data check target clock path reporting resembles
// both source (reportSrcPath) and target (reportTgtClk) clocks.
2018-09-28 08:54:21 -07:00
// It is like a source because it can be a non-clock path.
// It is like a target because crpr and uncertainty are reported.
// It is always propagated, even if the clock is ideal.
2020-12-28 19:51:34 -08:00
reportTgtClk(end, 0.0, true);
2025-03-26 18:21:03 -07:00
const Path *data_clk_path = end->dataClkPath();
2018-09-28 08:54:21 -07:00
if (!data_clk_path->isClock(this)) {
// Report the path from the clk network to the data check.
PathExpanded clk_expanded(data_clk_path, this);
float src_offset = end->sourceClkOffset(this);
2018-11-26 09:15:52 -08:00
Delay clk_delay = end->targetClkDelay(this);
2026-03-13 14:06:35 -07:00
const MinMax *min_max = data_clk_path->minMax(this);
2018-11-26 09:15:52 -08:00
Arrival clk_arrival = end->targetClkArrival(this);
2023-01-19 11:23:45 -07:00
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
2026-03-13 14:06:35 -07:00
float prev = delayAsFloat(clk_arrival, min_max, this) + src_offset;
float offset = prev - delayAsFloat(clk_delay, min_max, this) - tgt_clk_edge->time();
2025-08-18 13:27:30 -07:00
// Delay to startpoint is already included.
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
2026-01-03 16:59:35 -08:00
true, false, prev, offset);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportRequired(end, checkRoleReason(end));
reportSlack(end);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndpoint(const PathEndDataCheck *end) const
2018-09-28 08:54:21 -07:00
{
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-28 19:13:35 -07:00
const std::string inst_name = cmd_network_->pathName(inst);
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} edge-triggered data to data check clocked by {}",
asRisingFalling(end->dataClkPath()->transition(this)),
end->targetClk(this)->name());
2020-12-28 19:51:34 -08:00
reportEndpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndHeader() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-09-28 08:54:21 -07:00
// Line one.
2020-12-28 18:04:49 -08:00
reportDescription("", line);
line += ' ';
reportField("Required", field_total_, line);
line += ' ';
reportField("Actual", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
// Line two.
2020-12-28 18:04:49 -08:00
line.clear();
reportDescription("Endpoint", line);
line += ' ';
reportField("Delay", field_total_, line);
line += ' ';
reportField("Delay", field_total_, line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportEndLine(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
std::string endpoint = pathEndpoint(end);
2026-03-28 19:13:35 -07:00
reportDescription(endpoint, line);
2020-12-28 19:51:34 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, line);
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
reportSpaceSlack(end, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSummaryHeader() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("Startpoint", line);
line += ' ';
reportDescription("Endpoint", line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() * 2 + field_total_->width() + 1);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSummaryLine(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-09-28 08:54:21 -07:00
PathExpanded expanded(end->path(), this);
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
2026-03-15 14:35:24 -07:00
std::string startpoint = pathStartpoint(end, expanded);
2026-03-28 19:13:35 -07:00
reportDescription(startpoint, line);
2020-12-28 18:04:49 -08:00
line += ' ';
2026-03-15 14:35:24 -07:00
std::string endpoint = pathEndpoint(end);
2026-03-28 19:13:35 -07:00
reportDescription(endpoint, line);
2018-09-28 08:54:21 -07:00
if (end->isUnconstrained())
2020-12-28 18:04:49 -08:00
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
2018-09-28 08:54:21 -07:00
else
2022-06-10 19:37:33 -07:00
reportSpaceFieldDelay(end->slack(this), EarlyLate::early(), line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::pathStartpoint(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
const Path *start = expanded.startPath();
2018-09-28 08:54:21 -07:00
Pin *pin = start->pin(graph_);
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(pin);
2018-09-28 08:54:21 -07:00
if (network_->isTopLevelPort(pin)) {
PortDirection *dir = network_->direction(pin);
2026-03-15 14:35:24 -07:00
return sta::format("{} ({})", pin_name, dir->name());
2018-09-28 08:54:21 -07:00
}
else {
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-28 19:13:35 -07:00
std::string cell_name = cmd_network_->name(network_->cell(inst));
2026-03-15 14:35:24 -07:00
return sta::format("{} ({})", pin_name, cell_name);
2018-09-28 08:54:21 -07:00
}
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::pathEndpoint(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
Pin *pin = end->vertex(this)->pin();
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(pin);
2018-09-28 08:54:21 -07:00
if (network_->isTopLevelPort(pin)) {
PortDirection *dir = network_->direction(pin);
2026-03-15 14:35:24 -07:00
return sta::format("{} ({})", pin_name, dir->name());
2018-09-28 08:54:21 -07:00
}
else {
Instance *inst = network_->instance(end->vertex(this)->pin());
2026-03-28 19:13:35 -07:00
std::string cell_name = cmd_network_->name(network_->cell(inst));
2026-03-15 14:35:24 -07:00
return sta::format("{} ({})", pin_name, cell_name);
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
2024-09-16 17:04:31 -07:00
void
2025-02-01 14:53:28 -08:00
ReportPath::reportJsonHeader() const
2024-09-16 17:04:31 -07:00
{
2026-03-20 10:14:57 -07:00
report_->report("{{\"checks\": [");
2024-09-16 17:04:31 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportJsonFooter() const
2024-09-16 17:04:31 -07:00
{
2026-03-15 14:35:24 -07:00
report_->report("]");
2026-03-20 10:14:57 -07:00
report_->report("}}");
2024-09-16 17:04:31 -07:00
}
void
ReportPath::reportJson(const PathEnd *end,
2025-02-01 14:53:28 -08:00
bool last) const
2024-09-16 17:04:31 -07:00
{
2026-03-02 12:13:13 -08:00
std::string result;
2024-09-16 17:04:31 -07:00
result += "{\n";
2026-03-08 16:39:48 -07:00
result += " \"type\": \"";
result += end->typeName();
result += "\",\n";
result += " \"path_group\": \"";
result += end->pathGroup()->name();
result += "\",\n";
result += " \"path_type\": \"";
result += end->minMax(this)->to_string();
result += "\",\n";
2024-09-16 17:04:31 -07:00
PathExpanded expanded(end->path(), this);
const Pin *startpoint = expanded.startPath()->vertex(this)->pin();
const Pin *endpoint = expanded.endPath()->vertex(this)->pin();
2026-03-15 14:35:24 -07:00
result += sta::format(" \"startpoint\": \"{}\",\n",
sdc_network_->pathName(startpoint));
2026-03-15 14:35:24 -07:00
result += sta::format(" \"endpoint\": \"{}\",\n",
sdc_network_->pathName(endpoint));
2024-09-16 17:04:31 -07:00
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
const Path *src_clk_path = expanded.clkPath();
2025-03-26 18:21:03 -07:00
const Path *tgt_clk_path = end->targetClkPath();
2024-09-16 17:04:31 -07:00
if (src_clk_edge) {
2026-03-15 14:35:24 -07:00
result += sta::format(" \"source_clock\": \"{}\",\n",
2024-09-16 17:04:31 -07:00
src_clk_edge->clock()->name());
2026-03-15 14:35:24 -07:00
result += sta::format(" \"source_clock_edge\": \"{}\",\n",
2024-09-16 17:04:31 -07:00
src_clk_edge->transition()->name());
}
if (src_clk_path)
reportJson(src_clk_path, "source_clock_path", 2, true, result);
2024-09-16 17:04:31 -07:00
reportJson(expanded, "source_path", 2, !end->isUnconstrained(), result);
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
if (tgt_clk_edge) {
2026-03-15 14:35:24 -07:00
result += sta::format(" \"target_clock\": \"{}\",\n",
2024-09-16 17:04:31 -07:00
tgt_clk_edge->clock()->name());
2026-03-15 14:35:24 -07:00
result += sta::format(" \"target_clock_edge\": \"{}\",\n",
2024-09-16 17:04:31 -07:00
tgt_clk_edge->transition()->name());
}
if (tgt_clk_path)
reportJson(end->targetClkPath(), "target_clock_path", 2, true, result);
if (end->checkRole(this)) {
2026-03-15 14:35:24 -07:00
result += sta::format(" \"data_arrival_time\": {:.3e},\n",
2024-11-15 15:58:52 -08:00
delayAsFloat(end->dataArrivalTimeOffset(this)));
2024-09-16 17:04:31 -07:00
const MultiCyclePath *mcp = end->multiCyclePath();
if (mcp)
2026-03-15 14:35:24 -07:00
result += sta::format(" \"multi_cycle_path\": {},\n",
2024-09-16 17:04:31 -07:00
mcp->pathMultiplier());
PathDelay *path_delay = end->pathDelay();
if (path_delay)
2026-03-15 14:35:24 -07:00
result += sta::format(" \"path_delay\": {:.3e},\n",
2024-09-16 17:04:31 -07:00
path_delay->delay());
2026-03-15 14:35:24 -07:00
result += sta::format(" \"crpr\": {:.3e},\n",
2024-11-15 15:58:52 -08:00
delayAsFloat(end->checkCrpr(this)));
2026-03-15 14:35:24 -07:00
result += sta::format(" \"margin\": {:.3e},\n",
2024-11-15 15:58:52 -08:00
delayAsFloat(end->margin(this)));
2026-03-15 14:35:24 -07:00
result += sta::format(" \"required_time\": {:.3e},\n",
2024-11-15 15:58:52 -08:00
delayAsFloat(end->requiredTimeOffset(this)));
2026-03-15 14:35:24 -07:00
result += sta::format(" \"slack\": {:.3e}\n",
2024-11-15 15:58:52 -08:00
delayAsFloat(end->slack(this)));
2024-09-16 17:04:31 -07:00
}
result += "}";
if (!last)
result += ",";
2026-03-15 14:35:24 -07:00
report_->reportLine(result);
2024-09-16 17:04:31 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportJson(const Path *path) const
2024-09-16 17:04:31 -07:00
{
2026-03-02 12:13:13 -08:00
std::string result;
2024-09-16 17:04:31 -07:00
result += "{\n";
reportJson(path, "path", 0, false, result);
result += "}\n";
2026-03-15 14:35:24 -07:00
report_->reportLine(result);
2024-09-16 17:04:31 -07:00
}
void
ReportPath::reportJson(const Path *path,
2026-03-28 19:13:35 -07:00
std::string_view path_name,
2024-09-16 17:04:31 -07:00
int indent,
bool trailing_comma,
2026-03-02 12:13:13 -08:00
std::string &result) const
2024-09-16 17:04:31 -07:00
{
PathExpanded expanded(path, this);
reportJson(expanded, path_name, indent, trailing_comma, result);
}
void
ReportPath::reportJson(const PathExpanded &expanded,
2026-03-28 19:13:35 -07:00
std::string_view path_name,
2024-09-16 17:04:31 -07:00
int indent,
bool trailing_comma,
2026-03-02 12:13:13 -08:00
std::string &result) const
2024-09-16 17:04:31 -07:00
{
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}}\"{}\": [\n", "", indent, path_name);
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
2025-03-26 18:21:03 -07:00
const Path *path = expanded.path(i);
2024-09-16 17:04:31 -07:00
const Pin *pin = path->vertex(this)->pin();
const Net *net = network_->net(pin);
const Instance *inst = network_->instance(pin);
const RiseFall *rf = path->transition(this);
2026-01-03 16:59:35 -08:00
const Scene *scene = path->scene(this);
const MinMax *min_max = path->minMax(this);
bool is_driver = network_->isDriver(pin);
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} {{\n", "", indent);
if (inst) {
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"instance\": \"{}\",\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->pathName(inst));
Cell *cell = network_->cell(inst);
if (cell)
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"cell\": \"{}\",\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->name(cell));
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"verilog_src\": \"{}\",\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->getAttribute(inst, "src"));
}
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"pin\": \"{}\",\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->pathName(pin));
if (net) {
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"net\": \"{}\",\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->pathName(net));
}
PinSeq pins_above;
hierPinsAbove(pin, network_, pins_above);
if (!pins_above.empty()) {
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"hier_pins\": [\n", "", indent);
for (const Pin *hpin : pins_above) {
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"{}\"{}\n",
2026-03-28 19:13:35 -07:00
"", indent,
sdc_network_->pathName(hpin),
(hpin != pins_above.back()) ? "," : "");
}
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} ],\n", "", indent);
}
2024-09-16 17:04:31 -07:00
double x, y;
bool exists;
network_->location(pin, x, y, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"x\": {:.9f},\n", "", indent, x);
result += sta::format("{:>{}} \"y\": {:.9f},\n", "", indent, y);
2024-09-16 17:04:31 -07:00
}
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"arrival\": {:.3e},\n",
2026-03-28 19:13:35 -07:00
"", indent,
delayAsFloat(path->arrival()));
if (is_driver)
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"capacitance\": {:.3e},\n",
2026-03-28 19:13:35 -07:00
"", indent,
graph_delay_calc_->loadCap(pin, rf, scene, min_max));
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} \"slew\": {:.3e}\n",
2026-03-28 19:13:35 -07:00
"", indent,
delayAsFloat(path->slew(this)));
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}} }}{}\n",
2026-03-28 19:13:35 -07:00
"", indent,
(i < expanded.size() - 1) ? "," : "");
2024-09-16 17:04:31 -07:00
}
2026-03-15 14:35:24 -07:00
result += sta::format("{:>{}}]{}\n",
2026-03-28 19:13:35 -07:00
"", indent,
trailing_comma ? "," : "");
2024-09-16 17:04:31 -07:00
}
////////////////////////////////////////////////////////////////
2018-09-28 08:54:21 -07:00
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSlackOnlyHeader() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("Group", line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field_total_->width() + 1);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSlackOnly(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
2026-03-28 19:13:35 -07:00
reportDescription(end->pathGroup()->name(), line);
2018-09-28 08:54:21 -07:00
if (end->isUnconstrained())
2020-12-28 18:04:49 -08:00
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
2018-09-28 08:54:21 -07:00
else
2020-12-28 18:04:49 -08:00
reportSpaceFieldDelay(end->slack(this), early_late, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2026-01-03 16:59:35 -08:00
ReportPath::reportMpwCheck(const MinPulseWidthCheck &check,
bool verbose) const
2018-09-28 08:54:21 -07:00
{
if (verbose) {
2020-12-28 18:04:49 -08:00
reportVerbose(check);
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
else {
2020-12-28 18:04:49 -08:00
reportMpwHeaderShort();
reportShort(check);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportMpwChecks(const MinPulseWidthCheckSeq &checks,
bool verbose) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
if (!checks.empty()) {
2018-09-28 08:54:21 -07:00
if (verbose) {
2026-01-03 16:59:35 -08:00
for (const MinPulseWidthCheck &check : checks) {
2025-02-01 14:53:28 -08:00
reportVerbose(check);
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
}
else {
2020-12-28 18:04:49 -08:00
reportMpwHeaderShort();
2026-01-03 16:59:35 -08:00
for (const MinPulseWidthCheck &check : checks)
reportShort(check);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportMpwHeaderShort() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("", line);
line += ' ';
reportField("Required", field_total_, line);
line += ' ';
reportField("Actual", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line.clear();
reportDescription("Pin", line);
line += ' ';
reportField("Width", field_total_, line);
line += ' ';
reportField("Width", field_total_, line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportShort(const MinPulseWidthCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2026-03-15 14:35:24 -07:00
std::string what = sta::format("{} ({})",
cmd_network_->pathName(check.pin(this)),
mpwCheckHiLow(check));
2026-03-28 19:13:35 -07:00
reportDescription(what, line);
2026-01-03 16:59:35 -08:00
reportSpaceFieldTime(check.minWidth(this), line);
reportSpaceFieldDelay(check.width(this), EarlyLate::late(), line);
reportSpaceSlack(check.slack(this), line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportVerbose(const MinPulseWidthCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(check.pin(this));
std::string line = "Pin: " + pin_name;
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2026-03-15 14:35:24 -07:00
report_->report("Check: sequential_clock_pulse_width");
2020-12-28 19:51:34 -08:00
reportBlankLine();
reportPathHeader();
2018-09-28 08:54:21 -07:00
2018-11-26 09:15:52 -08:00
const EarlyLate *open_el = EarlyLate::late();
2026-01-03 16:59:35 -08:00
const ClockEdge *open_clk_edge = check.openClkEdge(this);
2023-01-19 11:23:45 -07:00
const Clock *open_clk = open_clk_edge->clock();
2018-09-28 08:54:21 -07:00
float open_clk_time = open_clk_edge->time();
2026-03-15 14:35:24 -07:00
std::string open_clk_msg = sta::format("clock {} ({} edge)",
open_clk->name(),
asRiseFall(open_clk_edge->transition()));
2026-03-28 19:13:35 -07:00
reportLine(open_clk_msg, open_clk_time, open_clk_time, open_el);
2020-12-28 18:04:49 -08:00
2026-01-03 16:59:35 -08:00
Arrival open_arrival = check.openArrival(this);
bool is_prop = isPropagated(check.openPath());
2026-03-28 19:13:35 -07:00
std::string_view clk_ideal_prop = clkNetworkDelayIdealProp(is_prop);
2026-01-03 16:59:35 -08:00
reportLine(clk_ideal_prop, check.openDelay(this), open_arrival, open_el);
2020-12-28 19:51:34 -08:00
reportLine(pin_name, delay_zero, open_arrival, open_el);
reportLine("open edge arrival time", open_arrival, open_el);
reportBlankLine();
2018-09-28 08:54:21 -07:00
2018-11-26 09:15:52 -08:00
const EarlyLate *close_el = EarlyLate::late();
2026-01-03 16:59:35 -08:00
const ClockEdge *close_clk_edge = check.closeClkEdge(this);
2023-01-19 11:23:45 -07:00
const Clock *close_clk = close_clk_edge->clock();
2026-01-03 16:59:35 -08:00
float close_offset = check.closeOffset(this);
2018-09-28 08:54:21 -07:00
float close_clk_time = close_clk_edge->time() + close_offset;
2026-03-15 14:35:24 -07:00
std::string close_clk_msg = sta::format("clock {} ({} edge)",
close_clk->name(),
asRiseFall(close_clk_edge->transition()));
2026-03-28 19:13:35 -07:00
reportLine(close_clk_msg, close_clk_time, close_clk_time, close_el);
2026-03-13 14:06:35 -07:00
Arrival close_arrival = delaySum(check.closeArrival(this), close_offset, this);
2026-01-03 16:59:35 -08:00
reportLine(clk_ideal_prop, check.closeDelay(this), close_arrival, close_el);
2026-03-13 14:06:35 -07:00
2020-12-28 19:51:34 -08:00
reportLine(pin_name, delay_zero, close_arrival, close_el);
2018-09-28 08:54:21 -07:00
2025-04-09 16:35:15 -07:00
if (variables_->crprEnabled()) {
2026-01-03 16:59:35 -08:00
Crpr pessimism = check.checkCrpr(this);
2026-03-13 14:06:35 -07:00
close_arrival = delaySum(close_arrival, pessimism, this);
2020-12-28 19:51:34 -08:00
reportLine("clock reconvergence pessimism", pessimism, close_arrival, close_el);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportLine("close edge arrival time", close_arrival, close_el);
reportDashLine();
2018-11-26 09:15:52 -08:00
2026-01-03 16:59:35 -08:00
float min_width = check.minWidth(this);
2026-03-15 14:35:24 -07:00
std::string rpw_msg = sta::format("required pulse width ({})",
mpwCheckHiLow(check));
2026-03-28 19:13:35 -07:00
reportLine(rpw_msg, min_width, EarlyLate::early());
2026-01-03 16:59:35 -08:00
reportLine("actual pulse width", check.width(this), EarlyLate::early());
2020-12-28 19:51:34 -08:00
reportDashLine();
2026-01-03 16:59:35 -08:00
reportSlack(check.slack(this));
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2026-01-03 16:59:35 -08:00
ReportPath::mpwCheckHiLow(const MinPulseWidthCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
if (check.openTransition(this) == RiseFall::rise())
2018-09-28 08:54:21 -07:00
return "high";
else
return "low";
}
////////////////////////////////////////////////////////////////
void
2026-01-03 16:59:35 -08:00
ReportPath::reportCheck(const MinPeriodCheck &check,
bool verbose) const
2018-09-28 08:54:21 -07:00
{
if (verbose) {
2020-12-28 18:04:49 -08:00
reportVerbose(check);
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
else {
2020-12-28 18:04:49 -08:00
reportPeriodHeaderShort();
reportShort(check);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportChecks(const MinPeriodCheckSeq &checks,
bool verbose) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
if (!checks.empty()) {
2018-09-28 08:54:21 -07:00
if (verbose) {
2026-01-03 16:59:35 -08:00
for (const MinPeriodCheck &check : checks) {
reportVerbose(check);
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
}
else {
2020-12-28 18:04:49 -08:00
reportPeriodHeaderShort();
2026-01-03 16:59:35 -08:00
for (const MinPeriodCheck &check : checks)
reportShort(check);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPeriodHeaderShort() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("", line);
line += ' ';
reportField("", field_total_, line);
line += ' ';
reportField("Min", field_total_, line);
line += ' ';
reportField("", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line.clear();
reportDescription("Pin", line);
line += ' ';
reportField("Period", field_total_, line);
line += ' ';
reportField("Period", field_total_, line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportShort(const MinPeriodCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2026-03-28 19:13:35 -07:00
const std::string pin_name = cmd_network_->pathName(check.pin());
2020-12-28 18:04:49 -08:00
reportDescription(pin_name, line);
2026-01-03 16:59:35 -08:00
reportSpaceFieldDelay(check.period(), EarlyLate::early(), line);
reportSpaceFieldDelay(check.minPeriod(this), EarlyLate::early(), line);
reportSpaceSlack(check.slack(this), line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportVerbose(const MinPeriodCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string line = "Pin: " + cmd_network_->pathName(check.pin());
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2026-01-03 16:59:35 -08:00
reportLine("period", check.period(), EarlyLate::early());
reportLine("min period", -check.minPeriod(this), EarlyLate::early());
2020-12-28 19:51:34 -08:00
reportDashLine();
2020-12-28 18:04:49 -08:00
2026-01-03 16:59:35 -08:00
reportSlack(check.slack(this));
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2026-01-03 16:59:35 -08:00
ReportPath::reportChecks(const MaxSkewCheckSeq &checks,
bool verbose) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
if (!checks.empty()) {
2018-09-28 08:54:21 -07:00
if (verbose) {
2026-01-03 16:59:35 -08:00
for (const MaxSkewCheck &check : checks)
reportVerbose(check);
2018-09-28 08:54:21 -07:00
}
else {
2020-12-28 18:04:49 -08:00
reportMaxSkewHeaderShort();
2026-01-03 16:59:35 -08:00
for (const MaxSkewCheck &check : checks)
reportShort(check);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportMaxSkewHeaderShort() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("", line);
line += ' ';
reportField("Required", field_total_, line);
line += ' ';
reportField("Actual", field_total_, line);
line += ' ';
reportField("", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line.clear();
reportDescription("Pin", line);
line += ' ';
reportField("Skew", field_total_, line);
line += ' ';
reportField("Skew", field_total_, line);
line += ' ';
reportField("Slack", field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportShort(const MaxSkewCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2026-01-03 16:59:35 -08:00
Pin *clk_pin = check.clkPin(this);
TimingArc *check_arc = check.checkArc();
2026-03-15 14:35:24 -07:00
std::string what = sta::format("{} ({}->{})",
network_->pathName(clk_pin),
check_arc->fromEdge()->to_string(),
check_arc->toEdge()->to_string());
2026-03-28 19:13:35 -07:00
reportDescription(what, line);
2019-10-09 18:02:54 -10:00
const EarlyLate *early_late = EarlyLate::early();
2026-01-03 16:59:35 -08:00
reportSpaceFieldDelay(check.maxSkew(this), early_late, line);
2026-03-13 14:06:35 -07:00
reportSpaceFieldDelay(check.skew(this), early_late, line);
2026-01-03 16:59:35 -08:00
reportSpaceSlack(check.slack(this), line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2026-01-03 16:59:35 -08:00
ReportPath::reportVerbose(const MaxSkewCheck &check) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
line += "Constrained Pin: ";
2026-03-15 14:35:24 -07:00
line += cmd_network_->pathName(check.clkPin(this));
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line = "Reference Pin: ";
2026-03-15 14:35:24 -07:00
line += cmd_network_->pathName(check.refPin(this));
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line = "Check: max_skew";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
2020-12-28 19:51:34 -08:00
reportPathHeader();
2026-01-03 16:59:35 -08:00
reportSkewClkPath("reference pin arrival time", check.refPath());
reportSkewClkPath("constrained pin arrival time", check.clkPath());
2018-09-28 08:54:21 -07:00
2020-12-28 19:51:34 -08:00
reportDashLine();
2026-01-03 16:59:35 -08:00
reportLine("allowable skew", check.maxSkew(this), EarlyLate::early());
2026-03-13 14:06:35 -07:00
reportLine("actual skew", check.skew(this), EarlyLate::late());
2020-12-28 19:51:34 -08:00
reportDashLine();
2026-01-03 16:59:35 -08:00
reportSlack(check.slack(this));
2018-09-28 08:54:21 -07:00
}
// Based on reportTgtClk.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportSkewClkPath(std::string_view arrival_msg,
2026-01-03 16:59:35 -08:00
const Path *clk_path) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = clk_path->clkEdge(this);
const Clock *clk = clk_edge->clock();
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = clk_path->minMax(this);
2019-11-11 15:30:19 -07:00
const RiseFall *clk_rf = clk_edge->transition();
const RiseFall *clk_end_rf = clk_path->transition(this);
2026-03-02 12:13:13 -08:00
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
2018-09-28 08:54:21 -07:00
float clk_time = clk_edge->time();
const Arrival &clk_arrival = search_->clkPathArrival(clk_path);
2026-03-13 14:06:35 -07:00
Arrival clk_delay = delayDiff(clk_arrival,
clk_time,
this);
2026-01-03 16:59:35 -08:00
const MinMax *min_max = clk_path->minMax(this);
2018-09-28 08:54:21 -07:00
Vertex *clk_vertex = clk_path->vertex(this);
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, min_max);
2019-01-16 15:37:31 -08:00
2018-09-28 08:54:21 -07:00
bool is_prop = isPropagated(clk_path);
if (is_prop && reportClkPath()) {
2026-01-03 16:59:35 -08:00
const Mode *mode = clk_path->mode(this);
const Sdc *sdc = mode->sdc();
2018-09-28 08:54:21 -07:00
const EarlyLate *early_late = TimingRole::skew()->tgtClkEarlyLate();
2026-01-03 16:59:35 -08:00
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late, sdc))
reportGenClkSrcAndPath(clk_path, clk, clk_rf, early_late, 0.0, 0.0,
false, mode);
2018-09-28 08:54:21 -07:00
else {
Arrival insertion, latency;
PathEnd::checkTgtClkDelay(clk_path, clk_edge, TimingRole::skew(), this,
2026-01-03 16:59:35 -08:00
insertion, latency);
2020-12-28 19:51:34 -08:00
reportClkSrcLatency(insertion, clk_time, early_late);
2018-09-28 08:54:21 -07:00
PathExpanded clk_expanded(clk_path, this);
2025-08-18 13:27:30 -07:00
reportPath1(clk_path, clk_expanded, false, 0.0);
2018-09-28 08:54:21 -07:00
}
}
else {
2020-12-28 19:51:34 -08:00
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival, early_late);
2026-03-28 19:13:35 -07:00
reportLine(descriptionField(clk_vertex), clk_arrival,
2026-01-03 16:59:35 -08:00
early_late, clk_end_rf);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportLine(arrival_msg, search_->clkPathArrival(clk_path), early_late);
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportLimitShortHeader(const ReportField *field) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
reportDescription("Pin", line);
line += ' ';
reportField("Limit", field, line);
line += ' ';
reportField(field->title(), field, line);
line += ' ';
reportField("Slack", field, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
reportDashLine(field_description_->width() + field->width() * 3 + 3);
2018-09-28 08:54:21 -07:00
}
void
2020-06-02 15:19:09 -07:00
ReportPath::reportLimitShort(const ReportField *field,
2026-01-03 16:59:35 -08:00
const Pin *pin,
float value,
float limit,
float slack) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2026-03-28 19:13:35 -07:00
const std::string pin_name = cmd_network_->pathName(pin);
2020-12-28 18:04:49 -08:00
reportDescription(pin_name, line);
line += ' ';
reportField(limit, field, line);
line += ' ';
reportField(value, field, line);
line += ' ';
reportField(slack, field, line);
line += (slack >= 0.0)
2020-06-02 16:28:12 -07:00
? " (MET)"
: " (VIOLATED)";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2020-06-02 15:19:09 -07:00
ReportPath::reportLimitVerbose(const ReportField *field,
2026-01-03 16:59:35 -08:00
const Pin *pin,
const RiseFall *rf,
float value,
float limit,
float slack,
const Scene *scene,
2025-02-01 14:53:28 -08:00
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 18:04:49 -08:00
line += "Pin ";
line += cmd_network_->pathName(pin);
line += ' ';
2020-06-02 11:08:48 -07:00
if (rf)
2020-12-28 18:04:49 -08:00
line += rf->shortName();
2020-06-02 11:08:48 -07:00
else
2020-12-28 18:04:49 -08:00
line += ' ';
2026-01-03 16:59:35 -08:00
// Don't report scene if the default scene is the only scene.
if (scene && multiScene()) {
line += " (corner ";
2026-01-03 16:59:35 -08:00
line += scene->name();
line += ")";
}
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2025-03-30 15:27:53 -07:00
line = min_max->to_string();
2020-12-28 18:04:49 -08:00
line += ' ';
line += field->name();
line += ' ';
reportField(limit, field, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 18:04:49 -08:00
line = field->name();
line += " ";
reportField(value, field, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2026-03-28 19:13:35 -07:00
size_t name_width = field->name().size() + 5;
2020-12-28 18:04:49 -08:00
reportDashLine(name_width + field->width());
2018-09-28 08:54:21 -07:00
2020-12-28 18:04:49 -08:00
line = "Slack";
2026-03-28 19:13:35 -07:00
for (size_t i = strlen("Slack"); i < name_width; i++)
2020-12-28 18:04:49 -08:00
line += ' ';
reportField(slack, field, line);
line += (slack >= 0.0)
2020-06-02 16:28:12 -07:00
? " (MET)"
: " (VIOLATED)";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
ReportPath::reportStartpoint(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
const Path *path = end->path();
2026-01-03 16:59:35 -08:00
const Sdc *sdc = path->sdc(this);
2025-03-26 18:21:03 -07:00
const Path *start = expanded.startPath();
2025-02-01 14:53:28 -08:00
const TimingArc *prev_arc = expanded.startPrevArc();
2025-03-26 18:21:03 -07:00
const Edge *prev_edge = start->prevEdge(this);
2025-02-01 14:53:28 -08:00
const Pin *pin = start->pin(graph_);
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = path->clkEdge(this);
const Clock *clk = path->clock(search_);
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(pin);
2018-09-28 08:54:21 -07:00
if (pathFromClkPin(path, pin)) {
2026-03-28 19:13:35 -07:00
const std::string &clk_name = clk->name();
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("clock source '{}'", clk_name);
2020-12-28 19:51:34 -08:00
reportStartpoint(pin_name, reason);
2018-09-28 08:54:21 -07:00
}
else if (network_->isTopLevelPort(pin)) {
if (clk
2026-01-03 16:59:35 -08:00
&& clk != sdc->defaultArrivalClock()) {
2026-03-28 19:13:35 -07:00
const std::string &clk_name = clk->name();
2018-09-28 08:54:21 -07:00
// Pin direction is "input" even for bidirects.
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("input port clocked by {}", clk_name);
2020-12-28 19:51:34 -08:00
reportStartpoint(pin_name, reason);
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportStartpoint(pin_name, "input port");
2018-09-28 08:54:21 -07:00
}
else if (network_->isLeaf(pin) && prev_arc) {
Instance *inst = network_->instance(pin);
2026-03-28 19:13:35 -07:00
std::string inst_name = cmd_network_->pathName(inst);
2018-09-28 08:54:21 -07:00
if (clk_edge) {
2019-11-11 15:30:19 -07:00
const RiseFall *clk_rf = clk_edge->transition();
2025-03-26 18:21:03 -07:00
const Path *clk_path = expanded.clkPath();
bool clk_inverted = clk_path
2026-01-03 16:59:35 -08:00
&& clk_rf != clk_path->transition(this);
2026-03-02 12:13:13 -08:00
std::string clk_name = clkName(clk, clk_inverted);
2026-03-28 19:13:35 -07:00
std::string_view reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name);
2020-12-28 19:51:34 -08:00
reportStartpoint(inst_name, reason);
2018-09-28 08:54:21 -07:00
}
else {
2026-03-28 19:13:35 -07:00
std::string_view reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
reportStartpoint(inst_name, std::string(reg_desc));
2018-09-28 08:54:21 -07:00
}
}
else if (network_->isLeaf(pin)) {
if (clk_edge) {
Clock *clk = clk_edge->clock();
2026-01-03 16:59:35 -08:00
if (clk != sdc->defaultArrivalClock()) {
2026-03-15 14:35:24 -07:00
std::string reason = sta::format("internal path startpoint clocked by {}",
clk->name());
2026-01-03 16:59:35 -08:00
reportStartpoint(pin_name, reason);
2018-09-28 08:54:21 -07:00
}
else
2026-01-03 16:59:35 -08:00
reportStartpoint(pin_name, "internal path startpoint");
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportStartpoint(pin_name, "internal pin");
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportStartpoint(pin_name, "");
2018-09-28 08:54:21 -07:00
}
bool
2025-02-01 14:53:28 -08:00
ReportPath::pathFromClkPin(const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
const Path *start = expanded.startPath();
const Path *end = expanded.endPath();
2018-09-28 08:54:21 -07:00
const Pin *start_pin = start->pin(graph_);
return pathFromClkPin(end, start_pin);
}
bool
ReportPath::pathFromClkPin(const Path *path,
2026-01-03 16:59:35 -08:00
const Pin *start_pin) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const Clock *clk = path->clock(search_);
2018-09-28 08:54:21 -07:00
return clk
2026-01-03 16:59:35 -08:00
&& clk->leafPins().contains(const_cast<Pin*>(start_pin));
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportStartpoint(std::string_view start,
const std::string &reason) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartEndPoint(start, reason, "Startpoint");
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportUnclockedEndpoint(const PathEnd *end,
2026-03-28 19:13:35 -07:00
std::string_view default_reason) const
2018-09-28 08:54:21 -07:00
{
Vertex *vertex = end->vertex(this);
Pin *pin = vertex->pin();
if (network_->isTopLevelPort(pin)) {
// Pin direction is "output" even for bidirects.
2020-12-28 19:51:34 -08:00
reportEndpoint(cmd_network_->pathName(pin), "output port");
2018-09-28 08:54:21 -07:00
}
else if (network_->isLeaf(pin)) {
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->genericRole() == TimingRole::setup()) {
2026-01-03 16:59:35 -08:00
Vertex *clk_vertex = edge->from(graph_);
VertexOutEdgeIterator clk_edge_iter(clk_vertex, graph_);
while (clk_edge_iter.hasNext()) {
Edge *clk_edge = clk_edge_iter.next();
2026-03-28 19:13:35 -07:00
Instance *inst = network_->instance(pin);
std::string inst_name = cmd_network_->pathName(inst);
2026-01-03 16:59:35 -08:00
if (clk_edge->role() == TimingRole::regClkToQ()) {
2026-03-28 19:13:35 -07:00
std::string_view reason =
regDesc(clk_edge->timingArcSet()->isRisingFallingEdge());
reportEndpoint(inst_name, std::string(reason));
2026-01-03 16:59:35 -08:00
return;
}
if (clk_edge->role() == TimingRole::latchEnToQ()) {
2026-03-28 19:13:35 -07:00
std::string_view reason =
latchDesc(clk_edge->timingArcSet()->isRisingFallingEdge());
reportEndpoint(inst_name, std::string(reason));
2026-01-03 16:59:35 -08:00
return;
}
}
2018-09-28 08:54:21 -07:00
}
}
2026-03-28 19:13:35 -07:00
reportEndpoint(cmd_network_->pathName(pin), std::string(default_reason));
2018-09-28 08:54:21 -07:00
}
else
2020-12-28 19:51:34 -08:00
reportEndpoint(cmd_network_->pathName(pin), "");
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportEndpoint(std::string_view end,
const std::string &reason) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportStartEndPoint(end, reason, "Endpoint");
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportStartEndPoint(std::string_view pt,
const std::string &reason,
std::string_view key) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-09-28 08:54:21 -07:00
// Account for punctuation in the line.
2026-03-28 19:13:35 -07:00
size_t line_len = key.size() + 2 + pt.size() + 2 + reason.size() + 1;
2018-09-28 08:54:21 -07:00
if (!no_split_
&& line_len > start_end_pt_width_) {
2026-03-28 19:13:35 -07:00
line = std::string(key);
2020-12-28 19:51:34 -08:00
line += ": ";
line += pt;
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
2020-12-28 19:51:34 -08:00
line.clear();
2026-03-28 19:13:35 -07:00
for (size_t i = 0; i < key.size(); i++)
2020-12-28 19:51:34 -08:00
line += ' ';
2018-09-28 08:54:21 -07:00
2020-12-28 19:51:34 -08:00
line += " (";
line += reason;
line += ")";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
else {
2026-03-28 19:13:35 -07:00
line = std::string(key);
2020-12-28 19:51:34 -08:00
line += ": ";
line += pt;
line += " (";
line += reason;
line += ")";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportGroup(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 19:51:34 -08:00
line = "Path Group: ";
PathGroup *group = end->pathGroup();
2022-01-15 12:51:05 -07:00
line += group ? group->name() : "(none)";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 19:51:34 -08:00
line = "Path Type: ";
2025-03-30 15:27:53 -07:00
line += end->minMax(this)->to_string();
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 19:51:34 -08:00
2026-01-03 16:59:35 -08:00
if (modes_.size() > 1) {
line = "Mode: ";
line += end->path()->mode(this)->name();
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2026-01-03 16:59:35 -08:00
}
if (multiScene()) {
2020-12-28 19:51:34 -08:00
line = "Corner: ";
2026-01-03 16:59:35 -08:00
line += end->path()->scene(this)->name();
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::checkRoleReason(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
return sta::format("{} time", end->checkRole(this)->to_string());
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::tgtClkName(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
2018-09-28 08:54:21 -07:00
const Clock *tgt_clk = tgt_clk_edge->clock();
2019-11-11 15:30:19 -07:00
const RiseFall *clk_rf = tgt_clk_edge->transition();
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
return clkName(tgt_clk, clk_end_rf != clk_rf);
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2019-01-16 15:37:31 -08:00
ReportPath::clkName(const Clock *clk,
2026-01-03 16:59:35 -08:00
bool inverted) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string name = clk->name();
2019-01-16 15:37:31 -08:00
if (inverted)
name += '\'';
return name;
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::clkRegLatchDesc(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
// Goofy libraries can have registers with both rising and falling
// clk->q timing arcs. Try and match the timing check transition.
2022-02-13 17:46:45 -07:00
const RiseFall *check_clk_rf=end->checkArc()->fromEdge()->asRiseFall();
2019-03-12 17:25:53 -07:00
TimingArcSet *clk_set = nullptr;
2019-11-11 15:30:19 -07:00
TimingArcSet *clk_rf_set = nullptr;
2018-09-28 08:54:21 -07:00
Vertex *tgt_clk_vertex = end->targetClkPath()->vertex(this);
VertexOutEdgeIterator iter(tgt_clk_vertex, graph_);
while (iter.hasNext()) {
Edge *edge = iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
2025-03-30 15:27:53 -07:00
const TimingRole *role = arc_set->role();
2018-09-28 08:54:21 -07:00
if (role == TimingRole::regClkToQ()
2026-01-03 16:59:35 -08:00
|| role == TimingRole::latchEnToQ()) {
2024-06-27 13:57:58 -07:00
const RiseFall *arc_rf = arc_set->isRisingFallingEdge();
2018-09-28 08:54:21 -07:00
clk_set = arc_set;
2019-11-11 15:30:19 -07:00
if (arc_rf == check_clk_rf)
2026-01-03 16:59:35 -08:00
clk_rf_set = arc_set;
2018-09-28 08:54:21 -07:00
}
}
2019-11-11 15:30:19 -07:00
if (clk_rf_set)
return checkRegLatchDesc(clk_rf_set->role(),
2026-01-03 16:59:35 -08:00
clk_rf_set->isRisingFallingEdge());
2018-09-28 08:54:21 -07:00
else if (clk_set)
return checkRegLatchDesc(clk_set->role(),
2026-01-03 16:59:35 -08:00
clk_set->isRisingFallingEdge());
2018-09-28 08:54:21 -07:00
else
2019-11-11 15:30:19 -07:00
return checkRegLatchDesc(TimingRole::regClkToQ(), check_clk_rf);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportSrcPathArrival(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportBlankLine();
reportSrcPath(end, expanded);
2018-11-26 09:15:52 -08:00
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
2026-01-03 16:59:35 -08:00
end->pathEarlyLate(this));
2020-12-28 19:51:34 -08:00
reportBlankLine();
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportSrcPath(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportPathHeader();
2018-09-28 08:54:21 -07:00
float src_clk_offset = end->sourceClkOffset(this);
Arrival src_clk_insertion = end->sourceClkInsertionDelay(this);
Arrival src_clk_latency = end->sourceClkLatency(this);
const Path *path = end->path();
reportSrcClkAndPath(path, expanded, src_clk_offset, src_clk_insertion,
2026-01-03 16:59:35 -08:00
src_clk_latency, end->isPathDelay());
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportSrcClkAndPath(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
float time_offset,
Arrival clk_insertion,
Arrival clk_latency,
bool is_path_delay) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = path->clkEdge(this);
2026-01-03 16:59:35 -08:00
const Mode *mode = path->mode(this);
const Sdc *sdc = mode->sdc();
2019-01-26 23:03:01 -08:00
const MinMax *min_max = path->minMax(this);
2018-09-28 08:54:21 -07:00
if (clk_edge) {
Clock *clk = clk_edge->clock();
2025-03-30 15:27:53 -07:00
const RiseFall *clk_rf = clk_edge->transition();
2018-09-28 08:54:21 -07:00
float clk_time = clk_edge->time() + time_offset;
2026-01-03 16:59:35 -08:00
if (clk == sdc->defaultArrivalClock()) {
2018-09-28 08:54:21 -07:00
if (!is_path_delay) {
2026-01-03 16:59:35 -08:00
float clk_end_time = clk_time + time_offset;
const EarlyLate *early_late = min_max;
reportLine("clock (input port clock) (rise edge)",
clk_end_time, clk_end_time, early_late);
reportLine(clkNetworkDelayIdealProp(false), 0.0, clk_end_time, early_late);
2018-09-28 08:54:21 -07:00
}
2020-12-28 19:51:34 -08:00
reportPath1(path, expanded, false, time_offset);
2018-09-28 08:54:21 -07:00
}
else {
bool path_from_input = false;
bool input_has_ref_path = false;
Arrival clk_delay, clk_end_time;
2025-03-26 18:21:03 -07:00
const Path *clk_path = expanded.clkPath();
2019-11-11 15:30:19 -07:00
const RiseFall *clk_end_rf;
2025-03-26 18:21:03 -07:00
if (clk_path) {
2026-03-13 14:06:35 -07:00
clk_end_time = delaySum(search_->clkPathArrival(clk_path),
time_offset,
this);
clk_delay = delayDiff(clk_end_time,
clk_time,
this);
2026-01-03 16:59:35 -08:00
clk_end_rf = clk_path->transition(this);
2018-09-28 08:54:21 -07:00
}
else {
2026-01-03 16:59:35 -08:00
// Path from input port or clk used as data.
clk_end_rf = clk_rf;
2026-03-13 14:06:35 -07:00
clk_delay = delaySum(clk_insertion, clk_latency, this);
clk_end_time = delaySum(clk_time, clk_delay, this);
2026-01-03 16:59:35 -08:00
const Path *first_path = expanded.startPath();
const InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) {
path_from_input = true;
const Pin *ref_pin = input_delay->refPin();
if (ref_pin && clk->isPropagated()) {
Path ref_path;
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull()) {
const Arrival &ref_end_time = ref_path.arrival();
2026-03-13 14:06:35 -07:00
clk_delay = delayDiff(ref_end_time,
clk_time,
this);
clk_end_time = delaySum(ref_end_time,
time_offset,
this);
2026-01-03 16:59:35 -08:00
input_has_ref_path = true;
}
}
}
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string clk_name = clkName(clk, clk_rf != clk_end_rf);
2018-09-28 08:54:21 -07:00
bool clk_used_as_data = pathFromClkPin(expanded);
bool is_prop = isPropagated(path);
const EarlyLate *early_late = min_max;
2026-01-03 16:59:35 -08:00
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late, sdc)
&& !(path_from_input && !input_has_ref_path)) {
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, min_max);
2026-01-03 16:59:35 -08:00
reportGenClkSrcAndPath(path, clk, clk_rf, early_late, time_offset,
time_offset, clk_used_as_data, mode);
2018-09-28 08:54:21 -07:00
}
else if (clk_used_as_data
2026-01-03 16:59:35 -08:00
&& pathFromGenPropClk(path, path->minMax(this))) {
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, min_max);
2026-01-03 16:59:35 -08:00
const ClkInfo *clk_info = path->tag(search_)->clkInfo();
if (clk_info->isPropagated())
reportClkSrcLatency(clk_insertion, clk_time, early_late);
reportPath1(path, expanded, true, time_offset);
2018-09-28 08:54:21 -07:00
}
else if (is_prop
2026-01-03 16:59:35 -08:00
&& reportClkPath()
&& !(path_from_input && !input_has_ref_path)) {
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, early_late);
2026-01-03 16:59:35 -08:00
reportClkSrcLatency(clk_insertion, clk_time, early_late);
reportPath1(path, expanded, false, time_offset);
2018-09-28 08:54:21 -07:00
}
else if (clk_used_as_data) {
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, early_late);
2026-01-03 16:59:35 -08:00
if (delayGreater(clk_insertion, 0.0, this))
reportClkSrcLatency(clk_insertion, clk_time, early_late);
if (reportClkPath())
reportPath1(path, expanded, true, time_offset);
else {
Arrival clk_arrival = clk_end_time;
2026-03-13 14:06:35 -07:00
Arrival end_arrival = delaySum(path->arrival(),
time_offset,
this);
Delay clk_delay = delayDiff(end_arrival, clk_arrival, this);
2026-01-03 16:59:35 -08:00
reportLine("clock network delay", clk_delay,
end_arrival, early_late);
Vertex *end_vertex = path->vertex(this);
2026-03-28 19:13:35 -07:00
reportLine(descriptionField(end_vertex),
2026-01-03 16:59:35 -08:00
end_arrival, early_late, clk_end_rf);
}
2018-09-28 08:54:21 -07:00
}
else {
2026-01-03 16:59:35 -08:00
if (is_path_delay) {
if (delayGreater(clk_delay, 0.0, this))
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
clk_end_time, early_late);
}
else {
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, clk_time, min_max);
2026-01-03 16:59:35 -08:00
Arrival clk_arrival = clk_end_time;
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
clk_arrival, early_late);
}
reportPath1(path, expanded, false, time_offset);
2018-09-28 08:54:21 -07:00
}
}
}
else
2020-12-28 19:51:34 -08:00
reportPath1(path, expanded, false, time_offset);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportTgtClk(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportTgtClk(end, 0.0);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportTgtClk(const PathEnd *end,
2026-01-03 16:59:35 -08:00
float prev_time) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const Clock *clk = end->targetClk(this);
2018-09-28 08:54:21 -07:00
const Path *clk_path = end->targetClkPath();
2020-12-28 19:51:34 -08:00
reportTgtClk(end, prev_time, isPropagated(clk_path, clk));
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportTgtClk(const PathEnd *end,
2026-01-03 16:59:35 -08:00
float prev_time,
bool is_prop) const
2018-09-28 08:54:21 -07:00
{
float src_offset = end->sourceClkOffset(this);
reportTgtClk(end, prev_time, src_offset, is_prop);
}
void
ReportPath::reportTgtClk(const PathEnd *end,
2026-01-03 16:59:35 -08:00
float prev_time,
float src_offset,
bool is_prop) const
{
2018-09-28 08:54:21 -07:00
const ClockEdge *clk_edge = end->targetClkEdge(this);
2026-03-13 14:06:35 -07:00
const Clock *clk = clk_edge->clock();
2019-11-11 15:30:19 -07:00
const RiseFall *clk_rf = clk_edge->transition();
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
2026-03-02 12:13:13 -08:00
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
2018-09-28 08:54:21 -07:00
float clk_time = prev_time
+ end->targetClkTime(this)
+ end->targetClkMcpAdjustment(this)
+ src_offset;
Arrival clk_delay = end->targetClkDelay(this);
2026-03-13 14:06:35 -07:00
Arrival clk_arrival = delaySum(clk_delay, clk_time, this);
2026-01-03 16:59:35 -08:00
const MinMax *min_max = end->path()->tgtClkMinMax(this);
2018-09-28 08:54:21 -07:00
const Path *clk_path = end->targetClkPath();
2026-03-28 19:13:35 -07:00
reportClkLine(clk, clk_name, clk_end_rf, prev_time, clk_time, min_max);
2025-03-30 15:27:53 -07:00
const TimingRole *check_role = end->checkRole(this);
2018-09-28 08:54:21 -07:00
if (is_prop && reportClkPath()) {
float time_offset = prev_time
+ end->targetClkOffset(this)
+ end->targetClkMcpAdjustment(this);
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
2026-01-03 16:59:35 -08:00
const Mode *mode = end->path()->mode(this);
const Sdc *sdc = mode->sdc();
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late, sdc)) {
2018-09-28 08:54:21 -07:00
float insertion_offset =
2026-01-03 16:59:35 -08:00
clk_path ? tgtClkInsertionOffet(clk_path, early_late) : 0.0;
reportGenClkSrcAndPath(clk_path, clk, clk_rf, early_late, time_offset,
time_offset + insertion_offset, false, mode);
2018-09-28 08:54:21 -07:00
}
else {
Arrival insertion = end->targetClkInsertionDelay(this);
if (clk_path) {
2026-01-03 16:59:35 -08:00
reportClkSrcLatency(insertion, clk_time, early_late);
PathExpanded clk_expanded(clk_path, this);
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late);
reportPath6(clk_path, clk_expanded, 0, is_prop, reportClkPath(),
delay_zero, time_offset + insertion_offset);
2018-09-28 08:54:21 -07:00
}
else {
2026-01-03 16:59:35 -08:00
// Output departure.
2026-03-13 14:06:35 -07:00
Arrival clk_arrival = delaySum(clk_time, clk_delay, this);
2026-01-03 16:59:35 -08:00
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
clk_delay, clk_arrival, min_max);
2018-09-28 08:54:21 -07:00
}
}
2020-12-28 19:51:34 -08:00
reportClkUncertainty(end, clk_arrival);
reportCommonClkPessimism(end, clk_arrival);
2018-09-28 08:54:21 -07:00
}
else {
2020-12-28 19:51:34 -08:00
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
clk_arrival, min_max);
reportClkUncertainty(end, clk_arrival);
reportCommonClkPessimism(end, clk_arrival);
2018-09-28 08:54:21 -07:00
if (clk_path) {
Vertex *clk_vertex = clk_path->vertex(this);
2026-03-28 19:13:35 -07:00
reportLine(descriptionField(clk_vertex),
delaySum(delaySum(prev_time,
end->targetClkArrival(this),
this),
end->sourceClkOffset(this),
this),
2026-01-03 16:59:35 -08:00
min_max, clk_end_rf);
2018-09-28 08:54:21 -07:00
}
}
}
float
ReportPath::tgtClkInsertionOffet(const Path *clk_path,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2025-09-16 15:30:16 -07:00
const ClkInfo *clk_info = clk_path->clkInfo(this);
2018-09-28 08:54:21 -07:00
const Pin *src_pin = clk_info->clkSrc();
const ClockEdge *clk_edge = clk_info->clkEdge();
const Clock *clk = clk_edge->clock();
2019-11-11 15:30:19 -07:00
const RiseFall *clk_rf = clk_edge->transition();
2026-01-03 16:59:35 -08:00
const MinMax *min_max = clk_path->minMax(this);
const Mode *mode = clk_path->mode(this);
2019-11-11 15:30:19 -07:00
Arrival path_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
2026-01-03 16:59:35 -08:00
min_max, min_max, mode);
2019-11-11 15:30:19 -07:00
Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
2026-01-03 16:59:35 -08:00
min_max, early_late, mode);
2026-03-13 14:06:35 -07:00
return delayAsFloat(delayDiff(tgt_insertion, path_insertion, this));
2018-09-28 08:54:21 -07:00
}
bool
ReportPath::pathFromGenPropClk(const Path *clk_path,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2025-09-16 15:30:16 -07:00
const ClkInfo *clk_info = clk_path->tag(search_)->clkInfo();
2018-09-28 08:54:21 -07:00
const ClockEdge *clk_edge = clk_info->clkEdge();
if (clk_edge) {
2026-01-03 16:59:35 -08:00
const Sdc *sdc = clk_path->sdc(this);
2018-09-28 08:54:21 -07:00
const Clock *clk = clk_edge->clock();
float insertion;
bool exists;
2026-01-03 16:59:35 -08:00
sdc->clockInsertion(clk, clk_info->clkSrc(),
clk_edge->transition(),
clk_path->minMax(this),
early_late,
insertion, exists);
2018-09-28 08:54:21 -07:00
return !exists
&& clk->isGeneratedWithPropagatedMaster();
}
else
return false;
}
bool
ReportPath::isGenPropClk(const Clock *clk,
2026-01-03 16:59:35 -08:00
const RiseFall *clk_rf,
const MinMax *min_max,
const EarlyLate *early_late,
const Sdc *sdc) const
2018-09-28 08:54:21 -07:00
{
float insertion;
bool exists;
2026-01-03 16:59:35 -08:00
sdc->clockInsertion(clk, clk->srcPin(), clk_rf,
min_max, early_late,
insertion, exists);
2018-09-28 08:54:21 -07:00
return !exists
&& clk->isGeneratedWithPropagatedMaster();
}
void
ReportPath::reportClkLine(const Clock *clk,
2026-03-28 19:13:35 -07:00
std::string_view clk_name,
2026-01-03 16:59:35 -08:00
const RiseFall *clk_rf,
Arrival clk_time,
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportClkLine(clk, clk_name, clk_rf, 0.0, clk_time, min_max);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportClkLine(const Clock *clk,
2026-03-28 19:13:35 -07:00
std::string_view clk_name,
2026-01-03 16:59:35 -08:00
const RiseFall *clk_rf,
Arrival prev_time,
Arrival clk_time,
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view rise_fall = asRiseFall(clk_rf);
2026-03-15 14:35:24 -07:00
std::string clk_msg = sta::format("clock {} ({} edge)", clk_name, rise_fall);
2018-09-28 08:54:21 -07:00
if (clk->isPropagated())
2026-03-28 19:13:35 -07:00
reportLine(clk_msg,
2026-03-13 14:06:35 -07:00
delayDiff(clk_time, prev_time, this),
clk_time,
min_max);
2018-09-28 08:54:21 -07:00
else {
// Report ideal clock slew.
2019-11-11 15:30:19 -07:00
float clk_slew = clk->slew(clk_rf, min_max);
2026-03-28 19:13:35 -07:00
reportLine(clk_msg,
2026-03-13 14:06:35 -07:00
clk_slew,
delayDiff(clk_time, prev_time, this),
clk_time,
min_max);
2018-09-28 08:54:21 -07:00
}
}
bool
ReportPath::reportGenClkSrcPath(const Path *clk_path,
2026-01-03 16:59:35 -08:00
const Clock *clk,
const RiseFall *clk_rf,
const MinMax *min_max,
const EarlyLate *early_late,
const Sdc *sdc) const
2018-09-28 08:54:21 -07:00
{
bool from_gen_prop_clk = clk_path
? pathFromGenPropClk(clk_path, early_late)
2026-01-03 16:59:35 -08:00
: isGenPropClk(clk, clk_rf, min_max, early_late, sdc);
2018-09-28 08:54:21 -07:00
return from_gen_prop_clk
2019-03-12 17:25:53 -07:00
&& format_ == ReportPathFormat::full_clock_expanded;
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportGenClkSrcAndPath(const Path *path,
2026-01-03 16:59:35 -08:00
const Clock *clk,
const RiseFall *clk_rf,
const EarlyLate *early_late,
float time_offset,
float path_time_offset,
bool clk_used_as_data,
const Mode *mode) const
2018-09-28 08:54:21 -07:00
{
const Pin *clk_pin = path
? path->clkInfo(search_)->clkSrc()
: clk->defaultPin();
2019-11-11 15:30:19 -07:00
float gclk_time = clk->edge(clk_rf)->time() + time_offset;
bool skip_first_path = reportGenClkSrcPath1(clk, clk_pin, clk_rf,
2026-01-03 16:59:35 -08:00
early_late, gclk_time,
time_offset, clk_used_as_data,
mode);
2018-09-28 08:54:21 -07:00
if (path) {
PathExpanded expanded(path, this);
2025-08-18 13:27:30 -07:00
reportPath2(path, expanded, skip_first_path, clk_used_as_data,
2026-01-03 16:59:35 -08:00
path_time_offset);
2018-09-28 08:54:21 -07:00
}
}
bool
2023-01-19 11:23:45 -07:00
ReportPath::reportGenClkSrcPath1(const Clock *clk,
2026-01-03 16:59:35 -08:00
const Pin *clk_pin,
const RiseFall *clk_rf,
const EarlyLate *early_late,
float gclk_time,
float time_offset,
bool clk_used_as_data,
const Mode *mode) const
{
const Path *src_path = mode->genclks()->srcPath(clk, clk_pin, clk_rf, early_late);
2025-03-26 18:21:03 -07:00
if (src_path) {
2025-09-16 15:30:16 -07:00
const ClkInfo *src_clk_info = src_path->clkInfo(this);
2023-01-19 11:23:45 -07:00
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
const Clock *src_clk = src_clk_info->clock();
2026-01-03 16:59:35 -08:00
const MinMax *min_max = src_path->minMax(this);
2022-01-15 12:51:05 -07:00
if (src_clk) {
bool skip_first_path = false;
const RiseFall *src_clk_rf = src_clk_edge->transition();
const Pin *src_clk_pin = src_clk_info->clkSrc();
if (src_clk->isGeneratedWithPropagatedMaster()
&& src_clk_info->isPropagated()) {
skip_first_path = reportGenClkSrcPath1(src_clk, src_clk_pin,
2026-01-03 16:59:35 -08:00
src_clk_rf, early_late,
2022-01-15 12:51:05 -07:00
gclk_time, time_offset,
2026-01-03 16:59:35 -08:00
clk_used_as_data,
mode);
2022-01-15 12:51:05 -07:00
}
else {
2026-01-03 16:59:35 -08:00
const Mode *mode = src_path->mode(this);
2022-01-15 12:51:05 -07:00
const Arrival insertion = search_->clockInsertion(src_clk, src_clk_pin,
src_clk_rf,
2026-01-03 16:59:35 -08:00
min_max,
early_late, mode);
2022-01-15 12:51:05 -07:00
reportClkSrcLatency(insertion, gclk_time, early_late);
}
2025-03-26 18:21:03 -07:00
PathExpanded src_expanded(src_path, this);
2025-08-18 13:27:30 -07:00
reportPath2(src_path, src_expanded, skip_first_path,
2022-11-17 10:03:42 -07:00
clk_used_as_data, gclk_time);
2022-01-15 12:51:05 -07:00
if (!clk->isPropagated())
reportLine("clock network delay (ideal)", 0.0,
2025-03-26 18:21:03 -07:00
src_path->arrival(), min_max);
2018-09-28 08:54:21 -07:00
}
}
else {
if (clk->isPropagated())
2020-12-28 19:51:34 -08:00
reportClkSrcLatency(0.0, gclk_time, early_late);
2018-09-28 08:54:21 -07:00
else if (!clk_used_as_data)
2026-01-03 16:59:35 -08:00
reportLine("clock network delay (ideal)", 0.0, gclk_time, MinMax::max());
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
return src_path != nullptr;
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportClkSrcLatency(Arrival insertion,
2026-01-03 16:59:35 -08:00
float clk_time,
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-03-13 14:06:35 -07:00
Arrival clk_arrival = delaySum(clk_time,
insertion,
this);
reportLine("clock source latency", insertion, clk_arrival, early_late);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportPathLine(const Path *path,
2026-03-13 14:06:35 -07:00
const Delay &incr,
const Arrival &time,
2026-03-28 19:13:35 -07:00
std::string_view line_case) const
2018-09-28 08:54:21 -07:00
{
Vertex *vertex = path->vertex(this);
Pin *pin = vertex->pin();
2026-03-02 12:13:13 -08:00
const std::string what = descriptionField(vertex);
2019-11-11 15:30:19 -07:00
const RiseFall *rf = path->transition(this);
2018-09-28 08:54:21 -07:00
bool is_driver = network_->isDriver(pin);
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late = path->minMax(this);
const Scene *scene = path->scene(this);
const MinMax *min_max = path->minMax(this);
DcalcAPIndex slew_index = path->dcalcAnalysisPtIndex(this);
Slew slew = graph_->slew(vertex, rf, slew_index);
2018-09-28 08:54:21 -07:00
float cap = field_blank_;
2024-10-15 17:28:52 -07:00
Instance *inst = network_->instance(pin);
2026-03-29 09:58:06 -07:00
std::string src_attr;
2024-10-15 17:28:52 -07:00
if (inst)
src_attr = network_->getAttribute(inst, "src");
2018-09-28 08:54:21 -07:00
// Don't show capacitance field for input pins.
if (is_driver && field_capacitance_->enabled())
2026-01-03 16:59:35 -08:00
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
2026-05-12 11:24:24 -07:00
reportLine(what, path, cap, slew, field_blank_, incr, field_blank_,
2026-03-28 19:13:35 -07:00
time, false, early_late, rf, src_attr, line_case);
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportRequired(const PathEnd *end,
2026-04-13 14:58:16 -07:00
const std::string& margin_msg) const
2018-09-28 08:54:21 -07:00
{
Required req_time = end->requiredTimeOffset(this);
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->clkEarlyLate(this);
float macro_clk_tree_delay = end->macroClkTreeDelay(this);
2018-09-28 08:54:21 -07:00
ArcDelay margin = end->margin(this);
if (end->minMax(this) == MinMax::min()) {
2026-03-13 14:06:35 -07:00
margin = delayDiff(delay_zero, margin, this);
macro_clk_tree_delay = -macro_clk_tree_delay;
}
if (macro_clk_tree_delay != 0.0)
reportLine("macro clock tree delay", -macro_clk_tree_delay,
2026-03-13 14:06:35 -07:00
delaySum(req_time, margin, this), early_late);
2026-03-28 19:13:35 -07:00
reportLine(margin_msg,
2026-03-13 14:06:35 -07:00
delayDiff(delay_zero, margin, this),
req_time,
early_late);
2020-12-28 19:51:34 -08:00
reportLine("data required time", req_time, early_late);
reportDashLine();
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSlack(const PathEnd *end) const
2018-09-28 08:54:21 -07:00
{
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->pathEarlyLate(this);
reportLine("data required time", end->requiredTimeOffset(this),
2026-01-03 16:59:35 -08:00
early_late->opposite());
2020-12-28 19:51:34 -08:00
reportLineNegative("data arrival time", end->dataArrivalTimeOffset(this), early_late);
reportDashLine();
reportSlack(end->slack(this));
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSlack(Slack slack) const
2018-09-28 08:54:21 -07:00
{
2019-10-09 18:02:54 -10:00
const EarlyLate *early_late = EarlyLate::early();
2026-03-28 19:13:35 -07:00
std::string_view msg = (delayAsFloat(slack, early_late, this) >= 0.0)
2019-10-09 18:02:54 -10:00
? "slack (MET)"
: "slack (VIOLATED)";
2020-12-28 19:51:34 -08:00
reportLine(msg, slack, early_late);
2019-10-09 18:02:54 -10:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportSpaceSlack(const PathEnd *end,
2026-03-02 12:13:13 -08:00
std::string &result) const
2019-10-09 18:02:54 -10:00
{
Slack slack = end->slack(this);
reportSpaceSlack(slack, result);
}
void
ReportPath::reportSpaceSlack(Slack slack,
2026-03-02 12:13:13 -08:00
std::string &result) const
2020-12-28 18:04:49 -08:00
{
const EarlyLate *early_late = EarlyLate::early();
reportSpaceFieldDelay(slack, early_late, result);
result += (delayAsFloat(slack, early_late, this) >= 0.0)
? " (MET)"
: " (VIOLATED)";
}
2018-09-28 08:54:21 -07:00
void
ReportPath::reportCommonClkPessimism(const PathEnd *end,
2026-01-03 16:59:35 -08:00
Arrival &clk_arrival) const
2018-09-28 08:54:21 -07:00
{
2025-04-09 16:35:15 -07:00
if (variables_->crprEnabled()) {
2024-06-27 13:57:58 -07:00
Crpr pessimism = end->checkCrpr(this);
2026-03-13 14:06:35 -07:00
clk_arrival = delaySum(clk_arrival, pessimism, this);
2018-11-26 09:15:52 -08:00
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
2026-01-03 16:59:35 -08:00
end->clkEarlyLate(this));
2018-09-28 08:54:21 -07:00
}
}
void
ReportPath::reportClkUncertainty(const PathEnd *end,
2026-01-03 16:59:35 -08:00
Arrival &clk_arrival) const
2018-09-28 08:54:21 -07:00
{
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = end->clkEarlyLate(this);
2018-09-28 08:54:21 -07:00
float uncertainty = end->targetNonInterClkUncertainty(this);
2026-03-13 14:06:35 -07:00
clk_arrival = delaySum(clk_arrival,
uncertainty,
this);
2018-09-28 08:54:21 -07:00
if (uncertainty != 0.0)
2020-12-28 19:51:34 -08:00
reportLine("clock uncertainty", uncertainty, clk_arrival, early_late);
2018-09-28 08:54:21 -07:00
float inter_uncertainty = end->interClkUncertainty(this);
2026-03-13 14:06:35 -07:00
clk_arrival = delaySum(clk_arrival,
inter_uncertainty,
this);
2018-09-28 08:54:21 -07:00
if (inter_uncertainty != 0.0)
2020-12-28 19:51:34 -08:00
reportLine("inter-clock uncertainty", inter_uncertainty,
clk_arrival, early_late);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
ReportPath::reportPath(const PathEnd *end,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportPathHeader();
2018-09-28 08:54:21 -07:00
// Source clk offset for path delays removes clock phase time.
float src_clk_offset = end->sourceClkOffset(this);
2020-12-28 19:51:34 -08:00
reportPath1(end->path(), expanded, pathFromClkPin(expanded), src_clk_offset);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPath(const Path *path) const
2020-07-06 15:18:13 -07:00
{
switch (format_) {
case ReportPathFormat::full:
case ReportPathFormat::full_clock:
case ReportPathFormat::full_clock_expanded:
2020-12-28 19:51:34 -08:00
reportPathFull(path);
2020-07-06 15:18:13 -07:00
break;
case ReportPathFormat::json:
2024-09-16 17:04:31 -07:00
reportJson(path);
2020-07-06 15:18:13 -07:00
break;
2024-09-16 17:04:31 -07:00
case ReportPathFormat::shorter:
case ReportPathFormat::endpoint:
2020-07-06 15:18:13 -07:00
case ReportPathFormat::summary:
case ReportPathFormat::slack_only:
2026-03-15 14:35:24 -07:00
report_->report("Format not supported.");
2020-07-06 15:18:13 -07:00
break;
}
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathFull(const Path *path) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportPathHeader();
2018-09-28 08:54:21 -07:00
PathExpanded expanded(path, this);
2020-12-28 19:51:34 -08:00
reportSrcClkAndPath(path, expanded, 0.0, delay_zero, delay_zero, false);
2018-09-28 08:54:21 -07:00
}
2024-09-16 17:04:31 -07:00
////////////////////////////////////////////////////////////////
2020-07-06 15:18:13 -07:00
2025-08-18 13:27:30 -07:00
// Main entry point for reporting a path.
2018-09-28 08:54:21 -07:00
void
ReportPath::reportPath1(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
bool clk_used_as_data,
float time_offset) const
2025-08-18 13:27:30 -07:00
{
reportPath2(path, expanded, false, clk_used_as_data, time_offset);
}
// Alternate entry point with skip_first_path arg.
void
ReportPath::reportPath2(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
bool skip_first_path,
bool clk_used_as_data,
float time_offset) const
2025-08-18 13:27:30 -07:00
{
bool clk_is_propagated = path->clkInfo(search_)->isPropagated();
bool report_clk_path = (reportClkPath() && clk_is_propagated)
|| clk_used_as_data;
bool propagated_clk = clk_is_propagated || clk_used_as_data;
reportPath4(path, expanded, skip_first_path, propagated_clk,
2026-01-03 16:59:35 -08:00
report_clk_path, time_offset);
2025-08-18 13:27:30 -07:00
}
// Alternate entry point with report_clk_path arg.
void
ReportPath::reportPath3(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
bool report_clk_path,
float time_offset) const
2025-08-18 13:27:30 -07:00
{
bool propagated_clk = path->clkInfo(search_)->isPropagated();
reportPath4(path, expanded, false, propagated_clk,
2026-01-03 16:59:35 -08:00
report_clk_path, time_offset);
2025-08-18 13:27:30 -07:00
}
void
ReportPath::reportPath4(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
const Path *d_path, *q_path;
2018-09-28 08:54:21 -07:00
Edge *d_q_edge;
expanded.latchPaths(d_path, q_path, d_q_edge);
if (d_path) {
Arrival latch_time_given, latch_enable_time;
2025-03-26 18:21:03 -07:00
Path *latch_enable_path;
2018-09-28 08:54:21 -07:00
latches_->latchTimeGivenToStartpoint(d_path, q_path, d_q_edge,
2025-03-26 18:21:03 -07:00
latch_time_given, latch_enable_path);
if (latch_enable_path) {
const EarlyLate *early_late = latch_enable_path->minMax(this);
latch_enable_time = search_->clkPathArrival(latch_enable_path);
2025-08-18 13:27:30 -07:00
if (report_clk_path) {
2026-01-03 16:59:35 -08:00
PathExpanded enable_expanded(latch_enable_path, this);
// Report the path to the latch enable.
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
propagated_clk, report_clk_path, time_offset);
2018-09-28 08:54:21 -07:00
}
2026-03-13 14:06:35 -07:00
Arrival time = delaySum(latch_enable_time,
latch_time_given,
this);
2018-09-28 08:54:21 -07:00
Arrival incr = latch_time_given;
2020-07-11 17:43:30 -07:00
if (delayGreaterEqual(incr, 0.0, this))
2026-01-03 16:59:35 -08:00
reportLine("time given to startpoint", incr, time, early_late);
2018-09-28 08:54:21 -07:00
else
2026-01-03 16:59:35 -08:00
reportLine("time borrowed from startpoint", incr, time, early_late);
2018-09-28 08:54:21 -07:00
// Override latch D arrival with enable + given.
2020-12-28 19:51:34 -08:00
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
2025-08-18 13:27:30 -07:00
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
2026-03-13 14:06:35 -07:00
delaySum(latch_enable_time,
latch_time_given,
this),
time_offset);
2018-09-28 08:54:21 -07:00
}
}
else
2025-08-18 13:27:30 -07:00
reportPath5(path, expanded, skip_first_path, propagated_clk,
2026-01-03 16:59:35 -08:00
report_clk_path, time_offset);
2018-09-28 08:54:21 -07:00
}
void
2025-08-18 13:27:30 -07:00
ReportPath::reportPath5(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
2018-09-28 08:54:21 -07:00
{
size_t path_first_index = 0;
2025-08-18 13:27:30 -07:00
Arrival prev_time = 0.0;
2018-09-28 08:54:21 -07:00
if (skip_first_path) {
path_first_index = 1;
2025-03-26 18:21:03 -07:00
const Path *start = expanded.path(0);
2026-03-13 14:06:35 -07:00
prev_time = delaySum(start->arrival(),
time_offset,
this);
2018-09-28 08:54:21 -07:00
}
2025-08-18 13:27:30 -07:00
reportPath6(path, expanded, path_first_index, propagated_clk,
2026-01-03 16:59:35 -08:00
report_clk_path, prev_time, time_offset);
2018-09-28 08:54:21 -07:00
}
2025-08-18 13:27:30 -07:00
// This does the real workk of reporting an expanded path.
2018-09-28 08:54:21 -07:00
void
2025-08-18 13:27:30 -07:00
ReportPath::reportPath6(const Path *path,
2026-01-03 16:59:35 -08:00
const PathExpanded &expanded,
size_t path_first_index,
bool propagated_clk,
bool report_clk_path,
Arrival prev_time,
float time_offset) const
2018-09-28 08:54:21 -07:00
{
2025-08-18 13:27:30 -07:00
size_t path_last_index = expanded.size() - 1;
2026-01-03 16:59:35 -08:00
const Scene *scene = path->scene(this);
2018-09-28 08:54:21 -07:00
const MinMax *min_max = path->minMax(this);
2026-01-03 16:59:35 -08:00
const Sdc *sdc = path->sdc(this);
DcalcAPIndex slew_index = path->dcalcAnalysisPtIndex(this);
2025-03-26 18:21:03 -07:00
const Path *clk_path = expanded.clkPath();
Vertex *clk_start = clk_path ? clk_path->vertex(this) : nullptr;
2018-09-28 08:54:21 -07:00
for (size_t i = path_first_index; i <= path_last_index; i++) {
2025-03-26 18:21:03 -07:00
const Path *path1 = expanded.path(i);
const TimingArc *prev_arc = path1->prevArc(this);
2018-09-28 08:54:21 -07:00
Vertex *vertex = path1->vertex(this);
Pin *pin = vertex->pin();
2026-03-13 14:06:35 -07:00
Arrival time = delaySum(path1->arrival(), time_offset, this);
2020-05-30 18:09:14 -07:00
Delay incr = 0.0;
2026-04-13 14:58:16 -07:00
std::string_view line_case;
bool is_clk_start = path1->vertex(this) == clk_start;
2018-09-28 08:54:21 -07:00
bool is_clk = path1->isClock(search_);
2024-10-15 17:28:52 -07:00
Instance *inst = network_->instance(pin);
2026-03-29 09:58:06 -07:00
std::string src_attr;
2024-10-15 17:28:52 -07:00
if (inst)
src_attr = network_->getAttribute(inst, "src");
2018-09-28 08:54:21 -07:00
// Always show the search start point (register clk pin).
// Skip reporting the clk tree unless it is requested.
if (is_clk_start
2026-01-03 16:59:35 -08:00
|| report_clk_path
|| !is_clk) {
2019-11-11 15:30:19 -07:00
const RiseFall *rf = path1->transition(this);
2026-01-03 16:59:35 -08:00
Slew slew = graph_->slew(vertex, rf, slew_index);
2019-03-12 17:25:53 -07:00
if (prev_arc == nullptr) {
2026-01-03 16:59:35 -08:00
// First path.
reportInputExternalDelay(path1, time_offset);
size_t next_index = i + 1;
const Path *next_path = expanded.path(next_index);
if (network_->isTopLevelPort(pin)
&& next_path
&& !nextArcAnnotated(next_path, next_index, expanded, slew_index)
&& hasExtInputDriver(pin, rf, min_max, sdc)) {
// Pin is an input port with drive_cell/drive_resistance.
// The delay calculator annotates wire delays on the edges
// from the input to the loads. Report the wire delay on the
// input pin instead.
2026-03-13 14:06:35 -07:00
Arrival next_time = delaySum(next_path->arrival(),
time_offset,
this);
2026-01-03 16:59:35 -08:00
incr = delayIncr(next_time, time, min_max);
time = next_time;
line_case = "input_drive";
}
else if (is_clk) {
if (!propagated_clk)
// Clock latency at path endpoint in case latency was set
// on a clock pin other than the clock source.
2026-03-13 14:06:35 -07:00
time = delaySum(search_->clkPathArrival(path1), time_offset, this);
2026-01-03 16:59:35 -08:00
incr = 0.0;
line_case = "clk_first";
}
else {
incr = 0.0;
line_case = "first";
}
2018-09-28 08:54:21 -07:00
}
else if (is_clk_start
2026-01-03 16:59:35 -08:00
&& is_clk
&& !report_clk_path) {
// Clock start point and clock path are not reported.
incr = 0.0;
if (!propagated_clk) {
// Ideal clock.
const ClockEdge *src_clk_edge = path->clkEdge(this);
2026-03-13 14:06:35 -07:00
time = delaySum(search_->clkPathArrival(path1),
time_offset,
this);
2026-01-03 16:59:35 -08:00
if (src_clk_edge) {
Clock *src_clk = src_clk_edge->clock();
const RiseFall *src_clk_rf = src_clk_edge->transition();
slew = src_clk->slew(src_clk_rf, min_max);
}
}
line_case = "clk_start";
2018-09-28 08:54:21 -07:00
}
else if (is_clk
2026-01-03 16:59:35 -08:00
&& report_clk_path
&& !propagated_clk) {
// Zero the clock network delays for ideal clocks.
incr = 0.0;
time = prev_time;
const ClockEdge *src_clk_edge = path->clkEdge(this);
const Clock *src_clk = src_clk_edge->clock();
const RiseFall *src_clk_rf = src_clk_edge->transition();
slew = src_clk->slew(src_clk_rf, min_max);
line_case = "clk_ideal";
2018-09-28 08:54:21 -07:00
}
else if (is_clk && !is_clk_start) {
2026-01-03 16:59:35 -08:00
incr = delayIncr(time, prev_time, min_max);
line_case = "clk_prop";
2018-09-28 08:54:21 -07:00
}
else {
2026-01-03 16:59:35 -08:00
incr = delayIncr(time, prev_time, min_max);
line_case = "normal";
2018-09-28 08:54:21 -07:00
}
if (vertex->isDriver(network_)) {
2026-03-13 14:06:35 -07:00
// Report delay arc pocv variation between input and driver.
reportVariation(path1);
float cap = field_blank_;
float fanout = field_blank_;
if (field_capacitance_->enabled())
2026-01-03 16:59:35 -08:00
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
if (field_fanout_->enabled())
2026-01-03 16:59:35 -08:00
fanout = drvrFanout(vertex, scene, min_max);
2026-03-02 12:13:13 -08:00
const std::string what = descriptionField(vertex);
2026-05-12 11:24:24 -07:00
reportLine(what, path1, cap, slew, fanout,
2026-03-13 14:06:35 -07:00
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
if (report_net_) {
2026-03-02 12:13:13 -08:00
const std::string what2 = descriptionNet(pin);
2026-05-12 11:24:24 -07:00
reportLine(what2, path1, field_blank_, field_blank_, field_blank_,
2026-03-13 14:06:35 -07:00
field_blank_, field_blank_, field_blank_, false, min_max,
nullptr, src_attr, "");
}
prev_time = time;
}
else {
2025-03-26 18:21:03 -07:00
reportHierPinsThru(path1);
if (report_input_pin_
|| (i == 0)
|| (i == path_last_index)
|| is_clk_start) {
2026-03-02 12:13:13 -08:00
const std::string what = descriptionField(vertex);
2026-05-12 11:24:24 -07:00
reportLine(what, path1, field_blank_, slew, field_blank_,
2026-03-13 14:06:35 -07:00
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
prev_time = time;
}
2018-09-28 08:54:21 -07:00
}
}
else
prev_time = time;
}
}
2026-03-13 14:06:35 -07:00
void
ReportPath::reportVariation(const Path *path) const
{
if (field_variation_->enabled()) {
const Edge *prev_edge = path->prevEdge(this);
if (prev_edge) {
const TimingArc *prev_arc = path->prevArc(this);
const MinMax *min_max = path->minMax(this);
DcalcAPIndex slew_index = path->dcalcAnalysisPtIndex(this);
const ArcDelay &arc_delay=graph_->arcDelay(prev_edge, prev_arc,slew_index);
switch (variables_->pocvMode()) {
case PocvMode::normal: {
float std_dev = arc_delay.stdDev();
2026-05-12 11:24:24 -07:00
reportLine("sigma", path, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, std_dev, field_blank_, true, min_max,
nullptr, "", "");
2026-03-13 14:06:35 -07:00
break;
}
case PocvMode::skew_normal: {
float mean = arc_delay.mean();
2026-05-12 11:24:24 -07:00
reportLine("mean", path, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, mean, field_blank_, true, min_max,
nullptr, "", "");
2026-03-13 14:06:35 -07:00
float mean_shift = arc_delay.meanShift();
2026-05-12 11:24:24 -07:00
reportLine("mean_shift", path, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, mean_shift, field_blank_, true, min_max,
nullptr, "", "");
2026-03-13 14:06:35 -07:00
float std_dev = arc_delay.stdDev();
2026-05-12 11:24:24 -07:00
reportLine("std_dev", path, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, std_dev, field_blank_, true, min_max,
nullptr, "", "");
2026-03-13 14:06:35 -07:00
// skewness is dimensionless, so scale it to the field's time units.
float skewness = arc_delay.skewness() * units_->timeUnit()->scale();
2026-05-12 11:24:24 -07:00
reportLine("skewness", path, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, skewness, field_blank_, true, min_max,
nullptr, "", "");
2026-03-13 14:06:35 -07:00
break;
}
default:
break;
}
}
}
}
Delay
ReportPath::delayIncr(const Delay &time,
const Delay &prev,
const MinMax *min_max) const
{
return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this);
}
void
2025-03-26 18:21:03 -07:00
ReportPath::reportHierPinsThru(const Path *path) const
{
if (report_hier_pins_) {
2025-03-26 18:21:03 -07:00
const Edge *prev_edge = path->prevEdge(this);
if (prev_edge && prev_edge->isWire()) {
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
2026-03-02 12:13:13 -08:00
const std::string what = descriptionField(hpin);
2026-05-12 11:24:24 -07:00
reportLine(what, path, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, field_blank_, false,
path->minMax(this), nullptr, "", "");
}
}
}
}
2018-09-28 08:54:21 -07:00
bool
2025-03-26 18:21:03 -07:00
ReportPath::nextArcAnnotated(const Path *next_path,
2026-01-03 16:59:35 -08:00
size_t next_index,
const PathExpanded &expanded,
DcalcAPIndex ap_index) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
const TimingArc *arc = expanded.path(next_index)->prevArc(this);
Edge *edge = next_path->prevEdge(this);
return graph_->arcDelayAnnotated(edge, arc, ap_index);
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::descriptionField(const Vertex *vertex) const
2018-09-28 08:54:21 -07:00
{
return descriptionField(vertex->pin());
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::descriptionField(const Pin *pin) const
{
2026-03-28 19:13:35 -07:00
std::string name2;
2018-09-28 08:54:21 -07:00
if (network_->isTopLevelPort(pin)) {
PortDirection *dir = network_->direction(pin);
// Translate port direction. Note that this is intentionally
// inconsistent with the direction reported for top level ports as
// startpoints.
if (dir->isInput())
name2 = "in";
else if (dir->isOutput() || dir->isTristate())
name2 = "out";
else if (dir->isBidirect())
name2 = "inout";
else
name2 = "?";
}
else {
Instance *inst = network_->instance(pin);
name2 = network_->cellName(inst);
}
2026-03-28 19:13:35 -07:00
std::string pin_name = cmd_network_->pathName(pin);
2026-03-15 14:35:24 -07:00
return sta::format("{} ({})", pin_name, name2);
2018-09-28 08:54:21 -07:00
}
2026-03-02 12:13:13 -08:00
std::string
2025-02-01 14:53:28 -08:00
ReportPath::descriptionNet(const Pin *pin) const
{
2026-03-28 19:13:35 -07:00
if (network_->isTopLevelPort(pin))
return sta::format("{} (net)", cmd_network_->pathName(pin));
else {
Net *net = network_->net(pin);
if (net) {
Net *highest_net = network_->highestNetAbove(net);
2026-03-28 19:13:35 -07:00
std::string net_name = cmd_network_->pathName(highest_net);
2026-03-15 14:35:24 -07:00
return sta::format("{} (net)", net_name);
}
else
return "(unconnected)";
}
}
2018-09-28 08:54:21 -07:00
float
ReportPath::drvrFanout(Vertex *drvr,
2026-01-03 16:59:35 -08:00
const Scene *scene,
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
const Sdc *sdc = scene->sdc();
2018-09-28 08:54:21 -07:00
float fanout = 0.0;
VertexOutEdgeIterator iter(drvr, graph_);
while (iter.hasNext()) {
Edge *edge = iter.next();
2022-09-18 16:11:21 -07:00
if (edge->isWire()) {
Pin *pin = edge->to(graph_)->pin();
if (network_->isTopLevelPort(pin)) {
// Output port counts as a fanout.
Port *port = network_->port(pin);
2026-01-03 16:59:35 -08:00
fanout += sdc->portExtFanout(port, min_max) + 1;
2022-09-18 16:11:21 -07:00
}
else
fanout++;
2018-09-28 08:54:21 -07:00
}
}
return fanout;
}
bool
ReportPath::hasExtInputDriver(const Pin *pin,
2026-01-03 16:59:35 -08:00
const RiseFall *rf,
const MinMax *min_max,
const Sdc *sdc) const
2018-09-28 08:54:21 -07:00
{
Port *port = network_->port(pin);
2026-01-03 16:59:35 -08:00
InputDrive *drive = sdc->findInputDrive(port);
2018-09-28 08:54:21 -07:00
return (drive
2026-01-03 16:59:35 -08:00
&& (drive->hasDriveResistance(rf, min_max)
|| drive->hasDriveCell(rf, min_max)));
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportInputExternalDelay(const Path *first_path,
2026-01-03 16:59:35 -08:00
float time_offset) const
2018-09-28 08:54:21 -07:00
{
const Pin *first_pin = first_path->pin(graph_);
if (!pathFromClkPin(first_path, first_pin)) {
2019-11-11 15:30:19 -07:00
const RiseFall *rf = first_path->transition(this);
2026-03-13 14:06:35 -07:00
Arrival time = delaySum(first_path->arrival(),
time_offset,
this);
2018-11-26 09:15:52 -08:00
const EarlyLate *early_late = first_path->minMax(this);
2018-09-28 08:54:21 -07:00
InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) {
const Pin *ref_pin = input_delay->refPin();
if (ref_pin) {
2026-01-03 16:59:35 -08:00
Path ref_path;
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull() && reportClkPath()) {
PathExpanded ref_expanded(&ref_path, this);
reportPath3(&ref_path, ref_expanded, true, 0.0);
}
2018-09-28 08:54:21 -07:00
}
float input_arrival =
2026-01-03 16:59:35 -08:00
input_delay->delays()->value(rf, first_path->minMax(this));
2018-11-26 09:15:52 -08:00
reportLine("input external delay", input_arrival, time,
2026-01-03 16:59:35 -08:00
early_late, rf);
2018-09-28 08:54:21 -07:00
}
else if (network_->isTopLevelPort(first_pin))
2020-12-28 19:51:34 -08:00
reportLine("input external delay", 0.0, time, early_late, rf);
2018-09-28 08:54:21 -07:00
}
}
// Return the input delay at the start of a path.
InputDelay *
ReportPath::pathInputDelay(const Path *first_path) const
{
return first_path->tag(this)->inputDelay();
}
void
ReportPath::pathInputDelayRefPath(const Path *path,
2026-01-03 16:59:35 -08:00
const InputDelay *input_delay,
// Return value.
Path &ref_path) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const Pin *ref_pin = input_delay->refPin();
2025-02-01 14:53:28 -08:00
const RiseFall *ref_rf = input_delay->refTransition();
2018-09-28 08:54:21 -07:00
Vertex *ref_vertex = graph_->pinDrvrVertex(ref_pin);
2022-01-15 12:51:05 -07:00
if (ref_vertex) {
const ClockEdge *clk_edge = path->clkEdge(this);
2026-01-03 16:59:35 -08:00
VertexPathIterator path_iter(ref_vertex, path->scene(this),
path->minMax(this), ref_rf,this);
2022-01-15 12:51:05 -07:00
while (path_iter.hasNext()) {
2025-03-26 18:21:03 -07:00
Path *path = path_iter.next();
2022-01-15 12:51:05 -07:00
if (path->isClock(this)
&& path->clkEdge(this) == clk_edge) {
2025-03-26 18:21:03 -07:00
ref_path = path;
2022-01-15 12:51:05 -07:00
break;
}
2018-09-28 08:54:21 -07:00
}
}
}
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
ReportPath::reportPathHeader() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-09-28 08:54:21 -07:00
bool first_field = true;
2025-02-01 14:53:28 -08:00
for (const ReportField *field : fields_) {
2018-09-28 08:54:21 -07:00
if (field->enabled()) {
if (!first_field)
2026-01-03 16:59:35 -08:00
line += ' ';
2020-12-28 19:51:34 -08:00
reportField(field->title(), field, line);
2019-03-03 17:50:56 -08:00
first_field = false;
2018-09-28 08:54:21 -07:00
}
}
2020-12-28 19:51:34 -08:00
trimRight(line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2020-12-28 19:51:34 -08:00
reportDashLine();
2018-09-28 08:54:21 -07:00
}
// Report total.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-01-03 16:59:35 -08:00
Delay total,
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, total, false, early_late, nullptr, "", "");
2018-09-28 08:54:21 -07:00
}
// Report negative total.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLineNegative(std::string_view what,
2026-01-03 16:59:35 -08:00
Delay total,
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
2026-03-13 14:06:35 -07:00
field_blank_, field_blank_, total, true /* tota_with_minus */,
early_late, nullptr, "", "");
2018-09-28 08:54:21 -07:00
}
// Report total, and transition suffix.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-01-03 16:59:35 -08:00
Delay total,
const EarlyLate *early_late,
const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
field_blank_, field_blank_, total, false, early_late, rf, "", "");
2018-09-28 08:54:21 -07:00
}
// Report increment, and total.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-03-13 14:06:35 -07:00
const Delay &incr,
const Delay &total,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
incr, field_blank_, total, false, early_late, nullptr, "", "");
2018-09-28 08:54:21 -07:00
}
// Report increment, total, and transition suffix.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-03-13 14:06:35 -07:00
const Delay &incr,
const Delay &total,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late,
const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
2026-03-28 19:13:35 -07:00
incr, field_blank_, total, false, early_late, rf, "", "");
2018-09-28 08:54:21 -07:00
}
// Report slew, increment, and total.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-03-13 14:06:35 -07:00
const Slew &slew,
const Delay &incr,
const Delay &total,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-05-12 11:24:24 -07:00
reportLine(what, nullptr, field_blank_, slew, field_blank_,
2026-03-28 19:13:35 -07:00
incr, field_blank_, total, false, early_late, nullptr, "", "");
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLine(std::string_view what,
2026-05-12 11:24:24 -07:00
const Path *path,
2026-01-03 16:59:35 -08:00
float cap,
2026-03-13 14:06:35 -07:00
const Slew &slew,
2026-01-03 16:59:35 -08:00
float fanout,
2026-03-13 14:06:35 -07:00
const Delay &incr,
float variation,
const Delay &total,
2026-01-03 16:59:35 -08:00
bool total_with_minus,
const EarlyLate *early_late,
const RiseFall *rf,
2026-03-29 09:58:06 -07:00
std::string_view src_attr,
2026-03-28 19:13:35 -07:00
std::string_view line_case) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2019-03-03 17:50:56 -08:00
size_t field_index = 0;
bool first_field = true;
2025-02-01 14:53:28 -08:00
for (const ReportField *field : fields_) {
2019-03-03 17:50:56 -08:00
bool last_field = field_index == (fields_.size() - 1);
2018-09-28 08:54:21 -07:00
if (field->enabled()) {
2019-02-16 12:07:59 -08:00
if (!first_field)
2026-01-03 16:59:35 -08:00
line += ' ';
2018-09-28 08:54:21 -07:00
if (field == field_description_)
2026-01-03 16:59:35 -08:00
reportDescription(what, first_field, last_field, line);
2018-09-28 08:54:21 -07:00
else if (field == field_fanout_) {
2026-01-03 16:59:35 -08:00
if (fanout == field_blank_)
reportFieldBlank(field, line);
else
2026-03-15 14:35:24 -07:00
line += sta::format("{:{}}",
2026-03-28 19:13:35 -07:00
fanout,
2026-03-15 14:35:24 -07:00
field_fanout_->width());
2018-09-28 08:54:21 -07:00
}
else if (field == field_capacitance_)
2026-01-03 16:59:35 -08:00
reportField(cap, field, line);
2018-09-28 08:54:21 -07:00
else if (field == field_slew_)
2026-01-03 16:59:35 -08:00
reportFieldDelay(slew, early_late, field, line);
2018-09-28 08:54:21 -07:00
else if (field == field_incr_)
2026-01-03 16:59:35 -08:00
reportFieldDelay(incr, early_late, field, line);
2026-03-13 14:06:35 -07:00
else if (field == field_variation_)
reportFieldDelay(variation, early_late, field, line);
2018-09-28 08:54:21 -07:00
else if (field == field_total_) {
2026-01-03 16:59:35 -08:00
if (total_with_minus)
reportFieldDelayMinus(total, early_late, field, line);
else
reportFieldDelay(total, early_late, field, line);
2018-09-28 08:54:21 -07:00
}
else if (field == field_edge_) {
2026-01-03 16:59:35 -08:00
if (rf)
reportField(rf->shortName(), field, line);
else
reportFieldBlank(field, line);
2024-10-15 17:28:52 -07:00
}
2026-03-13 14:06:35 -07:00
else if (field == field_variation_)
reportFieldBlank(field, line);
2024-10-15 17:28:52 -07:00
else if (field == field_src_attr_) {
2026-04-13 14:58:16 -07:00
if (!src_attr.empty())
2026-03-28 19:13:35 -07:00
reportField(src_attr, field, line);
2026-01-03 16:59:35 -08:00
else
reportFieldBlank(field, line);
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
else if (field == field_case_)
reportField(line_case, field, line);
2026-05-12 11:24:24 -07:00
else if (field->getValue())
reportField(field->value(path, this), field, line);
2019-02-16 12:07:59 -08:00
2019-03-03 17:50:56 -08:00
first_field = false;
2018-09-28 08:54:21 -07:00
}
2019-02-16 12:07:59 -08:00
field_index++;
2018-09-28 08:54:21 -07:00
}
2024-10-15 17:28:52 -07:00
// Trim trailing spaces and report the line.
2026-03-02 12:13:13 -08:00
std::string line_stdstr = line;
2024-10-15 17:28:52 -07:00
trimRight(line_stdstr);
2026-03-15 14:35:24 -07:00
report_->reportLine(line_stdstr);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
// Only the total field.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLineTotal(std::string_view what,
2026-03-13 14:06:35 -07:00
const Delay &incr,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportLineTotal1(what, incr, false, early_late);
2018-09-28 08:54:21 -07:00
}
// Only the total field and always with leading minus sign.
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLineTotalMinus(std::string_view what,
2026-03-13 14:06:35 -07:00
const Delay &decr,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportLineTotal1(what, decr, true, early_late);
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportLineTotal1(std::string_view what,
2026-03-13 14:06:35 -07:00
const Delay &incr,
2026-01-03 16:59:35 -08:00
bool incr_with_minus,
const EarlyLate *early_late) const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2020-12-28 19:51:34 -08:00
reportDescription(what, line);
line += ' ';
2018-09-28 08:54:21 -07:00
if (incr_with_minus)
2020-12-28 19:51:34 -08:00
reportFieldDelayMinus(incr, early_late, field_total_, line);
2018-09-28 08:54:21 -07:00
else
2020-12-28 19:51:34 -08:00
reportFieldDelay(incr, early_late, field_total_, line);
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportDashLineTotal() const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
reportDashLine(field_description_->width() + field_total_->width() + 1);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2026-03-28 19:13:35 -07:00
ReportPath::reportDescription(std::string_view what,
2026-03-02 12:13:13 -08:00
std::string &line) const
2019-02-16 12:07:59 -08:00
{
2020-12-28 19:51:34 -08:00
reportDescription(what, false, false, line);
2019-02-16 12:07:59 -08:00
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportDescription(std::string_view what,
2026-01-03 16:59:35 -08:00
bool first_field,
bool last_field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
line += what;
2026-03-28 19:13:35 -07:00
size_t length = what.size();
2019-02-16 12:07:59 -08:00
if (!no_split_
&& first_field
&& length > field_description_->width()) {
2020-12-28 19:51:34 -08:00
reportBlankLine();
2026-03-28 19:13:35 -07:00
for (size_t i = 0; i < field_description_->width(); i++)
2020-12-28 19:51:34 -08:00
line += ' ';
2018-09-28 08:54:21 -07:00
}
2019-02-16 12:07:59 -08:00
else if (!last_field) {
2026-03-28 19:13:35 -07:00
for (size_t i = length; i < field_description_->width(); i++)
2020-12-28 19:51:34 -08:00
line += ' ';
2018-09-28 08:54:21 -07:00
}
}
void
2018-11-26 09:15:52 -08:00
ReportPath::reportFieldTime(float value,
2026-01-03 16:59:35 -08:00
ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-11-26 09:15:52 -08:00
{
if (delayAsFloat(value) == field_blank_)
2020-12-28 19:51:34 -08:00
reportFieldBlank(field, line);
2018-11-26 09:15:52 -08:00
else {
2026-03-15 14:35:24 -07:00
std::string str = units_->timeUnit()->asString(value, digits_);
if (str == minus_zero_)
2018-11-26 09:15:52 -08:00
// Filter "-0.00" fields.
str = plus_zero_;
2026-03-28 19:13:35 -07:00
reportField(str, field, line);
2018-11-26 09:15:52 -08:00
}
}
void
ReportPath::reportSpaceFieldTime(float value,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
line += ' ';
reportFieldTime(value, field_total_, line);
2018-09-28 08:54:21 -07:00
}
void
2026-03-13 14:06:35 -07:00
ReportPath::reportSpaceFieldDelay(const Delay &value,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-11-26 09:15:52 -08:00
{
2020-12-28 19:51:34 -08:00
line += ' ';
reportTotalDelay(value, early_late, line);
2018-11-26 09:15:52 -08:00
}
void
2026-03-13 14:06:35 -07:00
ReportPath::reportTotalDelay(const Delay &value,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
std::string str = delayAsString(value, early_late, digits_, this);
if (str == minus_zero_)
2018-09-28 08:54:21 -07:00
// Filter "-0.00" fields.
2018-11-26 09:15:52 -08:00
str = plus_zero_;
2026-03-28 19:13:35 -07:00
reportField(str, field_total_, line);
2018-09-28 08:54:21 -07:00
}
// Total time always with leading minus sign.
void
2026-03-13 14:06:35 -07:00
ReportPath::reportFieldDelayMinus(const Delay &value,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late,
const ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-11-26 09:15:52 -08:00
{
if (delayAsFloat(value) == field_blank_)
2020-12-28 19:51:34 -08:00
reportFieldBlank(field, line);
2018-11-26 09:15:52 -08:00
else {
2026-03-13 14:06:35 -07:00
// Opposite min/max for negative value.
2026-03-15 14:35:24 -07:00
std::string str = delayAsString(delayDiff(delay_zero, value, this),
2026-03-13 14:06:35 -07:00
early_late->opposite(), digits_, this);
2026-03-15 14:35:24 -07:00
if (str == plus_zero_)
2018-11-26 09:15:52 -08:00
// Force leading minus sign.
str = minus_zero_;
2026-03-28 19:13:35 -07:00
reportField(str, field, line);
2018-11-26 09:15:52 -08:00
}
}
void
2026-03-13 14:06:35 -07:00
ReportPath::reportFieldDelay(const Delay &value,
2026-01-03 16:59:35 -08:00
const EarlyLate *early_late,
const ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
2026-03-13 14:06:35 -07:00
if (value.mean() == field_blank_)
2020-12-28 19:51:34 -08:00
reportFieldBlank(field, line);
2018-11-26 09:15:52 -08:00
else {
2026-03-15 14:35:24 -07:00
std::string str = delayAsString(value, early_late, digits_, this);
if (str == minus_zero_)
2018-11-26 09:15:52 -08:00
// Filter "-0.00" fields.
str = plus_zero_;
2026-03-28 19:13:35 -07:00
reportField(str, field, line);
2018-11-26 09:15:52 -08:00
}
2018-09-28 08:54:21 -07:00
}
void
ReportPath::reportField(float value,
2026-01-03 16:59:35 -08:00
const ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
if (value == field_blank_)
2020-12-28 19:51:34 -08:00
reportFieldBlank(field, line);
2018-09-28 08:54:21 -07:00
else {
2020-06-02 15:19:09 -07:00
Unit *unit = field->unit();
2023-03-13 10:24:13 -07:00
if (unit) {
2026-03-15 14:35:24 -07:00
std::string value_str = unit->asString(value, digits_);
2026-03-28 19:13:35 -07:00
reportField(value_str, field, line);
2023-03-13 10:24:13 -07:00
}
else {
2020-06-02 15:19:09 -07:00
// fanout
2026-03-15 14:35:24 -07:00
std::string value_str = sta::format("{:.0f}", value);
2026-03-28 19:13:35 -07:00
reportField(value_str, field, line);
2023-03-13 10:24:13 -07:00
}
2018-09-28 08:54:21 -07:00
}
}
void
2026-03-28 19:13:35 -07:00
ReportPath::reportField(std::string_view value,
2026-01-03 16:59:35 -08:00
const ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
if (field->leftJustify())
2020-12-28 19:51:34 -08:00
line += value;
2026-03-28 19:13:35 -07:00
for (size_t i = static_cast<int>(value.size()); i < field->width(); i++)
2020-12-28 19:51:34 -08:00
line += ' ';
2018-09-28 08:54:21 -07:00
if (!field->leftJustify())
2020-12-28 19:51:34 -08:00
line += value;
2018-09-28 08:54:21 -07:00
}
void
2020-06-02 15:19:09 -07:00
ReportPath::reportFieldBlank(const ReportField *field,
2026-03-02 12:13:13 -08:00
std::string &line) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
line += field->blank();
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportDashLine() const
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2025-02-01 14:53:28 -08:00
for (const ReportField *field : fields_) {
2018-09-28 08:54:21 -07:00
if (field->enabled()) {
2026-03-28 19:13:35 -07:00
for (size_t i = 0; i < field->width(); i++)
2026-01-03 16:59:35 -08:00
line += '-';
2018-09-28 08:54:21 -07:00
}
}
2020-12-28 19:51:34 -08:00
line += "------";
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
2020-12-28 18:04:49 -08:00
void
2025-02-01 14:53:28 -08:00
ReportPath::reportDashLine(int line_width) const
2020-12-28 18:04:49 -08:00
{
2026-03-02 12:13:13 -08:00
std::string line;
2018-09-28 08:54:21 -07:00
for (int i = 0; i < line_width; i++)
2020-12-28 19:51:34 -08:00
line += '-';
2026-03-15 14:35:24 -07:00
report_->reportLine(line);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
ReportPath::reportBlankLine() const
2018-09-28 08:54:21 -07:00
{
2021-01-04 18:14:04 -08:00
report_->reportBlankLine();
2018-09-28 08:54:21 -07:00
}
bool
ReportPath::reportClkPath() const
{
2019-03-12 17:25:53 -07:00
return format_ == ReportPathFormat::full_clock
|| format_ == ReportPathFormat::full_clock_expanded;
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::asRisingFalling(const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
if (rf == RiseFall::rise())
2018-09-28 08:54:21 -07:00
return "rising";
else
return "falling";
}
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::asRiseFall(const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
if (rf == RiseFall::rise())
2018-09-28 08:54:21 -07:00
return "rise";
else
return "fall";
}
// Find the startpoint type from the first path edge.
2026-03-28 19:13:35 -07:00
std::string_view
2025-02-01 14:53:28 -08:00
ReportPath::edgeRegLatchDesc(const Edge *first_edge,
2026-01-03 16:59:35 -08:00
const TimingArc *first_arc) const
2018-09-28 08:54:21 -07:00
{
2025-03-30 15:27:53 -07:00
const TimingRole *role = first_arc->role();
2018-09-28 08:54:21 -07:00
if (role == TimingRole::latchDtoQ()) {
Instance *inst = network_->instance(first_edge->to(graph_)->pin());
LibertyCell *cell = network_->libertyCell(inst);
if (cell) {
2024-06-27 13:57:58 -07:00
const LibertyPort *enable_port;
const FuncExpr *enable_func;
2024-07-07 17:56:55 -07:00
const RiseFall *enable_rf;
2018-09-28 08:54:21 -07:00
cell->latchEnable(first_edge->timingArcSet(),
2026-01-03 16:59:35 -08:00
enable_port, enable_func, enable_rf);
2019-11-11 15:30:19 -07:00
return latchDesc(enable_rf);
2018-09-28 08:54:21 -07:00
}
}
else if (role == TimingRole::regClkToQ())
2022-02-13 17:46:45 -07:00
return regDesc(first_arc->fromEdge()->asRiseFall());
2018-09-28 08:54:21 -07:00
else if (role == TimingRole::latchEnToQ())
2022-02-13 17:46:45 -07:00
return latchDesc(first_arc->fromEdge()->asRiseFall());
2018-09-28 08:54:21 -07:00
// Who knows...
2022-02-13 17:46:45 -07:00
return regDesc(first_arc->fromEdge()->asRiseFall());
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2018-09-28 08:54:21 -07:00
ReportPath::checkRegLatchDesc(const TimingRole *role,
2026-01-03 16:59:35 -08:00
const RiseFall *clk_rf) const
2018-09-28 08:54:21 -07:00
{
if (role == TimingRole::regClkToQ())
2019-11-11 15:30:19 -07:00
return regDesc(clk_rf);
2018-09-28 08:54:21 -07:00
else if (role == TimingRole::latchEnToQ()
2026-01-03 16:59:35 -08:00
|| role == TimingRole::latchDtoQ())
2019-11-11 15:30:19 -07:00
return latchDesc(clk_rf);
2018-09-28 08:54:21 -07:00
else
// Default when we don't know better.
return "edge-triggered flip-flop";
}
2026-03-28 19:13:35 -07:00
std::string_view
2019-11-11 15:30:19 -07:00
ReportPath::regDesc(const RiseFall *clk_rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
if (clk_rf == RiseFall::rise())
2018-09-28 08:54:21 -07:00
return "rising edge-triggered flip-flop";
2019-11-11 15:30:19 -07:00
else if (clk_rf == RiseFall::fall())
2018-09-28 08:54:21 -07:00
return "falling edge-triggered flip-flop";
else
return "edge-triggered flip-flop";
}
2026-03-28 19:13:35 -07:00
std::string_view
2019-11-11 15:30:19 -07:00
ReportPath::latchDesc(const RiseFall *clk_rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
return (clk_rf == RiseFall::rise())
2018-09-28 08:54:21 -07:00
? "positive level-sensitive latch"
: "negative level-sensitive latch";
}
////////////////////////////////////////////////////////////////
static PinSeq
hierPinsThruEdge(const Edge *edge,
const Network *network,
const Graph *graph)
{
const Pin *drvr_pin = edge->from(graph)->pin();
const Pin *load_pin = edge->to(graph)->pin();
PinSeq drvr_hpins;
PinSeq load_hpins;
hierPinsAbove(drvr_pin, network, drvr_hpins);
hierPinsAbove(load_pin, network, load_hpins);
if (drvr_hpins.empty()) {
2026-04-13 14:58:16 -07:00
std::ranges::reverse(load_hpins);
return load_hpins;
}
if (load_hpins.empty())
return drvr_hpins;
for (size_t l1 = 0; l1 < load_hpins.size(); l1++) {
const Pin *load_hpin = load_hpins[l1];
const Net *load_net = network->net(load_hpin);
for (size_t d1 = 0; d1 < drvr_hpins.size(); d1++) {
const Pin *drvr_hpin = drvr_hpins[d1];
const Net *drvr_net = network->net(drvr_hpin);
if (load_net == drvr_net) {
PinSeq hpins_thru;
for (size_t d2 = 0; d2 < d1; d2++) {
const Pin *drvr_hpin2 = drvr_hpins[d2];
hpins_thru.push_back(drvr_hpin2);
}
hpins_thru.push_back(drvr_hpin);
hpins_thru.push_back(load_hpin);
for (size_t l2 = 0; l2 < l1; l2++) {
const Pin *load_hpin2 = load_hpins[l2];
hpins_thru.push_back(load_hpin2);
}
return hpins_thru;
}
}
}
return PinSeq();
}
static void
hierPinsAbove(const Pin *pin,
const Network *network,
PinSeq &pins_above)
{
const Net *net = network->net(pin);
hierPinsAbove(net, network, pins_above);
}
static void
hierPinsAbove(const Net *net,
const Network *network,
PinSeq &pins_above)
{
if (net) {
NetTermIterator *term_iter = network->termIterator(net);
while (term_iter->hasNext()) {
const Term *term = term_iter->next();
const Pin *net_pin = network->pin(term);
if (network->isHierarchical(net_pin))
pins_above.push_back(net_pin);
const Net *hpin_net = network->net(net_pin);
if (hpin_net)
hierPinsAbove(hpin_net, network, pins_above);
}
2025-01-13 17:45:39 -07:00
delete term_iter;
}
}
2026-04-13 14:58:16 -07:00
} // namespace sta