Merge remote-tracking branch 'parallax/master'
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
commit
9afc487f07
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
133288
examples/nangate45_fast.lib
133288
examples/nangate45_fast.lib
File diff suppressed because it is too large
Load Diff
Binary file not shown.
133288
examples/nangate45_slow.lib
133288
examples/nangate45_slow.lib
File diff suppressed because it is too large
Load Diff
Binary file not shown.
133288
examples/nangate45_typ.lib
133288
examples/nangate45_typ.lib
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
173160
examples/sky130hd_tt.lib
173160
examples/sky130hd_tt.lib
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) :
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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 ,
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ record_sta_tests {
|
|||
get_filter
|
||||
get_noargs
|
||||
get_objrefs
|
||||
report_checks_src_attr
|
||||
}
|
||||
|
||||
define_test_group fast [group_tests all]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue