diff --git a/README.md b/README.md
index 6b457019..84be85e5 100644
--- a/README.md
+++ b/README.md
@@ -247,22 +247,20 @@ should be a short description of the problem. Attach a test case to
reproduce the issue as described below. Issues without test cases are
unlikely to get a response.
-The files in the test case should be collected into a directory named
-YYYYMMDD where YYYY is the year, MM is the month, and DD is the
-day (this format allows "ls" to report them in chronological order).
-The contents of the directory should be collected into a compressed
-tarfile named YYYYMMDD.tgz.
-
The test case should have a tcl command file recreates the issue named
-run.tcl. If there are more than one command file using the same data
+run.tcl. If is are more than one command file using the same data
files, there should be separate command files, run1.tcl, run2.tcl
etc. The bug report can refer to these command files by name.
Command files should not have absolute filenames like
-"/home/cho/OpenSTA_Request/write_path_spice/dump_spice" in them.
+"/home/john/OpenSTA_bug/write_path_spice/dump_spice" in them.
These obviously are not portable. Use filenames relative to the test
case directory.
+The files in the test case should be collected into a directory.
+The contents of the directory should be collected into a compressed
+tarfile.
+
## Contributions
Contributors must sign the Contributor License Agreement (doc/CLA.txt)
diff --git a/cmake/FindTCL.cmake b/cmake/FindTCL.cmake
index 46d61f33..17cb3a62 100644
--- a/cmake/FindTCL.cmake
+++ b/cmake/FindTCL.cmake
@@ -31,7 +31,10 @@ set(TCL_POSSIBLE_NAMES
# tcl lib path guesses.
if (NOT TCL_LIB_PATHS)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
- set(TCL_LIB_PATHS /opt/homebrew/Cellar/tcl-tk@8/8.6.16/lib /opt/homebrew/opt/tcl-tk/lib /usr/local/lib)
+ set(TCL_LIB_PATHS
+ /opt/homebrew/Cellar/tcl-tk@8/8.6.17/lib
+ /opt/homebrew/Cellar/tcl-tk@8/8.6.16/lib
+ /opt/homebrew/opt/tcl-tk/lib /usr/local/lib)
set(TCL_NO_DEFAULT_PATH TRUE)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(TCL_LIB_PATHS /usr/lib /usr/lib64 /usr/local/lib)
diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc
index b0b0402d..6fcaa870 100644
--- a/dcalc/GraphDelayCalc.cc
+++ b/dcalc/GraphDelayCalc.cc
@@ -184,6 +184,19 @@ GraphDelayCalc::delayInvalid(Vertex *vertex)
}
}
+void
+GraphDelayCalc::levelsChangedBefore()
+{
+ delaysInvalid();
+}
+
+void
+GraphDelayCalc::levelChangedBefore(Vertex *vertex)
+{
+ iter_->remove(vertex);
+ delayInvalid(vertex);
+}
+
void
GraphDelayCalc::deleteVertexBefore(Vertex *vertex)
{
diff --git a/doc/ApiChanges.txt b/doc/ApiChanges.txt
index 9cda8fa7..d2ad43f8 100644
--- a/doc/ApiChanges.txt
+++ b/doc/ApiChanges.txt
@@ -53,6 +53,9 @@ The following classes now return const objects.
Liberty PgPorts are now LibertyPorts with additional member functions for
liberty pg_pins.
+The write_verilog command always sorts the verilog file instances.
+The -sort argument is ignored.
+
Release 2.6.1 2025/03/??
-------------------------
diff --git a/doc/OpenSTA.fodt b/doc/OpenSTA.fodt
index 84751fab..f7a17c62 100644
--- a/doc/OpenSTA.fodt
+++ b/doc/OpenSTA.fodt
@@ -13772,18 +13772,9 @@
write_verilog
- [-sort]
[-include_pwr_gnd][-remove_cells lib_cells]filename
-
-
- -sort
-
-
- Sort the instances in the netlist.
-
-
-include_pwr_gnd
@@ -13809,7 +13800,7 @@
- The write_verilog command writes a Verilog netlist to filename. Use -sort to sort the instances so the results are reproducible across operating systems. Use -remove_cells to remove instances of lib_cells from the netlist.
+ The write_verilog command writes a Verilog netlist to filename. Instances are always sorted so the results are reproducible across operating systems. Use -remove_cells to remove instances of lib_cells from the netlist.
Filter Expressions
The get_cells, get_pins, get_ports and get_timing_edges functions support filtering the returned objects by property values. Supported filter expressions are shown below.
diff --git a/include/sta/Bfs.hh b/include/sta/Bfs.hh
index 89080010..c95fc5cb 100644
--- a/include/sta/Bfs.hh
+++ b/include/sta/Bfs.hh
@@ -106,6 +106,8 @@ protected:
virtual void incrLevel(Level &level) const = 0;
void findNext(Level to_level);
void deleteEntries();
+ void checkLevel(Vertex *vertex,
+ Level level);
BfsIndex bfs_index_;
Level level_min_;
diff --git a/include/sta/DispatchQueue.hh b/include/sta/DispatchQueue.hh
index a8f6d60e..f28d94c5 100644
--- a/include/sta/DispatchQueue.hh
+++ b/include/sta/DispatchQueue.hh
@@ -24,6 +24,7 @@ public:
DispatchQueue(size_t thread_cnt);
~DispatchQueue();
void setThreadCount(size_t thread_count);
+ size_t getThreadCount() const;
// Dispatch and copy.
void dispatch(const fp_t& op);
// Dispatch and move.
diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh
index 942c8468..6a746fc4 100644
--- a/include/sta/GraphDelayCalc.hh
+++ b/include/sta/GraphDelayCalc.hh
@@ -58,10 +58,12 @@ public:
virtual void setObserver(DelayCalcObserver *observer);
// Invalidate all delays/slews.
virtual void delaysInvalid();
+ virtual void levelsChangedBefore();
// Invalidate vertex and downstream delays/slews.
virtual void delayInvalid(Vertex *vertex);
virtual void delayInvalid(const Pin *pin);
virtual void deleteVertexBefore(Vertex *vertex);
+ virtual void levelChangedBefore(Vertex *vertex);
// Reset to virgin state.
virtual void clear();
// Find arc delays and vertex slews thru level.
diff --git a/include/sta/Parasitics.hh b/include/sta/Parasitics.hh
index 18a64da6..948843f2 100644
--- a/include/sta/Parasitics.hh
+++ b/include/sta/Parasitics.hh
@@ -276,6 +276,7 @@ public:
// Network edit before/after methods.
virtual void disconnectPinBefore(const Pin *pin,
const Network *network) = 0;
+ virtual void deletePinBefore(const Pin *pin) = 0;
virtual void loadPinCapacitanceChanged(const Pin *pin) = 0;
protected:
diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh
index 0cfac597..c61eb16a 100644
--- a/include/sta/PathEnd.hh
+++ b/include/sta/PathEnd.hh
@@ -69,7 +69,7 @@ public:
};
virtual PathEnd *copy() const = 0;
- virtual ~PathEnd();
+ virtual ~PathEnd() {}
void deletePath();
Path *path() { return path_; }
const Path *path() const { return path_; }
diff --git a/include/sta/Search.hh b/include/sta/Search.hh
index d0c7c458..b23ef5c4 100644
--- a/include/sta/Search.hh
+++ b/include/sta/Search.hh
@@ -418,7 +418,8 @@ public:
void checkPrevPaths() const;
void deletePaths(Vertex *vertex);
void deleteTagGroup(TagGroup *group);
- bool postpone_latch_outputs_;
+ bool postponeLatchOutputs() const { return postpone_latch_outputs_; }
+ void saveEnumPath(Path *path);
protected:
void init(StaState *sta);
@@ -671,8 +672,10 @@ protected:
VertexSet *filtered_arrivals_;
std::mutex filtered_arrivals_lock_;
bool found_downstream_clk_pins_;
+ bool postpone_latch_outputs_;
PathGroups *path_groups_;
VisitPathEnds *visit_path_ends_;
+ std::vector enum_paths_;
GatedClk *gated_clk_;
CheckCrpr *check_crpr_;
Genclks *genclks_;
diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh
index f7b233da..cdf67203 100644
--- a/include/sta/Sta.hh
+++ b/include/sta/Sta.hh
@@ -1365,6 +1365,7 @@ protected:
virtual void makeCheckMaxSkews();
virtual void makeReportPath();
virtual void makePower();
+ virtual void makeClkSkews();
virtual void makeObservers();
NetworkEdit *networkCmdEdit();
diff --git a/include/sta/Units.hh b/include/sta/Units.hh
index ffee1840..8b54be5f 100644
--- a/include/sta/Units.hh
+++ b/include/sta/Units.hh
@@ -42,10 +42,15 @@ public:
void operator=(const Unit &unit);
float scale() const { return scale_; }
void setScale(float scale);
- const char *scaleAbbreviation() const;
- const char *suffix() const { return suffix_.c_str(); }
+ // Mkmunpf abbreviation for scale.
+ std::string scaleAbbreviation() const;
+ // 1Mkmunpf or scale
+ std::string scaleString() const;
+ std::string suffix() const { return suffix_; }
+ // scaleString + suffix
+ std::string scaleSuffix() const;
// scale abbreviation + suffix
- const char *scaledSuffix() const { return scaled_suffix_.c_str(); }
+ std::string scaleAbbrevSuffix() const { return scale_abbrev_suffix_; }
void setSuffix(const char *suffix);
int digits() const { return digits_; }
void setDigits(int digits);
@@ -57,11 +62,11 @@ public:
int digits) const;
private:
- void setScaledSuffix();
+ void setScaleAbbrevSuffix();
float scale_; // multiplier from user units to internal units
std::string suffix_; // print suffix
- std::string scaled_suffix_;
+ std::string scale_abbrev_suffix_;
int digits_; // print digits (after decimal pt)
};
diff --git a/include/sta/VerilogWriter.hh b/include/sta/VerilogWriter.hh
index ec44dd30..b4a08e8c 100644
--- a/include/sta/VerilogWriter.hh
+++ b/include/sta/VerilogWriter.hh
@@ -30,7 +30,6 @@ namespace sta {
void
writeVerilog(const char *filename,
- bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells,
Network *network);
diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc
index 10cce09b..2c4dd1a7 100644
--- a/liberty/LibertyWriter.cc
+++ b/liberty/LibertyWriter.cc
@@ -137,20 +137,20 @@ LibertyWriter::writeHeader()
fprintf(stream_, " simulation : false;\n");
const Unit *cap_unit = library_->units()->capacitanceUnit();
fprintf(stream_, " capacitive_load_unit (1,%s);\n",
- cap_unit->scaledSuffix());
+ cap_unit->scaleAbbrevSuffix().c_str());
fprintf(stream_, " leakage_power_unit : 1pW;\n");
const Unit *current_unit = library_->units()->currentUnit();
fprintf(stream_, " current_unit : \"1%s\";\n",
- current_unit->scaledSuffix());
+ current_unit->scaleAbbrevSuffix().c_str());
const Unit *res_unit = library_->units()->resistanceUnit();
fprintf(stream_, " pulling_resistance_unit : \"1%s\";\n",
- res_unit->scaledSuffix());
+ res_unit->scaleAbbrevSuffix().c_str());
const Unit *time_unit = library_->units()->timeUnit();
fprintf(stream_, " time_unit : \"1%s\";\n",
- time_unit->scaledSuffix());
+ time_unit->scaleAbbrevSuffix().c_str());
const Unit *volt_unit = library_->units()->voltageUnit();
fprintf(stream_, " voltage_unit : \"1%s\";\n",
- volt_unit->scaledSuffix());
+ volt_unit->scaleAbbrevSuffix().c_str());
fprintf(stream_, " library_features(report_delay_calculation);\n");
fprintf(stream_, "\n");
diff --git a/liberty/Units.cc b/liberty/Units.cc
index 70e4e8d3..8dcbb4f0 100644
--- a/liberty/Units.cc
+++ b/liberty/Units.cc
@@ -40,7 +40,7 @@ Unit::Unit(const char *suffix) :
suffix_(suffix),
digits_(3)
{
- setScaledSuffix();
+ setScaleAbbrevSuffix();
}
Unit::Unit(float scale,
@@ -50,13 +50,13 @@ Unit::Unit(float scale,
suffix_(suffix),
digits_(digits)
{
- setScaledSuffix();
+ setScaleAbbrevSuffix();
}
void
-Unit::setScaledSuffix()
+Unit::setScaleAbbrevSuffix()
{
- scaled_suffix_ = scaleAbbreviation() + suffix_;
+ scale_abbrev_suffix_ = scaleAbbreviation() + suffix_;
}
void
@@ -64,7 +64,7 @@ Unit::operator=(const Unit &unit)
{
scale_ = unit.scale_;
suffix_ = unit.suffix_;
- scaled_suffix_ = unit.scaled_suffix_;
+ scale_abbrev_suffix_ = unit.scale_abbrev_suffix_;
digits_ = unit.digits_;
}
@@ -84,10 +84,10 @@ void
Unit::setScale(float scale)
{
scale_ = scale;
- setScaledSuffix();
+ setScaleAbbrevSuffix();
}
-const char *
+std::string
Unit::scaleAbbreviation() const
{
if (fuzzyEqual(scale_, 1E+6))
@@ -110,11 +110,40 @@ Unit::scaleAbbreviation() const
return "?";
}
+std::string
+Unit::scaleString() const
+{
+ if (fuzzyEqual(scale_, 1E+6))
+ return "1M";
+ else if (fuzzyEqual(scale_, 1E+3))
+ return "1k";
+ if (fuzzyEqual(scale_, 1.0))
+ return "1";
+ else if (fuzzyEqual(scale_, 1E-3))
+ return "1m";
+ else if (fuzzyEqual(scale_, 1E-6))
+ return "1u";
+ else if (fuzzyEqual(scale_, 1E-9))
+ return "1n";
+ else if (fuzzyEqual(scale_, 1E-12))
+ return "1p";
+ else if (fuzzyEqual(scale_, 1E-15))
+ return "1f";
+ else
+ return stdstrPrint("%.1e", scale_);
+}
+
+std::string
+Unit::scaleSuffix() const
+{
+ return scaleString() + suffix_;
+}
+
void
Unit::setSuffix(const char *suffix)
{
suffix_ = suffix;
- setScaledSuffix();
+ setScaleAbbrevSuffix();
}
void
diff --git a/network/ConcreteNetwork.cc b/network/ConcreteNetwork.cc
index 2c6cc63c..d165e9f3 100644
--- a/network/ConcreteNetwork.cc
+++ b/network/ConcreteNetwork.cc
@@ -1286,7 +1286,6 @@ ConcreteNetwork::replaceCell(Instance *inst,
if (cport) {
rpins[cport->pinIndex()] = cpin;
cpin->port_ = cport;
- cpin->id_ = ConcreteNetwork::nextObjectId();
}
}
}
diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc
index f36a5470..9d7f5844 100644
--- a/parasitics/ConcreteParasitics.cc
+++ b/parasitics/ConcreteParasitics.cc
@@ -721,11 +721,13 @@ ConcreteParasiticNetwork::disconnectPin(const Pin *pin,
ccapacitor->replaceNode(node, subnode);
}
- pin_nodes_.erase(pin);
+ pin_nodes_.erase(pin_node);
delete node;
}
}
+////////////////////////////////////////////////////////////////
+
NetIdPairLess::NetIdPairLess(const Network *network) :
net_less_(network)
{
@@ -893,6 +895,13 @@ ConcreteParasitics::disconnectPinBefore(const Pin *pin,
}
}
+void
+ConcreteParasitics::deletePinBefore(const Pin *pin)
+{
+ // Actions are the same.
+ disconnectPinBefore(pin, network_);
+}
+
void
ConcreteParasitics::loadPinCapacitanceChanged(const Pin *pin)
{
diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh
index ae0f9bc9..9a06058d 100644
--- a/parasitics/ConcreteParasitics.hh
+++ b/parasitics/ConcreteParasitics.hh
@@ -173,6 +173,7 @@ public:
void disconnectPinBefore(const Pin *pin,
const Network *network) override;
+ void deletePinBefore(const Pin *pin) override;
void loadPinCapacitanceChanged(const Pin *pin) override;
void deleteReducedParasitics(const Net *net,
diff --git a/power/Power.cc b/power/Power.cc
index f50fb67d..3265fe96 100644
--- a/power/Power.cc
+++ b/power/Power.cc
@@ -101,6 +101,7 @@ Power::Power(StaState *sta) :
seq_activity_map_(100, SeqPinHash(network_), SeqPinEqual()),
activities_valid_(false),
bdd_(sta),
+ instance_powers_(InstanceIdLess(network_)),
instance_powers_valid_(false),
corner_(nullptr)
{
@@ -694,8 +695,8 @@ Power::evalBddActivity(DdNode *bdd,
Cudd_RecursiveDeref(bdd_.cuddMgr(), diff);
float var_density = var_activity.density() * diff_duty;
density += var_density;
- debugPrint(debug_, "power_activity", 3, "var %s %.3e * %.3f = %.3e",
- port->name(),
+ debugPrint(debug_, "power_activity", 3, "%s %.3e * %.3f = %.3e",
+ network_->pathName(pin),
var_activity.density(),
diff_duty,
var_density);
@@ -834,24 +835,34 @@ Power::seedRegOutputActivities(const Instance *reg,
{
const Pin *out_pin = network_->findPin(reg, output);
if (!hasUserActivity(out_pin)) {
- PwrActivity activity = evalActivity(seq->data(), reg);
- // Register output activity cannnot exceed one transition per clock cycle,
- // but latch output can.
- if (seq->isRegister()) {
- FuncExpr *clk_func = seq->clock();
- if (clk_func->port()) {
- const Pin *pin = network_->findPin(reg, clk_func->port());
- const Clock *clk = findClk(pin);
- if (clk) {
- if (activity.density() > 1.0 / clk->period())
- activity.setDensity(1.0 / clk->period());
- }
+ PwrActivity in_activity = evalActivity(seq->data(), reg);
+ float in_density = in_activity.density();
+ float in_duty = in_activity.duty();
+ // Default propagates input density/duty thru reg/latch.
+ float out_density = in_density;
+ float out_duty = in_duty;
+ PwrActivity clk_activity = evalActivity(seq->clock(), reg);
+ float clk_density = clk_activity.density();
+ if (in_density > clk_density / 2) {
+ if (seq->isRegister())
+ out_density = 2 * in_duty * (1 - in_duty) * clk_density;
+ else if (seq->isLatch()) {
+ PwrActivity clk_activity = evalActivity(seq->clock(), reg);
+ float clk_duty = clk_activity.duty();
+ FuncExpr *clk_func = seq->clock();
+ bool clk_invert = clk_func
+ && clk_func->op() == FuncExpr::op_not
+ && clk_func->left()->op() == FuncExpr::op_port;
+ if (clk_invert)
+ out_density = in_density * (1 - clk_duty);
+ else
+ out_density = in_density * clk_duty;
}
}
if (invert)
- activity.setDuty(1.0 - activity.duty());
- activity.setOrigin(PwrActivityOrigin::propagated);
- setSeqActivity(reg, output, activity);
+ out_duty = 1.0 - out_duty;
+ PwrActivity out_activity(out_density, out_duty, PwrActivityOrigin::propagated);
+ setSeqActivity(reg, output, out_activity);
}
}
diff --git a/power/Power.hh b/power/Power.hh
index 5c45fd60..abed2f40 100644
--- a/power/Power.hh
+++ b/power/Power.hh
@@ -238,7 +238,7 @@ private:
PwrSeqActivityMap seq_activity_map_;
bool activities_valid_;
Bdd bdd_;
- std::map instance_powers_;
+ std::map instance_powers_;
bool instance_powers_valid_;
const Corner *corner_;
diff --git a/power/Power.tcl b/power/Power.tcl
index 420a97a9..97769501 100644
--- a/power/Power.tcl
+++ b/power/Power.tcl
@@ -35,13 +35,14 @@ define_cmd_args "report_power" \
[-highest_power_instances count]\
[-corner corner]\
[-digits digits]\
+ [-format format]\
[> filename] [>> filename] }
proc_redirect report_power {
global sta_report_default_digits
parse_key_args "report_power" args \
- keys {-instances -highest_power_instances -corner -digits} flags {}
+ keys {-instances -highest_power_instances -corner -digits -format} flags {}
check_argc_eq0 "report_power" $args
@@ -56,16 +57,37 @@ proc_redirect report_power {
}
set corner [parse_corner keys]
+ if { [info exists keys(-format)] } {
+ set format $keys(-format)
+ if { $format != "text" && $format != "json" } {
+ sta_error 311 "unknown power report -format $format"
+ }
+ } else {
+ set format "text"
+ }
+
if { [info exists keys(-instances)] } {
set insts [get_instances_error "-instances" $keys(-instances)]
- report_power_insts $insts $corner $digits
+ if { $format == "json" } {
+ report_power_insts_json $insts $corner $digits
+ } else {
+ report_power_insts $insts $corner $digits
+ }
} elseif { [info exists keys(-highest_power_instances)] } {
set count $keys(-highest_power_instances)
check_positive_integer "-highest_power_instances" $count
set insts [highest_power_instances $count $corner]
- report_power_insts $insts $corner $digits
+ if { $format == "json" } {
+ report_power_insts_json $insts $corner $digits
+ } else {
+ report_power_insts $insts $corner $digits
+ }
} else {
- report_power_design $corner $digits
+ if { $format == "json" } {
+ report_power_design_json $corner $digits
+ } else {
+ report_power_design $corner $digits
+ }
}
}
@@ -104,6 +126,35 @@ proc report_power_design { corner digits } {
report_line "[format %-20s {}][power_col_percent $design_internal $design_total $field_width][power_col_percent $design_switching $design_total $field_width][power_col_percent $design_leakage $design_total $field_width]"
}
+proc report_power_design_json { corner digits } {
+ set power_result [design_power $corner]
+ set totals [lrange $power_result 0 3]
+ set sequential [lrange $power_result 4 7]
+ set combinational [lrange $power_result 8 11]
+ set clock [lrange $power_result 12 15]
+ set macro [lrange $power_result 16 19]
+ set pad [lrange $power_result 20 end]
+
+ report_line "\{"
+ report_power_row_json "Sequential" $sequential $digits ","
+ report_power_row_json "Combinational" $combinational $digits ","
+ report_power_row_json "Clock" $clock $digits ","
+ report_power_row_json "Macro" $macro $digits ","
+ report_power_row_json "Pad" $pad $digits ","
+ report_power_row_json "Total" $totals $digits ""
+ report_line "\}"
+}
+
+proc report_power_row_json { name row_result digits separator } {
+ lassign $row_result internal switching leakage total
+ report_line " \"$name\": \{"
+ report_line " \"internal\": [format %.${digits}e $internal],"
+ report_line " \"switching\": [format %.${digits}e $switching],"
+ report_line " \"leakage\": [format %.${digits}e $leakage],"
+ report_line " \"total\": [format %.${digits}e $total]"
+ report_line " \}$separator"
+}
+
proc max { x y } {
if { $x >= $y } {
return $x
@@ -206,6 +257,40 @@ proc report_power_insts { insts corner digits } {
}
}
+proc report_power_insts_json { insts corner digits } {
+ set inst_pwrs {}
+ foreach inst $insts {
+ set power_result [instance_power $inst $corner]
+ lappend inst_pwrs [list $inst $power_result]
+ }
+ set inst_pwrs [lsort -command inst_pwr_cmp $inst_pwrs]
+
+ report_line "\["
+ set first 1
+ foreach inst_pwr $inst_pwrs {
+ set inst [lindex $inst_pwr 0]
+ set power [lindex $inst_pwr 1]
+ if { !$first } {
+ report_line ","
+ }
+ set first 0
+ report_power_inst_json $inst $power $digits
+ }
+ report_line "\]"
+}
+
+proc report_power_inst_json { inst power digits } {
+ lassign $power internal switching leakage total
+ set inst_name [get_full_name $inst]
+ report_line "\{"
+ report_line " \"name\": \"$inst_name\","
+ report_line " \"internal\": [format %.${digits}e $internal],"
+ report_line " \"switching\": [format %.${digits}e $switching],"
+ report_line " \"leakage\": [format %.${digits}e $leakage],"
+ report_line " \"total\": [format %.${digits}e $total]"
+ report_line "\}"
+}
+
proc inst_pwr_cmp { inst_pwr1 inst_pwr2 } {
set pwr1 [lindex $inst_pwr1 1]
set pwr2 [lindex $inst_pwr2 1]
diff --git a/power/VcdParse.cc b/power/VcdParse.cc
index e27d45b6..071fcdf7 100644
--- a/power/VcdParse.cc
+++ b/power/VcdParse.cc
@@ -24,6 +24,7 @@
#include "VcdParse.hh"
+#include
#include
#include
@@ -74,14 +75,19 @@ VcdParse::read(const char *filename,
// empty body
readStmtString();
else if (token == "$dumpall")
- parseVarValues();
+ // Ignore dumpall body.
+ readStmtTokens();
else if (token == "$dumpvars")
// Initial values.
parseVarValues();
+ else if (token[0] == '#') {
+ time_ = stoll(token.substr(1));
+ reader_->setTimeMin(time_);
+ prev_time_ = time_;
+ }
else if (token[0] == '$')
report_->fileError(800, filename_, stmt_line_, "unhandled vcd command.");
- else
- parseVarValues();
+
token = getToken();
}
gzclose(stream_);
@@ -205,18 +211,11 @@ void
VcdParse::parseVarValues()
{
string token = getToken();
- bool first_time = true;
while (!token.empty()) {
char char0 = toupper(token[0]);
if (char0 == '#' && token.size() > 1) {
VcdTime time = stoll(token.substr(1));
- if (first_time) {
- prev_time_ = time;
- first_time = false;
- reader_->setTimeMin(time);
- }
- else
- prev_time_ = time_;
+ prev_time_ = time_;
time_ = time;
if (time_ > prev_time_)
reader_->varMinDeltaTime(time_ - prev_time_);
@@ -233,27 +232,15 @@ VcdParse::parseVarValues()
reader_->varAppendValue(id, time_, char0);
}
else if (char0 == 'B') {
- char char1 = toupper(token[1]);
- if (char1 == 'X'
- || char1 == 'U'
- || char1 == 'Z') {
- string id = getToken();
- if (!reader_->varIdValid(id))
- report_->fileError(806, filename_, stmt_line_,
- "unknown variable %s", id.c_str());
- // Bus mixed 0/1/X/U not supported.
- reader_->varAppendValue(id, time_, char1);
- }
+ string bus_value = token.substr(1);
+ string id = getToken();
+ if (!reader_->varIdValid(id))
+ report_->fileError(807, filename_, stmt_line_,
+ "unknown variable %s", id.c_str());
else {
- string bin = token.substr(1);
- char *end;
- int64_t bus_value = strtol(bin.c_str(), &end, 2);
- string id = getToken();
- if (!reader_->varIdValid(id))
- report_->fileError(807, filename_, stmt_line_,
- "unknown variable %s", id.c_str());
- else
- reader_->varAppendBusValue(id, time_, bus_value);
+ // Reverse the bus value to match the bit order in the VCD file.
+ std::reverse(bus_value.begin(), bus_value.end());
+ reader_->varAppendBusValue(id, time_, bus_value);
}
}
token = getToken();
diff --git a/power/VcdParse.hh b/power/VcdParse.hh
index 94df9e1a..267aff3c 100644
--- a/power/VcdParse.hh
+++ b/power/VcdParse.hh
@@ -118,7 +118,7 @@ public:
char value) = 0;
virtual void varAppendBusValue(const std::string &id,
VcdTime time,
- int64_t bus_value) = 0;
+ const std::string &bus_value) = 0;
};
class VcdValue
diff --git a/power/VcdReader.cc b/power/VcdReader.cc
index 77059615..f208c8ad 100644
--- a/power/VcdReader.cc
+++ b/power/VcdReader.cc
@@ -153,7 +153,7 @@ public:
char value) override;
void varAppendBusValue(const string &id,
VcdTime time,
- int64_t bus_value) override;
+ const string &bus_value) override;
private:
void addVarPin(const string &pin_name,
@@ -329,14 +329,21 @@ VcdCountReader::varAppendValue(const string &id,
void
VcdCountReader::varAppendBusValue(const string &id,
VcdTime time,
- int64_t bus_value)
+ const string &bus_value)
{
const auto &itr = vcd_count_map_.find(id);
if (itr != vcd_count_map_.end()) {
VcdCounts &vcd_counts = itr->second;
for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) {
- char bit_value = ((bus_value >> bit_idx) & 0x1) ? '1' : '0';
+ char bit_value;
+ if (bus_value.size() == 1)
+ bit_value = bus_value[0];
+ else if (bit_idx < bus_value.size())
+ bit_value = bus_value[bit_idx];
+ else
+ bit_value = '0';
VcdCount &vcd_count = vcd_counts[bit_idx];
+ vcd_count.incrCounts(time, bit_value);
if (debug_->check("read_vcd", 3)) {
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c",
@@ -345,7 +352,6 @@ VcdCountReader::varAppendBusValue(const string &id,
bit_value);
}
}
- vcd_count.incrCounts(time, bit_value);
}
}
}
diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl
index d61b3ddd..112ea504 100644
--- a/sdc/Sdc.tcl
+++ b/sdc/Sdc.tcl
@@ -144,11 +144,11 @@ proc check_unit { unit key suffix key_var } {
set arg_suffix [string range $value end-[expr $suffix_length - 1] end]
if { [string match -nocase $arg_suffix $suffix] } {
set arg_prefix [string range $value 0 end-$suffix_length]
- if { [regexp "^(10*)?(\[Mkmunpf\])?$" $arg_prefix ignore mult prefix] } {
+ if { [regexp "^(10*\\\.?0*)?(\[Mkmunpf\])?$" $arg_prefix ignore mult prefix] } {
if { $mult == "" } {
set mult 1
}
- set scale [unit_prefix_scale $unit $prefix ]
+ set scale [unit_prefix_scale $unit $prefix]
check_unit_scale $unit [expr $scale * $mult]
} else {
sta_error 343 "unknown unit $unit prefix '${arg_prefix}'."
diff --git a/search/Bfs.cc b/search/Bfs.cc
index d6987508..ebea9fdb 100644
--- a/search/Bfs.cc
+++ b/search/Bfs.cc
@@ -146,7 +146,8 @@ BfsIterator::visit(Level to_level,
int visit_count = 0;
while (levelLessOrEqual(first_level_, last_level_)
&& levelLessOrEqual(first_level_, to_level)) {
- VertexSeq &level_vertices = queue_[first_level_];
+ Level level = first_level_;
+ VertexSeq &level_vertices = queue_[level];
incrLevel(first_level_);
// Note that ArrivalVisitor::enqueueRefPinInputDelays may enqueue
// vertices at this level so range iteration fails if the vector grows.
@@ -154,6 +155,7 @@ BfsIterator::visit(Level to_level,
Vertex *vertex = level_vertices.back();
level_vertices.pop_back();
if (vertex) {
+ checkLevel(vertex, level);
vertex->setBfsInQueue(bfs_index_, false);
visitor->visit(vertex);
visit_count++;
@@ -181,12 +183,14 @@ BfsIterator::visitParallel(Level to_level,
while (levelLessOrEqual(first_level_, last_level_)
&& levelLessOrEqual(first_level_, to_level)) {
VertexSeq &level_vertices = queue_[first_level_];
+ Level level = first_level_;
incrLevel(first_level_);
if (!level_vertices.empty()) {
size_t vertex_count = level_vertices.size();
if (vertex_count < thread_count) {
for (Vertex *vertex : level_vertices) {
if (vertex) {
+ checkLevel(vertex, level);
vertex->setBfsInQueue(bfs_index_, false);
visitor->visit(vertex);
}
@@ -203,6 +207,7 @@ BfsIterator::visitParallel(Level to_level,
for (size_t i = from; i < to; i++) {
Vertex *vertex = level_vertices[i];
if (vertex) {
+ checkLevel(vertex, level);
vertex->setBfsInQueue(bfs_index, false);
visitors[k]->visit(vertex);
}
@@ -259,8 +264,10 @@ BfsIterator::findNext(Level to_level)
Vertex *vertex = level_vertices.back();
if (vertex == nullptr)
level_vertices.pop_back();
- else
+ else {
+ checkLevel(vertex, first_level_);
return;
+ }
}
incrLevel(first_level_);
}
@@ -313,6 +320,17 @@ BfsIterator::checkInQueue(Vertex *vertex)
vertex->to_string(this).c_str());
}
+void
+BfsIterator::checkLevel(Vertex *vertex,
+ Level level)
+{
+ if (vertex->level() != level)
+ report_->error(2300, "vertex %s level %d != bfs level %d",
+ vertex->to_string(this).c_str(),
+ vertex->level(),
+ level);
+}
+
void
BfsIterator::deleteVertexBefore(Vertex *vertex)
{
diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc
index eb32989c..33df2af6 100644
--- a/search/ClkSkew.cc
+++ b/search/ClkSkew.cc
@@ -50,40 +50,6 @@ namespace sta {
using std::abs;
-// Source/target clock skew.
-class ClkSkew
-{
-public:
- ClkSkew();
- ClkSkew(Path *src_path,
- Path *tgt_path,
- bool include_internal_latency,
- StaState *sta);
- ClkSkew(const ClkSkew &clk_skew);
- void operator=(const ClkSkew &clk_skew);
- Path *srcPath() { return src_path_; }
- Path *tgtPath() { return tgt_path_; }
- float srcLatency(const StaState *sta);
- float tgtLatency(const StaState *sta);
- float srcInternalClkLatency(const StaState *sta);
- float tgtInternalClkLatency(const StaState *sta);
- Crpr crpr(const StaState *sta);
- float uncertainty(const StaState *sta);
- float skew() const { return skew_; }
- static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
- ClkSkew &clk_skew2,
- const StaState *sta);
-
-private:
- float clkTreeDelay(Path *clk_path,
- const StaState *sta);
-
- Path *src_path_;
- Path *tgt_path_;
- bool include_internal_latency_;
- float skew_;
-};
-
ClkSkew::ClkSkew() :
src_path_(nullptr),
tgt_path_(nullptr),
@@ -206,10 +172,18 @@ ClkSkew::srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkews::ClkSkews(StaState *sta) :
StaState(sta),
+ corner_(nullptr),
+ include_internal_latency_(true),
fanout_pred_(sta)
{
}
+void
+ClkSkews::clear()
+{
+ skews_.clear();
+}
+
void
ClkSkews::reportClkSkew(ConstClockSeq &clks,
const Corner *corner,
@@ -217,8 +191,7 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks,
bool include_internal_latency,
int digits)
{
- ClkSkewMap skews = findClkSkew(clks, corner, setup_hold,
- include_internal_latency);
+ findClkSkew(clks, corner, include_internal_latency);
// Sort the clocks to report in a stable order.
ConstClockSeq sorted_clks;
@@ -228,9 +201,9 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks,
for (const Clock *clk : sorted_clks) {
report_->reportLine("Clock %s", clk->name());
- auto skew_itr = skews.find(clk);
- if (skew_itr != skews.end())
- reportClkSkew(skew_itr->second, digits);
+ auto skew_itr = skews_.find(clk);
+ if (skew_itr != skews_.end())
+ reportClkSkew(skew_itr->second[setup_hold->index()], digits);
else
report_->reportLine("No launch/capture paths found.");
report_->reportBlankLine();
@@ -289,25 +262,30 @@ ClkSkews::findWorstClkSkew(const Corner *corner,
ConstClockSeq clks;
for (const Clock *clk : *sdc_->clocks())
clks.push_back(clk);
- ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, include_internal_latency);
+ findClkSkew(clks, corner, include_internal_latency);
float worst_skew = 0.0;
- for (const auto& [clk, clk_skew] : skews) {
- float skew = clk_skew.skew();
+ for (const auto& [clk, clk_skews] : skews_) {
+ float skew = clk_skews[setup_hold->index()].skew();
if (abs(skew) > abs(worst_skew))
worst_skew = skew;
}
return worst_skew;
}
-ClkSkewMap
+void
ClkSkews::findClkSkew(ConstClockSeq &clks,
const Corner *corner,
- const SetupHold *setup_hold,
bool include_internal_latency)
{
- ClkSkewMap skews;
+ if (corner == corner_
+ && include_internal_latency == include_internal_latency_
+ && clks == clks_
+ && !skews_.empty())
+ return;
+
+ skews_.clear();
+ clks_ = clks;
corner_ = corner;
- setup_hold_ = setup_hold;
include_internal_latency_ = include_internal_latency;
clk_set_.clear();
@@ -315,7 +293,7 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
clk_set_.insert(clk);
if (thread_count_ > 1) {
- std::vector partial_skews(thread_count_, skews);
+ std::vector partial_skews(thread_count_);
for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (hasClkPaths(src_vertex)) {
dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) {
@@ -328,14 +306,30 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
// Reduce skews from each register source.
for (size_t i = 0; i < partial_skews.size(); i++) {
for (auto& [clk, partial_skew] : partial_skews[i]) {
- auto ins = skews.insert(std::make_pair(clk, partial_skew));
- if (!ins.second) {
- ClkSkew &final_skew = ins.first->second;
- if (abs(partial_skew.skew()) > abs(final_skew.skew())
- || (fuzzyEqual(abs(partial_skew.skew()), abs(final_skew.skew()))
- // Break ties based on source/target path names.
- && ClkSkew::srcTgtPathNameLess(partial_skew, final_skew, this)))
- final_skew = partial_skew;
+ auto itr = skews_.find(clk);
+ if (itr == skews_.end()) {
+ // Insert new entry using emplace with piecewise_construct
+ // This will default-construct the array, then we copy the elements
+ auto result = skews_.emplace(std::piecewise_construct,
+ std::forward_as_tuple(clk),
+ std::make_tuple());
+ itr = result.first;
+ // Copy array elements
+ for (int setup_hold_idx : SetupHold::rangeIndex())
+ itr->second[setup_hold_idx] = partial_skew[setup_hold_idx];
+ } else {
+ // Update existing entry
+ for (int setup_hold_idx : SetupHold::rangeIndex()) {
+ ClkSkew &final_skew = itr->second[setup_hold_idx];
+ ClkSkew &partial_skew_val = partial_skew[setup_hold_idx];
+ float partial_skew1 = partial_skew_val.skew();
+ float final_skew1 = final_skew.skew();
+ if (abs(partial_skew1) > abs(final_skew1)
+ || (fuzzyEqual(abs(partial_skew1), abs(final_skew1))
+ // Break ties based on source/target path names.
+ && ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this)))
+ final_skew = partial_skew_val;
+ }
}
}
}
@@ -343,10 +337,9 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
else {
for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (hasClkPaths(src_vertex))
- findClkSkewFrom(src_vertex, skews);
+ findClkSkewFrom(src_vertex, skews_);
}
}
- return skews;
}
bool
@@ -392,11 +385,8 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
const TimingRole *role = edge->role();
- if (role->isTimingCheck()
- && ((setup_hold_ == SetupHold::max()
- && role->genericRole() == TimingRole::setup())
- || ((setup_hold_ == SetupHold::min()
- && role->genericRole() == TimingRole::hold())))) {
+ if (role->genericRole() == TimingRole::setup()
+ || role->genericRole() == TimingRole::hold()) {
Vertex *tgt_vertex = edge->from(graph_);
const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge();
const RiseFallBoth *tgt_rf = tgt_rf1
@@ -416,16 +406,15 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
ClkSkewMap &skews)
{
Unit *time_unit = units_->timeUnit();
- const SetupHold *tgt_min_max = setup_hold_->opposite();
VertexPathIterator src_iter(src_vertex, this);
while (src_iter.hasNext()) {
Path *src_path = src_iter.next();
const Clock *src_clk = src_path->clock(this);
if (src_path->isClock(this)
&& src_rf->matches(src_path->transition(this))
- && src_path->minMax(this) == setup_hold_
&& clk_set_.find(src_clk) != clk_set_.end()) {
Corner *src_corner = src_path->pathAnalysisPt(this)->corner();
+ const MinMax *tgt_min_max = src_path->minMax(this)->opposite();
if (corner_ == nullptr
|| src_corner == corner_) {
VertexPathIterator tgt_iter(tgt_vertex, this);
@@ -438,7 +427,8 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
&& tgt_path->minMax(this) == tgt_min_max
&& tgt_path->pathAnalysisPt(this)->corner() == src_corner) {
ClkSkew probe(src_path, tgt_path, include_internal_latency_, this);
- ClkSkew &clk_skew = skews[src_clk];
+ const SetupHold *setup_hold = src_path->minMax(this);
+ ClkSkew &clk_skew = skews[src_clk][setup_hold->index()];
debugPrint(debug_, "clk_skew", 2,
"%s %s %s -> %s %s %s crpr = %s skew = %s",
network_->pathName(src_path->pin(this)),
diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh
index 712e7b8b..f59d03dc 100644
--- a/search/ClkSkew.hh
+++ b/search/ClkSkew.hh
@@ -36,10 +36,43 @@
namespace sta {
-class ClkSkew;
class SearchPred;
-typedef std::map ClkSkewMap;
+// Source/target clock skew.
+class ClkSkew
+{
+public:
+ ClkSkew();
+ ClkSkew(Path *src_path,
+ Path *tgt_path,
+ bool include_internal_latency,
+ StaState *sta);
+ ClkSkew(const ClkSkew &clk_skew);
+ void operator=(const ClkSkew &clk_skew);
+ Path *srcPath() { return src_path_; }
+ Path *tgtPath() { return tgt_path_; }
+ float srcLatency(const StaState *sta);
+ float tgtLatency(const StaState *sta);
+ float srcInternalClkLatency(const StaState *sta);
+ float tgtInternalClkLatency(const StaState *sta);
+ Crpr crpr(const StaState *sta);
+ float uncertainty(const StaState *sta);
+ float skew() const { return skew_; }
+ static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
+ ClkSkew &clk_skew2,
+ const StaState *sta);
+
+private:
+ float clkTreeDelay(Path *clk_path,
+ const StaState *sta);
+
+ Path *src_path_;
+ Path *tgt_path_;
+ bool include_internal_latency_;
+ float skew_;
+};
+
+typedef std::map ClkSkewMap;
class FanOutSrchPred : public SearchPred1
{
@@ -53,6 +86,7 @@ class ClkSkews : public StaState
{
public:
ClkSkews(StaState *sta);
+ void clear();
// Report clk skews for clks.
void reportClkSkew(ConstClockSeq &clks,
const Corner *corner,
@@ -65,10 +99,9 @@ public:
bool include_internal_latency);
protected:
- ClkSkewMap findClkSkew(ConstClockSeq &clks,
- const Corner *corner,
- const SetupHold *setup_hold,
- bool include_internal_latency);
+ void findClkSkew(ConstClockSeq &clks,
+ const Corner *corner,
+ bool include_internal_latency);
bool hasClkPaths(Vertex *vertex);
void findClkSkewFrom(Vertex *src_vertex,
ClkSkewMap &skews);
@@ -88,11 +121,12 @@ protected:
void reportClkSkew(ClkSkew &clk_skew,
int digits);
+ ConstClockSeq clks_;
ConstClockSet clk_set_;
const Corner *corner_;
- const SetupHold *setup_hold_;
bool include_internal_latency_;
FanOutSrchPred fanout_pred_;
+ ClkSkewMap skews_;
};
} // namespace
diff --git a/search/PathEnd.cc b/search/PathEnd.cc
index d042ca7e..12b539d4 100644
--- a/search/PathEnd.cc
+++ b/search/PathEnd.cc
@@ -54,12 +54,6 @@ PathEnd::PathEnd(Path *path) :
{
}
-PathEnd::~PathEnd()
-{
- if (path_->isEnum())
- delete path_;
-}
-
void
PathEnd::setPath(Path *path)
{
diff --git a/search/PathEnum.cc b/search/PathEnum.cc
index 9650aff0..c3a1189a 100644
--- a/search/PathEnum.cc
+++ b/search/PathEnum.cc
@@ -97,7 +97,11 @@ DiversionGreater::operator()(Diversion *div1,
static void
deleteDiversionPathEnd(Diversion *div)
{
- delete div->pathEnd();
+ PathEnd *div_end = div->pathEnd();
+ Path *div_path = div_end->path();
+ if (div_path->isEnum())
+ delete div_path;
+ delete div_end;
delete div;
}
@@ -197,6 +201,7 @@ PathEnum::findNext()
makeDiversions(path_end, div->divPath());
// Caller owns the path end now, so don't delete it.
next_ = path_end;
+ //search_->saveEnumPath(path_end->path());
delete div;
break;
}
diff --git a/search/Search.cc b/search/Search.cc
index 736957f0..8a5f69a3 100644
--- a/search/Search.cc
+++ b/search/Search.cc
@@ -409,11 +409,22 @@ Search::deletePaths()
Vertex *vertex = vertex_iter.next();
deletePaths(vertex);
}
+
+ for (Path *path : enum_paths_)
+ delete path;
+ enum_paths_.clear();
+
filtered_arrivals_->clear();
arrivals_exist_ = false;
}
}
+void
+Search::saveEnumPath(Path *path)
+{
+ enum_paths_.push_back(path);
+}
+
// Delete with incremental tns/wns update.
void
Search::deletePathsIncr(Vertex *vertex)
@@ -2304,7 +2315,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
if (min_max == MinMax::max()
&& clk) {
bool postponed = false;
- if (search_->postpone_latch_outputs_) {
+ if (search_->postponeLatchOutputs()) {
const Path *from_clk_path = from_clk_info->crprClkPath(this);
if (from_clk_path) {
Vertex *d_clk_vertex = from_clk_path->vertex(this);
diff --git a/search/Sta.cc b/search/Sta.cc
index 99675388..eb389646 100644
--- a/search/Sta.cc
+++ b/search/Sta.cc
@@ -209,16 +209,19 @@ StaSimObserver::fanoutEdgesChangeAfter(Vertex *vertex)
class StaLevelizeObserver : public LevelizeObserver
{
public:
- StaLevelizeObserver(Search *search);
+ StaLevelizeObserver(Search *search, GraphDelayCalc *graph_delay_calc);
void levelsChangedBefore() override;
void levelChangedBefore(Vertex *vertex) override;
private:
Search *search_;
+ GraphDelayCalc *graph_delay_calc_;
};
-StaLevelizeObserver::StaLevelizeObserver(Search *search) :
- search_(search)
+StaLevelizeObserver::StaLevelizeObserver(Search *search,
+ GraphDelayCalc *graph_delay_calc) :
+ search_(search),
+ graph_delay_calc_(graph_delay_calc)
{
}
@@ -226,12 +229,14 @@ void
StaLevelizeObserver::levelsChangedBefore()
{
search_->levelsChangedBefore();
+ graph_delay_calc_->levelsChangedBefore();
}
void
StaLevelizeObserver::levelChangedBefore(Vertex *vertex)
{
search_->levelChangedBefore(vertex);
+ graph_delay_calc_->levelChangedBefore(vertex);
}
////////////////////////////////////////////////////////////////
@@ -310,6 +315,8 @@ Sta::makeComponents()
makeSdcNetwork();
makeReportPath();
makePower();
+ makeClkSkews();
+
setCmdNamespace1(CmdNamespace::sdc);
setThreadCount1(defaultThreadCount());
updateComponentsState();
@@ -324,7 +331,7 @@ Sta::makeObservers()
{
graph_delay_calc_->setObserver(new StaDelayCalcObserver(search_));
sim_->setObserver(new StaSimObserver(graph_delay_calc_, levelize_, search_));
- levelize_->setObserver(new StaLevelizeObserver(search_));
+ levelize_->setObserver(new StaLevelizeObserver(search_, graph_delay_calc_));
}
int
@@ -371,8 +378,7 @@ Sta::updateComponentsState()
if (check_timing_)
check_timing_->copyState(this);
clk_network_->copyState(this);
- if (clk_skews_)
- clk_skews_->copyState(this);
+ clk_skews_->copyState(this);
if (power_)
power_->copyState(this);
}
@@ -590,6 +596,7 @@ Sta::clear()
check_min_pulse_widths_->clear();
if (check_min_periods_)
check_min_periods_->clear();
+ clk_skews_->clear();
delete graph_;
graph_ = nullptr;
current_instance_ = nullptr;
@@ -611,6 +618,7 @@ Sta::networkChanged()
check_min_pulse_widths_->clear();
if (check_min_periods_)
check_min_periods_->clear();
+ clk_skews_->clear();
delete graph_;
graph_ = nullptr;
graph_sdc_annotated_ = false;
@@ -2481,6 +2489,7 @@ Sta::findPathEnds(ExceptionFrom *from,
bool clk_gating_hold)
{
searchPreamble();
+ clk_skews_->clear();
return search_->findPathEnds(from, thrus, to, unconstrained,
corner, min_max, group_path_count,
endpoint_path_count,
@@ -2628,8 +2637,9 @@ float
Sta::findWorstClkSkew(const SetupHold *setup_hold,
bool include_internal_latency)
{
+
clkSkewPreamble();
- return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold,
+ return clk_skews_->findWorstClkSkew(nullptr, setup_hold,
include_internal_latency);
}
@@ -2637,8 +2647,12 @@ void
Sta::clkSkewPreamble()
{
ensureClkArrivals();
- if (clk_skews_ == nullptr)
- clk_skews_ = new ClkSkews(this);
+}
+
+void
+Sta::makeClkSkews()
+{
+ clk_skews_ = new ClkSkews(this);
}
////////////////////////////////////////////////////////////////
@@ -4367,6 +4381,7 @@ Sta::replaceCellBefore(const Instance *inst,
}
}
delete pin_iter;
+ clk_skews_->clear();
}
}
@@ -4431,6 +4446,7 @@ Sta::connectPinAfter(const Pin *pin)
}
sdc_->connectPinAfter(pin);
sim_->connectPinAfter(pin);
+ clk_skews_->clear();
}
void
@@ -4521,6 +4537,7 @@ Sta::disconnectPinBefore(const Pin *pin)
}
}
}
+ clk_skews_->clear();
}
}
@@ -4671,6 +4688,7 @@ Sta::deletePinBefore(const Pin *pin)
sim_->deletePinBefore(pin);
clk_network_->deletePinBefore(pin);
power_->deletePinBefore(pin);
+ clk_skews_->clear();
}
void
diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl
index deb4c51f..a2380ace 100644
--- a/tcl/CmdUtil.tcl
+++ b/tcl/CmdUtil.tcl
@@ -122,7 +122,7 @@ define_cmd_args "report_units" {}
proc report_units { args } {
check_argc_eq0 "report_units" $args
foreach unit {"time" "capacitance" "resistance" "voltage" "current" "power" "distance"} {
- report_line " $unit 1[unit_scaled_suffix $unit]"
+ report_line " $unit [unit_scale_suffix $unit]"
}
}
@@ -130,9 +130,9 @@ proc write_units_json { jsonfile } {
set f [open $jsonfile w]
puts $f "{"
foreach unit {"time" "capacitance" "resistance" "voltage" "current" "power"} {
- puts $f " \"$unit\": \"[unit_scaled_suffix $unit]\","
+ puts $f " \"$unit\": \"[unit_scale_suffix $unit]\","
}
- puts $f " \"distance\": \"[unit_scaled_suffix distance]\""
+ puts $f " \"distance\": \"[unit_scale_suffix distance]\""
puts $f "}"
close $f
}
@@ -167,13 +167,13 @@ proc set_unit_values { unit key suffix key_var } {
set arg_suffix [string range $value end-[expr $suffix_length - 1] end]
if { [string match -nocase $arg_suffix $suffix] } {
set arg_prefix [string range $value 0 end-$suffix_length]
- if { [regexp "^(10*)?(\[Mkmunpf\])?$" $arg_prefix ignore mult prefix] } {
+ if { [regexp "^(10*\\\.?0*)?(\[Mkmunpf\])?$" $arg_prefix ignore mult prefix] } {
#puts "$arg_prefix '$mult' '$prefix'"
if { $mult == "" } {
set mult 1
}
set scale [unit_prefix_scale $unit $prefix ]
- set_cmd_unit_scale $unit $scale
+ set_cmd_unit_scale $unit [expr $scale * $mult]
} else {
sta_error 166 "unknown unit $unit prefix '${arg_prefix}'."
}
diff --git a/tcl/Exception.i b/tcl/Exception.i
index 39d73c46..0c4d788e 100644
--- a/tcl/Exception.i
+++ b/tcl/Exception.i
@@ -23,7 +23,7 @@
// This notice may not be removed or altered from any source distribution.
%exception {
- try { $function }
+ try { $action }
catch (std::bad_alloc &) {
fprintf(stderr, "Error: out of memory.\n");
exit(1);
diff --git a/tcl/Util.tcl b/tcl/Util.tcl
index 0cb2083b..ad47cdce 100644
--- a/tcl/Util.tcl
+++ b/tcl/Util.tcl
@@ -185,6 +185,17 @@ proc define_hidden_cmd_args { cmd arglist } {
namespace export $cmd
}
+# "Optional Upvar"
+# If $other_var is not empty, the upvar is executed.
+# Otherwise, $my_var is set to empty.
+proc upvar_opt { level other_var my_var } {
+ if { $other_var != "" } {
+ uplevel 1 "upvar $level $other_var $my_var"
+ } else {
+ uplevel 1 "set $my_var \"\""
+ }
+}
+
################################################################
proc sta_warn { msg_id msg } {
diff --git a/test/power_json.ok b/test/power_json.ok
new file mode 100644
index 00000000..3db9bee6
--- /dev/null
+++ b/test/power_json.ok
@@ -0,0 +1,55 @@
+{
+ "Sequential": {
+ "internal": 8.01e-06,
+ "switching": 4.99e-08,
+ "leakage": 1.45e-09,
+ "total": 8.06e-06
+ },
+ "Combinational": {
+ "internal": 2.03e-07,
+ "switching": 5.32e-08,
+ "leakage": 1.59e-10,
+ "total": 2.56e-07
+ },
+ "Clock": {
+ "internal": 0.00e+00,
+ "switching": 0.00e+00,
+ "leakage": 0.00e+00,
+ "total": 0.00e+00
+ },
+ "Macro": {
+ "internal": 0.00e+00,
+ "switching": 0.00e+00,
+ "leakage": 0.00e+00,
+ "total": 0.00e+00
+ },
+ "Pad": {
+ "internal": 0.00e+00,
+ "switching": 0.00e+00,
+ "leakage": 0.00e+00,
+ "total": 0.00e+00
+ },
+ "Total": {
+ "internal": 8.22e-06,
+ "switching": 1.03e-07,
+ "leakage": 1.61e-09,
+ "total": 8.32e-06
+ }
+}
+[
+{
+ "name": "u2",
+ "internal": 1.05e-07,
+ "switching": 2.74e-08,
+ "leakage": 9.07e-11,
+ "total": 1.32e-07
+}
+,
+{
+ "name": "u1",
+ "internal": 9.83e-08,
+ "switching": 2.58e-08,
+ "leakage": 6.82e-11,
+ "total": 1.24e-07
+}
+]
diff --git a/test/power_json.tcl b/test/power_json.tcl
new file mode 100644
index 00000000..7edf1d3c
--- /dev/null
+++ b/test/power_json.tcl
@@ -0,0 +1,8 @@
+# report_power reg1_asap7
+read_liberty asap7_small.lib.gz
+read_verilog reg1_asap7.v
+link_design top
+create_clock -name clk -period 500 {clk1 clk2 clk3}
+set_propagated_clock {clk1 clk2 clk3}
+report_power -format json
+report_power -format json -instances {u1 u2}
diff --git a/test/prima3.tcl b/test/prima3.tcl
index c04dc722..b2e20eab 100644
--- a/test/prima3.tcl
+++ b/test/prima3.tcl
@@ -1,7 +1,5 @@
# prima reg1 asap7
-read_liberty asap7_invbuf.lib.gz
-read_liberty asap7_seq.lib.gz
-read_liberty asap7_simple.lib.gz
+read_liberty asap7_small.lib.gz
read_verilog reg1_asap7.v
link_design top
create_clock -name clk -period 500 {clk1 clk2 clk3}
diff --git a/test/regression b/test/regression
index 2688454a..a64ac704 100755
--- a/test/regression
+++ b/test/regression
@@ -31,6 +31,7 @@ exec tclsh $0 ${1+"$@"}
# Directory containing tests.
set test_dir [file dirname [file normalize [info script]]]
+set sta_dir [file normalize [file join $test_dir ".."]]
source [file join $test_dir regression_vars.tcl]
source [file join $test_dir regression.tcl]
diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl
index f3eb42e9..acf6906b 100644
--- a/test/regression_vars.tcl
+++ b/test/regression_vars.tcl
@@ -34,7 +34,6 @@
# Application program to run tests on.
set app "sta"
-set sta_dir [file dirname $test_dir]
set app_path [file join $sta_dir "build" $app]
# Application options.
set app_options "-no_init -no_splash -exit"
@@ -52,7 +51,7 @@ if [info exists env(DIFF_OPTIONS)] {
}
set valgrind_suppress [file join $test_dir valgrind.suppress]
-set valgrind_options "--num-callers=20 --leak-check=full --freelist-vol=100000000 --leak-resolution=high --suppressions=$valgrind_suppress"
+set valgrind_options "--num-callers=20 --leak-check=full --show-leak-kinds=all --leak-resolution=high --suppressions=$valgrind_suppress"
if { [exec "uname"] == "Darwin" } {
append valgrind_options " --dsymutil=yes"
}
@@ -71,31 +70,6 @@ proc record_test { test cmd_dir } {
return $test
}
-# Record tests in the $STA/test directory.
-proc record_sta_tests { tests } {
- global test_dir
- foreach test $tests {
- # Prune commented tests from the list.
- if { [string index $test 0] != "#" } {
- record_test $test $test_dir
- }
- }
-}
-
-# Record tests in the $STA/examples directory.
-proc record_example_tests { tests } {
- global test_dir test_groups
- set example_dir [file join $test_dir ".." "examples"]
- foreach test $tests {
- # Prune commented tests from the list.
- if { [string index $test 0] != "#" } {
- record_test $test $example_dir
- }
- }
-}
-
-################################################################
-
proc define_test_group { name tests } {
global test_groups
set test_groups($name) $tests
@@ -124,6 +98,38 @@ proc list_delete { list delete } {
################################################################
+# Record tests in $STA/test.
+proc record_public_tests { tests } {
+ global sta_dir cmd_dirs test_groups test_dir
+ set public_dir [file join $sta_dir "test"]
+ foreach test $tests {
+ if { [string index $test 0] != "#" } {
+ record_test $test $public_dir
+ # sync pvt/test okfiles to sta/test
+ set public_ok [file join $public_dir $test.ok]
+ if { [file exists $public_ok] } {
+ file copy -force $public_ok [file join $test_dir $test.ok]
+ }
+ }
+ }
+ define_test_group public $tests
+}
+
+# Record tests in the $STA/examples directory.
+proc record_example_tests { tests } {
+ global test_dir test_groups
+ set example_dir [file join $test_dir ".." "examples"]
+ foreach test $tests {
+ # Prune commented tests from the list.
+ if { [string index $test 0] != "#" } {
+ record_test $test $example_dir
+ }
+ }
+ define_test_group examples $tests
+}
+
+################################################################
+
# Regression test lists.
# Record tests in sta/examples
@@ -137,7 +143,7 @@ record_example_tests {
spef_parasitics
}
-record_sta_tests {
+record_public_tests {
disconnect_mcp_pin
get_filter
get_is_buffer
@@ -153,6 +159,7 @@ record_sta_tests {
liberty_latch3
package_require
path_group_names
+ power_json
prima3
report_checks_sorted
report_checks_src_attr
diff --git a/test/save_ok b/test/save_ok
index 7eb25bc3..584d31b5 100755
--- a/test/save_ok
+++ b/test/save_ok
@@ -28,6 +28,7 @@ exec tclsh $0 ${1+"$@"}
# Directory containing tests.
set test_dir [file dirname [info script]]
+set sta_dir [file normalize [file join $test_dir ".."]]
source [file join $test_dir regression_vars.tcl]
source [file join $test_dir regression.tcl]
diff --git a/util/DispatchQueue.cc b/util/DispatchQueue.cc
index c5f85e62..4e828c23 100644
--- a/util/DispatchQueue.cc
+++ b/util/DispatchQueue.cc
@@ -49,6 +49,12 @@ DispatchQueue::setThreadCount(size_t thread_count)
}
}
+size_t
+DispatchQueue::getThreadCount() const
+{
+ return threads_.size();
+}
+
void
DispatchQueue::finishTasks()
{
diff --git a/util/Util.i b/util/Util.i
index 674a40e0..6c7ec10f 100644
--- a/util/Util.i
+++ b/util/Util.i
@@ -23,6 +23,7 @@
// This notice may not be removed or altered from any source distribution.
%module util
+%include
%{
@@ -415,7 +416,7 @@ set_cmd_unit_suffix(const char *unit_name,
}
}
-const char *
+std::string
unit_scale_abbreviation (const char *unit_name)
{
Unit *unit = Sta::sta()->units()->find(unit_name);
@@ -425,7 +426,7 @@ unit_scale_abbreviation (const char *unit_name)
return "";
}
-const char *
+std::string
unit_suffix(const char *unit_name)
{
Unit *unit = Sta::sta()->units()->find(unit_name);
@@ -435,12 +436,23 @@ unit_suffix(const char *unit_name)
return "";
}
-const char *
-unit_scaled_suffix(const char *unit_name)
+std::string
+unit_scale_suffix(const char *unit_name)
+{
+ Unit *unit = Sta::sta()->units()->find(unit_name);
+ if (unit) {
+ return unit->scaleSuffix();
+ }
+ else
+ return "";
+}
+
+std::string
+unit_scale_abbrev_suffix(const char *unit_name)
{
Unit *unit = Sta::sta()->units()->find(unit_name);
if (unit)
- return unit->scaledSuffix();
+ return unit->scaleAbbrevSuffix();
else
return "";
}
diff --git a/verilog/Verilog.i b/verilog/Verilog.i
index 63561423..5e1744ef 100644
--- a/verilog/Verilog.i
+++ b/verilog/Verilog.i
@@ -39,14 +39,13 @@ read_verilog_cmd(const char *filename)
void
write_verilog_cmd(const char *filename,
- bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells)
{
// This does NOT want the SDC (cmd) network because it wants
// to see the sta internal names.
Network *network = Sta::sta()->network();
- writeVerilog(filename, sort, include_pwr_gnd, remove_cells, network);
+ writeVerilog(filename, include_pwr_gnd, remove_cells, network);
delete remove_cells;
}
diff --git a/verilog/Verilog.tcl b/verilog/Verilog.tcl
index bf024119..f4a459f5 100644
--- a/verilog/Verilog.tcl
+++ b/verilog/Verilog.tcl
@@ -31,22 +31,25 @@ proc_redirect read_verilog {
read_verilog_cmd [file nativename [lindex $args 0]]
}
-define_cmd_args "write_verilog" {[-sort] [-include_pwr_gnd]\
+define_cmd_args "write_verilog" {[-include_pwr_gnd]\
[-remove_cells cells] filename}
proc write_verilog { args } {
+ # -sort deprecated 12/12/2025
parse_key_args "write_verilog" args keys {-remove_cells} \
flags {-sort -include_pwr_gnd}
+ if { [info exists flags(-sort)] } {
+ sta_warn 1338 "The -sort flag is ignored."
+ }
set remove_cells {}
if { [info exists keys(-remove_cells)] } {
set remove_cells [parse_cell_arg $keys(-remove_cells)]
}
- set sort [info exists flags(-sort)]
set include_pwr_gnd [info exists flags(-include_pwr_gnd)]
check_argc_eq1 "write_verilog" $args
set filename [file nativename [lindex $args 0]]
- write_verilog_cmd $filename $sort $include_pwr_gnd $remove_cells
+ write_verilog_cmd $filename $include_pwr_gnd $remove_cells
}
# sta namespace end
diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc
index 52c9d548..dd856d7b 100644
--- a/verilog/VerilogWriter.cc
+++ b/verilog/VerilogWriter.cc
@@ -45,7 +45,6 @@ class VerilogWriter
{
public:
VerilogWriter(const char *filename,
- bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells,
FILE *stream,
@@ -81,7 +80,6 @@ protected:
const Port *port);
const char *filename_;
- bool sort_;
bool include_pwr_gnd_;
CellSet remove_cells_;
FILE *stream_;
@@ -91,7 +89,6 @@ protected:
void
writeVerilog(const char *filename,
- bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells,
Network *network)
@@ -99,7 +96,7 @@ writeVerilog(const char *filename,
if (network->topInstance()) {
FILE *stream = fopen(filename, "w");
if (stream) {
- VerilogWriter writer(filename, sort, include_pwr_gnd,
+ VerilogWriter writer(filename, include_pwr_gnd,
remove_cells, stream, network);
writer.writeModules();
fclose(stream);
@@ -110,13 +107,11 @@ writeVerilog(const char *filename,
}
VerilogWriter::VerilogWriter(const char *filename,
- bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells,
FILE *stream,
Network *network) :
filename_(filename),
- sort_(sort),
include_pwr_gnd_(include_pwr_gnd),
remove_cells_(network),
stream_(stream),
@@ -146,13 +141,12 @@ VerilogWriter::findHierChildren()
CellSet cells(network_);
findHierChildren(network_->topInstance(), children, cells);
- if (sort_)
- sort(children, [this](const Instance *inst1,
- const Instance *inst2) {
- const char *cell_name1 = network_->cellName(inst1);
- const char *cell_name2 = network_->cellName(inst2);
- return stringLess(cell_name1, cell_name2);
- });
+ sort(children, [this](const Instance *inst1,
+ const Instance *inst2) {
+ const char *cell_name1 = network_->cellName(inst1);
+ const char *cell_name2 = network_->cellName(inst2);
+ return stringLess(cell_name1, cell_name2);
+ });
return children;
}
@@ -327,11 +321,10 @@ VerilogWriter::writeChildren(const Instance *inst)
}
delete child_iter;
- if (sort_)
- sort(children, [this](const Instance *inst1,
- const Instance *inst2) {
- return stringLess(network_->name(inst1), network_->name(inst2));
- });
+ sort(children, [this](const Instance *inst1,
+ const Instance *inst2) {
+ return stringLess(network_->name(inst1), network_->name(inst2));
+ });
for (auto child : children)
writeChild(child);