Merge remote-tracking branch 'parallax/master'

This commit is contained in:
Matt Liberty 2026-01-09 18:28:40 +00:00
commit 4966240d28
47 changed files with 571 additions and 258 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)
{

View File

@ -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/??
-------------------------

View File

@ -13772,18 +13772,9 @@
<text:p text:style-name="P29"><text:alphabetical-index-mark-start text:id="IMark53760024032"/><text:span text:style-name="Command_20_Heading">write_verilog</text:span><text:alphabetical-index-mark-end text:id="IMark53760024032"/></text:p>
</table:table-cell>
<table:table-cell table:style-name="Table109.A1" office:value-type="string">
<text:p text:style-name="P264">[-sort<text:span text:style-name="T22">]</text:span></text:p>
<text:p text:style-name="P264"><text:span text:style-name="T22">[-include_pwr_gnd]</text:span><text:line-break/>[-remove_cells <text:span text:style-name="T1">lib_cells</text:span><text:span text:style-name="T22">]</text:span><text:line-break/><text:span text:style-name="T1">filename</text:span></text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name="Table109.1">
<table:table-cell table:style-name="Table109.A2" office:value-type="string">
<text:p text:style-name="P265"><text:span text:style-name="Command_20_Argument"><text:span text:style-name="T317">-sort</text:span></text:span></text:p>
</table:table-cell>
<table:table-cell table:style-name="Table109.A2" office:value-type="string">
<text:p text:style-name="P29"><text:span text:style-name="Default_20_Paragraph_20_Font">Sort the instances in the netlist.</text:span></text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name="Table109.1">
<table:table-cell table:style-name="Table109.A2" office:value-type="string">
<text:p text:style-name="P288">-include_pwr_gnd</text:p>
@ -13809,7 +13800,7 @@
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P290">The <text:span text:style-name="T7">write_verilog</text:span> command writes a Verilog netlist to <text:span text:style-name="T3">filename</text:span>. Use <text:span text:style-name="T317">-sort</text:span> to sort the instances so the results are reproducible across operating systems. Use <text:span text:style-name="T7">-remove_cells</text:span> to remove instances of <text:span text:style-name="T3">lib_cells</text:span> from the netlist.</text:p>
<text:p text:style-name="P290">The <text:span text:style-name="T7">write_verilog</text:span> command writes a Verilog netlist to <text:span text:style-name="T3">filename</text:span>. Instances are always sorted so the results are reproducible across operating systems. Use <text:span text:style-name="T7">-remove_cells</text:span> to remove instances of <text:span text:style-name="T3">lib_cells</text:span> from the netlist.</text:p>
<text:h text:style-name="Heading_20_1" text:outline-level="1"><text:bookmark-start text:name="__RefHeading___Toc42589_2528141652"/><text:alphabetical-index-mark-start text:id="IMark53760024032"/>Filter Expressions<text:bookmark-end text:name="__RefHeading___Toc42589_2528141652"/><text:alphabetical-index-mark-end text:id="IMark53760024032"/></text:h>
<text:p text:style-name="P291">The <text:span text:style-name="Example">get_cells</text:span>, <text:span text:style-name="Example">get_pins</text:span>, <text:span text:style-name="Example">get_ports</text:span> and <text:span text:style-name="Example">get_timing_edges</text:span> functions support filtering the returned objects by property values. Supported filter expressions are shown below.</text:p>
<table:table table:name="Table66" table:style-name="Table66">

View File

@ -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_;

View File

@ -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.

View File

@ -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.

View File

@ -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:

View File

@ -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_; }

View File

@ -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<Path*> enum_paths_;
GatedClk *gated_clk_;
CheckCrpr *check_crpr_;
Genclks *genclks_;

View File

@ -1365,6 +1365,7 @@ protected:
virtual void makeCheckMaxSkews();
virtual void makeReportPath();
virtual void makePower();
virtual void makeClkSkews();
virtual void makeObservers();
NetworkEdit *networkCmdEdit();

View File

@ -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)
};

View File

@ -30,7 +30,6 @@ namespace sta {
void
writeVerilog(const char *filename,
bool sort,
bool include_pwr_gnd,
CellSeq *remove_cells,
Network *network);

View File

@ -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");

View File

@ -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

View File

@ -1286,7 +1286,6 @@ ConcreteNetwork::replaceCell(Instance *inst,
if (cport) {
rpins[cport->pinIndex()] = cpin;
cpin->port_ = cport;
cpin->id_ = ConcreteNetwork::nextObjectId();
}
}
}

View File

@ -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)
{

View File

@ -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,

View File

@ -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);
}
}

View File

@ -238,7 +238,7 @@ private:
PwrSeqActivityMap seq_activity_map_;
bool activities_valid_;
Bdd bdd_;
std::map<const Instance*, PowerResult> instance_powers_;
std::map<const Instance*, PowerResult, InstanceIdLess> instance_powers_;
bool instance_powers_valid_;
const Corner *corner_;

View File

@ -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]

View File

@ -24,6 +24,7 @@
#include "VcdParse.hh"
#include <algorithm>
#include <cctype>
#include <cinttypes>
@ -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();

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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}'."

View File

@ -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)
{

View File

@ -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<ClkSkewMap> partial_skews(thread_count_, skews);
std::vector<ClkSkewMap> 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)),

View File

@ -36,10 +36,43 @@
namespace sta {
class ClkSkew;
class SearchPred;
typedef std::map<const Clock*, ClkSkew> 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<const Clock*, ClkSkew[SetupHold::index_count]> 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

View File

@ -54,12 +54,6 @@ PathEnd::PathEnd(Path *path) :
{
}
PathEnd::~PathEnd()
{
if (path_->isEnum())
delete path_;
}
void
PathEnd::setPath(Path *path)
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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}'."
}

View File

@ -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);

View File

@ -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 } {

55
test/power_json.ok Normal file
View File

@ -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
}
]

8
test/power_json.tcl Normal file
View File

@ -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}

View File

@ -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}

View File

@ -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]

View File

@ -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

View File

@ -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]

View File

@ -49,6 +49,12 @@ DispatchQueue::setThreadCount(size_t thread_count)
}
}
size_t
DispatchQueue::getThreadCount() const
{
return threads_.size();
}
void
DispatchQueue::finishTasks()
{

View File

@ -23,6 +23,7 @@
// This notice may not be removed or altered from any source distribution.
%module util
%include <std_string.i>
%{
@ -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 "";
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);