2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, Parallax Software, Inc.
|
2018-09-28 17:54:21 +02: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 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01: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 17:54:21 +02:00
|
|
|
|
2024-12-26 01:44:28 +01:00
|
|
|
#include <algorithm> // reverse
|
|
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "ReportPath.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Error.hh"
|
|
|
|
|
#include "StringUtil.hh"
|
|
|
|
|
#include "Fuzzy.hh"
|
|
|
|
|
#include "Units.hh"
|
|
|
|
|
#include "TimingRole.hh"
|
|
|
|
|
#include "Transition.hh"
|
|
|
|
|
#include "TimingArc.hh"
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "PortDirection.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "Graph.hh"
|
|
|
|
|
#include "PortDelay.hh"
|
|
|
|
|
#include "ExceptionPath.hh"
|
|
|
|
|
#include "InputDrive.hh"
|
|
|
|
|
#include "Sdc.hh"
|
|
|
|
|
#include "Parasitics.hh"
|
|
|
|
|
#include "DcalcAnalysisPt.hh"
|
|
|
|
|
#include "ArcDelayCalc.hh"
|
|
|
|
|
#include "GraphDelayCalc.hh"
|
|
|
|
|
#include "ClkInfo.hh"
|
|
|
|
|
#include "Tag.hh"
|
|
|
|
|
#include "PathAnalysisPt.hh"
|
|
|
|
|
#include "PathGroup.hh"
|
|
|
|
|
#include "CheckMinPulseWidths.hh"
|
|
|
|
|
#include "CheckMinPeriods.hh"
|
|
|
|
|
#include "CheckMaxSkews.hh"
|
2025-03-27 02:21:03 +01:00
|
|
|
#include "Path.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Search.hh"
|
|
|
|
|
#include "PathExpanded.hh"
|
|
|
|
|
#include "Latches.hh"
|
|
|
|
|
#include "Corner.hh"
|
|
|
|
|
#include "Genclks.hh"
|
2025-04-10 01:35:15 +02:00
|
|
|
#include "Variables.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2025-05-22 18:25:56 +02:00
|
|
|
using std::string;
|
|
|
|
|
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
static void
|
|
|
|
|
hierPinsAbove(const Net *net,
|
|
|
|
|
const Network *network,
|
|
|
|
|
PinSeq &pins_above);
|
|
|
|
|
static void
|
|
|
|
|
hierPinsAbove(const Pin *pin,
|
|
|
|
|
const Network *network,
|
|
|
|
|
PinSeq &pins_above);
|
|
|
|
|
|
2024-12-26 01:44:28 +01:00
|
|
|
static PinSeq
|
|
|
|
|
hierPinsThruEdge(const Edge *edge,
|
|
|
|
|
const Network *network,
|
|
|
|
|
const Graph *graph);
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
ReportField::ReportField(const char *name,
|
|
|
|
|
const char *title,
|
|
|
|
|
int width,
|
|
|
|
|
bool left_justify,
|
|
|
|
|
Unit *unit,
|
|
|
|
|
bool enabled) :
|
|
|
|
|
name_(name),
|
|
|
|
|
title_(stringCopy(title)),
|
|
|
|
|
left_justify_(left_justify),
|
|
|
|
|
unit_(unit),
|
2018-11-09 19:04:16 +01:00
|
|
|
enabled_(enabled),
|
2019-03-13 01:25:53 +01:00
|
|
|
blank_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
setWidth(width);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReportField::~ReportField()
|
|
|
|
|
{
|
|
|
|
|
stringDelete(title_);
|
|
|
|
|
stringDelete(blank_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportField::setProperties(const char *title,
|
|
|
|
|
int width,
|
|
|
|
|
bool left_justify)
|
|
|
|
|
{
|
|
|
|
|
if (title_)
|
|
|
|
|
stringDelete(title_);
|
|
|
|
|
title_ = stringCopy(title);
|
|
|
|
|
left_justify_ = left_justify;
|
|
|
|
|
setWidth(width);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportField::setWidth(int width)
|
|
|
|
|
{
|
|
|
|
|
width_ = width;
|
|
|
|
|
|
|
|
|
|
if (blank_)
|
|
|
|
|
stringDelete(blank_);
|
2019-02-16 21:07:59 +01:00
|
|
|
blank_ = new char[width_ + 1];
|
2018-09-28 17:54:21 +02:00
|
|
|
int i;
|
2019-02-16 21:07:59 +01:00
|
|
|
for (i = 0; i < width_; i++)
|
2018-09-28 17:54:21 +02:00
|
|
|
blank_[i] = ' ';
|
|
|
|
|
blank_[i] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportField::setEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
enabled_ = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
const float ReportPath::field_blank_ = -1.0;
|
|
|
|
|
|
|
|
|
|
ReportPath::ReportPath(StaState *sta) :
|
|
|
|
|
StaState(sta),
|
2019-03-13 01:25:53 +01:00
|
|
|
format_(ReportPathFormat::full),
|
2019-02-16 21:07:59 +01:00
|
|
|
no_split_(false),
|
2019-12-24 17:53:45 +01:00
|
|
|
report_sigmas_(false),
|
2019-02-16 21:07:59 +01:00
|
|
|
start_end_pt_width_(80),
|
2019-03-13 01:25:53 +01:00
|
|
|
plus_zero_(nullptr),
|
|
|
|
|
minus_zero_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-02-16 21:07:59 +01:00
|
|
|
setDigits(2);
|
2018-09-28 17:54:21 +02:00
|
|
|
makeFields();
|
2024-12-26 01:44:28 +01:00
|
|
|
setReportFields(false, false, false, false, false, false, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReportPath::~ReportPath()
|
|
|
|
|
{
|
|
|
|
|
delete field_description_;
|
|
|
|
|
delete field_total_;
|
|
|
|
|
delete field_incr_;
|
|
|
|
|
delete field_capacitance_;
|
|
|
|
|
delete field_slew_;
|
|
|
|
|
delete field_fanout_;
|
2024-10-16 02:28:52 +02:00
|
|
|
delete field_src_attr_;
|
2018-09-28 17:54:21 +02:00
|
|
|
delete field_edge_;
|
|
|
|
|
delete field_case_;
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
stringDelete(plus_zero_);
|
|
|
|
|
stringDelete(minus_zero_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::makeFields()
|
|
|
|
|
{
|
2020-06-03 00:19:09 +02:00
|
|
|
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
|
2019-02-16 21:07:59 +01:00
|
|
|
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
|
2018-09-28 17:54:21 +02:00
|
|
|
units_->capacitanceUnit(), true);
|
2019-02-16 21:07:59 +01:00
|
|
|
field_slew_ = makeField("slew", "Slew", 6, false, units_->timeUnit(),
|
|
|
|
|
true);
|
|
|
|
|
field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(),
|
|
|
|
|
true);
|
|
|
|
|
field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(),
|
|
|
|
|
true);
|
2019-03-13 01:25:53 +01:00
|
|
|
field_edge_ = makeField("edge", "", 1, false, nullptr, true);
|
|
|
|
|
field_case_ = makeField("case", "case", 11, false, nullptr, false);
|
2019-02-16 21:07:59 +01:00
|
|
|
field_description_ = makeField("description", "Description", 36,
|
2019-03-13 01:25:53 +01:00
|
|
|
true, nullptr, true);
|
2024-10-16 02:28:52 +02:00
|
|
|
field_src_attr_ = makeField("src_attr", "Src Attr", 40,
|
|
|
|
|
true, nullptr, true);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReportField *
|
|
|
|
|
ReportPath::makeField(const char *name,
|
|
|
|
|
const char *title,
|
|
|
|
|
int width,
|
|
|
|
|
bool left_justify,
|
|
|
|
|
Unit *unit,
|
|
|
|
|
bool enabled)
|
|
|
|
|
{
|
|
|
|
|
ReportField *field = new ReportField(name, title, width, left_justify,
|
|
|
|
|
unit, enabled);
|
2019-02-16 21:07:59 +01:00
|
|
|
fields_.push_back(field);
|
2018-09-28 17:54:21 +02:00
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReportField *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::findField(const char *name) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-02-01 23:53:28 +01:00
|
|
|
for (ReportField *field : fields_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (stringEq(name, field->name()))
|
2019-12-24 17:53:45 +01:00
|
|
|
return field;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::setReportFieldOrder(StringSeq *field_names)
|
|
|
|
|
{
|
|
|
|
|
// Disable all fields.
|
|
|
|
|
ReportFieldSeq::Iterator field_iter1(fields_);
|
|
|
|
|
while (field_iter1.hasNext()) {
|
|
|
|
|
ReportField *field = field_iter1.next();
|
|
|
|
|
field->setEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-16 21:07:59 +01:00
|
|
|
ReportFieldSeq next_fields;
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const char *field_name : *field_names) {
|
2018-09-28 17:54:21 +02:00
|
|
|
ReportField *field = findField(field_name);
|
2022-01-15 20:51:05 +01:00
|
|
|
if (field) {
|
|
|
|
|
next_fields.push_back(field);
|
|
|
|
|
field->setEnabled(true);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
// Push remaining disabled fields on the end.
|
2025-02-01 23:53:28 +01:00
|
|
|
for (ReportField *field : fields_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!field->enabled())
|
2019-02-16 21:07:59 +01:00
|
|
|
next_fields.push_back(field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fields_.clear();
|
2025-02-01 23:53:28 +01:00
|
|
|
for (ReportField *field : next_fields)
|
2019-02-16 21:07:59 +01:00
|
|
|
fields_.push_back(field);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::setReportFields(bool report_input_pin,
|
2024-12-26 01:44:28 +01:00
|
|
|
bool report_hier_pins,
|
2018-09-28 17:54:21 +02:00
|
|
|
bool report_net,
|
|
|
|
|
bool report_cap,
|
2023-08-02 22:11:09 +02:00
|
|
|
bool report_slew,
|
2024-10-16 02:28:52 +02:00
|
|
|
bool report_fanout,
|
|
|
|
|
bool report_src_attr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
report_input_pin_ = report_input_pin;
|
2024-12-26 01:44:28 +01:00
|
|
|
report_hier_pins_ = report_hier_pins;
|
2018-09-28 17:54:21 +02:00
|
|
|
report_net_ = report_net;
|
|
|
|
|
|
|
|
|
|
field_capacitance_->setEnabled(report_cap);
|
|
|
|
|
field_slew_->setEnabled(report_slew);
|
2023-08-02 22:11:09 +02:00
|
|
|
field_fanout_->setEnabled(report_fanout);
|
2024-10-16 02:28:52 +02:00
|
|
|
field_src_attr_->setEnabled(report_src_attr);
|
2018-09-28 17:54:21 +02:00
|
|
|
// for debug
|
|
|
|
|
field_case_->setEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::setPathFormat(ReportPathFormat format)
|
|
|
|
|
{
|
|
|
|
|
format_ = format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::setNoSplit(bool no_split)
|
|
|
|
|
{
|
|
|
|
|
no_split_ = no_split;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::setDigits(int digits)
|
|
|
|
|
{
|
|
|
|
|
digits_ = digits;
|
|
|
|
|
|
2023-03-13 18:24:13 +01:00
|
|
|
stringDelete(plus_zero_);
|
|
|
|
|
stringDelete(minus_zero_);
|
2019-01-17 00:37:31 +01:00
|
|
|
minus_zero_ = stringPrint("-%.*f", digits_, 0.0);
|
|
|
|
|
plus_zero_ = stringPrint("%.*f", digits_, 0.0);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-24 17:53:45 +01:00
|
|
|
void
|
|
|
|
|
ReportPath::setReportSigmas(bool report)
|
|
|
|
|
{
|
|
|
|
|
report_sigmas_ = report;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathEnd(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2024-09-17 02:04:31 +02:00
|
|
|
reportPathEnd(end, nullptr, true);
|
2018-12-21 07:41:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathEnd(const PathEnd *end,
|
|
|
|
|
const PathEnd *prev_end,
|
|
|
|
|
bool last) const
|
2018-12-21 07:41:54 +01:00
|
|
|
{
|
2018-09-28 17:54:21 +02:00
|
|
|
switch (format_) {
|
2019-03-13 01:25:53 +01:00
|
|
|
case ReportPathFormat::full:
|
|
|
|
|
case ReportPathFormat::full_clock:
|
|
|
|
|
case ReportPathFormat::full_clock_expanded:
|
2020-12-29 04:51:34 +01:00
|
|
|
end->reportFull(this);
|
|
|
|
|
reportBlankLine();
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case ReportPathFormat::shorter:
|
2020-12-29 04:51:34 +01:00
|
|
|
end->reportShort(this);
|
|
|
|
|
reportBlankLine();
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case ReportPathFormat::endpoint:
|
2018-12-21 07:41:54 +01:00
|
|
|
reportEndpointHeader(end, prev_end);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndLine(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case ReportPathFormat::summary:
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSummaryLine(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case ReportPathFormat::slack_only:
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSlackOnly(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
2024-09-17 02:04:31 +02:00
|
|
|
case ReportPathFormat::json:
|
|
|
|
|
reportJson(end, last);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathEnds(const PathEndSeq *ends) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2018-12-21 07:41:54 +01:00
|
|
|
reportPathEndHeader();
|
2025-01-17 00:32:53 +01:00
|
|
|
if (ends && !ends->empty()) {
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
PathEnd *prev_end = nullptr;
|
2025-02-01 23:53:28 +01:00
|
|
|
PathEndSeq::ConstIterator end_iter(ends);
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
while (end_iter.hasNext()) {
|
|
|
|
|
PathEnd *end = end_iter.next();
|
|
|
|
|
reportPathEnd(end, prev_end, !end_iter.hasNext());
|
|
|
|
|
prev_end = end;
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-01-17 00:32:53 +01:00
|
|
|
else {
|
|
|
|
|
if (format_ != ReportPathFormat::json)
|
|
|
|
|
report_->reportLine("No paths found.");
|
|
|
|
|
}
|
2018-12-21 07:41:54 +01:00
|
|
|
reportPathEndFooter();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathEndHeader() const
|
2024-09-17 02:04:31 +02: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 23:53:28 +01:00
|
|
|
ReportPath::reportPathEndFooter() const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
string header;
|
|
|
|
|
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 17:54:21 +02:00
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpointHeader(const PathEnd *end,
|
|
|
|
|
const PathEnd *prev_end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
PathGroup *prev_group = nullptr;
|
2018-12-21 07:41:54 +01:00
|
|
|
if (prev_end)
|
2025-10-30 16:53:36 +01:00
|
|
|
prev_group = prev_end->pathGroup();
|
|
|
|
|
PathGroup *group = end->pathGroup();
|
2022-01-15 20:51:05 +01:00
|
|
|
if (group && group != prev_group) {
|
2018-12-21 07:41:54 +01:00
|
|
|
if (prev_group)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-12-21 07:41:54 +01:00
|
|
|
const char *setup_hold = (end->minMax(this) == MinMax::min())
|
|
|
|
|
? "min_delay/hold"
|
|
|
|
|
: "max_delay/setup";
|
2020-12-28 18:04:57 +01:00
|
|
|
report_->reportLine("%s group %s",
|
|
|
|
|
setup_hold,
|
|
|
|
|
group->name());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2020-12-29 03:04:49 +01:00
|
|
|
reportEndHeader();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndUnconstrained *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndUnconstrained *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportUnclockedEndpoint(end, "internal pin");
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndUnconstrained *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath(end, expanded);
|
2018-11-26 18:15:52 +01:00
|
|
|
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
2020-12-29 04:51:34 +01:00
|
|
|
end->pathEarlyLate(this));
|
|
|
|
|
reportDashLine();
|
|
|
|
|
report_->reportLine("(Path is unconstrained)");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndCheck *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportEndpoint(end);
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportSrcPathArrival(end, expanded);
|
|
|
|
|
reportTgtClk(end);
|
|
|
|
|
reportRequired(end, checkRoleString(end));
|
|
|
|
|
reportSlack(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::checkRoleString(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-31 00:27:53 +02:00
|
|
|
return stdstrPrint("library %s time",
|
|
|
|
|
end->checkRole(this)->to_string().c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = tgtClkName(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *rise_fall = asRisingFalling(end->targetClkEndTrans(this));
|
|
|
|
|
const TimingRole *check_role = end->checkRole(this);
|
|
|
|
|
const TimingRole *check_generic_role = check_role->genericRole();
|
|
|
|
|
if (check_role == TimingRole::recovery()
|
|
|
|
|
|| check_role == TimingRole::removal()) {
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s check against %s-edge clock %s",
|
2025-03-31 00:27:53 +02:00
|
|
|
check_role->to_string().c_str(),
|
2019-01-17 00:37:31 +01:00
|
|
|
rise_fall,
|
|
|
|
|
clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (check_generic_role == TimingRole::setup()
|
|
|
|
|
|| check_generic_role == TimingRole::hold()) {
|
|
|
|
|
LibertyCell *cell = network_->libertyCell(inst);
|
|
|
|
|
if (cell->isClockGate()) {
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s",
|
|
|
|
|
rise_fall, clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const char *reg_desc = clkRegLatchDesc(end);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndLatchCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndLatchCheck *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportEndpoint(end);
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndLatchCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportBlankLine();
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
PathDelay *path_delay = end->pathDelay();
|
|
|
|
|
bool ignore_clk_latency = path_delay && path_delay->ignoreClkLatency();
|
|
|
|
|
if (ignore_clk_latency) {
|
|
|
|
|
// Based on reportSrcPath.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSrcPath(end, expanded);
|
|
|
|
|
reportLine("data arrival time", end->dataArrivalTimeOffset(this), early_late);
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
Required req_time;
|
|
|
|
|
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
|
|
|
|
|
end->latchRequired(this, req_time, borrow, adjusted_data_arrival,
|
|
|
|
|
time_given_to_startpoint);
|
|
|
|
|
// Adjust required to requiredTimeOffset.
|
|
|
|
|
req_time += end->sourceClkOffset(this);
|
|
|
|
|
if (path_delay) {
|
|
|
|
|
float delay = path_delay->delay();
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("max_delay", delay, delay, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!ignore_clk_latency) {
|
|
|
|
|
if (reportClkPath()
|
|
|
|
|
&& isPropagated(end->targetClkPath()))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportTgtClk(end, delay);
|
2018-11-26 18:15:52 +01:00
|
|
|
else {
|
|
|
|
|
Delay delay1(delay);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportCommonClkPessimism(end, delay1);
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportTgtClk(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-07-12 02:43:30 +02:00
|
|
|
if (delayGreaterEqual(borrow, 0.0, this))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("time borrowed from endpoint", borrow, req_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 04:51:34 +01: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 17:54:21 +02:00
|
|
|
if (end->checkGenericRole(this) == TimingRole::setup()
|
|
|
|
|
&& !ignore_clk_latency) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
|
|
|
|
reportBorrowing(end, borrow, time_given_to_startpoint);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndLatchCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = tgtClkName(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *reg_desc = latchDesc(end);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::latchDesc(const PathEndLatchCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
TimingArc *check_arc = end->checkArc();
|
2024-07-08 02:56:55 +02:00
|
|
|
const RiseFall *en_rf = check_arc->fromEdge()->asRiseFall()->opposite();
|
|
|
|
|
return latchDesc(en_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|
|
|
|
Arrival &borrow,
|
2025-02-01 23:53:28 +01:00
|
|
|
Arrival &time_given_to_startpoint) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Delay open_latency, latency_diff, max_borrow;
|
2018-12-11 19:47:04 +01:00
|
|
|
float nom_pulse_width, open_uncertainty;
|
|
|
|
|
Crpr open_crpr, crpr_diff;
|
2018-09-28 17:54:21 +02:00
|
|
|
bool borrow_limit_exists;
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = EarlyLate::late();
|
2018-09-28 17:54:21 +02:00
|
|
|
end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff,
|
|
|
|
|
open_uncertainty, open_crpr, crpr_diff,
|
|
|
|
|
max_borrow, borrow_limit_exists);
|
2020-12-29 04:51:34 +01:00
|
|
|
report_->reportLine("Time Borrowing Information");
|
|
|
|
|
reportDashLineTotal();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (borrow_limit_exists)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal("user max time borrow", max_borrow, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
2019-01-17 00:37:31 +01:00
|
|
|
string tgt_clk_name = tgtClkName(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
Arrival tgt_clk_width = end->targetClkWidth(this);
|
|
|
|
|
const Path *tgt_clk_path = end->targetClkPath();
|
|
|
|
|
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
|
2019-01-17 00:37:31 +01:00
|
|
|
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late);
|
2020-07-12 01:24:48 +02:00
|
|
|
if (!delayZero(latency_diff))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotalMinus("clock latency difference", latency_diff, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-01-17 00:37:31 +01:00
|
|
|
auto width_msg = stdstrPrint("%s pulse width", tgt_clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal(width_msg.c_str(), tgt_clk_width, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
ArcDelay margin = end->margin(this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotalMinus("library setup time", margin, early_late);
|
|
|
|
|
reportDashLineTotal();
|
2020-07-12 01:24:48 +02:00
|
|
|
if (!delayZero(crpr_diff))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotalMinus("CRPR difference", crpr_diff, early_late);
|
|
|
|
|
reportLineTotal("max time borrow", max_borrow, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-07-12 02:43:30 +02:00
|
|
|
if (delayGreater(borrow, delay_zero, this)
|
2018-09-28 17:54:21 +02:00
|
|
|
&& (!fuzzyZero(open_uncertainty)
|
2020-07-12 01:24:48 +02:00
|
|
|
|| !delayZero(open_crpr))) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDashLineTotal();
|
|
|
|
|
reportLineTotal("actual time borrow", borrow, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!fuzzyZero(open_uncertainty))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal("open edge uncertainty", open_uncertainty, early_late);
|
2020-07-12 01:24:48 +02:00
|
|
|
if (!delayZero(open_crpr))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal("open edge CRPR", open_crpr, early_late);
|
|
|
|
|
reportDashLineTotal();
|
|
|
|
|
reportLineTotal("time given to startpoint", time_given_to_startpoint, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal("actual time borrow", borrow, early_late);
|
|
|
|
|
reportDashLineTotal();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndPathDelay *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndPathDelay *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (end->targetClk(this))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportUnclockedEndpoint(end, "internal path endpoint");
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndPathDelay *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-06-25 22:38:47 +02:00
|
|
|
if (end->hasOutputDelay())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpointOutputDelay(end);
|
2020-06-25 22:38:47 +02:00
|
|
|
else {
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
|
|
|
|
string clk_name = tgtClkName(end);
|
|
|
|
|
const char *reg_desc = clkRegLatchDesc(end);
|
|
|
|
|
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2020-06-25 22:38:47 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndPathDelay *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
// Based on reportSrcPathArrival.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
PathDelay *path_delay = end->pathDelay();
|
2024-08-06 01:51:46 +02:00
|
|
|
if (end->ignoreClkLatency(this)) {
|
2018-09-28 17:54:21 +02:00
|
|
|
// Based on reportSrcPath.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSrcPath(end, expanded);
|
|
|
|
|
reportLine("data arrival time", end->dataArrivalTimeOffset(this), early_late);
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
ArcDelay margin = end->margin(this);
|
2025-03-31 00:27:53 +02:00
|
|
|
const MinMax *min_max = path_delay->minMax()->asMinMax();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (min_max == MinMax::max())
|
|
|
|
|
margin = -margin;
|
|
|
|
|
|
2025-03-31 00:27:53 +02:00
|
|
|
string delay_msg = min_max->to_string() + "_delay";
|
2018-09-28 17:54:21 +02:00
|
|
|
float delay = path_delay->delay();
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(delay_msg.c_str(), delay, delay, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!path_delay->ignoreClkLatency()) {
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *tgt_clk = end->targetClk(this);
|
2020-06-25 22:38:47 +02:00
|
|
|
if (tgt_clk) {
|
|
|
|
|
const Path *tgt_clk_path = end->targetClkPath();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (reportClkPath()
|
2020-06-25 22:38:47 +02:00
|
|
|
&& isPropagated(tgt_clk_path, tgt_clk))
|
2024-10-02 22:20:29 +02:00
|
|
|
reportTgtClk(end, delay, 0.0, true);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
|
|
|
|
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
2020-07-12 01:24:48 +02:00
|
|
|
if (!delayZero(tgt_clk_delay))
|
2018-09-28 17:54:21 +02:00
|
|
|
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
|
2020-12-29 04:51:34 +01:00
|
|
|
tgt_clk_delay, tgt_clk_arrival, early_late);
|
|
|
|
|
reportClkUncertainty(end, tgt_clk_arrival);
|
|
|
|
|
reportCommonClkPessimism(end, tgt_clk_arrival);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-17 00:37:31 +01:00
|
|
|
if (end->pathDelayMarginIsExternal())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportRequired(end, "output external delay");
|
2019-01-17 00:37:31 +01:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportRequired(end, checkRoleString(end));
|
|
|
|
|
reportSlack(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::isPropagated(const Path *clk_path) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return clk_path->clkInfo(search_)->isPropagated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::isPropagated(const Path *clk_path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const Clock *clk) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (clk_path)
|
|
|
|
|
return clk_path->clkInfo(search_)->isPropagated();
|
|
|
|
|
else
|
|
|
|
|
return clk->isPropagated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::clkNetworkDelayIdealProp(bool is_prop) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (is_prop)
|
|
|
|
|
return "clock network delay (propagated)";
|
|
|
|
|
else
|
|
|
|
|
return "clock network delay (ideal)";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndOutputDelay *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndOutputDelay *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportEndpoint(end);
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndOutputDelay *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportSrcPathArrival(end, expanded);
|
|
|
|
|
reportTgtClk(end);
|
|
|
|
|
reportRequired(end, "output external delay");
|
|
|
|
|
reportSlack(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndOutputDelay *end) const
|
2020-06-25 22:38:47 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpointOutputDelay(end);
|
2020-06-25 22:38:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Vertex *vertex = end->vertex(this);
|
|
|
|
|
Pin *pin = vertex->pin();
|
|
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *tgt_clk = end->targetClk(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
// Pin direction is "output" even for bidirects.
|
|
|
|
|
if (tgt_clk) {
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = tgtClkName(end);
|
|
|
|
|
auto reason = stdstrPrint("output port clocked by %s", clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(pin_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(pin_name, "output port");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (tgt_clk) {
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = tgtClkName(end);
|
2021-01-05 03:26:58 +01:00
|
|
|
auto reason = stdstrPrint("internal path endpoint clocked by %s",
|
|
|
|
|
clk_name.c_str());
|
2020-06-25 22:38:47 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(pin_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(pin_name, "internal path endpoint");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndGatedClock *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndGatedClock *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportEndpoint(end);
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndGatedClock *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportSrcPathArrival(end, expanded);
|
|
|
|
|
reportTgtClk(end);
|
|
|
|
|
reportRequired(end, checkRoleReason(end));
|
|
|
|
|
reportSlack(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndGatedClock *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = tgtClkName(end);
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
|
|
|
|
|
const RiseFall *clk_rf =
|
|
|
|
|
(end->minMax(this) == MinMax::max()) ? clk_end_rf : clk_end_rf->opposite();
|
|
|
|
|
const char *rise_fall = asRisingFalling(clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Note that target clock transition is ignored.
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s",
|
|
|
|
|
rise_fall,
|
|
|
|
|
clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const PathEndDataCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportShort(const PathEndDataCheck *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(end, expanded);
|
|
|
|
|
reportEndpoint(end);
|
|
|
|
|
reportGroup(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportFull(const PathEndDataCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportShort(end, expanded);
|
|
|
|
|
reportSrcPathArrival(end, expanded);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-07-13 16:38:39 +02:00
|
|
|
// Data check target clock path reporting resembles
|
|
|
|
|
// both source (reportSrcPath) and target (reportTgtClk) clocks.
|
2018-09-28 17:54:21 +02: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-29 04:51:34 +01:00
|
|
|
reportTgtClk(end, 0.0, true);
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *data_clk_path = end->dataClkPath();
|
2018-09-28 17:54:21 +02: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 18:15:52 +01:00
|
|
|
Delay clk_delay = end->targetClkDelay(this);
|
|
|
|
|
Arrival clk_arrival = end->targetClkArrival(this);
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
2020-07-13 16:38:39 +02:00
|
|
|
float prev = delayAsFloat(clk_arrival) + src_offset;
|
|
|
|
|
float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time();
|
2025-08-18 22:27:30 +02:00
|
|
|
// Delay to startpoint is already included.
|
|
|
|
|
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
|
|
|
|
|
true, false, prev, offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportRequired(end, checkRoleReason(end));
|
|
|
|
|
reportSlack(end);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndpoint(const PathEndDataCheck *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
2019-11-11 23:30:19 +01:00
|
|
|
const char *tgt_clk_rf = asRisingFalling(end->dataClkPath()->transition(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *tgt_clk_name = end->targetClk(this)->name();
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s edge-triggered data to data check clocked by %s",
|
2019-11-11 23:30:19 +01:00
|
|
|
tgt_clk_rf,
|
2019-01-17 00:37:31 +01:00
|
|
|
tgt_clk_name);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndHeader() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
// Line one.
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription("", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Required", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Actual", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
// Line two.
|
2020-12-29 03:04:49 +01:00
|
|
|
line.clear();
|
|
|
|
|
reportDescription("Endpoint", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Delay", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Delay", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportEndLine(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
2019-01-17 00:37:31 +01:00
|
|
|
string endpoint = pathEndpoint(end);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDescription(endpoint.c_str(), line);
|
|
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
|
|
|
|
reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, line);
|
|
|
|
|
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
|
|
|
|
|
reportSpaceSlack(end, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSummaryHeader() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("Startpoint", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportDescription("Endpoint", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
reportDashLine(field_description_->width() * 2 + field_total_->width() + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSummaryLine(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
PathExpanded expanded(end->path(), this);
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto startpoint = pathStartpoint(end, expanded);
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription(startpoint.c_str(), line);
|
|
|
|
|
line += ' ';
|
2019-01-17 00:37:31 +01:00
|
|
|
auto endpoint = pathEndpoint(end);
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription(endpoint.c_str(), line);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (end->isUnconstrained())
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2022-06-11 04:37:33 +02:00
|
|
|
reportSpaceFieldDelay(end->slack(this), EarlyLate::early(), line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::pathStartpoint(const PathEnd *end,
|
|
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *start = expanded.startPath();
|
2018-09-28 17:54:21 +02:00
|
|
|
Pin *pin = start->pin(graph_);
|
|
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
|
|
|
|
if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
PortDirection *dir = network_->direction(pin);
|
2019-01-17 00:37:31 +01:00
|
|
|
return stdstrPrint("%s (%s)", pin_name, dir->name());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *cell_name = cmd_network_->name(network_->cell(inst));
|
2019-01-17 00:37:31 +01:00
|
|
|
return stdstrPrint("%s (%s)", pin_name, cell_name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::pathEndpoint(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Pin *pin = end->vertex(this)->pin();
|
|
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
|
|
|
|
if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
PortDirection *dir = network_->direction(pin);
|
2019-01-17 00:37:31 +01:00
|
|
|
return stdstrPrint("%s (%s)", pin_name, dir->name());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Instance *inst = network_->instance(end->vertex(this)->pin());
|
|
|
|
|
const char *cell_name = cmd_network_->name(network_->cell(inst));
|
2019-01-17 00:37:31 +01:00
|
|
|
return stdstrPrint("%s (%s)", pin_name, cell_name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportJsonHeader() const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
report_->reportLine("{\"checks\": [");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportJsonFooter() const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
report_->reportLine("]");
|
|
|
|
|
report_->reportLine("}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportJson(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool last) const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
string result;
|
|
|
|
|
result += "{\n";
|
|
|
|
|
stringAppend(result, " \"type\": \"%s\",\n", end->typeName());
|
|
|
|
|
stringAppend(result, " \"path_group\": \"%s\",\n",
|
2025-10-30 16:53:36 +01:00
|
|
|
end->pathGroup()->name());
|
2024-09-17 02:04:31 +02:00
|
|
|
stringAppend(result, " \"path_type\": \"%s\",\n",
|
2025-03-31 00:27:53 +02:00
|
|
|
end->minMax(this)->to_string().c_str());
|
2024-09-17 02:04:31 +02:00
|
|
|
|
|
|
|
|
PathExpanded expanded(end->path(), this);
|
|
|
|
|
const Pin *startpoint = expanded.startPath()->vertex(this)->pin();
|
|
|
|
|
const Pin *endpoint = expanded.endPath()->vertex(this)->pin();
|
|
|
|
|
stringAppend(result, " \"startpoint\": \"%s\",\n",
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
sdc_network_->pathName(startpoint));
|
2024-09-17 02:04:31 +02:00
|
|
|
stringAppend(result, " \"endpoint\": \"%s\",\n",
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
sdc_network_->pathName(endpoint));
|
2024-09-17 02:04:31 +02:00
|
|
|
|
|
|
|
|
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
|
2025-08-13 18:53:44 +02:00
|
|
|
const Path *src_clk_path = expanded.clkPath();
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *tgt_clk_path = end->targetClkPath();
|
2024-09-17 02:04:31 +02:00
|
|
|
if (src_clk_edge) {
|
|
|
|
|
stringAppend(result, " \"source_clock\": \"%s\",\n",
|
|
|
|
|
src_clk_edge->clock()->name());
|
|
|
|
|
stringAppend(result, " \"source_clock_edge\": \"%s\",\n",
|
|
|
|
|
src_clk_edge->transition()->name());
|
|
|
|
|
}
|
2025-08-13 18:53:44 +02:00
|
|
|
if (src_clk_path)
|
|
|
|
|
reportJson(src_clk_path, "source_clock_path", 2, true, result);
|
2024-09-17 02:04:31 +02:00
|
|
|
reportJson(expanded, "source_path", 2, !end->isUnconstrained(), result);
|
|
|
|
|
|
|
|
|
|
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
|
|
|
|
if (tgt_clk_edge) {
|
|
|
|
|
stringAppend(result, " \"target_clock\": \"%s\",\n",
|
|
|
|
|
tgt_clk_edge->clock()->name());
|
|
|
|
|
stringAppend(result, " \"target_clock_edge\": \"%s\",\n",
|
|
|
|
|
tgt_clk_edge->transition()->name());
|
|
|
|
|
}
|
|
|
|
|
if (tgt_clk_path)
|
|
|
|
|
reportJson(end->targetClkPath(), "target_clock_path", 2, true, result);
|
|
|
|
|
|
|
|
|
|
if (end->checkRole(this)) {
|
2024-11-16 00:58:52 +01:00
|
|
|
stringAppend(result, " \"data_arrival_time\": %.3e,\n",
|
|
|
|
|
delayAsFloat(end->dataArrivalTimeOffset(this)));
|
2024-09-17 02:04:31 +02:00
|
|
|
|
|
|
|
|
const MultiCyclePath *mcp = end->multiCyclePath();
|
|
|
|
|
if (mcp)
|
|
|
|
|
stringAppend(result, " \"multi_cycle_path\": %d,\n",
|
|
|
|
|
mcp->pathMultiplier());
|
|
|
|
|
|
|
|
|
|
PathDelay *path_delay = end->pathDelay();
|
|
|
|
|
if (path_delay)
|
|
|
|
|
stringAppend(result, " \"path_delay\": %.3e,\n",
|
|
|
|
|
path_delay->delay());
|
|
|
|
|
|
2024-11-16 00:58:52 +01:00
|
|
|
stringAppend(result, " \"crpr\": %.3e,\n",
|
|
|
|
|
delayAsFloat(end->checkCrpr(this)));
|
|
|
|
|
stringAppend(result, " \"margin\": %.3e,\n",
|
|
|
|
|
delayAsFloat(end->margin(this)));
|
|
|
|
|
stringAppend(result, " \"required_time\": %.3e,\n",
|
|
|
|
|
delayAsFloat(end->requiredTimeOffset(this)));
|
|
|
|
|
stringAppend(result, " \"slack\": %.3e\n",
|
|
|
|
|
delayAsFloat(end->slack(this)));
|
2024-09-17 02:04:31 +02:00
|
|
|
}
|
|
|
|
|
result += "}";
|
|
|
|
|
if (!last)
|
|
|
|
|
result += ",";
|
|
|
|
|
report_->reportLineString(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportJson(const Path *path) const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
string result;
|
|
|
|
|
result += "{\n";
|
|
|
|
|
reportJson(path, "path", 0, false, result);
|
|
|
|
|
result += "}\n";
|
|
|
|
|
report_->reportLineString(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportJson(const Path *path,
|
|
|
|
|
const char *path_name,
|
|
|
|
|
int indent,
|
|
|
|
|
bool trailing_comma,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &result) const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
PathExpanded expanded(path, this);
|
|
|
|
|
reportJson(expanded, path_name, indent, trailing_comma, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportJson(const PathExpanded &expanded,
|
|
|
|
|
const char *path_name,
|
|
|
|
|
int indent,
|
|
|
|
|
bool trailing_comma,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &result) const
|
2024-09-17 02:04:31 +02:00
|
|
|
{
|
|
|
|
|
stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name);
|
2025-08-13 18:53:44 +02:00
|
|
|
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *path = expanded.path(i);
|
2024-09-17 02:04:31 +02:00
|
|
|
const Pin *pin = path->vertex(this)->pin();
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
const Net *net = network_->net(pin);
|
|
|
|
|
const Instance *inst = network_->instance(pin);
|
|
|
|
|
const RiseFall *rf = path->transition(this);
|
|
|
|
|
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
|
|
|
|
|
bool is_driver = network_->isDriver(pin);
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
stringAppend(result, "%*s {\n", indent, "");
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
|
|
|
|
|
if (inst) {
|
|
|
|
|
stringAppend(result, "%*s \"instance\": \"%s\",\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
sdc_network_->pathName(inst));
|
|
|
|
|
Cell *cell = network_->cell(inst);
|
|
|
|
|
if (cell)
|
|
|
|
|
stringAppend(result, "%*s \"cell\": \"%s\",\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
sdc_network_->name(cell));
|
|
|
|
|
stringAppend(result, "%*s \"verilog_src\": \"%s\",\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
sdc_network_->getAttribute(inst, "src").c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
stringAppend(result, "%*s \"pin\": \"%s\",\n",
|
|
|
|
|
indent, "",
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
sdc_network_->pathName(pin));
|
|
|
|
|
|
|
|
|
|
if (net) {
|
|
|
|
|
stringAppend(result, "%*s \"net\": \"%s\",\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
sdc_network_->pathName(net));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PinSeq pins_above;
|
|
|
|
|
hierPinsAbove(pin, network_, pins_above);
|
|
|
|
|
if (!pins_above.empty()) {
|
|
|
|
|
stringAppend(result, "%*s \"hier_pins\": [\n", indent, "");
|
|
|
|
|
for (const Pin *hpin : pins_above) {
|
|
|
|
|
stringAppend(result, "%*s \"%s\"%s\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
sdc_network_->pathName(hpin),
|
|
|
|
|
(hpin != pins_above.back()) ? "," : "");
|
|
|
|
|
}
|
|
|
|
|
stringAppend(result, "%*s ],\n", indent, "");
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
double x, y;
|
|
|
|
|
bool exists;
|
|
|
|
|
network_->location(pin, x, y, exists);
|
|
|
|
|
if (exists) {
|
|
|
|
|
stringAppend(result, "%*s \"x\": %.9f,\n", indent, "", x);
|
|
|
|
|
stringAppend(result, "%*s \"y\": %.9f,\n", indent, "", y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stringAppend(result, "%*s \"arrival\": %.3e,\n",
|
|
|
|
|
indent, "",
|
2025-03-27 02:21:03 +01:00
|
|
|
delayAsFloat(path->arrival()));
|
Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)
* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`
* Smallfix
* Improved nets
* Race condition fix
* Fixes
* Small whitespace fix
* Add no paths corner case stuff
* Adjustments to naming of fields
* Requested fixes
* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning
* Fix escapeBackslashes to use preferred style
* No backslash escaping
* Make requested fixes
2025-01-14 04:28:04 +01:00
|
|
|
if (is_driver)
|
|
|
|
|
stringAppend(result, "%*s \"capacitance\": %.3e,\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
graph_delay_calc_->loadCap(pin, rf, dcalc_ap));
|
2024-09-17 02:04:31 +02:00
|
|
|
stringAppend(result, "%*s \"slew\": %.3e\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
delayAsFloat(path->slew(this)));
|
|
|
|
|
stringAppend(result, "%*s }%s\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
(i < expanded.size() - 1) ? "," : "");
|
|
|
|
|
}
|
|
|
|
|
stringAppend(result, "%*s]%s\n",
|
|
|
|
|
indent, "",
|
|
|
|
|
trailing_comma ? "," : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSlackOnlyHeader() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("Group", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
reportDashLine(field_description_->width() + field_total_->width() + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSlackOnly(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
2025-10-30 16:53:36 +01:00
|
|
|
reportDescription(end->pathGroup()->name(), line);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (end->isUnconstrained())
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSpaceFieldDelay(end->slack(this), early_late, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportMpwCheck(const MinPulseWidthCheck *check,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (verbose) {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportVerbose(check);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportMpwHeaderShort();
|
|
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportMpwChecks(const MinPulseWidthCheckSeq *checks,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (!checks->empty()) {
|
|
|
|
|
if (verbose) {
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MinPulseWidthCheck *check : *checks) {
|
|
|
|
|
reportVerbose(check);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportMpwHeaderShort();
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MinPulseWidthCheck *check : *checks)
|
2020-12-29 03:04:49 +01:00
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportMpwHeaderShort() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Required", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Actual", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
line.clear();
|
|
|
|
|
reportDescription("Pin", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Width", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Width", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const MinPulseWidthCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(check->pin(this));
|
|
|
|
|
const char *hi_low = mpwCheckHiLow(check);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto what = stdstrPrint("%s (%s)", pin_name, hi_low);
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription(what.c_str(), line);
|
|
|
|
|
reportSpaceFieldTime(check->minWidth(this), line);
|
|
|
|
|
reportSpaceFieldDelay(check->width(this), EarlyLate::late(), line);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSpaceSlack(check->slack(this), line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportVerbose(const MinPulseWidthCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(check->pin(this));
|
2020-12-29 03:04:49 +01:00
|
|
|
line += "Pin: ";
|
|
|
|
|
line += pin_name;
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
report_->reportLine("Check: sequential_clock_pulse_width");
|
|
|
|
|
reportBlankLine();
|
|
|
|
|
reportPathHeader();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *open_el = EarlyLate::late();
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *open_clk_edge = check->openClkEdge(this);
|
|
|
|
|
const Clock *open_clk = open_clk_edge->clock();
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *open_clk_name = open_clk->name();
|
|
|
|
|
const char *open_rise_fall = asRiseFall(open_clk_edge->transition());
|
|
|
|
|
float open_clk_time = open_clk_edge->time();
|
2019-01-17 00:37:31 +01:00
|
|
|
auto open_clk_msg = stdstrPrint("clock %s (%s edge)", open_clk_name, open_rise_fall);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(open_clk_msg.c_str(), open_clk_time, open_clk_time, open_el);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
Arrival open_arrival = check->openArrival(this);
|
|
|
|
|
bool is_prop = isPropagated(check->openPath());
|
|
|
|
|
const char *clk_ideal_prop = clkNetworkDelayIdealProp(is_prop);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clk_ideal_prop, check->openDelay(this), open_arrival, open_el);
|
|
|
|
|
reportLine(pin_name, delay_zero, open_arrival, open_el);
|
|
|
|
|
reportLine("open edge arrival time", open_arrival, open_el);
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *close_el = EarlyLate::late();
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *close_clk_edge = check->closeClkEdge(this);
|
|
|
|
|
const Clock *close_clk = close_clk_edge->clock();
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *close_clk_name = close_clk->name();
|
|
|
|
|
const char *close_rise_fall = asRiseFall(close_clk_edge->transition());
|
|
|
|
|
float close_offset = check->closeOffset(this);
|
|
|
|
|
float close_clk_time = close_clk_edge->time() + close_offset;
|
2019-01-17 00:37:31 +01:00
|
|
|
auto close_clk_msg = stdstrPrint("clock %s (%s edge)", close_clk_name, close_rise_fall);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(close_clk_msg.c_str(), close_clk_time, close_clk_time, close_el);
|
2018-09-28 17:54:21 +02:00
|
|
|
Arrival close_arrival = check->closeArrival(this) + close_offset;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival, close_el);
|
|
|
|
|
reportLine(pin_name, delay_zero, close_arrival, close_el);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-04-10 01:35:15 +02:00
|
|
|
if (variables_->crprEnabled()) {
|
2024-06-27 22:57:58 +02:00
|
|
|
Crpr pessimism = check->checkCrpr(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
close_arrival += pessimism;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("clock reconvergence pessimism", pessimism, close_arrival, close_el);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("close edge arrival time", close_arrival, close_el);
|
|
|
|
|
reportDashLine();
|
2018-11-26 18:15:52 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
float min_width = check->minWidth(this);
|
|
|
|
|
const char *hi_low = mpwCheckHiLow(check);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto rpw_msg = stdstrPrint("required pulse width (%s)", hi_low);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(rpw_msg.c_str(), min_width, EarlyLate::early());
|
|
|
|
|
reportLine("actual pulse width", check->width(this), EarlyLate::early());
|
|
|
|
|
reportDashLine();
|
|
|
|
|
reportSlack(check->slack(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::mpwCheckHiLow(const MinPulseWidthCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
if (check->openTransition(this) == RiseFall::rise())
|
2018-09-28 17:54:21 +02:00
|
|
|
return "high";
|
|
|
|
|
else
|
|
|
|
|
return "low";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportCheck(const MinPeriodCheck *check,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (verbose) {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportVerbose(check);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportPeriodHeaderShort();
|
|
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportChecks(const MinPeriodCheckSeq *checks,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (!checks->empty()) {
|
|
|
|
|
if (verbose) {
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MinPeriodCheck *check : *checks) {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportVerbose(check);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportPeriodHeaderShort();
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MinPeriodCheck *check : *checks)
|
2020-12-29 03:04:49 +01:00
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPeriodHeaderShort() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Min", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
line.clear();
|
|
|
|
|
reportDescription("Pin", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Period", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Period", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const MinPeriodCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(check->pin());
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription(pin_name, line);
|
|
|
|
|
reportSpaceFieldDelay(check->period(), EarlyLate::early(), line);
|
|
|
|
|
reportSpaceFieldDelay(check->minPeriod(this), EarlyLate::early(), line);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSpaceSlack(check->slack(this), line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportVerbose(const MinPeriodCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(check->pin());
|
2020-12-29 03:04:49 +01:00
|
|
|
line += "Pin: ";
|
|
|
|
|
line += pin_name;
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("period", check->period(), EarlyLate::early());
|
|
|
|
|
reportLine("min period", -check->minPeriod(this), EarlyLate::early());
|
|
|
|
|
reportDashLine();
|
2020-12-29 03:04:49 +01:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSlack(check->slack(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportCheck(const MaxSkewCheck *check,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (verbose) {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportVerbose(check);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportMaxSkewHeaderShort();
|
|
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportChecks(const MaxSkewCheckSeq *checks,
|
|
|
|
|
bool verbose) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (!checks->empty()) {
|
|
|
|
|
if (verbose) {
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MaxSkewCheck *check : *checks)
|
2020-12-29 03:04:49 +01:00
|
|
|
reportVerbose(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 03:04:49 +01:00
|
|
|
reportMaxSkewHeaderShort();
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const MaxSkewCheck *check : *checks)
|
2020-12-29 03:04:49 +01:00
|
|
|
reportShort(check);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportMaxSkewHeaderShort() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Required", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Actual", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
line.clear();
|
|
|
|
|
reportDescription("Pin", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Skew", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Skew", field_total_, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
reportDashLine(field_description_->width() + field_total_->width() * 3 + 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportShort(const MaxSkewCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
Pin *clk_pin = check->clkPin(this);
|
|
|
|
|
const char *clk_pin_name = network_->pathName(clk_pin);
|
|
|
|
|
TimingArc *check_arc = check->checkArc();
|
2019-01-17 00:37:31 +01:00
|
|
|
auto what = stdstrPrint("%s (%s->%s)",
|
|
|
|
|
clk_pin_name,
|
2025-03-31 00:27:53 +02:00
|
|
|
check_arc->fromEdge()->to_string().c_str(),
|
|
|
|
|
check_arc->toEdge()->to_string().c_str());
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDescription(what.c_str(), line);
|
2019-10-10 06:02:54 +02:00
|
|
|
const EarlyLate *early_late = EarlyLate::early();
|
2020-12-29 03:04:49 +01:00
|
|
|
reportSpaceFieldDelay(check->maxSkew(this), early_late, line);
|
2025-03-27 02:21:03 +01:00
|
|
|
reportSpaceFieldDelay(check->skew(), early_late, line);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSpaceSlack(check->slack(this), line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportVerbose(const MaxSkewCheck *check) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *clk_pin_name = cmd_network_->pathName(check->clkPin(this));
|
2020-12-29 03:04:49 +01:00
|
|
|
line += "Constrained Pin: ";
|
|
|
|
|
line += clk_pin_name;
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
const char *ref_pin_name = cmd_network_->pathName(check->refPin(this));
|
2020-12-29 03:04:49 +01:00
|
|
|
line = "Reference Pin: ";
|
|
|
|
|
line += ref_pin_name;
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
line = "Check: max_skew";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
|
|
|
|
reportSkewClkPath("reference pin arrival time", check->refPath());
|
|
|
|
|
reportSkewClkPath("constrained pin arrival time", check->clkPath());
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDashLine();
|
|
|
|
|
reportLine("allowable skew", check->maxSkew(this), EarlyLate::early());
|
2025-03-27 02:21:03 +01:00
|
|
|
reportLine("actual skew", check->skew(), EarlyLate::late());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDashLine();
|
|
|
|
|
reportSlack(check->slack(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Based on reportTgtClk.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSkewClkPath(const char *arrival_msg,
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *clk_path) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *clk_edge = clk_path->clkEdge(this);
|
|
|
|
|
const Clock *clk = clk_edge->clock();
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = clk_path->minMax(this);
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf = clk_edge->transition();
|
|
|
|
|
const RiseFall *clk_end_rf = clk_path->transition(this);
|
|
|
|
|
string clk_name = clkName(clk, clk_end_rf != clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
float clk_time = clk_edge->time();
|
|
|
|
|
const Arrival &clk_arrival = search_->clkPathArrival(clk_path);
|
|
|
|
|
Arrival clk_delay = clk_arrival - clk_time;
|
|
|
|
|
PathAnalysisPt *path_ap = clk_path->pathAnalysisPt(this);
|
|
|
|
|
const MinMax *min_max = path_ap->pathMinMax();
|
|
|
|
|
Vertex *clk_vertex = clk_path->vertex(this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max);
|
2019-01-17 00:37:31 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
bool is_prop = isPropagated(clk_path);
|
|
|
|
|
if (is_prop && reportClkPath()) {
|
|
|
|
|
const EarlyLate *early_late = TimingRole::skew()->tgtClkEarlyLate();
|
2019-11-11 23:30:19 +01:00
|
|
|
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late))
|
|
|
|
|
reportGenClkSrcAndPath(clk_path, clk, clk_rf, early_late, path_ap,
|
2020-12-29 04:51:34 +01:00
|
|
|
0.0, 0.0, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
Arrival insertion, latency;
|
|
|
|
|
PathEnd::checkTgtClkDelay(clk_path, clk_edge, TimingRole::skew(), this,
|
|
|
|
|
insertion, latency);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkSrcLatency(insertion, clk_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
PathExpanded clk_expanded(clk_path, this);
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath1(clk_path, clk_expanded, false, 0.0);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival, early_late);
|
2019-01-17 00:37:31 +01:00
|
|
|
reportLine(descriptionField(clk_vertex).c_str(), clk_arrival,
|
2020-12-29 04:51:34 +01:00
|
|
|
early_late, clk_end_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(arrival_msg, search_->clkPathArrival(clk_path), early_late);
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportLimitShortHeader(const ReportField *field) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription("Pin", line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Limit", field, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField(field->title(), field, line);
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField("Slack", field, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDashLine(field_description_->width() + field->width() * 3 + 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-06-03 00:19:09 +02:00
|
|
|
ReportPath::reportLimitShort(const ReportField *field,
|
2020-06-02 20:08:48 +02:00
|
|
|
Pin *pin,
|
|
|
|
|
float value,
|
|
|
|
|
float limit,
|
2025-02-01 23:53:28 +01:00
|
|
|
float slack) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
2020-12-29 03:04:49 +01: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-03 01:28:12 +02:00
|
|
|
? " (MET)"
|
|
|
|
|
: " (VIOLATED)";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-06-03 00:19:09 +02:00
|
|
|
ReportPath::reportLimitVerbose(const ReportField *field,
|
2020-06-02 20:08:48 +02:00
|
|
|
Pin *pin,
|
|
|
|
|
const RiseFall *rf,
|
|
|
|
|
float value,
|
|
|
|
|
float limit,
|
|
|
|
|
float slack,
|
2021-04-16 20:09:43 +02:00
|
|
|
const Corner *corner,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 03:04:49 +01:00
|
|
|
string line;
|
|
|
|
|
line += "Pin ";
|
|
|
|
|
line += cmd_network_->pathName(pin);
|
|
|
|
|
line += ' ';
|
2020-06-02 20:08:48 +02:00
|
|
|
if (rf)
|
2020-12-29 03:04:49 +01:00
|
|
|
line += rf->shortName();
|
2020-06-02 20:08:48 +02:00
|
|
|
else
|
2020-12-29 03:04:49 +01:00
|
|
|
line += ' ';
|
2021-04-16 20:09:43 +02:00
|
|
|
// Don't report corner if the default corner is the only corner.
|
|
|
|
|
if (corner && corners_->count() > 1) {
|
|
|
|
|
line += " (corner ";
|
|
|
|
|
line += corner->name();
|
|
|
|
|
line += ")";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-03-31 00:27:53 +02:00
|
|
|
line = min_max->to_string();
|
2020-12-29 03:04:49 +01:00
|
|
|
line += ' ';
|
|
|
|
|
line += field->name();
|
|
|
|
|
line += ' ';
|
|
|
|
|
reportField(limit, field, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 03:04:49 +01:00
|
|
|
|
|
|
|
|
line = field->name();
|
|
|
|
|
line += " ";
|
|
|
|
|
reportField(value, field, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-06-03 01:28:12 +02:00
|
|
|
int name_width = strlen(field->name()) + 5;
|
2020-12-29 03:04:49 +01:00
|
|
|
reportDashLine(name_width + field->width());
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
line = "Slack";
|
2020-06-03 01:28:12 +02:00
|
|
|
for (int i = strlen("Slack"); i < name_width; i++)
|
2020-12-29 03:04:49 +01:00
|
|
|
line += ' ';
|
|
|
|
|
reportField(slack, field, line);
|
|
|
|
|
line += (slack >= 0.0)
|
2020-06-03 01:28:12 +02:00
|
|
|
? " (MET)"
|
|
|
|
|
: " (VIOLATED)";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportStartpoint(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
const Path *path = end->path();
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *start = expanded.startPath();
|
2025-02-01 23:53:28 +01:00
|
|
|
const TimingArc *prev_arc = expanded.startPrevArc();
|
2025-03-27 02:21:03 +01:00
|
|
|
const Edge *prev_edge = start->prevEdge(this);
|
2025-02-01 23:53:28 +01:00
|
|
|
const Pin *pin = start->pin(graph_);
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
|
|
|
|
const Clock *clk = path->clock(search_);
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
|
|
|
|
if (pathFromClkPin(path, pin)) {
|
|
|
|
|
const char *clk_name = clk->name();
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("clock source '%s'", clk_name);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
if (clk
|
|
|
|
|
&& clk != sdc_->defaultArrivalClock()) {
|
|
|
|
|
const char *clk_name = clk->name();
|
|
|
|
|
// Pin direction is "input" even for bidirects.
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("input port clocked by %s", clk_name);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, "input port");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (network_->isLeaf(pin) && prev_arc) {
|
|
|
|
|
Instance *inst = network_->instance(pin);
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
|
|
|
|
if (clk_edge) {
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf = clk_edge->transition();
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *clk_path = expanded.clkPath();
|
|
|
|
|
bool clk_inverted = clk_path
|
|
|
|
|
&& clk_rf != clk_path->transition(this);
|
2019-01-17 00:37:31 +01:00
|
|
|
string clk_name = clkName(clk, clk_inverted);
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(inst_name, reg_desc);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (network_->isLeaf(pin)) {
|
|
|
|
|
if (clk_edge) {
|
|
|
|
|
Clock *clk = clk_edge->clock();
|
|
|
|
|
if (clk != sdc_->defaultArrivalClock()) {
|
|
|
|
|
const char *clk_name = clk->name();
|
2019-01-17 00:37:31 +01:00
|
|
|
auto reason = stdstrPrint("internal path startpoint clocked by %s", clk_name);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, "internal path startpoint");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, "internal pin");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartpoint(pin_name, "");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::pathFromClkPin(const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *start = expanded.startPath();
|
|
|
|
|
const Path *end = expanded.endPath();
|
2018-09-28 17:54:21 +02:00
|
|
|
const Pin *start_pin = start->pin(graph_);
|
|
|
|
|
return pathFromClkPin(end, start_pin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::pathFromClkPin(const Path *path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const Pin *start_pin) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *clk = path->clock(search_);
|
2018-09-28 17:54:21 +02:00
|
|
|
return clk
|
2019-10-25 17:51:59 +02:00
|
|
|
&& clk->leafPins().hasKey(const_cast<Pin*>(start_pin));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportStartpoint(const char *start,
|
2025-02-01 23:53:28 +01:00
|
|
|
const string reason) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartEndPoint(start, reason, "Startpoint");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportUnclockedEndpoint(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const char *default_reason) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Vertex *vertex = end->vertex(this);
|
|
|
|
|
Pin *pin = vertex->pin();
|
|
|
|
|
if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
// Pin direction is "output" even for bidirects.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(cmd_network_->pathName(pin), "output port");
|
2018-09-28 17:54:21 +02: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()) {
|
|
|
|
|
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();
|
|
|
|
|
if (clk_edge->role() == TimingRole::regClkToQ()) {
|
|
|
|
|
Instance *inst = network_->instance(pin);
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
|
|
|
|
const char *reason = regDesc(clk_edge->timingArcSet()->isRisingFallingEdge());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (clk_edge->role() == TimingRole::latchEnToQ()) {
|
|
|
|
|
Instance *inst = network_->instance(pin);
|
|
|
|
|
const char *inst_name = cmd_network_->pathName(inst);
|
|
|
|
|
const char *reason = latchDesc(clk_edge->timingArcSet()->isRisingFallingEdge());
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(inst_name, reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(cmd_network_->pathName(pin), default_reason);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportEndpoint(cmd_network_->pathName(pin), "");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2019-01-17 00:37:31 +01:00
|
|
|
ReportPath::reportEndpoint(const char *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const string reason) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportStartEndPoint(end, reason, "Endpoint");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportStartEndPoint(const char *pt,
|
2019-01-17 00:37:31 +01:00
|
|
|
string reason,
|
2025-02-01 23:53:28 +01:00
|
|
|
const char *key) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
// Account for punctuation in the line.
|
2019-01-17 00:37:31 +01:00
|
|
|
int line_len = strlen(key) + 2 + strlen(pt) + 2 + reason.size() + 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!no_split_
|
|
|
|
|
&& line_len > start_end_pt_width_) {
|
2020-12-29 04:51:34 +01:00
|
|
|
line = key;
|
|
|
|
|
line += ": ";
|
|
|
|
|
line += pt;
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
line.clear();
|
2018-11-09 19:04:16 +01:00
|
|
|
for (unsigned i = 0; i < strlen(key); i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-12-29 04:51:34 +01:00
|
|
|
line += " (";
|
|
|
|
|
line += reason;
|
|
|
|
|
line += ")";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 04:51:34 +01:00
|
|
|
line = key;
|
|
|
|
|
line += ": ";
|
|
|
|
|
line += pt;
|
|
|
|
|
line += " (";
|
|
|
|
|
line += reason;
|
|
|
|
|
line += ")";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportGroup(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
|
|
|
|
line = "Path Group: ";
|
2025-10-30 16:53:36 +01:00
|
|
|
PathGroup *group = end->pathGroup();
|
2022-01-15 20:51:05 +01:00
|
|
|
line += group ? group->name() : "(none)";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 04:51:34 +01:00
|
|
|
|
|
|
|
|
line = "Path Type: ";
|
2025-03-31 00:27:53 +02:00
|
|
|
line += end->minMax(this)->to_string();
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 04:51:34 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if (corners_->multiCorner()) {
|
2020-12-29 04:51:34 +01:00
|
|
|
line = "Corner: ";
|
|
|
|
|
line += end->pathAnalysisPt(this)->corner()->name();
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::checkRoleReason(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-31 00:27:53 +02:00
|
|
|
return stdstrPrint("%s time", end->checkRole(this)->to_string().c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::tgtClkName(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
const Clock *tgt_clk = tgt_clk_edge->clock();
|
2019-11-11 23:30:19 +01: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 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
|
|
|
|
ReportPath::clkName(const Clock *clk,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool inverted) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
string name = clk->name();
|
|
|
|
|
if (inverted)
|
|
|
|
|
name += '\'';
|
|
|
|
|
return name;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::clkRegLatchDesc(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
// Goofy libraries can have registers with both rising and falling
|
|
|
|
|
// clk->q timing arcs. Try and match the timing check transition.
|
2022-02-14 01:46:45 +01:00
|
|
|
const RiseFall *check_clk_rf=end->checkArc()->fromEdge()->asRiseFall();
|
2019-03-13 01:25:53 +01:00
|
|
|
TimingArcSet *clk_set = nullptr;
|
2019-11-11 23:30:19 +01:00
|
|
|
TimingArcSet *clk_rf_set = nullptr;
|
2018-09-28 17:54:21 +02: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-31 00:27:53 +02:00
|
|
|
const TimingRole *role = arc_set->role();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (role == TimingRole::regClkToQ()
|
|
|
|
|
|| role == TimingRole::latchEnToQ()) {
|
2024-06-27 22:57:58 +02:00
|
|
|
const RiseFall *arc_rf = arc_set->isRisingFallingEdge();
|
2018-09-28 17:54:21 +02:00
|
|
|
clk_set = arc_set;
|
2019-11-11 23:30:19 +01:00
|
|
|
if (arc_rf == check_clk_rf)
|
|
|
|
|
clk_rf_set = arc_set;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-11 23:30:19 +01:00
|
|
|
if (clk_rf_set)
|
|
|
|
|
return checkRegLatchDesc(clk_rf_set->role(),
|
|
|
|
|
clk_rf_set->isRisingFallingEdge());
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (clk_set)
|
|
|
|
|
return checkRegLatchDesc(clk_set->role(),
|
|
|
|
|
clk_set->isRisingFallingEdge());
|
|
|
|
|
else
|
2019-11-11 23:30:19 +01:00
|
|
|
return checkRegLatchDesc(TimingRole::regClkToQ(), check_clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSrcPathArrival(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
|
|
|
|
reportSrcPath(end, expanded);
|
2018-11-26 18:15:52 +01:00
|
|
|
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
2020-12-29 04:51:34 +01:00
|
|
|
end->pathEarlyLate(this));
|
|
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSrcPath(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
2018-09-28 17:54:21 +02: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,
|
2020-12-29 04:51:34 +01:00
|
|
|
src_clk_latency, end->isPathDelay());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSrcClkAndPath(const Path *path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded,
|
2018-09-28 17:54:21 +02:00
|
|
|
float time_offset,
|
|
|
|
|
Arrival clk_insertion,
|
|
|
|
|
Arrival clk_latency,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool is_path_delay) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
2019-01-27 08:03:01 +01:00
|
|
|
const MinMax *min_max = path->minMax(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_edge) {
|
|
|
|
|
Clock *clk = clk_edge->clock();
|
2025-03-31 00:27:53 +02:00
|
|
|
const RiseFall *clk_rf = clk_edge->transition();
|
2018-09-28 17:54:21 +02:00
|
|
|
float clk_time = clk_edge->time() + time_offset;
|
|
|
|
|
if (clk == sdc_->defaultArrivalClock()) {
|
|
|
|
|
if (!is_path_delay) {
|
|
|
|
|
float clk_end_time = clk_time + time_offset;
|
2019-01-27 08:03:01 +01:00
|
|
|
const EarlyLate *early_late = min_max;
|
2018-09-28 17:54:21 +02:00
|
|
|
reportLine("clock (input port clock) (rise edge)",
|
2020-12-29 04:51:34 +01:00
|
|
|
clk_end_time, clk_end_time, early_late);
|
|
|
|
|
reportLine(clkNetworkDelayIdealProp(false), 0.0, clk_end_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath1(path, expanded, false, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bool path_from_input = false;
|
|
|
|
|
bool input_has_ref_path = false;
|
|
|
|
|
Arrival clk_delay, clk_end_time;
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *clk_path = expanded.clkPath();
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_end_rf;
|
2025-03-27 02:21:03 +01:00
|
|
|
if (clk_path) {
|
|
|
|
|
clk_end_time = search_->clkPathArrival(clk_path) + time_offset;
|
2018-09-28 17:54:21 +02:00
|
|
|
clk_delay = clk_end_time - clk_time;
|
2025-03-27 02:21:03 +01:00
|
|
|
clk_end_rf = clk_path->transition(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Path from input port or clk used as data.
|
2019-11-11 23:30:19 +01:00
|
|
|
clk_end_rf = clk_rf;
|
2018-09-28 17:54:21 +02:00
|
|
|
clk_delay = clk_insertion + clk_latency;
|
|
|
|
|
clk_end_time = clk_time + clk_delay;
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *first_path = expanded.startPath();
|
2025-02-01 23:53:28 +01:00
|
|
|
const InputDelay *input_delay = pathInputDelay(first_path);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (input_delay) {
|
|
|
|
|
path_from_input = true;
|
2023-01-19 19:23:45 +01:00
|
|
|
const Pin *ref_pin = input_delay->refPin();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (ref_pin && clk->isPropagated()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path ref_path;
|
2018-09-28 17:54:21 +02:00
|
|
|
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
|
|
|
|
if (!ref_path.isNull()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
const Arrival &ref_end_time = ref_path.arrival();
|
2018-09-28 17:54:21 +02:00
|
|
|
clk_delay = ref_end_time - clk_time;
|
|
|
|
|
clk_end_time = ref_end_time + time_offset;
|
|
|
|
|
input_has_ref_path = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-11 23:30:19 +01:00
|
|
|
string clk_name = clkName(clk, clk_rf != clk_end_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
bool clk_used_as_data = pathFromClkPin(expanded);
|
|
|
|
|
bool is_prop = isPropagated(path);
|
|
|
|
|
const EarlyLate *early_late = min_max;
|
2025-03-27 02:21:03 +01:00
|
|
|
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late)
|
2018-09-28 17:54:21 +02:00
|
|
|
&& !(path_from_input && !input_has_ref_path)) {
|
2019-11-11 23:30:19 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time,
|
2020-12-29 04:51:34 +01:00
|
|
|
min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
2019-11-11 23:30:19 +01:00
|
|
|
reportGenClkSrcAndPath(path, clk, clk_rf, early_late, path_ap,
|
2020-12-29 04:51:34 +01:00
|
|
|
time_offset, time_offset, clk_used_as_data);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (clk_used_as_data
|
|
|
|
|
&& pathFromGenPropClk(path, path->minMax(this))) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max);
|
2025-09-17 00:30:16 +02:00
|
|
|
const ClkInfo *clk_info = path->tag(search_)->clkInfo();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_info->isPropagated())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkSrcLatency(clk_insertion, clk_time, early_late);
|
|
|
|
|
reportPath1(path, expanded, true, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (is_prop
|
|
|
|
|
&& reportClkPath()
|
|
|
|
|
&& !(path_from_input && !input_has_ref_path)) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, early_late);
|
|
|
|
|
reportClkSrcLatency(clk_insertion, clk_time, early_late);
|
|
|
|
|
reportPath1(path, expanded, false, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (clk_used_as_data) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, early_late);
|
2020-07-12 02:43:30 +02:00
|
|
|
if (delayGreater(clk_insertion, 0.0, this))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkSrcLatency(clk_insertion, clk_time, early_late);
|
2020-07-11 02:08:44 +02:00
|
|
|
if (reportClkPath())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath1(path, expanded, true, time_offset);
|
2020-07-11 02:08:44 +02:00
|
|
|
else {
|
|
|
|
|
Arrival clk_arrival = clk_end_time;
|
2025-03-27 02:21:03 +01:00
|
|
|
Arrival end_arrival = path->arrival() + time_offset;
|
2020-07-11 02:08:44 +02:00
|
|
|
Delay clk_delay = end_arrival - clk_arrival;
|
|
|
|
|
reportLine("clock network delay", clk_delay,
|
2020-12-29 04:51:34 +01:00
|
|
|
end_arrival, early_late);
|
2020-07-11 02:08:44 +02:00
|
|
|
Vertex *end_vertex = path->vertex(this);
|
|
|
|
|
reportLine(descriptionField(end_vertex).c_str(),
|
2020-12-29 04:51:34 +01:00
|
|
|
end_arrival, early_late, clk_end_rf);
|
2020-07-11 02:08:44 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (is_path_delay) {
|
2020-07-12 02:43:30 +02:00
|
|
|
if (delayGreater(clk_delay, 0.0, this))
|
2018-09-28 17:54:21 +02:00
|
|
|
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
2020-12-29 04:51:34 +01:00
|
|
|
clk_end_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max);
|
2018-11-26 18:15:52 +01:00
|
|
|
Arrival clk_arrival = clk_end_time;
|
2018-09-28 17:54:21 +02:00
|
|
|
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
2020-12-29 04:51:34 +01:00
|
|
|
clk_arrival, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath1(path, expanded, false, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath1(path, expanded, false, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportTgtClk(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportTgtClk(end, 0.0);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportTgtClk(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
float prev_time) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *clk = end->targetClk(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
const Path *clk_path = end->targetClkPath();
|
2020-12-29 04:51:34 +01:00
|
|
|
reportTgtClk(end, prev_time, isPropagated(clk_path, clk));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportTgtClk(const PathEnd *end,
|
|
|
|
|
float prev_time,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool is_prop) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
float src_offset = end->sourceClkOffset(this);
|
2024-10-02 22:20:29 +02:00
|
|
|
reportTgtClk(end, prev_time, src_offset, is_prop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportTgtClk(const PathEnd *end,
|
|
|
|
|
float prev_time,
|
|
|
|
|
float src_offset,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool is_prop) const
|
2024-10-02 22:20:29 +02:00
|
|
|
{
|
2018-09-28 17:54:21 +02:00
|
|
|
const ClockEdge *clk_edge = end->targetClkEdge(this);
|
|
|
|
|
Clock *clk = clk_edge->clock();
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf = clk_edge->transition();
|
|
|
|
|
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
|
|
|
|
|
string clk_name = clkName(clk, clk_end_rf != clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
float clk_time = prev_time
|
|
|
|
|
+ end->targetClkTime(this)
|
|
|
|
|
+ end->targetClkMcpAdjustment(this)
|
|
|
|
|
+ src_offset;
|
|
|
|
|
Arrival clk_delay = end->targetClkDelay(this);
|
|
|
|
|
Arrival clk_arrival = clk_time + clk_delay;
|
|
|
|
|
PathAnalysisPt *path_ap = end->pathAnalysisPt(this)->tgtClkAnalysisPt();
|
|
|
|
|
const MinMax *min_max = path_ap->pathMinMax();
|
|
|
|
|
const Path *clk_path = end->targetClkPath();
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, prev_time, clk_time, min_max);
|
2025-03-31 00:27:53 +02:00
|
|
|
const TimingRole *check_role = end->checkRole(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (is_prop && reportClkPath()) {
|
|
|
|
|
float time_offset = prev_time
|
|
|
|
|
+ end->targetClkOffset(this)
|
|
|
|
|
+ end->targetClkMcpAdjustment(this);
|
|
|
|
|
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
|
2019-11-11 23:30:19 +01:00
|
|
|
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late)) {
|
2018-09-28 17:54:21 +02:00
|
|
|
float insertion_offset =
|
|
|
|
|
clk_path ? tgtClkInsertionOffet(clk_path, early_late, path_ap) : 0.0;
|
2019-11-11 23:30:19 +01:00
|
|
|
reportGenClkSrcAndPath(clk_path, clk, clk_rf, early_late, path_ap,
|
2020-12-29 04:51:34 +01:00
|
|
|
time_offset, time_offset + insertion_offset, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Arrival insertion = end->targetClkInsertionDelay(this);
|
|
|
|
|
if (clk_path) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkSrcLatency(insertion, clk_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
PathExpanded clk_expanded(clk_path, this);
|
|
|
|
|
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late,
|
|
|
|
|
path_ap);
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath6(clk_path, clk_expanded, 0, is_prop, reportClkPath(),
|
|
|
|
|
delay_zero, time_offset + insertion_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Output departure.
|
|
|
|
|
Arrival clk_arrival = clk_time + clk_delay;
|
|
|
|
|
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
|
2020-12-29 04:51:34 +01:00
|
|
|
clk_delay, clk_arrival, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkUncertainty(end, clk_arrival);
|
|
|
|
|
reportCommonClkPessimism(end, clk_arrival);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
|
|
|
|
clk_arrival, min_max);
|
|
|
|
|
reportClkUncertainty(end, clk_arrival);
|
|
|
|
|
reportCommonClkPessimism(end, clk_arrival);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_path) {
|
|
|
|
|
Vertex *clk_vertex = clk_path->vertex(this);
|
2019-01-17 00:37:31 +01:00
|
|
|
reportLine(descriptionField(clk_vertex).c_str(),
|
2018-09-28 17:54:21 +02:00
|
|
|
prev_time
|
|
|
|
|
+ end->targetClkArrival(this)
|
|
|
|
|
+ end->sourceClkOffset(this),
|
2020-12-29 04:51:34 +01:00
|
|
|
min_max, clk_end_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
ReportPath::tgtClkInsertionOffet(const Path *clk_path,
|
|
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathAnalysisPt *path_ap) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-09-17 00:30:16 +02:00
|
|
|
const ClkInfo *clk_info = clk_path->clkInfo(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
const Pin *src_pin = clk_info->clkSrc();
|
|
|
|
|
const ClockEdge *clk_edge = clk_info->clkEdge();
|
|
|
|
|
const Clock *clk = clk_edge->clock();
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf = clk_edge->transition();
|
2018-09-28 17:54:21 +02:00
|
|
|
const MinMax *min_max = path_ap->pathMinMax();
|
2019-11-11 23:30:19 +01:00
|
|
|
Arrival path_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
min_max, min_max,
|
|
|
|
|
path_ap);
|
2019-11-11 23:30:19 +01:00
|
|
|
Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
min_max, early_late,
|
|
|
|
|
path_ap);
|
|
|
|
|
return delayAsFloat(tgt_insertion - path_insertion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::pathFromGenPropClk(const Path *clk_path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-09-17 00:30:16 +02:00
|
|
|
const ClkInfo *clk_info = clk_path->tag(search_)->clkInfo();
|
2018-09-28 17:54:21 +02:00
|
|
|
const ClockEdge *clk_edge = clk_info->clkEdge();
|
|
|
|
|
if (clk_edge) {
|
|
|
|
|
const Clock *clk = clk_edge->clock();
|
|
|
|
|
float insertion;
|
|
|
|
|
bool exists;
|
|
|
|
|
sdc_->clockInsertion(clk, clk_info->clkSrc(),
|
2020-05-21 16:47:34 +02:00
|
|
|
clk_edge->transition(),
|
|
|
|
|
clk_path->minMax(this),
|
|
|
|
|
early_late,
|
|
|
|
|
insertion, exists);
|
2018-09-28 17:54:21 +02:00
|
|
|
return !exists
|
|
|
|
|
&& clk->isGeneratedWithPropagatedMaster();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::isGenPropClk(const Clock *clk,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
const MinMax *min_max,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
float insertion;
|
|
|
|
|
bool exists;
|
2019-11-11 23:30:19 +01:00
|
|
|
sdc_->clockInsertion(clk, clk->srcPin(), clk_rf,
|
2020-05-21 16:47:34 +02:00
|
|
|
min_max, early_late,
|
|
|
|
|
insertion, exists);
|
2018-09-28 17:54:21 +02:00
|
|
|
return !exists
|
|
|
|
|
&& clk->isGeneratedWithPropagatedMaster();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportClkLine(const Clock *clk,
|
|
|
|
|
const char *clk_name,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
Arrival clk_time,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkLine(clk, clk_name, clk_rf, 0.0, clk_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportClkLine(const Clock *clk,
|
|
|
|
|
const char *clk_name,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
Arrival prev_time,
|
|
|
|
|
Arrival clk_time,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
const char *rise_fall = asRiseFall(clk_rf);
|
2019-01-17 00:37:31 +01:00
|
|
|
auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk->isPropagated())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clk_msg.c_str(), clk_time - prev_time, clk_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
// Report ideal clock slew.
|
2019-11-11 23:30:19 +01:00
|
|
|
float clk_slew = clk->slew(clk_rf, min_max);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(clk_msg.c_str(), clk_slew, clk_time - prev_time, clk_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::reportGenClkSrcPath(const Path *clk_path,
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *clk,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
const MinMax *min_max,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
bool from_gen_prop_clk = clk_path
|
|
|
|
|
? pathFromGenPropClk(clk_path, early_late)
|
2019-11-11 23:30:19 +01:00
|
|
|
: isGenPropClk(clk, clk_rf, min_max, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
return from_gen_prop_clk
|
2019-03-13 01:25:53 +01:00
|
|
|
&& format_ == ReportPathFormat::full_clock_expanded;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportGenClkSrcAndPath(const Path *path,
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *clk,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
const EarlyLate *early_late,
|
|
|
|
|
const PathAnalysisPt *path_ap,
|
|
|
|
|
float time_offset,
|
|
|
|
|
float path_time_offset,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool clk_used_as_data) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
const Pin *clk_pin = path
|
|
|
|
|
? path->clkInfo(search_)->clkSrc()
|
|
|
|
|
: clk->defaultPin();
|
2019-11-11 23:30:19 +01:00
|
|
|
float gclk_time = clk->edge(clk_rf)->time() + time_offset;
|
|
|
|
|
bool skip_first_path = reportGenClkSrcPath1(clk, clk_pin, clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
early_late, path_ap, gclk_time,
|
2020-12-29 04:51:34 +01:00
|
|
|
time_offset, clk_used_as_data);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (path) {
|
|
|
|
|
PathExpanded expanded(path, this);
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath2(path, expanded, skip_first_path, clk_used_as_data,
|
2020-12-29 04:51:34 +01:00
|
|
|
path_time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2023-01-19 19:23:45 +01:00
|
|
|
ReportPath::reportGenClkSrcPath1(const Clock *clk,
|
2018-09-28 17:54:21 +02:00
|
|
|
const Pin *clk_pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
const EarlyLate *early_late,
|
|
|
|
|
const PathAnalysisPt *path_ap,
|
|
|
|
|
float gclk_time,
|
|
|
|
|
float time_offset,
|
2025-02-01 23:53:28 +01:00
|
|
|
bool clk_used_as_data) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
2018-11-26 18:15:52 +01:00
|
|
|
const MinMax *min_max = path_ap->pathMinMax();
|
2025-07-02 17:32:04 +02:00
|
|
|
const Path *src_path = search_->genclks()->srcPath(clk, clk_pin,
|
|
|
|
|
clk_rf, insert_ap);
|
2025-03-27 02:21:03 +01:00
|
|
|
if (src_path) {
|
2025-09-17 00:30:16 +02:00
|
|
|
const ClkInfo *src_clk_info = src_path->clkInfo(this);
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
|
|
|
|
const Clock *src_clk = src_clk_info->clock();
|
2022-01-15 20:51:05 +01: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,
|
|
|
|
|
src_clk_rf, early_late, path_ap,
|
|
|
|
|
gclk_time, time_offset,
|
|
|
|
|
clk_used_as_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const Arrival insertion = search_->clockInsertion(src_clk, src_clk_pin,
|
|
|
|
|
src_clk_rf,
|
|
|
|
|
path_ap->pathMinMax(),
|
|
|
|
|
early_late, path_ap);
|
|
|
|
|
reportClkSrcLatency(insertion, gclk_time, early_late);
|
|
|
|
|
}
|
2025-03-27 02:21:03 +01:00
|
|
|
PathExpanded src_expanded(src_path, this);
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath2(src_path, src_expanded, skip_first_path,
|
2022-11-17 18:03:42 +01:00
|
|
|
clk_used_as_data, gclk_time);
|
2022-01-15 20:51:05 +01:00
|
|
|
if (!clk->isPropagated())
|
|
|
|
|
reportLine("clock network delay (ideal)", 0.0,
|
2025-03-27 02:21:03 +01:00
|
|
|
src_path->arrival(), min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (clk->isPropagated())
|
2020-12-29 04:51:34 +01:00
|
|
|
reportClkSrcLatency(0.0, gclk_time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (!clk_used_as_data)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("clock network delay (ideal)", 0.0, gclk_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-03-27 02:21:03 +01:00
|
|
|
return src_path != nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportClkSrcLatency(Arrival insertion,
|
|
|
|
|
float clk_time,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("clock source latency", insertion, clk_time + insertion, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportPathLine(const Path *path,
|
|
|
|
|
Arrival incr,
|
|
|
|
|
Arrival time,
|
2025-02-01 23:53:28 +01:00
|
|
|
const char *line_case) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Vertex *vertex = path->vertex(this);
|
|
|
|
|
Pin *pin = vertex->pin();
|
2024-12-26 01:44:28 +01:00
|
|
|
const string what = descriptionField(vertex);
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf = path->transition(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
bool is_driver = network_->isDriver(pin);
|
2018-11-26 18:15:52 +01:00
|
|
|
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
|
|
|
|
const EarlyLate *early_late = path_ap->pathMinMax();
|
|
|
|
|
DcalcAnalysisPt *dcalc_ap = path_ap->dcalcAnalysisPt();
|
2018-09-28 17:54:21 +02:00
|
|
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
2019-11-11 23:30:19 +01:00
|
|
|
Slew slew = graph_->slew(vertex, rf, ap_index);
|
2018-09-28 17:54:21 +02:00
|
|
|
float cap = field_blank_;
|
2024-10-16 02:28:52 +02:00
|
|
|
Instance *inst = network_->instance(pin);
|
|
|
|
|
string src_attr = "";
|
|
|
|
|
if (inst)
|
|
|
|
|
src_attr = network_->getAttribute(inst, "src");
|
2018-09-28 17:54:21 +02:00
|
|
|
// Don't show capacitance field for input pins.
|
|
|
|
|
if (is_driver && field_capacitance_->enabled())
|
2024-02-08 21:54:52 +01:00
|
|
|
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
|
2019-01-17 00:37:31 +01:00
|
|
|
reportLine(what.c_str(), cap, slew, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
incr, time, false, early_late, rf, src_attr,
|
|
|
|
|
line_case);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportRequired(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
string margin_msg) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Required req_time = end->requiredTimeOffset(this);
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->clkEarlyLate(this);
|
2024-12-08 01:35:14 +01:00
|
|
|
float macro_clk_tree_delay = end->macroClkTreeDelay(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
ArcDelay margin = end->margin(this);
|
2024-12-08 01:35:14 +01:00
|
|
|
if (end->minMax(this) == MinMax::min()) {
|
2018-09-28 17:54:21 +02:00
|
|
|
margin = -margin;
|
2024-12-08 01:35:14 +01:00
|
|
|
macro_clk_tree_delay = -macro_clk_tree_delay;
|
|
|
|
|
}
|
|
|
|
|
if (macro_clk_tree_delay != 0.0)
|
|
|
|
|
reportLine("macro clock tree delay", -macro_clk_tree_delay,
|
|
|
|
|
req_time + margin, early_late);
|
|
|
|
|
reportLine(margin_msg.c_str(), -margin, req_time, early_late);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("data required time", req_time, early_late);
|
|
|
|
|
reportDashLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSlack(const PathEnd *end) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->pathEarlyLate(this);
|
|
|
|
|
reportLine("data required time", end->requiredTimeOffset(this),
|
2020-12-29 04:51:34 +01:00
|
|
|
early_late->opposite());
|
|
|
|
|
reportLineNegative("data arrival time", end->dataArrivalTimeOffset(this), early_late);
|
|
|
|
|
reportDashLine();
|
|
|
|
|
reportSlack(end->slack(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSlack(Slack slack) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-10-10 06:02:54 +02:00
|
|
|
const EarlyLate *early_late = EarlyLate::early();
|
|
|
|
|
const char *msg = (delayAsFloat(slack, early_late, this) >= 0.0)
|
|
|
|
|
? "slack (MET)"
|
|
|
|
|
: "slack (VIOLATED)";
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine(msg, slack, early_late);
|
2019-10-10 06:02:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportSpaceSlack(const PathEnd *end,
|
|
|
|
|
string &result) const
|
2019-10-10 06:02:54 +02:00
|
|
|
{
|
|
|
|
|
Slack slack = end->slack(this);
|
|
|
|
|
reportSpaceSlack(slack, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSpaceSlack(Slack slack,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &result) const
|
2020-12-29 03:04:49 +01: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 17:54:21 +02:00
|
|
|
void
|
|
|
|
|
ReportPath::reportCommonClkPessimism(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
Arrival &clk_arrival) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-04-10 01:35:15 +02:00
|
|
|
if (variables_->crprEnabled()) {
|
2024-06-27 22:57:58 +02:00
|
|
|
Crpr pessimism = end->checkCrpr(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
clk_arrival += pessimism;
|
2018-11-26 18:15:52 +01:00
|
|
|
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
|
2020-12-29 04:51:34 +01:00
|
|
|
end->clkEarlyLate(this));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportClkUncertainty(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
Arrival &clk_arrival) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = end->clkEarlyLate(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
float uncertainty = end->targetNonInterClkUncertainty(this);
|
|
|
|
|
clk_arrival += uncertainty;
|
|
|
|
|
if (uncertainty != 0.0)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("clock uncertainty", uncertainty, clk_arrival, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
float inter_uncertainty = end->interClkUncertainty(this);
|
|
|
|
|
clk_arrival += inter_uncertainty;
|
|
|
|
|
if (inter_uncertainty != 0.0)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("inter-clock uncertainty", inter_uncertainty,
|
|
|
|
|
clk_arrival, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportPath(const PathEnd *end,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
2018-09-28 17:54:21 +02:00
|
|
|
// Source clk offset for path delays removes clock phase time.
|
|
|
|
|
float src_clk_offset = end->sourceClkOffset(this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPath1(end->path(), expanded, pathFromClkPin(expanded), src_clk_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPath(const Path *path) const
|
2020-07-07 00:18:13 +02:00
|
|
|
{
|
|
|
|
|
switch (format_) {
|
|
|
|
|
case ReportPathFormat::full:
|
|
|
|
|
case ReportPathFormat::full_clock:
|
|
|
|
|
case ReportPathFormat::full_clock_expanded:
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathFull(path);
|
2020-07-07 00:18:13 +02:00
|
|
|
break;
|
|
|
|
|
case ReportPathFormat::json:
|
2024-09-17 02:04:31 +02:00
|
|
|
reportJson(path);
|
2020-07-07 00:18:13 +02:00
|
|
|
break;
|
2024-09-17 02:04:31 +02:00
|
|
|
case ReportPathFormat::shorter:
|
|
|
|
|
case ReportPathFormat::endpoint:
|
2020-07-07 00:18:13 +02:00
|
|
|
case ReportPathFormat::summary:
|
|
|
|
|
case ReportPathFormat::slack_only:
|
2024-09-17 02:04:31 +02:00
|
|
|
report_->reportLine("Format not supported.");
|
2020-07-07 00:18:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathFull(const Path *path) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathHeader();
|
2018-09-28 17:54:21 +02:00
|
|
|
PathExpanded expanded(path, this);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportSrcClkAndPath(path, expanded, 0.0, delay_zero, delay_zero, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-17 02:04:31 +02:00
|
|
|
////////////////////////////////////////////////////////////////
|
2020-07-07 00:18:13 +02:00
|
|
|
|
2025-08-18 22:27:30 +02:00
|
|
|
// Main entry point for reporting a path.
|
2018-09-28 17:54:21 +02:00
|
|
|
void
|
|
|
|
|
ReportPath::reportPath1(const Path *path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded,
|
2018-09-28 17:54:21 +02:00
|
|
|
bool clk_used_as_data,
|
2025-02-01 23:53:28 +01:00
|
|
|
float time_offset) const
|
2025-08-18 22:27:30 +02: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,
|
|
|
|
|
const PathExpanded &expanded,
|
|
|
|
|
bool skip_first_path,
|
|
|
|
|
bool clk_used_as_data,
|
|
|
|
|
float time_offset) const
|
|
|
|
|
{
|
|
|
|
|
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,
|
|
|
|
|
report_clk_path, time_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Alternate entry point with report_clk_path arg.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportPath3(const Path *path,
|
|
|
|
|
const PathExpanded &expanded,
|
|
|
|
|
bool report_clk_path,
|
|
|
|
|
float time_offset) const
|
|
|
|
|
{
|
|
|
|
|
bool propagated_clk = path->clkInfo(search_)->isPropagated();
|
|
|
|
|
reportPath4(path, expanded, false, propagated_clk,
|
|
|
|
|
report_clk_path, time_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportPath4(const Path *path,
|
|
|
|
|
const PathExpanded &expanded,
|
|
|
|
|
bool skip_first_path,
|
|
|
|
|
bool propagated_clk,
|
|
|
|
|
bool report_clk_path,
|
|
|
|
|
float time_offset) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *d_path, *q_path;
|
2018-09-28 17:54:21 +02: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-27 02:21:03 +01:00
|
|
|
Path *latch_enable_path;
|
2018-09-28 17:54:21 +02:00
|
|
|
latches_->latchTimeGivenToStartpoint(d_path, q_path, d_q_edge,
|
2025-03-27 02:21:03 +01: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 22:27:30 +02:00
|
|
|
if (report_clk_path) {
|
2025-03-27 02:21:03 +01:00
|
|
|
PathExpanded enable_expanded(latch_enable_path, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Report the path to the latch enable.
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
|
|
|
|
|
propagated_clk, report_clk_path, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
Arrival time = latch_enable_time + latch_time_given;
|
|
|
|
|
Arrival incr = latch_time_given;
|
2020-07-12 02:43:30 +02:00
|
|
|
if (delayGreaterEqual(incr, 0.0, this))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("time given to startpoint", incr, time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("time borrowed from startpoint", incr, time, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Override latch D arrival with enable + given.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
|
2020-12-29 04:51:34 +01:00
|
|
|
latch_enable_time + latch_time_given, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath5(path, expanded, skip_first_path, propagated_clk,
|
|
|
|
|
report_clk_path, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-08-18 22:27:30 +02:00
|
|
|
ReportPath::reportPath5(const Path *path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded,
|
2018-09-28 17:54:21 +02:00
|
|
|
bool skip_first_path,
|
2025-08-18 22:27:30 +02:00
|
|
|
bool propagated_clk,
|
|
|
|
|
bool report_clk_path,
|
2025-02-01 23:53:28 +01:00
|
|
|
float time_offset) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
size_t path_first_index = 0;
|
2025-08-18 22:27:30 +02:00
|
|
|
Arrival prev_time = 0.0;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (skip_first_path) {
|
|
|
|
|
path_first_index = 1;
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *start = expanded.path(0);
|
|
|
|
|
prev_time = start->arrival() + time_offset;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath6(path, expanded, path_first_index, propagated_clk,
|
|
|
|
|
report_clk_path, prev_time, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 22:27:30 +02:00
|
|
|
// This does the real workk of reporting an expanded path.
|
2018-09-28 17:54:21 +02:00
|
|
|
void
|
2025-08-18 22:27:30 +02:00
|
|
|
ReportPath::reportPath6(const Path *path,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded,
|
2018-09-28 17:54:21 +02:00
|
|
|
size_t path_first_index,
|
|
|
|
|
bool propagated_clk,
|
|
|
|
|
bool report_clk_path,
|
|
|
|
|
Arrival prev_time,
|
2025-02-01 23:53:28 +01:00
|
|
|
float time_offset) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-08-18 22:27:30 +02:00
|
|
|
size_t path_last_index = expanded.size() - 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
const MinMax *min_max = path->minMax(this);
|
|
|
|
|
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
|
|
|
|
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *clk_path = expanded.clkPath();
|
|
|
|
|
Vertex *clk_start = clk_path ? clk_path->vertex(this) : nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
for (size_t i = path_first_index; i <= path_last_index; i++) {
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *path1 = expanded.path(i);
|
|
|
|
|
const TimingArc *prev_arc = path1->prevArc(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
Vertex *vertex = path1->vertex(this);
|
|
|
|
|
Pin *pin = vertex->pin();
|
2025-03-27 02:21:03 +01:00
|
|
|
Arrival time = path1->arrival() + time_offset;
|
2020-05-31 03:09:14 +02:00
|
|
|
Delay incr = 0.0;
|
2019-03-13 01:25:53 +01:00
|
|
|
const char *line_case = nullptr;
|
2020-11-05 01:09:25 +01:00
|
|
|
bool is_clk_start = path1->vertex(this) == clk_start;
|
2018-09-28 17:54:21 +02:00
|
|
|
bool is_clk = path1->isClock(search_);
|
2024-10-16 02:28:52 +02:00
|
|
|
Instance *inst = network_->instance(pin);
|
|
|
|
|
string src_attr = "";
|
|
|
|
|
if (inst)
|
|
|
|
|
src_attr = network_->getAttribute(inst, "src");
|
2018-09-28 17:54:21 +02:00
|
|
|
// Always show the search start point (register clk pin).
|
|
|
|
|
// Skip reporting the clk tree unless it is requested.
|
|
|
|
|
if (is_clk_start
|
|
|
|
|
|| report_clk_path
|
|
|
|
|
|| !is_clk) {
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf = path1->transition(this);
|
|
|
|
|
Slew slew = graph_->slew(vertex, rf, ap_index);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (prev_arc == nullptr) {
|
2018-09-28 17:54:21 +02:00
|
|
|
// First path.
|
2020-12-29 04:51:34 +01:00
|
|
|
reportInputExternalDelay(path1, time_offset);
|
2018-09-28 17:54:21 +02:00
|
|
|
size_t next_index = i + 1;
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *next_path = expanded.path(next_index);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (network_->isTopLevelPort(pin)
|
|
|
|
|
&& next_path
|
|
|
|
|
&& !nextArcAnnotated(next_path, next_index, expanded, ap_index)
|
2019-11-11 23:30:19 +01:00
|
|
|
&& hasExtInputDriver(pin, rf, min_max)) {
|
2018-09-28 17:54:21 +02:00
|
|
|
// 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.
|
2025-03-27 02:21:03 +01:00
|
|
|
Arrival next_time = next_path->arrival() + time_offset;
|
2020-05-31 03:09:14 +02:00
|
|
|
incr = delayIncr(next_time, time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
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.
|
|
|
|
|
time = search_->clkPathArrival(path1) + time_offset;
|
|
|
|
|
incr = 0.0;
|
|
|
|
|
line_case = "clk_first";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
incr = 0.0;
|
|
|
|
|
line_case = "first";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (is_clk_start
|
|
|
|
|
&& is_clk
|
|
|
|
|
&& !report_clk_path) {
|
|
|
|
|
// Clock start point and clock path are not reported.
|
|
|
|
|
incr = 0.0;
|
|
|
|
|
if (!propagated_clk) {
|
|
|
|
|
// Ideal clock.
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *src_clk_edge = path->clkEdge(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
time = search_->clkPathArrival(path1) + time_offset;
|
|
|
|
|
if (src_clk_edge) {
|
|
|
|
|
Clock *src_clk = src_clk_edge->clock();
|
2025-03-31 00:27:53 +02:00
|
|
|
const RiseFall *src_clk_rf = src_clk_edge->transition();
|
2019-11-11 23:30:19 +01:00
|
|
|
slew = src_clk->slew(src_clk_rf, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
line_case = "clk_start";
|
|
|
|
|
}
|
|
|
|
|
else if (is_clk
|
|
|
|
|
&& report_clk_path
|
|
|
|
|
&& !propagated_clk) {
|
|
|
|
|
// Zero the clock network delays for ideal clocks.
|
|
|
|
|
incr = 0.0;
|
|
|
|
|
time = prev_time;
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *src_clk_edge = path->clkEdge(this);
|
|
|
|
|
const Clock *src_clk = src_clk_edge->clock();
|
2025-03-31 00:27:53 +02:00
|
|
|
const RiseFall *src_clk_rf = src_clk_edge->transition();
|
2019-11-11 23:30:19 +01:00
|
|
|
slew = src_clk->slew(src_clk_rf, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
line_case = "clk_ideal";
|
|
|
|
|
}
|
|
|
|
|
else if (is_clk && !is_clk_start) {
|
2020-05-31 03:09:14 +02:00
|
|
|
incr = delayIncr(time, prev_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
line_case = "clk_prop";
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-05-31 03:09:14 +02:00
|
|
|
incr = delayIncr(time, prev_time, min_max);
|
2018-09-28 17:54:21 +02:00
|
|
|
line_case = "normal";
|
|
|
|
|
}
|
2024-12-26 01:44:28 +01:00
|
|
|
|
|
|
|
|
if (vertex->isDriver(network_)) {
|
|
|
|
|
float cap = field_blank_;
|
2023-08-02 22:11:09 +02:00
|
|
|
float fanout = field_blank_;
|
2024-12-26 01:44:28 +01:00
|
|
|
if (field_capacitance_->enabled())
|
2024-02-08 21:54:52 +01:00
|
|
|
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
|
2024-12-26 01:44:28 +01:00
|
|
|
if (field_fanout_->enabled())
|
|
|
|
|
fanout = drvrFanout(vertex, dcalc_ap->corner(), min_max);
|
|
|
|
|
const string what = descriptionField(vertex);
|
|
|
|
|
reportLine(what.c_str(), cap, slew, fanout,
|
|
|
|
|
incr, time, false, min_max, rf, src_attr,
|
|
|
|
|
line_case);
|
|
|
|
|
|
|
|
|
|
if (report_net_) {
|
|
|
|
|
const string what2 = descriptionNet(pin);
|
|
|
|
|
reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
|
|
|
|
|
field_blank_, field_blank_, false, min_max,
|
|
|
|
|
nullptr, src_attr, "");
|
|
|
|
|
}
|
|
|
|
|
prev_time = time;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-03-27 02:21:03 +01:00
|
|
|
reportHierPinsThru(path1);
|
2024-12-26 01:44:28 +01:00
|
|
|
if (report_input_pin_
|
|
|
|
|
|| (i == 0)
|
|
|
|
|
|| (i == path_last_index)
|
|
|
|
|
|| is_clk_start) {
|
|
|
|
|
const string what = descriptionField(vertex);
|
|
|
|
|
reportLine(what.c_str(), field_blank_, slew, field_blank_,
|
|
|
|
|
incr, time, false, min_max, rf, src_attr,
|
|
|
|
|
line_case);
|
|
|
|
|
prev_time = time;
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
prev_time = time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-26 01:44:28 +01:00
|
|
|
void
|
2025-03-27 02:21:03 +01:00
|
|
|
ReportPath::reportHierPinsThru(const Path *path) const
|
2024-12-26 01:44:28 +01:00
|
|
|
{
|
|
|
|
|
if (report_hier_pins_) {
|
2025-03-27 02:21:03 +01:00
|
|
|
const Edge *prev_edge = path->prevEdge(this);
|
2024-12-26 01:44:28 +01:00
|
|
|
if (prev_edge && prev_edge->isWire()) {
|
|
|
|
|
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
|
|
|
|
|
const string what = descriptionField(hpin);
|
|
|
|
|
reportLine(what.c_str(), field_blank_, field_blank_, field_blank_,
|
|
|
|
|
field_blank_, field_blank_, false, path->minMax(this),
|
|
|
|
|
nullptr, "", "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 03:09:14 +02:00
|
|
|
Delay
|
|
|
|
|
ReportPath::delayIncr(Delay time,
|
|
|
|
|
Delay prev,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2020-05-31 03:09:14 +02:00
|
|
|
{
|
|
|
|
|
if (report_sigmas_)
|
|
|
|
|
return delayRemove(time, prev);
|
|
|
|
|
else
|
|
|
|
|
return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
bool
|
2025-03-27 02:21:03 +01:00
|
|
|
ReportPath::nextArcAnnotated(const Path *next_path,
|
2018-09-28 17:54:21 +02:00
|
|
|
size_t next_index,
|
2025-02-01 23:53:28 +01:00
|
|
|
const PathExpanded &expanded,
|
|
|
|
|
DcalcAPIndex ap_index) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
const TimingArc *arc = expanded.path(next_index)->prevArc(this);
|
|
|
|
|
Edge *edge = next_path->prevEdge(this);
|
2018-11-09 19:04:16 +01:00
|
|
|
return graph_->arcDelayAnnotated(edge, arc, ap_index);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::descriptionField(const Vertex *vertex) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2024-12-26 01:44:28 +01:00
|
|
|
return descriptionField(vertex->pin());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::descriptionField(const Pin *pin) const
|
2024-12-26 01:44:28 +01:00
|
|
|
{
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
|
|
|
|
const char *name2;
|
|
|
|
|
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);
|
|
|
|
|
}
|
2019-01-17 00:37:31 +01:00
|
|
|
return stdstrPrint("%s (%s)", pin_name, name2);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-26 01:44:28 +01:00
|
|
|
string
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::descriptionNet(const Pin *pin) const
|
2024-12-26 01:44:28 +01:00
|
|
|
{
|
|
|
|
|
if (network_->isTopLevelPort(pin)) {
|
|
|
|
|
const char *pin_name = cmd_network_->pathName(pin);
|
|
|
|
|
return stdstrPrint("%s (net)", pin_name);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Net *net = network_->net(pin);
|
|
|
|
|
if (net) {
|
|
|
|
|
Net *highest_net = network_->highestNetAbove(net);
|
|
|
|
|
const char *net_name = cmd_network_->pathName(highest_net);
|
|
|
|
|
return stdstrPrint("%s (net)", net_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "(unconnected)";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
float
|
|
|
|
|
ReportPath::drvrFanout(Vertex *drvr,
|
2023-01-19 19:23:45 +01:00
|
|
|
const Corner *corner,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
float fanout = 0.0;
|
|
|
|
|
VertexOutEdgeIterator iter(drvr, graph_);
|
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
|
Edge *edge = iter.next();
|
2022-09-19 01:11:21 +02: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);
|
2023-01-19 19:23:45 +01:00
|
|
|
fanout += sdc_->portExtFanout(port, corner, min_max) + 1;
|
2022-09-19 01:11:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fanout++;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return fanout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::hasExtInputDriver(const Pin *pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2025-02-01 23:53:28 +01:00
|
|
|
const MinMax *min_max) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
Port *port = network_->port(pin);
|
|
|
|
|
InputDrive *drive = sdc_->findInputDrive(port);
|
|
|
|
|
return (drive
|
2019-11-11 23:30:19 +01:00
|
|
|
&& (drive->hasDriveResistance(rf, min_max)
|
|
|
|
|
|| drive->hasDriveCell(rf, min_max)));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportInputExternalDelay(const Path *first_path,
|
2025-02-01 23:53:28 +01:00
|
|
|
float time_offset) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
const Pin *first_pin = first_path->pin(graph_);
|
|
|
|
|
if (!pathFromClkPin(first_path, first_pin)) {
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf = first_path->transition(this);
|
2025-03-27 02:21:03 +01:00
|
|
|
Arrival time = first_path->arrival() + time_offset;
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late = first_path->minMax(this);
|
2018-09-28 17:54:21 +02:00
|
|
|
InputDelay *input_delay = pathInputDelay(first_path);
|
|
|
|
|
if (input_delay) {
|
|
|
|
|
const Pin *ref_pin = input_delay->refPin();
|
|
|
|
|
if (ref_pin) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path ref_path;
|
2018-09-28 17:54:21 +02:00
|
|
|
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
|
|
|
|
if (!ref_path.isNull() && reportClkPath()) {
|
|
|
|
|
PathExpanded ref_expanded(&ref_path, this);
|
2025-08-18 22:27:30 +02:00
|
|
|
reportPath3(&ref_path, ref_expanded, true, 0.0);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
float input_arrival =
|
2019-11-11 23:30:19 +01:00
|
|
|
input_delay->delays()->value(rf, first_path->minMax(this));
|
2018-11-26 18:15:52 +01:00
|
|
|
reportLine("input external delay", input_arrival, time,
|
2020-12-29 04:51:34 +01:00
|
|
|
early_late, rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (network_->isTopLevelPort(first_pin))
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLine("input external delay", 0.0, time, early_late, rf);
|
2018-09-28 17:54:21 +02: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,
|
2025-02-01 23:53:28 +01:00
|
|
|
const InputDelay *input_delay,
|
2018-09-28 17:54:21 +02:00
|
|
|
// Return value.
|
2025-03-27 02:21:03 +01:00
|
|
|
Path &ref_path) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const Pin *ref_pin = input_delay->refPin();
|
2025-02-01 23:53:28 +01:00
|
|
|
const RiseFall *ref_rf = input_delay->refTransition();
|
2018-09-28 17:54:21 +02:00
|
|
|
Vertex *ref_vertex = graph_->pinDrvrVertex(ref_pin);
|
2022-01-15 20:51:05 +01:00
|
|
|
if (ref_vertex) {
|
|
|
|
|
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
|
|
|
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
|
|
|
|
VertexPathIterator path_iter(ref_vertex, ref_rf, path_ap, this);
|
|
|
|
|
while (path_iter.hasNext()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *path = path_iter.next();
|
2022-01-15 20:51:05 +01:00
|
|
|
if (path->isClock(this)
|
|
|
|
|
&& path->clkEdge(this) == clk_edge) {
|
2025-03-27 02:21:03 +01:00
|
|
|
ref_path = path;
|
2022-01-15 20:51:05 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportPathHeader() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
bool first_field = true;
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const ReportField *field : fields_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (field->enabled()) {
|
|
|
|
|
if (!first_field)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
|
|
|
|
reportField(field->title(), field, line);
|
2019-03-04 02:50:56 +01:00
|
|
|
first_field = false;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
trimRight(line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDashLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report total.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
Delay total,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
field_blank_, total, false, early_late, nullptr,
|
|
|
|
|
"", nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report negative total.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLineNegative(const char *what,
|
|
|
|
|
Delay total,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
field_blank_, total, true, early_late, nullptr,
|
|
|
|
|
"", nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report total, and transition suffix.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
Delay total,
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
const RiseFall *rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
field_blank_, total, false, early_late, rf, "",
|
|
|
|
|
nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report increment, and total.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
Delay incr,
|
|
|
|
|
Delay total,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
incr, total, false, early_late, nullptr, "",
|
|
|
|
|
nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report increment, total, and transition suffix.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
Delay incr,
|
|
|
|
|
Delay total,
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
const RiseFall *rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
incr, total, false, early_late, rf, "",
|
|
|
|
|
nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report slew, increment, and total.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
Slew slew,
|
|
|
|
|
Delay incr,
|
|
|
|
|
Delay total,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
reportLine(what, field_blank_, slew, field_blank_,
|
2024-10-16 02:28:52 +02:00
|
|
|
incr, total, false, early_late, nullptr,
|
|
|
|
|
"", nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLine(const char *what,
|
|
|
|
|
float cap,
|
|
|
|
|
Slew slew,
|
|
|
|
|
float fanout,
|
|
|
|
|
Delay incr,
|
|
|
|
|
Delay total,
|
|
|
|
|
bool total_with_minus,
|
2018-11-26 18:15:52 +01:00
|
|
|
const EarlyLate *early_late,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2024-10-16 02:28:52 +02:00
|
|
|
string src_attr,
|
2025-02-01 23:53:28 +01:00
|
|
|
const char *line_case) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
2019-03-04 02:50:56 +01:00
|
|
|
size_t field_index = 0;
|
|
|
|
|
bool first_field = true;
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const ReportField *field : fields_) {
|
2019-03-04 02:50:56 +01:00
|
|
|
bool last_field = field_index == (fields_.size() - 1);
|
2019-02-16 21:07:59 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if (field->enabled()) {
|
2019-02-16 21:07:59 +01:00
|
|
|
if (!first_field)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
if (field == field_description_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDescription(what, first_field, last_field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (field == field_fanout_) {
|
|
|
|
|
if (fanout == field_blank_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2019-01-17 00:37:31 +01:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
line += stdstrPrint("%*d",
|
|
|
|
|
field_fanout_->width(),
|
|
|
|
|
static_cast<int>(fanout));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (field == field_capacitance_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(cap, field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (field == field_slew_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelay(slew, early_late, field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (field == field_incr_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelay(incr, early_late, field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (field == field_total_) {
|
2018-11-26 18:15:52 +01:00
|
|
|
if (total_with_minus)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelayMinus(total, early_late, field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelay(total, early_late, field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (field == field_edge_) {
|
2019-11-11 23:30:19 +01:00
|
|
|
if (rf)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(rf->shortName(), field, line);
|
2024-10-16 02:28:52 +02:00
|
|
|
else
|
|
|
|
|
reportFieldBlank(field, line);
|
|
|
|
|
}
|
|
|
|
|
else if (field == field_src_attr_) {
|
|
|
|
|
if (src_attr != "")
|
|
|
|
|
reportField(src_attr.c_str(), field, line);
|
|
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else if (field == field_case_ && line_case)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += line_case;
|
2019-02-16 21:07:59 +01:00
|
|
|
|
2019-03-04 02:50:56 +01:00
|
|
|
first_field = false;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-02-16 21:07:59 +01:00
|
|
|
field_index++;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2024-10-16 02:28:52 +02:00
|
|
|
// Trim trailing spaces and report the line.
|
|
|
|
|
string line_stdstr = line;
|
|
|
|
|
trimRight(line_stdstr);
|
|
|
|
|
report_->reportLineString(line_stdstr.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Only the total field.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLineTotal(const char *what,
|
|
|
|
|
Delay incr,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal1(what, incr, false, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only the total field and always with leading minus sign.
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLineTotalMinus(const char *what,
|
|
|
|
|
Delay decr,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportLineTotal1(what, decr, true, early_late);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportLineTotal1(const char *what,
|
|
|
|
|
Delay incr,
|
|
|
|
|
bool incr_with_minus,
|
2025-02-01 23:53:28 +01:00
|
|
|
const EarlyLate *early_late) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
|
|
|
|
reportDescription(what, line);
|
|
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
if (incr_with_minus)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelayMinus(incr, early_late, field_total_, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldDelay(incr, early_late, field_total_, line);
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportDashLineTotal() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDashLine(field_description_->width() + field_total_->width() + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportDescription(const char *what,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2019-02-16 21:07:59 +01:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
reportDescription(what, false, false, line);
|
2019-02-16 21:07:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportDescription(const char *what,
|
|
|
|
|
bool first_field,
|
|
|
|
|
bool last_field,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
line += what;
|
2018-09-28 17:54:21 +02:00
|
|
|
int length = strlen(what);
|
2019-02-16 21:07:59 +01:00
|
|
|
if (!no_split_
|
|
|
|
|
&& first_field
|
|
|
|
|
&& length > field_description_->width()) {
|
2020-12-29 04:51:34 +01:00
|
|
|
reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
for (int i = 0; i < field_description_->width(); i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-02-16 21:07:59 +01:00
|
|
|
else if (!last_field) {
|
2018-09-28 17:54:21 +02:00
|
|
|
for (int i = length; i < field_description_->width(); i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2018-11-26 18:15:52 +01:00
|
|
|
ReportPath::reportFieldTime(float value,
|
|
|
|
|
ReportField *field,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-11-26 18:15:52 +01:00
|
|
|
{
|
|
|
|
|
if (delayAsFloat(value) == field_blank_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
else {
|
|
|
|
|
const char *str = units_->timeUnit()->asString(value, digits_);
|
|
|
|
|
if (stringEq(str, minus_zero_))
|
|
|
|
|
// Filter "-0.00" fields.
|
|
|
|
|
str = plus_zero_;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(str, field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportSpaceFieldTime(float value,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
|
|
|
|
reportFieldTime(value, field_total_, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2018-11-26 18:15:52 +01:00
|
|
|
ReportPath::reportSpaceFieldDelay(Delay value,
|
|
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-11-26 18:15:52 +01:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
|
|
|
|
reportTotalDelay(value, early_late, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportTotalDelay(Delay value,
|
|
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-01-27 08:03:01 +01:00
|
|
|
const char *str = delayAsString(value, early_late, this, digits_);
|
2018-11-26 18:15:52 +01:00
|
|
|
if (stringEq(str, minus_zero_))
|
2018-09-28 17:54:21 +02:00
|
|
|
// Filter "-0.00" fields.
|
2018-11-26 18:15:52 +01:00
|
|
|
str = plus_zero_;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(str, field_total_, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Total time always with leading minus sign.
|
|
|
|
|
void
|
2018-11-26 18:15:52 +01:00
|
|
|
ReportPath::reportFieldDelayMinus(Delay value,
|
|
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
const ReportField *field,
|
|
|
|
|
string &line) const
|
2018-11-26 18:15:52 +01:00
|
|
|
{
|
|
|
|
|
if (delayAsFloat(value) == field_blank_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
else {
|
2019-12-24 17:53:45 +01:00
|
|
|
const char *str = report_sigmas_
|
|
|
|
|
? delayAsString(-value, this, digits_)
|
2020-05-31 03:09:14 +02:00
|
|
|
// Opposite min/max for negative value.
|
|
|
|
|
: delayAsString(-value, early_late->opposite(), this, digits_);
|
2018-11-26 18:15:52 +01:00
|
|
|
if (stringEq(str, plus_zero_))
|
|
|
|
|
// Force leading minus sign.
|
|
|
|
|
str = minus_zero_;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(str, field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportFieldDelay(Delay value,
|
|
|
|
|
const EarlyLate *early_late,
|
2025-02-01 23:53:28 +01:00
|
|
|
const ReportField *field,
|
|
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2018-11-26 18:15:52 +01:00
|
|
|
if (delayAsFloat(value) == field_blank_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
else {
|
2019-12-24 17:53:45 +01:00
|
|
|
const char *str = report_sigmas_
|
|
|
|
|
? delayAsString(value, this, digits_)
|
|
|
|
|
: delayAsString(value, early_late, this, digits_);
|
2018-11-26 18:15:52 +01:00
|
|
|
if (stringEq(str, minus_zero_))
|
|
|
|
|
// Filter "-0.00" fields.
|
|
|
|
|
str = plus_zero_;
|
2020-12-29 04:51:34 +01:00
|
|
|
reportField(str, field, line);
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportField(float value,
|
2020-06-03 00:19:09 +02:00
|
|
|
const ReportField *field,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (value == field_blank_)
|
2020-12-29 04:51:34 +01:00
|
|
|
reportFieldBlank(field, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
2020-06-03 00:19:09 +02:00
|
|
|
Unit *unit = field->unit();
|
2023-03-13 18:24:13 +01:00
|
|
|
if (unit) {
|
|
|
|
|
const char *value_str = unit->asString(value, digits_);
|
|
|
|
|
reportField(value_str, field, line);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-06-03 00:19:09 +02:00
|
|
|
// fanout
|
2023-03-13 18:24:13 +01:00
|
|
|
string value_str;
|
|
|
|
|
stringPrint(value_str, "%.0f", value);
|
|
|
|
|
reportField(value_str.c_str(), field, line);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ReportPath::reportField(const char *value,
|
2020-06-03 00:19:09 +02:00
|
|
|
const ReportField *field,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (field->leftJustify())
|
2020-12-29 04:51:34 +01:00
|
|
|
line += value;
|
2018-09-28 17:54:21 +02:00
|
|
|
for (int i = strlen(value); i < field->width(); i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += ' ';
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!field->leftJustify())
|
2020-12-29 04:51:34 +01:00
|
|
|
line += value;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-06-03 00:19:09 +02:00
|
|
|
ReportPath::reportFieldBlank(const ReportField *field,
|
2025-02-01 23:53:28 +01:00
|
|
|
string &line) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
line += field->blank();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportDashLine() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2020-12-29 04:51:34 +01:00
|
|
|
string line;
|
2025-02-01 23:53:28 +01:00
|
|
|
for (const ReportField *field : fields_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (field->enabled()) {
|
|
|
|
|
for (int i = 0; i < field->width(); i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += '-';
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 04:51:34 +01:00
|
|
|
line += "------";
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-29 03:04:49 +01:00
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportDashLine(int line_width) const
|
2020-12-29 03:04:49 +01:00
|
|
|
{
|
|
|
|
|
string line;
|
2018-09-28 17:54:21 +02:00
|
|
|
for (int i = 0; i < line_width; i++)
|
2020-12-29 04:51:34 +01:00
|
|
|
line += '-';
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::reportBlankLine() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2021-01-05 03:14:04 +01:00
|
|
|
report_->reportBlankLine();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ReportPath::reportClkPath() const
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return format_ == ReportPathFormat::full_clock
|
|
|
|
|
|| format_ == ReportPathFormat::full_clock_expanded;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::asRisingFalling(const RiseFall *rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
if (rf == RiseFall::rise())
|
2018-09-28 17:54:21 +02:00
|
|
|
return "rising";
|
|
|
|
|
else
|
|
|
|
|
return "falling";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::asRiseFall(const RiseFall *rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
if (rf == RiseFall::rise())
|
2018-09-28 17:54:21 +02:00
|
|
|
return "rise";
|
|
|
|
|
else
|
|
|
|
|
return "fall";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the startpoint type from the first path edge.
|
|
|
|
|
const char *
|
2025-02-01 23:53:28 +01:00
|
|
|
ReportPath::edgeRegLatchDesc(const Edge *first_edge,
|
|
|
|
|
const TimingArc *first_arc) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-31 00:27:53 +02:00
|
|
|
const TimingRole *role = first_arc->role();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (role == TimingRole::latchDtoQ()) {
|
|
|
|
|
Instance *inst = network_->instance(first_edge->to(graph_)->pin());
|
|
|
|
|
LibertyCell *cell = network_->libertyCell(inst);
|
|
|
|
|
if (cell) {
|
2024-06-27 22:57:58 +02:00
|
|
|
const LibertyPort *enable_port;
|
|
|
|
|
const FuncExpr *enable_func;
|
2024-07-08 02:56:55 +02:00
|
|
|
const RiseFall *enable_rf;
|
2018-09-28 17:54:21 +02:00
|
|
|
cell->latchEnable(first_edge->timingArcSet(),
|
2019-11-11 23:30:19 +01:00
|
|
|
enable_port, enable_func, enable_rf);
|
|
|
|
|
return latchDesc(enable_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (role == TimingRole::regClkToQ())
|
2022-02-14 01:46:45 +01:00
|
|
|
return regDesc(first_arc->fromEdge()->asRiseFall());
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (role == TimingRole::latchEnToQ())
|
2022-02-14 01:46:45 +01:00
|
|
|
return latchDesc(first_arc->fromEdge()->asRiseFall());
|
2018-09-28 17:54:21 +02:00
|
|
|
// Who knows...
|
2022-02-14 01:46:45 +01:00
|
|
|
return regDesc(first_arc->fromEdge()->asRiseFall());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
ReportPath::checkRegLatchDesc(const TimingRole *role,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *clk_rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (role == TimingRole::regClkToQ())
|
2019-11-11 23:30:19 +01:00
|
|
|
return regDesc(clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (role == TimingRole::latchEnToQ()
|
|
|
|
|
|| role == TimingRole::latchDtoQ())
|
2019-11-11 23:30:19 +01:00
|
|
|
return latchDesc(clk_rf);
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
|
|
|
|
// Default when we don't know better.
|
|
|
|
|
return "edge-triggered flip-flop";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2019-11-11 23:30:19 +01:00
|
|
|
ReportPath::regDesc(const RiseFall *clk_rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
if (clk_rf == RiseFall::rise())
|
2018-09-28 17:54:21 +02:00
|
|
|
return "rising edge-triggered flip-flop";
|
2019-11-11 23:30:19 +01:00
|
|
|
else if (clk_rf == RiseFall::fall())
|
2018-09-28 17:54:21 +02:00
|
|
|
return "falling edge-triggered flip-flop";
|
|
|
|
|
else
|
|
|
|
|
return "edge-triggered flip-flop";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2019-11-11 23:30:19 +01:00
|
|
|
ReportPath::latchDesc(const RiseFall *clk_rf) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
return (clk_rf == RiseFall::rise())
|
2018-09-28 17:54:21 +02:00
|
|
|
? "positive level-sensitive latch"
|
|
|
|
|
: "negative level-sensitive latch";
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-26 01:44:28 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
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()) {
|
|
|
|
|
std::reverse(load_hpins.begin(), load_hpins.end());
|
|
|
|
|
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-14 01:45:39 +01:00
|
|
|
delete term_iter;
|
2024-12-26 01:44:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
} // namespace
|