Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2024-10-24 06:21:47 +00:00
commit 9afc487f07
49 changed files with 402 additions and 573205 deletions

View File

@ -19,13 +19,12 @@ RUN wget https://raw.githubusercontent.com/davidkebo/cudd/main/cudd_versions/cud
tar -xvf cudd-3.0.0.tar.gz && \
rm cudd-3.0.0.tar.gz
# Install CUDD
# Build CUDD
RUN source /opt/rh/devtoolset-8/enable && \
cd cudd-3.0.0 && \
mkdir ../cudd && \
./configure && \
make -j`nproc` && \
make install
make -j`nproc`
FROM base-dependencies AS builder
@ -34,7 +33,10 @@ WORKDIR /OpenSTA
# Build
RUN rm -rf build && mkdir build
RUN source /opt/rh/devtoolset-8/enable && cd build && cmake3 .. && make -j`nproc`
RUN source /opt/rh/devtoolset-8/enable && \
cd build && \
cmake3 -DCUDD_DIR=../cudd-3.0.0 .. && \
make -j`nproc`
# Run sta on entry
ENTRYPOINT ["OpenSTA/app/sta"]

View File

@ -1,23 +1,33 @@
FROM ubuntu:18.04
FROM ubuntu:22.04
LABEL author="James Cherry"
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
# Install basics
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y wget cmake gcc tcl-dev tcl-tclreadline libeigen3-dev swig bison flex
apt-get install -y \
wget \
cmake \
gcc \
tcl-dev \
tcl-tclreadline \
libeigen3-dev \
swig \
bison \
flex \
automake \
autotools-dev
# Download CUDD
RUN wget https://raw.githubusercontent.com/davidkebo/cudd/main/cudd_versions/cudd-3.0.0.tar.gz && \
tar -xvf cudd-3.0.0.tar.gz && \
rm cudd-3.0.0.tar.gz
# Install CUDD
# Build CUDD
RUN cd cudd-3.0.0 && \
mkdir ../cudd && \
./configure && \
make -j`nproc` && \
make install
make -j`nproc`
# Copy files and install OpenSTA
RUN mkdir OpenSTA
@ -26,7 +36,7 @@ RUN cd OpenSTA && \
rm -rf build && \
mkdir build && \
cd build && \
cmake .. && \
cmake -DCUDD_DIR=../cudd-3.0.0 .. && \
make -j`nproc`
# Run sta on entry

View File

@ -11,6 +11,8 @@ standard file formats.
* SDC timing constraints
* SDF delay annotation
* SPEF parasitics
* VCD power acitivies
* SAIF power acitivies
OpenSTA uses a TCL command interpreter to read the design, specify
timing constraints and print timing reports.
@ -51,8 +53,8 @@ netlist data structures without duplicating them.
* Simulator to propagate constants from constraints and netlist tie high/low
See doc/OpenSTA.pdf for command documentation.
See doc/StaApi.txt for timing engine API documentation.
See doc/ChangeLog.txt for changes to commands.
See doc/StaApi.txt for timing engine API documentation.
OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
is also licensed for commerical applications by Parallax Software without

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
# delay calc example
read_liberty nangate45_slow.lib
read_liberty nangate45_slow.lib.gz
read_verilog example1.v
link_design top
create_clock -name clk -period 10 {clk1 clk2 clk3}

View File

@ -1,6 +1,6 @@
# min/max delay calc example
read_liberty -max nangate45_slow.lib
read_liberty -min nangate45_fast.lib
read_liberty -max nangate45_slow.lib.gz
read_liberty -min nangate45_fast.lib.gz
read_verilog example1.v
link_design top
create_clock -name clk -period 10 {clk1 clk2 clk3}

View File

@ -1,8 +1,8 @@
# 3 corners with +/- 10% derating example
define_corners ss tt ff
read_liberty -corner ss nangate45_slow.lib
read_liberty -corner tt nangate45_typ.lib
read_liberty -corner ff nangate45_fast.lib
read_liberty -corner ss nangate45_slow.lib.gz
read_liberty -corner tt nangate45_typ.lib.gz
read_liberty -corner ff nangate45_fast.lib.gz
read_verilog example1.v
link_design top
set_timing_derate -early 0.9

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,5 +1,5 @@
# report_power gcd
read_liberty sky130hd_tt.lib
read_liberty sky130hd_tt.lib.gz
read_verilog gcd_sky130hd.v
link_design gcd

View File

@ -1,5 +1,5 @@
# read_vcd_activities gcd
read_liberty sky130hd_tt.lib
read_liberty sky130hd_tt.lib.gz
read_verilog gcd_sky130hd.v
link_design gcd

View File

@ -1,5 +1,5 @@
# sdf example
read_liberty nangate45_slow.lib
read_liberty nangate45_slow.lib.gz
read_verilog example1.v
link_design top
read_sdf example1.sdf

File diff suppressed because it is too large Load Diff

BIN
examples/sky130hd_tt.lib.gz Normal file

Binary file not shown.

View File

@ -1,5 +1,5 @@
# delay calc with spef parasitics
read_liberty nangate45_slow.lib
read_liberty nangate45_slow.lib.gz
read_verilog example1.v
link_design top
read_spef example1.dspef

View File

@ -660,12 +660,48 @@ Graph::prevPaths(Vertex *vertex) const
return prev_paths_.pointer(vertex->prevPaths());
}
void
Graph::deletePrevPaths(Vertex *vertex,
uint32_t count)
{
if (vertex->prevPaths() != object_id_null) {
{
LockGuard lock(prev_paths_lock_);
prev_paths_.destroy(vertex->prevPaths(), count);
}
vertex->setPrevPaths(object_id_null);
}
}
void
Graph::clearPrevPaths()
{
prev_paths_.clear();
}
// No locks.
void
Graph::deletePaths(Vertex *vertex,
uint32_t count)
{
if (vertex->arrivals() != arrival_null) {
arrivals_.destroy(vertex->arrivals(), count);
vertex->setArrivals(arrival_null);
}
if (vertex->requireds() != arrival_null) {
requireds_.destroy(vertex->requireds(), count);
vertex->setRequireds(arrival_null);
}
if (vertex->prevPaths() != object_id_null) {
prev_paths_.destroy(vertex->prevPaths(), count);
vertex->setPrevPaths(object_id_null);
}
vertex->tag_group_index_ = tag_group_index_max;
vertex->crpr_path_pruning_disabled_ = false;
}
////////////////////////////////////////////////////////////////
const Slew &
@ -1245,16 +1281,6 @@ Vertex::setPrevPaths(PrevPathId prev_paths)
prev_paths_ = prev_paths;
}
void
Vertex::deletePaths()
{
arrivals_ = arrival_null;
requireds_ = arrival_null;
prev_paths_ = prev_path_null;
tag_group_index_ = tag_group_index_max;
crpr_path_pruning_disabled_ = false;
}
LogicValue
Vertex::simValue() const
{

View File

@ -113,7 +113,13 @@ public:
PathVertexRep *makePrevPaths(Vertex *vertex,
uint32_t count);
PathVertexRep *prevPaths(Vertex *vertex) const;
void deletePrevPaths(Vertex *vertex,
uint32_t count);
void clearPrevPaths();
// Private to Search::deletePaths1(Vertex).
void deletePaths(Vertex *vertex,
uint32_t count);
// Reported slew are the same as those in the liberty tables.
// reported_slews = measured_slews / slew_derate_from_library
// Measured slews are between slew_lower_threshold and slew_upper_threshold.
@ -333,8 +339,6 @@ public:
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
void setObjectIdx(ObjectIdx idx);
// private to Search.cc
void deletePaths();
static int transitionCount() { return 2; } // rise/fall

View File

@ -543,6 +543,8 @@ public:
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
const char *footprint() const;
void setFootprint(const char *footprint);
const char *userFunctionClass() const;
void setUserFunctionClass(const char *user_function_class);
protected:
void addPort(ConcretePort *port);
@ -634,6 +636,7 @@ protected:
bool have_voltage_waveforms_;
std::mutex waveform_lock_;
const char *footprint_;
const char *user_function_class_;
private:
friend class LibertyLibrary;

View File

@ -498,6 +498,8 @@ protected:
const PathAnalysisPt *path_ap);
void deletePaths();
void deletePaths(Vertex *vertex);
// Delete with incremental tns/wns update.
void deletePathsIncr(Vertex *vertex);
TagGroup *findTagGroup(TagGroupBldr *group_bldr);
void deleteFilterTags();
void deleteFilterTagGroups();
@ -686,6 +688,7 @@ protected:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
@ -718,7 +721,8 @@ public:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Edge *edge,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
Vertex *to_vertex,
@ -787,6 +791,7 @@ protected:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,

View File

@ -892,7 +892,8 @@ public:
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout);
bool report_fanout,
bool report_src_attr);
ReportField *findReportPathField(const char *name);
void setReportPathDigits(int digits);
void setReportPathNoSplit(bool no_split);

View File

@ -941,7 +941,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
leakage_power_exists_(false),
has_internal_ports_(false),
have_voltage_waveforms_(false),
footprint_(nullptr)
footprint_(nullptr),
user_function_class_(nullptr)
{
liberty_cell_ = this;
}
@ -971,6 +972,7 @@ LibertyCell::~LibertyCell()
pg_port_map_.deleteContents();
stringDelete(footprint_);
stringDelete(user_function_class_);
}
LibertyPort *
@ -2004,6 +2006,18 @@ LibertyCell::footprint() const
return footprint_;
}
void
LibertyCell::setUserFunctionClass(const char *user_function_class)
{
user_function_class_ = stringCopy(user_function_class);
}
const char*
LibertyCell::userFunctionClass() const
{
return user_function_class_;
}
////////////////////////////////////////////////////////////////
LibertyCellPortIterator::LibertyCellPortIterator(const LibertyCell *cell) :

View File

@ -311,6 +311,8 @@ LibertyReader::defineVisitors()
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
defineAttrVisitor("cell_footprint", &LibertyReader::visitCellFootprint);
defineAttrVisitor("user_function_class",
&LibertyReader::visitCellUserFunctionClass);
// Pins
defineGroupVisitor("pin", &LibertyReader::beginPin,&LibertyReader::endPin);
@ -2159,6 +2161,7 @@ LibertyReader::makeStatetable()
internal_ports.push_back(port);
}
cell_->makeStatetable(input_ports, internal_ports, statetable_->table());
delete statetable_;
statetable_ = nullptr;
}
}
@ -3076,6 +3079,16 @@ LibertyReader::visitCellFootprint(LibertyAttr *attr)
}
}
void
LibertyReader::visitCellUserFunctionClass(LibertyAttr *attr)
{
if (cell_) {
const char *user_function_class = getAttrString(attr);
if (user_function_class)
cell_->setUserFunctionClass(user_function_class);
}
}
////////////////////////////////////////////////////////////////
void

View File

@ -206,6 +206,7 @@ public:
virtual void visitScalingFactors(LibertyAttr *attr);
virtual void visitCellLeakagePower(LibertyAttr *attr);
virtual void visitCellFootprint(LibertyAttr *attr);
virtual void visitCellUserFunctionClass(LibertyAttr *attr);
virtual void beginPin(LibertyGroup *group);
virtual void endPin(LibertyGroup *group);

View File

@ -289,6 +289,13 @@ LibertyWriter::writeCell(const LibertyCell *cell)
fprintf(stream_, " is_macro_cell : true;\n");
if (cell->interfaceTiming())
fprintf(stream_, " interface_timing : true;\n");
const char *footprint = cell->footprint();
if (footprint)
fprintf(stream_, " cell_footprint : \"%s\";\n", footprint);
const char *user_function_class = cell->userFunctionClass();
if (user_function_class)
fprintf(stream_, " user_function_class : \"%s\";\n",
user_function_class);
LibertyCellPortIterator port_iter(cell);
while (port_iter.hasNext()) {

View File

@ -175,15 +175,15 @@ SaifReader::setNetDurations(const char *net_name,
if (in_scope_level_ > 0) {
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
if (parent) {
const char *net_name1 = unescaped(net_name);
const Pin *pin = sdc_network_->findPin(parent, net_name1);
string unescaped_name = unescaped(net_name);
const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str());
if (pin) {
double t1 = durations[static_cast<int>(SaifState::T1)];
float duty = t1 / duration_;
double tc = durations[static_cast<int>(SaifState::TC)];
float activity = tc / (duration_ * timescale_ / clk_period_);
debugPrint(debug_, "read_saif", 2,
"%s duty %.0f / %" PRId64 " = %.2f tc %.0f activity %.2f",
"%s duty %.0f / %" PRIu64 " = %.2f tc %.0f activity %.2f",
sdc_network_->pathName(pin),
t1,
duration_,
@ -195,28 +195,22 @@ SaifReader::setNetDurations(const char *net_name,
}
}
}
stringDelete(net_name);
}
const char *
string
SaifReader::unescaped(const char *token)
{
char *unescaped = new char[strlen(token) + 1];
char *u = unescaped;
size_t token_length = strlen(token);
for (size_t i = 0; i < token_length; i++) {
char ch = token[i];
if (ch == escape_) {
char next_ch = token[i + 1];
*u++ = next_ch;
i++;
}
string unescaped;
for (const char *t = token; *t; t++) {
char ch = *t;
if (ch == escape_)
unescaped += *(t+1);
else
// Just the normal noises.
*u++ = ch;
unescaped += ch;
}
*u = '\0';
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped);
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped.c_str());
return unescaped;
}

View File

@ -21,6 +21,7 @@
#include <vector>
#include <string>
#include <set>
#include <array>
#include "Zlib.hh"
#include "NetworkClass.hh"
@ -84,7 +85,7 @@ public:
void notSupported(const char *feature);
private:
const char *unescaped(const char *token);
string unescaped(const char *token);
const char *filename_;
const char *scope_; // Divider delimited scope to begin annotation.

View File

@ -1812,6 +1812,9 @@ PathEndPathDelay::findSrcClkArrival(const StaState *sta)
Search *search = sta->search();
src_clk_arrival_ = search->pathClkPathArrival(&path_);
}
else
src_clk_arrival_ = 0.0;
}
void
@ -1941,11 +1944,10 @@ Required
PathEndPathDelay::requiredTime(const StaState *sta) const
{
float delay = path_delay_->delay();
if (ignoreClkLatency(sta)) {
if (minMax(sta) == MinMax::max())
return src_clk_arrival_ + delay - margin(sta);
else
return src_clk_arrival_ + delay + margin(sta);
if (path_delay_->ignoreClkLatency()) {
float src_offset = path_.isClock(sta) ? path_.clkEdge(sta)->time() : src_clk_arrival_;
return src_offset + delay
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
}
else {
Arrival tgt_clk_arrival = targetClkArrival(sta);

View File

@ -237,6 +237,7 @@ public:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
@ -315,6 +316,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
const RiseFall *,
Tag *,
PathVertex *from_path,
const Arrival &,
Edge *edge,
TimingArc *arc,
ArcDelay,

View File

@ -328,6 +328,7 @@ public:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
@ -380,6 +381,7 @@ PrevPathVisitor::visitFromToPath(const Pin *,
const RiseFall *,
Tag *from_tag,
PathVertex *from_path,
const Arrival &,
Edge *,
TimingArc *arc,
ArcDelay,

View File

@ -122,7 +122,7 @@ ReportPath::ReportPath(StaState *sta) :
{
setDigits(2);
makeFields();
setReportFields(false, false, false, false, false);
setReportFields(false, false, false, false, false, false);
}
ReportPath::~ReportPath()
@ -133,6 +133,7 @@ ReportPath::~ReportPath()
delete field_capacitance_;
delete field_slew_;
delete field_fanout_;
delete field_src_attr_;
delete field_edge_;
delete field_case_;
@ -156,6 +157,8 @@ ReportPath::makeFields()
field_case_ = makeField("case", "case", 11, false, nullptr, false);
field_description_ = makeField("description", "Description", 36,
true, nullptr, true);
field_src_attr_ = makeField("src_attr", "Src Attr", 40,
true, nullptr, true);
}
ReportField *
@ -225,15 +228,16 @@ ReportPath::setReportFields(bool report_input_pin,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout)
bool report_fanout,
bool report_src_attr)
{
report_input_pin_ = report_input_pin;
report_net_ = report_net;
field_fanout_->setEnabled(report_net_);
field_capacitance_->setEnabled(report_cap);
field_slew_->setEnabled(report_slew);
field_fanout_->setEnabled(report_fanout);
field_src_attr_->setEnabled(report_src_attr);
// for debug
field_case_->setEnabled(false);
}
@ -713,7 +717,7 @@ ReportPath::reportFull(const PathEndPathDelay *end)
const Path *tgt_clk_path = end->targetClkPath();
if (reportClkPath()
&& isPropagated(tgt_clk_path, tgt_clk))
reportTgtClk(end, delay);
reportTgtClk(end, delay, 0.0, true);
else {
Arrival tgt_clk_delay = end->targetClkDelay(this);
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
@ -2130,6 +2134,15 @@ ReportPath::reportTgtClk(const PathEnd *end,
bool is_prop)
{
float src_offset = end->sourceClkOffset(this);
reportTgtClk(end, prev_time, src_offset, is_prop);
}
void
ReportPath::reportTgtClk(const PathEnd *end,
float prev_time,
float src_offset,
bool is_prop)
{
const ClockEdge *clk_edge = end->targetClkEdge(this);
Clock *clk = clk_edge->clock();
const RiseFall *clk_rf = clk_edge->transition();
@ -2395,11 +2408,16 @@ ReportPath::reportPathLine(const Path *path,
DcalcAPIndex ap_index = dcalc_ap->index();
Slew slew = graph_->slew(vertex, rf, ap_index);
float cap = field_blank_;
Instance *inst = network_->instance(pin);
string src_attr = "";
if (inst)
src_attr = network_->getAttribute(inst, "src");
// Don't show capacitance field for input pins.
if (is_driver && field_capacitance_->enabled())
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
reportLine(what.c_str(), cap, slew, field_blank_,
incr, time, false, early_late, rf, line_case);
incr, time, false, early_late, rf, src_attr,
line_case);
}
void
@ -2655,6 +2673,10 @@ ReportPath::reportPath5(const Path *path,
const char *line_case = nullptr;
bool is_clk_start = path1->vertex(this) == clk_start;
bool is_clk = path1->isClock(search_);
Instance *inst = network_->instance(pin);
string src_attr = "";
if (inst)
src_attr = network_->getAttribute(inst, "src");
// Always show the search start point (register clk pin).
// Skip reporting the clk tree unless it is requested.
if (is_clk_start
@ -2750,7 +2772,8 @@ ReportPath::reportPath5(const Path *path,
auto what = descriptionField(vertex);
if (report_net_ && is_driver) {
reportLine(what.c_str(), cap, slew, fanout,
incr, time, false, min_max, rf, line_case);
incr, time, false, min_max, rf,
src_attr, line_case);
string what2;
if (network_->isTopLevelPort(pin)) {
const char *pin_name = cmd_network_->pathName(pin);
@ -2768,11 +2791,12 @@ ReportPath::reportPath5(const Path *path,
}
reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, false, min_max,
nullptr, line_case);
nullptr, src_attr, line_case);
}
else
reportLine(what.c_str(), cap, slew, fanout,
incr, time, false, min_max, rf, line_case);
incr, time, false, min_max, rf, src_attr,
line_case);
prev_time = time;
}
}
@ -2956,7 +2980,8 @@ ReportPath::reportLine(const char *what,
const EarlyLate *early_late)
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, nullptr, nullptr);
field_blank_, total, false, early_late, nullptr,
"", nullptr);
}
// Report negative total.
@ -2966,7 +2991,8 @@ ReportPath::reportLineNegative(const char *what,
const EarlyLate *early_late)
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, total, true, early_late, nullptr, nullptr);
field_blank_, total, true, early_late, nullptr,
"", nullptr);
}
// Report total, and transition suffix.
@ -2977,7 +3003,8 @@ ReportPath::reportLine(const char *what,
const RiseFall *rf)
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, rf, nullptr);
field_blank_, total, false, early_late, rf, "",
nullptr);
}
// Report increment, and total.
@ -2988,7 +3015,8 @@ ReportPath::reportLine(const char *what,
const EarlyLate *early_late)
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, total, false, early_late, nullptr, nullptr);
incr, total, false, early_late, nullptr, "",
nullptr);
}
// Report increment, total, and transition suffix.
@ -3000,7 +3028,8 @@ ReportPath::reportLine(const char *what,
const RiseFall *rf)
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, total, false, early_late, rf, nullptr);
incr, total, false, early_late, rf, "",
nullptr);
}
// Report slew, increment, and total.
@ -3012,7 +3041,8 @@ ReportPath::reportLine(const char *what,
const EarlyLate *early_late)
{
reportLine(what, field_blank_, slew, field_blank_,
incr, total, false, early_late, nullptr, nullptr);
incr, total, false, early_late, nullptr,
"", nullptr);
}
void
@ -3025,6 +3055,7 @@ ReportPath::reportLine(const char *what,
bool total_with_minus,
const EarlyLate *early_late,
const RiseFall *rf,
string src_attr,
const char *line_case)
{
ReportFieldSeq::Iterator field_iter(fields_);
@ -3064,8 +3095,13 @@ ReportPath::reportLine(const char *what,
else if (field == field_edge_) {
if (rf)
reportField(rf->shortName(), field, line);
// Compatibility kludge; suppress trailing spaces.
else if (field_iter.hasNext())
else
reportFieldBlank(field, line);
}
else if (field == field_src_attr_) {
if (src_attr != "")
reportField(src_attr.c_str(), field, line);
else
reportFieldBlank(field, line);
}
else if (field == field_case_ && line_case)
@ -3075,7 +3111,10 @@ ReportPath::reportLine(const char *what,
}
field_index++;
}
report_->reportLineString(line);
// Trim trailing spaces and report the line.
string line_stdstr = line;
trimRight(line_stdstr);
report_->reportLineString(line_stdstr.c_str());
}
////////////////////////////////////////////////////////////////

View File

@ -44,7 +44,8 @@ public:
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout);
bool report_fanout,
bool report_src_attr);
int digits() const { return digits_; }
void setDigits(int digits);
void setNoSplit(bool no_split);
@ -148,6 +149,7 @@ public:
ReportField *fieldSlew() const { return field_slew_; }
ReportField *fieldFanout() const { return field_fanout_; }
ReportField *fieldCapacitance() const { return field_capacitance_; }
ReportField *fieldSrcAttr() const { return field_src_attr_; }
protected:
void makeFields();
@ -213,6 +215,10 @@ protected:
void reportTgtClk(const PathEnd *end,
float prev_time,
bool is_prop);
void reportTgtClk(const PathEnd *end,
float prev_time,
float src_offset,
bool is_prop);
bool pathFromGenPropClk(const Path *clk_path,
const EarlyLate *early_late);
bool isGenPropClk(const Clock *clk,
@ -345,6 +351,7 @@ protected:
bool total_with_minus,
const EarlyLate *early_late,
const RiseFall *rf,
string src_attr,
const char *line_case);
void reportLineTotal(const char *what,
Delay incr,
@ -461,6 +468,7 @@ protected:
ReportField *field_capacitance_;
ReportField *field_slew_;
ReportField *field_fanout_;
ReportField *field_src_attr_;
ReportField *field_edge_;
ReportField *field_case_;

View File

@ -403,7 +403,7 @@ Search::deletePaths()
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
vertex->deletePaths();
deletePaths(vertex);
}
filtered_arrivals_->clear();
graph_->clearArrivals();
@ -412,13 +412,24 @@ Search::deletePaths()
}
}
// Delete with incremental tns/wns update.
void
Search::deletePaths(Vertex *vertex)
Search::deletePathsIncr(Vertex *vertex)
{
tnsNotifyBefore(vertex);
if (worst_slacks_)
worst_slacks_->worstSlackNotifyBefore(vertex);
vertex->deletePaths();
deletePaths(vertex);
}
void
Search::deletePaths(Vertex *vertex)
{
TagGroup *tag_group = tagGroup(vertex);
if (tag_group) {
int arrival_count = tag_group->arrivalCount();
graph_->deletePaths(vertex, arrival_count);
}
}
////////////////////////////////////////////////////////////////
@ -510,7 +521,7 @@ Search::deleteFilteredArrivals()
for (Vertex *vertex : *filtered_arrivals_) {
if (isClock(vertex))
clk_arrivals_valid_ = false;
deletePaths(vertex);
deletePathsIncr(vertex);
arrivalInvalid(vertex);
requiredInvalid(vertex);
}
@ -677,7 +688,7 @@ void
Search::deleteVertexBefore(Vertex *vertex)
{
if (arrivals_exist_) {
deletePaths(vertex);
deletePathsIncr(vertex);
arrival_iter_->deleteVertexBefore(vertex);
invalid_arrivals_->erase(vertex);
filtered_arrivals_->erase(vertex);
@ -759,7 +770,7 @@ void
Search::arrivalInvalidDelete(Vertex *vertex)
{
arrivalInvalid(vertex);
vertex->deletePaths();
deletePaths(vertex);
}
void
@ -1239,6 +1250,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *,
TimingArc *,
ArcDelay arc_delay,
@ -1268,7 +1280,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
if (tag_match == nullptr
|| delayGreater(to_arrival, arrival, min_max, this)) {
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
delayAsString(from_path->arrival(this), this),
delayAsString(from_arrival, this),
delayAsString(arc_delay, this),
delayAsString(to_arrival, this),
min_max == MinMax::max() ? ">" : "<",
@ -1456,7 +1468,7 @@ Search::seedArrival(Vertex *vertex)
setVertexArrivals(vertex, &tag_bldr);
}
else {
deletePaths(vertex);
deletePathsIncr(vertex);
if (search_adj_->searchFrom(vertex))
arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_);
}
@ -2199,7 +2211,8 @@ PathVisitor::visitFromPath(const Pin *from_pin,
}
}
if (to_tag)
return visitFromToPath(from_pin, from_vertex, from_rf, from_tag, from_path,
return visitFromToPath(from_pin, from_vertex, from_rf,
from_tag, from_path, from_arrival,
edge, arc, arc_delay,
to_vertex, to_rf, to_tag, to_arrival,
min_max, path_ap);
@ -2661,7 +2674,7 @@ Search::setVertexArrivals(Vertex *vertex,
TagGroupBldr *tag_bldr)
{
if (tag_bldr->empty())
deletePaths(vertex);
deletePathsIncr(vertex);
else {
TagGroup *prev_tag_group = tagGroup(vertex);
Arrival *prev_arrivals = graph_->arrivals(vertex);
@ -2680,7 +2693,7 @@ Search::setVertexArrivals(Vertex *vertex,
else {
// Prev paths not required.
prev_paths = nullptr;
vertex->setPrevPaths(prev_path_null);
graph_->deletePrevPaths(vertex, arrival_count);
}
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
vertex->setTagGroupIndex(tag_group->index());
@ -3477,6 +3490,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &,
Edge *edge,
TimingArc *,
ArcDelay arc_delay,

View File

@ -504,13 +504,15 @@ set_report_path_fields(bool report_input_pin,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout)
bool report_fanout,
bool report_src_attr)
{
Sta::sta()->setReportPathFields(report_input_pin,
report_net,
report_cap,
report_slew,
report_fanout);
report_fanout,
report_src_attr);
}
void

View File

@ -401,8 +401,8 @@ define_cmd_args "report_checks" \
[-slack_min slack_min]\
[-sort_by_slack]\
[-path_group group_name]\
[-format full|full_clock|full_clock_expanded|short|end|summary]\
[-fields capacitance|slew|input_pin|net]\
[-format full|full_clock|full_clock_expanded|short|end|slack_only|summary|json]\
[-fields capacitance|slew|input_pin|net|src_attr]\
[-digits digits]\
[-no_line_splits]\
[> filename] [>> filename]}
@ -903,15 +903,17 @@ proc parse_report_path_options { cmd args_var default_format
set report_net [expr [lsearch $fields "net*"] != -1]
set report_slew [expr [lsearch $fields "slew*"] != -1]
set report_fanout [expr [lsearch $fields "fanout*"] != -1]
set report_src_attr [expr [lsearch $fields "src_attr*"] != -1]
} else {
set report_input_pin 0
set report_cap 0
set report_net 0
set report_slew 0
set report_fanout 0
set report_src_attr 0
}
set_report_path_fields $report_input_pin $report_net \
$report_cap $report_slew $report_fanout
$report_cap $report_slew $report_fanout $report_src_attr
set_report_path_no_split [info exists path_options(-no_line_splits)]
}

View File

@ -2488,10 +2488,11 @@ Sta::setReportPathFields(bool report_input_pin,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout)
bool report_fanout,
bool report_src_attr)
{
report_path_->setReportFields(report_input_pin, report_net, report_cap,
report_slew, report_fanout);
report_slew, report_fanout, report_src_attr);
}
ReportField *

View File

@ -80,6 +80,7 @@ protected:
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
@ -254,6 +255,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
const RiseFall *,
Tag *from_tag,
PathVertex *from_path,
const Arrival &,
Edge *,
TimingArc *,
ArcDelay ,

View File

@ -285,6 +285,7 @@ proc run_test_plain { test cmd_file log_file } {
cleanse_logfile $test $log_file
return "ERROR $error"
}
file delete $run_file
cleanse_logfile $test $log_file
return ""
}

View File

@ -129,6 +129,7 @@ record_sta_tests {
get_filter
get_noargs
get_objrefs
report_checks_src_attr
}
define_test_group fast [group_tests all]

View File

@ -0,0 +1,28 @@
Startpoint: in (input port clocked by clk)
Endpoint: _1415_ (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: max
Cap Slew Delay Time Description Src Attr
---------------------------------------------------------------------------------------------------------------
0.00 0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 0.00 0.00 v in (in)
in (net)
0.00 0.00 0.00 v _1415_/D (sky130_fd_sc_hd__dfrtp_1) synthesis/tests/counter.v:22.3-28.6
0.00 data arrival time
0.00 10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
10.00 ^ _1415_/CLK (sky130_fd_sc_hd__dfrtp_1)
-0.10 9.90 library setup time
9.90 data required time
---------------------------------------------------------------------------------------------------------------
9.90 data required time
-0.00 data arrival time
---------------------------------------------------------------------------------------------------------------
9.90 slack (MET)

View File

@ -0,0 +1,7 @@
# report_checks all fields enabled
read_liberty ../examples/sky130hd_tt.lib.gz
read_verilog verilog_attribute.v
link_design counter
create_clock -name clk -period 10 clk
set_input_delay -clock clk 0 [all_inputs -no_clocks]
report_checks -path_group clk -fields {capacitance slew input_pin net src_attr}

View File

@ -1,5 +1,5 @@
# Tests whether Verilog attributes can be parsed and retrieved correctly
read_liberty ../examples/sky130hd_tt.lib
read_liberty ../examples/sky130hd_tt.lib.gz
read_verilog verilog_attribute.v
link_design counter
create_clock -name clk [get_ports clk] -period 50

View File

@ -11,6 +11,7 @@ module counter(clk, reset, in, out);
(* src = "synthesis/tests/counter.v:18.14-18.19" *)
input reset;
input in;
(* bottom_bound = 1'sh0 *)
(* src = "synthesis/tests/counter.v:22.3-28.6", attr1 = "test_attr1", attr2 = "test_attr2" *)
sky130_fd_sc_hd__dfrtp_1 _1415_ (
.CLK(clk),

View File

@ -76,22 +76,22 @@ ID_TOKEN {ID_ESCAPED_TOKEN}|{ID_ALPHA_TOKEN}
}
}
{SIGN}?{UNSIGNED_NUMBER}?"'"[bB][01_xz]+ {
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[bB][01_xz]+ {
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
return CONSTANT;
}
{SIGN}?{UNSIGNED_NUMBER}?"'"[oO][0-7_xz]+ {
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[oO][0-7_xz]+ {
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
return CONSTANT;
}
{SIGN}?{UNSIGNED_NUMBER}?"'"[dD][0-9_]+ {
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[dD][0-9_]+ {
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
return CONSTANT;
}
{SIGN}?{UNSIGNED_NUMBER}?"'"[hH][0-9a-fA-F_xz]+ {
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[hH][0-9a-fA-F_xz]+ {
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
return CONSTANT;
}

View File

@ -41,31 +41,35 @@ public:
CellSeq *remove_cells,
FILE *stream,
Network *network);
void writeModule(Instance *inst);
void writeModules();
protected:
void writePorts(Cell *cell);
void writePortDcls(Cell *cell);
void writeWireDcls(Instance *inst);
void writeModule(const Instance *inst);
InstanceSeq findHierChildren();
void findHierChildren(const Instance *inst,
InstanceSeq &children,
CellSet &cells);
void writePorts(const Cell *cell);
void writePortDcls(const Cell *cell);
void writeWireDcls(const Instance *inst);
const char *verilogPortDir(PortDirection *dir);
void writeChildren(Instance *inst);
void writeChild(Instance *child);
void writeInstPin(Instance *inst,
Port *port,
void writeChildren(const Instance *inst);
void writeChild(const Instance *child);
void writeInstPin(const Instance *inst,
const Port *port,
bool &first_port);
void writeInstBusPin(Instance *inst,
Port *port,
void writeInstBusPin(const Instance *inst,
const Port *port,
bool &first_port);
void writeInstBusPinBit(Instance *inst,
Port *port,
void writeInstBusPinBit(const Instance *inst,
const Port *port,
bool &first_member);
void writeAssigns(Instance *inst);
void writeAssigns(const Instance *inst);
int findUnconnectedNetCount();
int findNCcount(Instance *inst);
int findChildNCcount(Instance *child);
int findPortNCcount(Instance *inst,
Port *port);
int findUnconnectedNetCount(const Instance *inst);
int findChildNCcount(const Instance *child);
int findPortNCcount(const Instance *inst,
const Port *port);
const char *filename_;
bool sort_;
@ -73,9 +77,6 @@ protected:
CellSet remove_cells_;
FILE *stream_;
Network *network_;
CellSet written_cells_;
Vector<Instance*> pending_children_;
int unconnected_net_index_;
};
@ -91,7 +92,7 @@ writeVerilog(const char *filename,
if (stream) {
VerilogWriter writer(filename, sort, include_pwr_gnd,
remove_cells, stream, network);
writer.writeModule(network->topInstance());
writer.writeModules();
fclose(stream);
}
else
@ -111,7 +112,6 @@ VerilogWriter::VerilogWriter(const char *filename,
remove_cells_(network),
stream_(stream),
network_(network),
written_cells_(network),
unconnected_net_index_(1)
{
if (remove_cells) {
@ -121,7 +121,54 @@ VerilogWriter::VerilogWriter(const char *filename,
}
void
VerilogWriter::writeModule(Instance *inst)
VerilogWriter::writeModules()
{
// Write the top level modeule first.
writeModule(network_->topInstance());
InstanceSeq hier_childrenn = findHierChildren();
for (const Instance *child : hier_childrenn)
writeModule(child);
}
InstanceSeq
VerilogWriter::findHierChildren()
{
InstanceSeq children;
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);
});
return children;
}
void
VerilogWriter::findHierChildren(const Instance *inst,
InstanceSeq &children,
CellSet &cells)
{
InstanceChildIterator *child_iter = network_->childIterator(inst);
while (child_iter->hasNext()) {
const Instance *child = child_iter->next();
const Cell *cell = network_->cell(child);
if (network_->isHierarchical(child)
&& !cells.hasKey(cell)) {
children.push_back(child);
cells.insert(cell);
findHierChildren(child, children, cells);
}
}
delete child_iter;
}
void
VerilogWriter::writeModule(const Instance *inst)
{
Cell *cell = network_->cell(inst);
fprintf(stream_, "module %s (",
@ -134,22 +181,10 @@ VerilogWriter::writeModule(Instance *inst)
writeChildren(inst);
writeAssigns(inst);
fprintf(stream_, "endmodule\n");
written_cells_.insert(cell);
if (sort_)
sort(pending_children_, [this](const Instance *inst1,
const Instance *inst2) {
return stringLess(network_->cellName(inst1), network_->cellName(inst2));
});
for (auto child : pending_children_) {
Cell *child_cell = network_->cell(child);
if (!written_cells_.hasKey(child_cell))
writeModule(child);
}
}
void
VerilogWriter::writePorts(Cell *cell)
VerilogWriter::writePorts(const Cell *cell)
{
bool first = true;
CellPortIterator *port_iter = network_->portIterator(cell);
@ -170,7 +205,7 @@ VerilogWriter::writePorts(Cell *cell)
}
void
VerilogWriter::writePortDcls(Cell *cell)
VerilogWriter::writePortDcls(const Cell *cell)
{
CellPortIterator *port_iter = network_->portIterator(cell);
while (port_iter->hasNext()) {
@ -228,7 +263,7 @@ VerilogWriter::verilogPortDir(PortDirection *dir)
typedef std::pair<int, int> BusIndexRange;
void
VerilogWriter::writeWireDcls(Instance *inst)
VerilogWriter::writeWireDcls(const Instance *inst)
{
Cell *cell = network_->cell(inst);
char escape = network_->pathEscape();
@ -268,22 +303,19 @@ VerilogWriter::writeWireDcls(Instance *inst)
}
// Wire net dcls for writeInstBusPinBit.
int nc_count = findUnconnectedNetCount();
int nc_count = findUnconnectedNetCount(inst);
for (int i = 1; i < nc_count + 1; i++)
fprintf(stream_, " wire _NC%d;\n", i);
}
void
VerilogWriter::writeChildren(Instance *inst)
VerilogWriter::writeChildren(const Instance *inst)
{
Vector<Instance*> children;
InstanceChildIterator *child_iter = network_->childIterator(inst);
while (child_iter->hasNext()) {
Instance *child = child_iter->next();
children.push_back(child);
if (network_->isHierarchical(child)) {
pending_children_.push_back(child);
}
}
delete child_iter;
@ -298,7 +330,7 @@ VerilogWriter::writeChildren(Instance *inst)
}
void
VerilogWriter::writeChild(Instance *child)
VerilogWriter::writeChild(const Instance *child)
{
Cell *child_cell = network_->cell(child);
if (!remove_cells_.hasKey(child_cell)) {
@ -325,8 +357,8 @@ VerilogWriter::writeChild(Instance *child)
}
void
VerilogWriter::writeInstPin(Instance *inst,
Port *port,
VerilogWriter::writeInstPin(const Instance *inst,
const Port *port,
bool &first_port)
{
Pin *pin = network_->findPin(inst, port);
@ -348,8 +380,8 @@ VerilogWriter::writeInstPin(Instance *inst,
}
void
VerilogWriter::writeInstBusPin(Instance *inst,
Port *port,
VerilogWriter::writeInstBusPin(const Instance *inst,
const Port *port,
bool &first_port)
{
if (!first_port)
@ -382,8 +414,8 @@ VerilogWriter::writeInstBusPin(Instance *inst,
}
void
VerilogWriter::writeInstBusPinBit(Instance *inst,
Port *port,
VerilogWriter::writeInstBusPinBit(const Instance *inst,
const Port *port,
bool &first_member)
{
Pin *pin = network_->findPin(inst, port);
@ -405,28 +437,30 @@ VerilogWriter::writeInstBusPinBit(Instance *inst,
// Use an assign statement to alias the net when it is connected to
// multiple output ports.
void
VerilogWriter::writeAssigns(Instance *inst)
VerilogWriter::writeAssigns(const Instance *inst)
{
InstancePinIterator *pin_iter = network_->pinIterator(inst);
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
Term *term = network_->term(pin);
Net *net = network_->net(term);
Port *port = network_->port(pin);
if (port
&& (include_pwr_gnd_
|| !(network_->isPower(net) || network_->isGround(net)))
&& (network_->direction(port)->isAnyOutput()
|| (include_pwr_gnd_ && network_->direction(port)->isPowerGround()))
&& !stringEqual(network_->name(port), network_->name(net))) {
// Port name is different from net name.
string port_vname = netVerilogName(network_->name(port),
network_->pathEscape());
string net_vname = netVerilogName(network_->name(net),
network_->pathEscape());
fprintf(stream_, " assign %s = %s;\n",
port_vname.c_str(),
net_vname.c_str());
if (term) {
Net *net = network_->net(term);
Port *port = network_->port(pin);
if (port
&& (include_pwr_gnd_
|| !(network_->isPower(net) || network_->isGround(net)))
&& (network_->direction(port)->isAnyOutput()
|| (include_pwr_gnd_ && network_->direction(port)->isPowerGround()))
&& !stringEqual(network_->name(port), network_->name(net))) {
// Port name is different from net name.
string port_vname = netVerilogName(network_->name(port),
network_->pathEscape());
string net_vname = netVerilogName(network_->name(net),
network_->pathEscape());
fprintf(stream_, " assign %s = %s;\n",
port_vname.c_str(),
net_vname.c_str());
}
}
}
delete pin_iter;
@ -434,16 +468,8 @@ VerilogWriter::writeAssigns(Instance *inst)
////////////////////////////////////////////////////////////////
// Walk the hierarch counting unconnected nets used to connect to
// bus ports with concatenation.
int
VerilogWriter::findUnconnectedNetCount()
{
return findNCcount(network_->topInstance());
}
int
VerilogWriter::findNCcount(Instance *inst)
VerilogWriter::findUnconnectedNetCount(const Instance *inst)
{
int nc_count = 0;
InstanceChildIterator *child_iter = network_->childIterator(inst);
@ -456,7 +482,7 @@ VerilogWriter::findNCcount(Instance *inst)
}
int
VerilogWriter::findChildNCcount(Instance *child)
VerilogWriter::findChildNCcount(const Instance *child)
{
int nc_count = 0;
Cell *child_cell = network_->cell(child);
@ -473,8 +499,8 @@ VerilogWriter::findChildNCcount(Instance *child)
}
int
VerilogWriter::findPortNCcount(Instance *inst,
Port *port)
VerilogWriter::findPortNCcount(const Instance *inst,
const Port *port)
{
int nc_count = 0;
LibertyPort *lib_port = network_->libertyPort(port);