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 && \
|
tar -xvf cudd-3.0.0.tar.gz && \
|
||||||
rm cudd-3.0.0.tar.gz
|
rm cudd-3.0.0.tar.gz
|
||||||
|
|
||||||
# Install CUDD
|
# Build CUDD
|
||||||
RUN source /opt/rh/devtoolset-8/enable && \
|
RUN source /opt/rh/devtoolset-8/enable && \
|
||||||
cd cudd-3.0.0 && \
|
cd cudd-3.0.0 && \
|
||||||
mkdir ../cudd && \
|
mkdir ../cudd && \
|
||||||
./configure && \
|
./configure && \
|
||||||
make -j`nproc` && \
|
make -j`nproc`
|
||||||
make install
|
|
||||||
|
|
||||||
FROM base-dependencies AS builder
|
FROM base-dependencies AS builder
|
||||||
|
|
||||||
|
|
@ -34,7 +33,10 @@ WORKDIR /OpenSTA
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
RUN rm -rf build && mkdir 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
|
# Run sta on entry
|
||||||
ENTRYPOINT ["OpenSTA/app/sta"]
|
ENTRYPOINT ["OpenSTA/app/sta"]
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,33 @@
|
||||||
FROM ubuntu:18.04
|
FROM ubuntu:22.04
|
||||||
LABEL author="James Cherry"
|
LABEL author="James Cherry"
|
||||||
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
|
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
|
||||||
|
|
||||||
# Install basics
|
# Install basics
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get update && \
|
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
|
# Download CUDD
|
||||||
RUN wget https://raw.githubusercontent.com/davidkebo/cudd/main/cudd_versions/cudd-3.0.0.tar.gz && \
|
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 && \
|
tar -xvf cudd-3.0.0.tar.gz && \
|
||||||
rm cudd-3.0.0.tar.gz
|
rm cudd-3.0.0.tar.gz
|
||||||
|
|
||||||
# Install CUDD
|
# Build CUDD
|
||||||
RUN cd cudd-3.0.0 && \
|
RUN cd cudd-3.0.0 && \
|
||||||
mkdir ../cudd && \
|
mkdir ../cudd && \
|
||||||
./configure && \
|
./configure && \
|
||||||
make -j`nproc` && \
|
make -j`nproc`
|
||||||
make install
|
|
||||||
|
|
||||||
# Copy files and install OpenSTA
|
# Copy files and install OpenSTA
|
||||||
RUN mkdir OpenSTA
|
RUN mkdir OpenSTA
|
||||||
|
|
@ -26,7 +36,7 @@ RUN cd OpenSTA && \
|
||||||
rm -rf build && \
|
rm -rf build && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake -DCUDD_DIR=../cudd-3.0.0 .. && \
|
||||||
make -j`nproc`
|
make -j`nproc`
|
||||||
|
|
||||||
# Run sta on entry
|
# Run sta on entry
|
||||||
|
|
@ -11,6 +11,8 @@ standard file formats.
|
||||||
* SDC timing constraints
|
* SDC timing constraints
|
||||||
* SDF delay annotation
|
* SDF delay annotation
|
||||||
* SPEF parasitics
|
* SPEF parasitics
|
||||||
|
* VCD power acitivies
|
||||||
|
* SAIF power acitivies
|
||||||
|
|
||||||
OpenSTA uses a TCL command interpreter to read the design, specify
|
OpenSTA uses a TCL command interpreter to read the design, specify
|
||||||
timing constraints and print timing reports.
|
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
|
* Simulator to propagate constants from constraints and netlist tie high/low
|
||||||
|
|
||||||
See doc/OpenSTA.pdf for command documentation.
|
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/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
|
OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
|
||||||
is also licensed for commerical applications by Parallax Software without
|
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
|
# delay calc example
|
||||||
read_liberty nangate45_slow.lib
|
read_liberty nangate45_slow.lib.gz
|
||||||
read_verilog example1.v
|
read_verilog example1.v
|
||||||
link_design top
|
link_design top
|
||||||
create_clock -name clk -period 10 {clk1 clk2 clk3}
|
create_clock -name clk -period 10 {clk1 clk2 clk3}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# min/max delay calc example
|
# min/max delay calc example
|
||||||
read_liberty -max nangate45_slow.lib
|
read_liberty -max nangate45_slow.lib.gz
|
||||||
read_liberty -min nangate45_fast.lib
|
read_liberty -min nangate45_fast.lib.gz
|
||||||
read_verilog example1.v
|
read_verilog example1.v
|
||||||
link_design top
|
link_design top
|
||||||
create_clock -name clk -period 10 {clk1 clk2 clk3}
|
create_clock -name clk -period 10 {clk1 clk2 clk3}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# 3 corners with +/- 10% derating example
|
# 3 corners with +/- 10% derating example
|
||||||
define_corners ss tt ff
|
define_corners ss tt ff
|
||||||
read_liberty -corner ss nangate45_slow.lib
|
read_liberty -corner ss nangate45_slow.lib.gz
|
||||||
read_liberty -corner tt nangate45_typ.lib
|
read_liberty -corner tt nangate45_typ.lib.gz
|
||||||
read_liberty -corner ff nangate45_fast.lib
|
read_liberty -corner ff nangate45_fast.lib.gz
|
||||||
read_verilog example1.v
|
read_verilog example1.v
|
||||||
link_design top
|
link_design top
|
||||||
set_timing_derate -early 0.9
|
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
|
# report_power gcd
|
||||||
read_liberty sky130hd_tt.lib
|
read_liberty sky130hd_tt.lib.gz
|
||||||
read_verilog gcd_sky130hd.v
|
read_verilog gcd_sky130hd.v
|
||||||
link_design gcd
|
link_design gcd
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# read_vcd_activities gcd
|
# read_vcd_activities gcd
|
||||||
read_liberty sky130hd_tt.lib
|
read_liberty sky130hd_tt.lib.gz
|
||||||
read_verilog gcd_sky130hd.v
|
read_verilog gcd_sky130hd.v
|
||||||
link_design gcd
|
link_design gcd
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# sdf example
|
# sdf example
|
||||||
read_liberty nangate45_slow.lib
|
read_liberty nangate45_slow.lib.gz
|
||||||
read_verilog example1.v
|
read_verilog example1.v
|
||||||
link_design top
|
link_design top
|
||||||
read_sdf example1.sdf
|
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
|
# delay calc with spef parasitics
|
||||||
read_liberty nangate45_slow.lib
|
read_liberty nangate45_slow.lib.gz
|
||||||
read_verilog example1.v
|
read_verilog example1.v
|
||||||
link_design top
|
link_design top
|
||||||
read_spef example1.dspef
|
read_spef example1.dspef
|
||||||
|
|
|
||||||
|
|
@ -660,12 +660,48 @@ Graph::prevPaths(Vertex *vertex) const
|
||||||
return prev_paths_.pointer(vertex->prevPaths());
|
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
|
void
|
||||||
Graph::clearPrevPaths()
|
Graph::clearPrevPaths()
|
||||||
{
|
{
|
||||||
prev_paths_.clear();
|
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 &
|
const Slew &
|
||||||
|
|
@ -1245,16 +1281,6 @@ Vertex::setPrevPaths(PrevPathId prev_paths)
|
||||||
prev_paths_ = 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
|
LogicValue
|
||||||
Vertex::simValue() const
|
Vertex::simValue() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,13 @@ public:
|
||||||
PathVertexRep *makePrevPaths(Vertex *vertex,
|
PathVertexRep *makePrevPaths(Vertex *vertex,
|
||||||
uint32_t count);
|
uint32_t count);
|
||||||
PathVertexRep *prevPaths(Vertex *vertex) const;
|
PathVertexRep *prevPaths(Vertex *vertex) const;
|
||||||
|
void deletePrevPaths(Vertex *vertex,
|
||||||
|
uint32_t count);
|
||||||
void clearPrevPaths();
|
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 slew are the same as those in the liberty tables.
|
||||||
// reported_slews = measured_slews / slew_derate_from_library
|
// reported_slews = measured_slews / slew_derate_from_library
|
||||||
// Measured slews are between slew_lower_threshold and slew_upper_threshold.
|
// Measured slews are between slew_lower_threshold and slew_upper_threshold.
|
||||||
|
|
@ -333,8 +339,6 @@ public:
|
||||||
// ObjectTable interface.
|
// ObjectTable interface.
|
||||||
ObjectIdx objectIdx() const { return object_idx_; }
|
ObjectIdx objectIdx() const { return object_idx_; }
|
||||||
void setObjectIdx(ObjectIdx idx);
|
void setObjectIdx(ObjectIdx idx);
|
||||||
// private to Search.cc
|
|
||||||
void deletePaths();
|
|
||||||
|
|
||||||
static int transitionCount() { return 2; } // rise/fall
|
static int transitionCount() { return 2; } // rise/fall
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -543,6 +543,8 @@ public:
|
||||||
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
|
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
|
||||||
const char *footprint() const;
|
const char *footprint() const;
|
||||||
void setFootprint(const char *footprint);
|
void setFootprint(const char *footprint);
|
||||||
|
const char *userFunctionClass() const;
|
||||||
|
void setUserFunctionClass(const char *user_function_class);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addPort(ConcretePort *port);
|
void addPort(ConcretePort *port);
|
||||||
|
|
@ -634,6 +636,7 @@ protected:
|
||||||
bool have_voltage_waveforms_;
|
bool have_voltage_waveforms_;
|
||||||
std::mutex waveform_lock_;
|
std::mutex waveform_lock_;
|
||||||
const char *footprint_;
|
const char *footprint_;
|
||||||
|
const char *user_function_class_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class LibertyLibrary;
|
friend class LibertyLibrary;
|
||||||
|
|
|
||||||
|
|
@ -498,6 +498,8 @@ protected:
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
void deletePaths();
|
void deletePaths();
|
||||||
void deletePaths(Vertex *vertex);
|
void deletePaths(Vertex *vertex);
|
||||||
|
// Delete with incremental tns/wns update.
|
||||||
|
void deletePathsIncr(Vertex *vertex);
|
||||||
TagGroup *findTagGroup(TagGroupBldr *group_bldr);
|
TagGroup *findTagGroup(TagGroupBldr *group_bldr);
|
||||||
void deleteFilterTags();
|
void deleteFilterTags();
|
||||||
void deleteFilterTagGroups();
|
void deleteFilterTagGroups();
|
||||||
|
|
@ -686,6 +688,7 @@ protected:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -718,6 +721,7 @@ public:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -787,6 +791,7 @@ protected:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
|
||||||
|
|
@ -892,7 +892,8 @@ public:
|
||||||
bool report_net,
|
bool report_net,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout);
|
bool report_fanout,
|
||||||
|
bool report_src_attr);
|
||||||
ReportField *findReportPathField(const char *name);
|
ReportField *findReportPathField(const char *name);
|
||||||
void setReportPathDigits(int digits);
|
void setReportPathDigits(int digits);
|
||||||
void setReportPathNoSplit(bool no_split);
|
void setReportPathNoSplit(bool no_split);
|
||||||
|
|
|
||||||
|
|
@ -941,7 +941,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
|
||||||
leakage_power_exists_(false),
|
leakage_power_exists_(false),
|
||||||
has_internal_ports_(false),
|
has_internal_ports_(false),
|
||||||
have_voltage_waveforms_(false),
|
have_voltage_waveforms_(false),
|
||||||
footprint_(nullptr)
|
footprint_(nullptr),
|
||||||
|
user_function_class_(nullptr)
|
||||||
{
|
{
|
||||||
liberty_cell_ = this;
|
liberty_cell_ = this;
|
||||||
}
|
}
|
||||||
|
|
@ -971,6 +972,7 @@ LibertyCell::~LibertyCell()
|
||||||
pg_port_map_.deleteContents();
|
pg_port_map_.deleteContents();
|
||||||
|
|
||||||
stringDelete(footprint_);
|
stringDelete(footprint_);
|
||||||
|
stringDelete(user_function_class_);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibertyPort *
|
LibertyPort *
|
||||||
|
|
@ -2004,6 +2006,18 @@ LibertyCell::footprint() const
|
||||||
return footprint_;
|
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) :
|
LibertyCellPortIterator::LibertyCellPortIterator(const LibertyCell *cell) :
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,8 @@ LibertyReader::defineVisitors()
|
||||||
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
|
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
|
||||||
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
|
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
|
||||||
defineAttrVisitor("cell_footprint", &LibertyReader::visitCellFootprint);
|
defineAttrVisitor("cell_footprint", &LibertyReader::visitCellFootprint);
|
||||||
|
defineAttrVisitor("user_function_class",
|
||||||
|
&LibertyReader::visitCellUserFunctionClass);
|
||||||
|
|
||||||
// Pins
|
// Pins
|
||||||
defineGroupVisitor("pin", &LibertyReader::beginPin,&LibertyReader::endPin);
|
defineGroupVisitor("pin", &LibertyReader::beginPin,&LibertyReader::endPin);
|
||||||
|
|
@ -2159,6 +2161,7 @@ LibertyReader::makeStatetable()
|
||||||
internal_ports.push_back(port);
|
internal_ports.push_back(port);
|
||||||
}
|
}
|
||||||
cell_->makeStatetable(input_ports, internal_ports, statetable_->table());
|
cell_->makeStatetable(input_ports, internal_ports, statetable_->table());
|
||||||
|
delete statetable_;
|
||||||
statetable_ = nullptr;
|
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
|
void
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ public:
|
||||||
virtual void visitScalingFactors(LibertyAttr *attr);
|
virtual void visitScalingFactors(LibertyAttr *attr);
|
||||||
virtual void visitCellLeakagePower(LibertyAttr *attr);
|
virtual void visitCellLeakagePower(LibertyAttr *attr);
|
||||||
virtual void visitCellFootprint(LibertyAttr *attr);
|
virtual void visitCellFootprint(LibertyAttr *attr);
|
||||||
|
virtual void visitCellUserFunctionClass(LibertyAttr *attr);
|
||||||
|
|
||||||
virtual void beginPin(LibertyGroup *group);
|
virtual void beginPin(LibertyGroup *group);
|
||||||
virtual void endPin(LibertyGroup *group);
|
virtual void endPin(LibertyGroup *group);
|
||||||
|
|
|
||||||
|
|
@ -289,6 +289,13 @@ LibertyWriter::writeCell(const LibertyCell *cell)
|
||||||
fprintf(stream_, " is_macro_cell : true;\n");
|
fprintf(stream_, " is_macro_cell : true;\n");
|
||||||
if (cell->interfaceTiming())
|
if (cell->interfaceTiming())
|
||||||
fprintf(stream_, " interface_timing : true;\n");
|
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);
|
LibertyCellPortIterator port_iter(cell);
|
||||||
while (port_iter.hasNext()) {
|
while (port_iter.hasNext()) {
|
||||||
|
|
|
||||||
|
|
@ -175,15 +175,15 @@ SaifReader::setNetDurations(const char *net_name,
|
||||||
if (in_scope_level_ > 0) {
|
if (in_scope_level_ > 0) {
|
||||||
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
const char *net_name1 = unescaped(net_name);
|
string unescaped_name = unescaped(net_name);
|
||||||
const Pin *pin = sdc_network_->findPin(parent, net_name1);
|
const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str());
|
||||||
if (pin) {
|
if (pin) {
|
||||||
double t1 = durations[static_cast<int>(SaifState::T1)];
|
double t1 = durations[static_cast<int>(SaifState::T1)];
|
||||||
float duty = t1 / duration_;
|
float duty = t1 / duration_;
|
||||||
double tc = durations[static_cast<int>(SaifState::TC)];
|
double tc = durations[static_cast<int>(SaifState::TC)];
|
||||||
float activity = tc / (duration_ * timescale_ / clk_period_);
|
float activity = tc / (duration_ * timescale_ / clk_period_);
|
||||||
debugPrint(debug_, "read_saif", 2,
|
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),
|
sdc_network_->pathName(pin),
|
||||||
t1,
|
t1,
|
||||||
duration_,
|
duration_,
|
||||||
|
|
@ -195,28 +195,22 @@ SaifReader::setNetDurations(const char *net_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stringDelete(net_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
string
|
||||||
SaifReader::unescaped(const char *token)
|
SaifReader::unescaped(const char *token)
|
||||||
{
|
{
|
||||||
char *unescaped = new char[strlen(token) + 1];
|
string unescaped;
|
||||||
char *u = unescaped;
|
for (const char *t = token; *t; t++) {
|
||||||
size_t token_length = strlen(token);
|
char ch = *t;
|
||||||
|
if (ch == escape_)
|
||||||
for (size_t i = 0; i < token_length; i++) {
|
unescaped += *(t+1);
|
||||||
char ch = token[i];
|
|
||||||
if (ch == escape_) {
|
|
||||||
char next_ch = token[i + 1];
|
|
||||||
*u++ = next_ch;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
// Just the normal noises.
|
// Just the normal noises.
|
||||||
*u++ = ch;
|
unescaped += ch;
|
||||||
}
|
}
|
||||||
*u = '\0';
|
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped.c_str());
|
||||||
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped);
|
|
||||||
return unescaped;
|
return unescaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "Zlib.hh"
|
#include "Zlib.hh"
|
||||||
#include "NetworkClass.hh"
|
#include "NetworkClass.hh"
|
||||||
|
|
@ -84,7 +85,7 @@ public:
|
||||||
void notSupported(const char *feature);
|
void notSupported(const char *feature);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *unescaped(const char *token);
|
string unescaped(const char *token);
|
||||||
|
|
||||||
const char *filename_;
|
const char *filename_;
|
||||||
const char *scope_; // Divider delimited scope to begin annotation.
|
const char *scope_; // Divider delimited scope to begin annotation.
|
||||||
|
|
|
||||||
|
|
@ -1812,6 +1812,9 @@ PathEndPathDelay::findSrcClkArrival(const StaState *sta)
|
||||||
Search *search = sta->search();
|
Search *search = sta->search();
|
||||||
src_clk_arrival_ = search->pathClkPathArrival(&path_);
|
src_clk_arrival_ = search->pathClkPathArrival(&path_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
src_clk_arrival_ = 0.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1941,11 +1944,10 @@ Required
|
||||||
PathEndPathDelay::requiredTime(const StaState *sta) const
|
PathEndPathDelay::requiredTime(const StaState *sta) const
|
||||||
{
|
{
|
||||||
float delay = path_delay_->delay();
|
float delay = path_delay_->delay();
|
||||||
if (ignoreClkLatency(sta)) {
|
if (path_delay_->ignoreClkLatency()) {
|
||||||
if (minMax(sta) == MinMax::max())
|
float src_offset = path_.isClock(sta) ? path_.clkEdge(sta)->time() : src_clk_arrival_;
|
||||||
return src_clk_arrival_ + delay - margin(sta);
|
return src_offset + delay
|
||||||
else
|
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
|
||||||
return src_clk_arrival_ + delay + margin(sta);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Arrival tgt_clk_arrival = targetClkArrival(sta);
|
Arrival tgt_clk_arrival = targetClkArrival(sta);
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,7 @@ public:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -315,6 +316,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
Tag *,
|
Tag *,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay,
|
ArcDelay,
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,7 @@ public:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -380,6 +381,7 @@ PrevPathVisitor::visitFromToPath(const Pin *,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &,
|
||||||
Edge *,
|
Edge *,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay,
|
ArcDelay,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ ReportPath::ReportPath(StaState *sta) :
|
||||||
{
|
{
|
||||||
setDigits(2);
|
setDigits(2);
|
||||||
makeFields();
|
makeFields();
|
||||||
setReportFields(false, false, false, false, false);
|
setReportFields(false, false, false, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportPath::~ReportPath()
|
ReportPath::~ReportPath()
|
||||||
|
|
@ -133,6 +133,7 @@ ReportPath::~ReportPath()
|
||||||
delete field_capacitance_;
|
delete field_capacitance_;
|
||||||
delete field_slew_;
|
delete field_slew_;
|
||||||
delete field_fanout_;
|
delete field_fanout_;
|
||||||
|
delete field_src_attr_;
|
||||||
delete field_edge_;
|
delete field_edge_;
|
||||||
delete field_case_;
|
delete field_case_;
|
||||||
|
|
||||||
|
|
@ -156,6 +157,8 @@ ReportPath::makeFields()
|
||||||
field_case_ = makeField("case", "case", 11, false, nullptr, false);
|
field_case_ = makeField("case", "case", 11, false, nullptr, false);
|
||||||
field_description_ = makeField("description", "Description", 36,
|
field_description_ = makeField("description", "Description", 36,
|
||||||
true, nullptr, true);
|
true, nullptr, true);
|
||||||
|
field_src_attr_ = makeField("src_attr", "Src Attr", 40,
|
||||||
|
true, nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportField *
|
ReportField *
|
||||||
|
|
@ -225,15 +228,16 @@ ReportPath::setReportFields(bool report_input_pin,
|
||||||
bool report_net,
|
bool report_net,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout)
|
bool report_fanout,
|
||||||
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
report_input_pin_ = report_input_pin;
|
report_input_pin_ = report_input_pin;
|
||||||
report_net_ = report_net;
|
report_net_ = report_net;
|
||||||
|
|
||||||
field_fanout_->setEnabled(report_net_);
|
|
||||||
field_capacitance_->setEnabled(report_cap);
|
field_capacitance_->setEnabled(report_cap);
|
||||||
field_slew_->setEnabled(report_slew);
|
field_slew_->setEnabled(report_slew);
|
||||||
field_fanout_->setEnabled(report_fanout);
|
field_fanout_->setEnabled(report_fanout);
|
||||||
|
field_src_attr_->setEnabled(report_src_attr);
|
||||||
// for debug
|
// for debug
|
||||||
field_case_->setEnabled(false);
|
field_case_->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
@ -713,7 +717,7 @@ ReportPath::reportFull(const PathEndPathDelay *end)
|
||||||
const Path *tgt_clk_path = end->targetClkPath();
|
const Path *tgt_clk_path = end->targetClkPath();
|
||||||
if (reportClkPath()
|
if (reportClkPath()
|
||||||
&& isPropagated(tgt_clk_path, tgt_clk))
|
&& isPropagated(tgt_clk_path, tgt_clk))
|
||||||
reportTgtClk(end, delay);
|
reportTgtClk(end, delay, 0.0, true);
|
||||||
else {
|
else {
|
||||||
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
||||||
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
||||||
|
|
@ -2130,6 +2134,15 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
||||||
bool is_prop)
|
bool is_prop)
|
||||||
{
|
{
|
||||||
float src_offset = end->sourceClkOffset(this);
|
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);
|
const ClockEdge *clk_edge = end->targetClkEdge(this);
|
||||||
Clock *clk = clk_edge->clock();
|
Clock *clk = clk_edge->clock();
|
||||||
const RiseFall *clk_rf = clk_edge->transition();
|
const RiseFall *clk_rf = clk_edge->transition();
|
||||||
|
|
@ -2395,11 +2408,16 @@ ReportPath::reportPathLine(const Path *path,
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||||
Slew slew = graph_->slew(vertex, rf, ap_index);
|
Slew slew = graph_->slew(vertex, rf, ap_index);
|
||||||
float cap = field_blank_;
|
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.
|
// Don't show capacitance field for input pins.
|
||||||
if (is_driver && field_capacitance_->enabled())
|
if (is_driver && field_capacitance_->enabled())
|
||||||
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
|
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
|
||||||
reportLine(what.c_str(), cap, slew, field_blank_,
|
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
|
void
|
||||||
|
|
@ -2655,6 +2673,10 @@ ReportPath::reportPath5(const Path *path,
|
||||||
const char *line_case = nullptr;
|
const char *line_case = nullptr;
|
||||||
bool is_clk_start = path1->vertex(this) == clk_start;
|
bool is_clk_start = path1->vertex(this) == clk_start;
|
||||||
bool is_clk = path1->isClock(search_);
|
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).
|
// Always show the search start point (register clk pin).
|
||||||
// Skip reporting the clk tree unless it is requested.
|
// Skip reporting the clk tree unless it is requested.
|
||||||
if (is_clk_start
|
if (is_clk_start
|
||||||
|
|
@ -2750,7 +2772,8 @@ ReportPath::reportPath5(const Path *path,
|
||||||
auto what = descriptionField(vertex);
|
auto what = descriptionField(vertex);
|
||||||
if (report_net_ && is_driver) {
|
if (report_net_ && is_driver) {
|
||||||
reportLine(what.c_str(), cap, slew, fanout,
|
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;
|
string what2;
|
||||||
if (network_->isTopLevelPort(pin)) {
|
if (network_->isTopLevelPort(pin)) {
|
||||||
const char *pin_name = cmd_network_->pathName(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_,
|
reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
|
||||||
field_blank_, field_blank_, false, min_max,
|
field_blank_, field_blank_, false, min_max,
|
||||||
nullptr, line_case);
|
nullptr, src_attr, line_case);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
reportLine(what.c_str(), cap, slew, fanout,
|
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;
|
prev_time = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2956,7 +2980,8 @@ ReportPath::reportLine(const char *what,
|
||||||
const EarlyLate *early_late)
|
const EarlyLate *early_late)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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.
|
// Report negative total.
|
||||||
|
|
@ -2966,7 +2991,8 @@ ReportPath::reportLineNegative(const char *what,
|
||||||
const EarlyLate *early_late)
|
const EarlyLate *early_late)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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.
|
// Report total, and transition suffix.
|
||||||
|
|
@ -2977,7 +3003,8 @@ ReportPath::reportLine(const char *what,
|
||||||
const RiseFall *rf)
|
const RiseFall *rf)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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.
|
// Report increment, and total.
|
||||||
|
|
@ -2988,7 +3015,8 @@ ReportPath::reportLine(const char *what,
|
||||||
const EarlyLate *early_late)
|
const EarlyLate *early_late)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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.
|
// Report increment, total, and transition suffix.
|
||||||
|
|
@ -3000,7 +3028,8 @@ ReportPath::reportLine(const char *what,
|
||||||
const RiseFall *rf)
|
const RiseFall *rf)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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.
|
// Report slew, increment, and total.
|
||||||
|
|
@ -3012,7 +3041,8 @@ ReportPath::reportLine(const char *what,
|
||||||
const EarlyLate *early_late)
|
const EarlyLate *early_late)
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, slew, field_blank_,
|
reportLine(what, field_blank_, slew, field_blank_,
|
||||||
incr, total, false, early_late, nullptr, nullptr);
|
incr, total, false, early_late, nullptr,
|
||||||
|
"", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3025,6 +3055,7 @@ ReportPath::reportLine(const char *what,
|
||||||
bool total_with_minus,
|
bool total_with_minus,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
|
string src_attr,
|
||||||
const char *line_case)
|
const char *line_case)
|
||||||
{
|
{
|
||||||
ReportFieldSeq::Iterator field_iter(fields_);
|
ReportFieldSeq::Iterator field_iter(fields_);
|
||||||
|
|
@ -3064,8 +3095,13 @@ ReportPath::reportLine(const char *what,
|
||||||
else if (field == field_edge_) {
|
else if (field == field_edge_) {
|
||||||
if (rf)
|
if (rf)
|
||||||
reportField(rf->shortName(), field, line);
|
reportField(rf->shortName(), field, line);
|
||||||
// Compatibility kludge; suppress trailing spaces.
|
else
|
||||||
else if (field_iter.hasNext())
|
reportFieldBlank(field, line);
|
||||||
|
}
|
||||||
|
else if (field == field_src_attr_) {
|
||||||
|
if (src_attr != "")
|
||||||
|
reportField(src_attr.c_str(), field, line);
|
||||||
|
else
|
||||||
reportFieldBlank(field, line);
|
reportFieldBlank(field, line);
|
||||||
}
|
}
|
||||||
else if (field == field_case_ && line_case)
|
else if (field == field_case_ && line_case)
|
||||||
|
|
@ -3075,7 +3111,10 @@ ReportPath::reportLine(const char *what,
|
||||||
}
|
}
|
||||||
field_index++;
|
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_net,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout);
|
bool report_fanout,
|
||||||
|
bool report_src_attr);
|
||||||
int digits() const { return digits_; }
|
int digits() const { return digits_; }
|
||||||
void setDigits(int digits);
|
void setDigits(int digits);
|
||||||
void setNoSplit(bool no_split);
|
void setNoSplit(bool no_split);
|
||||||
|
|
@ -148,6 +149,7 @@ public:
|
||||||
ReportField *fieldSlew() const { return field_slew_; }
|
ReportField *fieldSlew() const { return field_slew_; }
|
||||||
ReportField *fieldFanout() const { return field_fanout_; }
|
ReportField *fieldFanout() const { return field_fanout_; }
|
||||||
ReportField *fieldCapacitance() const { return field_capacitance_; }
|
ReportField *fieldCapacitance() const { return field_capacitance_; }
|
||||||
|
ReportField *fieldSrcAttr() const { return field_src_attr_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void makeFields();
|
void makeFields();
|
||||||
|
|
@ -213,6 +215,10 @@ protected:
|
||||||
void reportTgtClk(const PathEnd *end,
|
void reportTgtClk(const PathEnd *end,
|
||||||
float prev_time,
|
float prev_time,
|
||||||
bool is_prop);
|
bool is_prop);
|
||||||
|
void reportTgtClk(const PathEnd *end,
|
||||||
|
float prev_time,
|
||||||
|
float src_offset,
|
||||||
|
bool is_prop);
|
||||||
bool pathFromGenPropClk(const Path *clk_path,
|
bool pathFromGenPropClk(const Path *clk_path,
|
||||||
const EarlyLate *early_late);
|
const EarlyLate *early_late);
|
||||||
bool isGenPropClk(const Clock *clk,
|
bool isGenPropClk(const Clock *clk,
|
||||||
|
|
@ -345,6 +351,7 @@ protected:
|
||||||
bool total_with_minus,
|
bool total_with_minus,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
|
string src_attr,
|
||||||
const char *line_case);
|
const char *line_case);
|
||||||
void reportLineTotal(const char *what,
|
void reportLineTotal(const char *what,
|
||||||
Delay incr,
|
Delay incr,
|
||||||
|
|
@ -461,6 +468,7 @@ protected:
|
||||||
ReportField *field_capacitance_;
|
ReportField *field_capacitance_;
|
||||||
ReportField *field_slew_;
|
ReportField *field_slew_;
|
||||||
ReportField *field_fanout_;
|
ReportField *field_fanout_;
|
||||||
|
ReportField *field_src_attr_;
|
||||||
ReportField *field_edge_;
|
ReportField *field_edge_;
|
||||||
ReportField *field_case_;
|
ReportField *field_case_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -403,7 +403,7 @@ Search::deletePaths()
|
||||||
VertexIterator vertex_iter(graph_);
|
VertexIterator vertex_iter(graph_);
|
||||||
while (vertex_iter.hasNext()) {
|
while (vertex_iter.hasNext()) {
|
||||||
Vertex *vertex = vertex_iter.next();
|
Vertex *vertex = vertex_iter.next();
|
||||||
vertex->deletePaths();
|
deletePaths(vertex);
|
||||||
}
|
}
|
||||||
filtered_arrivals_->clear();
|
filtered_arrivals_->clear();
|
||||||
graph_->clearArrivals();
|
graph_->clearArrivals();
|
||||||
|
|
@ -412,13 +412,24 @@ Search::deletePaths()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete with incremental tns/wns update.
|
||||||
void
|
void
|
||||||
Search::deletePaths(Vertex *vertex)
|
Search::deletePathsIncr(Vertex *vertex)
|
||||||
{
|
{
|
||||||
tnsNotifyBefore(vertex);
|
tnsNotifyBefore(vertex);
|
||||||
if (worst_slacks_)
|
if (worst_slacks_)
|
||||||
worst_slacks_->worstSlackNotifyBefore(vertex);
|
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_) {
|
for (Vertex *vertex : *filtered_arrivals_) {
|
||||||
if (isClock(vertex))
|
if (isClock(vertex))
|
||||||
clk_arrivals_valid_ = false;
|
clk_arrivals_valid_ = false;
|
||||||
deletePaths(vertex);
|
deletePathsIncr(vertex);
|
||||||
arrivalInvalid(vertex);
|
arrivalInvalid(vertex);
|
||||||
requiredInvalid(vertex);
|
requiredInvalid(vertex);
|
||||||
}
|
}
|
||||||
|
|
@ -677,7 +688,7 @@ void
|
||||||
Search::deleteVertexBefore(Vertex *vertex)
|
Search::deleteVertexBefore(Vertex *vertex)
|
||||||
{
|
{
|
||||||
if (arrivals_exist_) {
|
if (arrivals_exist_) {
|
||||||
deletePaths(vertex);
|
deletePathsIncr(vertex);
|
||||||
arrival_iter_->deleteVertexBefore(vertex);
|
arrival_iter_->deleteVertexBefore(vertex);
|
||||||
invalid_arrivals_->erase(vertex);
|
invalid_arrivals_->erase(vertex);
|
||||||
filtered_arrivals_->erase(vertex);
|
filtered_arrivals_->erase(vertex);
|
||||||
|
|
@ -759,7 +770,7 @@ void
|
||||||
Search::arrivalInvalidDelete(Vertex *vertex)
|
Search::arrivalInvalidDelete(Vertex *vertex)
|
||||||
{
|
{
|
||||||
arrivalInvalid(vertex);
|
arrivalInvalid(vertex);
|
||||||
vertex->deletePaths();
|
deletePaths(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1239,6 +1250,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *,
|
Edge *,
|
||||||
TimingArc *,
|
TimingArc *,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -1268,7 +1280,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
|
||||||
if (tag_match == nullptr
|
if (tag_match == nullptr
|
||||||
|| delayGreater(to_arrival, arrival, min_max, this)) {
|
|| delayGreater(to_arrival, arrival, min_max, this)) {
|
||||||
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
|
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
|
||||||
delayAsString(from_path->arrival(this), this),
|
delayAsString(from_arrival, this),
|
||||||
delayAsString(arc_delay, this),
|
delayAsString(arc_delay, this),
|
||||||
delayAsString(to_arrival, this),
|
delayAsString(to_arrival, this),
|
||||||
min_max == MinMax::max() ? ">" : "<",
|
min_max == MinMax::max() ? ">" : "<",
|
||||||
|
|
@ -1456,7 +1468,7 @@ Search::seedArrival(Vertex *vertex)
|
||||||
setVertexArrivals(vertex, &tag_bldr);
|
setVertexArrivals(vertex, &tag_bldr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deletePaths(vertex);
|
deletePathsIncr(vertex);
|
||||||
if (search_adj_->searchFrom(vertex))
|
if (search_adj_->searchFrom(vertex))
|
||||||
arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_);
|
arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_);
|
||||||
}
|
}
|
||||||
|
|
@ -2199,7 +2211,8 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (to_tag)
|
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,
|
edge, arc, arc_delay,
|
||||||
to_vertex, to_rf, to_tag, to_arrival,
|
to_vertex, to_rf, to_tag, to_arrival,
|
||||||
min_max, path_ap);
|
min_max, path_ap);
|
||||||
|
|
@ -2661,7 +2674,7 @@ Search::setVertexArrivals(Vertex *vertex,
|
||||||
TagGroupBldr *tag_bldr)
|
TagGroupBldr *tag_bldr)
|
||||||
{
|
{
|
||||||
if (tag_bldr->empty())
|
if (tag_bldr->empty())
|
||||||
deletePaths(vertex);
|
deletePathsIncr(vertex);
|
||||||
else {
|
else {
|
||||||
TagGroup *prev_tag_group = tagGroup(vertex);
|
TagGroup *prev_tag_group = tagGroup(vertex);
|
||||||
Arrival *prev_arrivals = graph_->arrivals(vertex);
|
Arrival *prev_arrivals = graph_->arrivals(vertex);
|
||||||
|
|
@ -2680,7 +2693,7 @@ Search::setVertexArrivals(Vertex *vertex,
|
||||||
else {
|
else {
|
||||||
// Prev paths not required.
|
// Prev paths not required.
|
||||||
prev_paths = nullptr;
|
prev_paths = nullptr;
|
||||||
vertex->setPrevPaths(prev_path_null);
|
graph_->deletePrevPaths(vertex, arrival_count);
|
||||||
}
|
}
|
||||||
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
|
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
|
||||||
vertex->setTagGroupIndex(tag_group->index());
|
vertex->setTagGroupIndex(tag_group->index());
|
||||||
|
|
@ -3477,6 +3490,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *,
|
TimingArc *,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
|
||||||
|
|
@ -504,13 +504,15 @@ set_report_path_fields(bool report_input_pin,
|
||||||
bool report_net,
|
bool report_net,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout)
|
bool report_fanout,
|
||||||
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
Sta::sta()->setReportPathFields(report_input_pin,
|
Sta::sta()->setReportPathFields(report_input_pin,
|
||||||
report_net,
|
report_net,
|
||||||
report_cap,
|
report_cap,
|
||||||
report_slew,
|
report_slew,
|
||||||
report_fanout);
|
report_fanout,
|
||||||
|
report_src_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -401,8 +401,8 @@ define_cmd_args "report_checks" \
|
||||||
[-slack_min slack_min]\
|
[-slack_min slack_min]\
|
||||||
[-sort_by_slack]\
|
[-sort_by_slack]\
|
||||||
[-path_group group_name]\
|
[-path_group group_name]\
|
||||||
[-format full|full_clock|full_clock_expanded|short|end|summary]\
|
[-format full|full_clock|full_clock_expanded|short|end|slack_only|summary|json]\
|
||||||
[-fields capacitance|slew|input_pin|net]\
|
[-fields capacitance|slew|input_pin|net|src_attr]\
|
||||||
[-digits digits]\
|
[-digits digits]\
|
||||||
[-no_line_splits]\
|
[-no_line_splits]\
|
||||||
[> filename] [>> filename]}
|
[> 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_net [expr [lsearch $fields "net*"] != -1]
|
||||||
set report_slew [expr [lsearch $fields "slew*"] != -1]
|
set report_slew [expr [lsearch $fields "slew*"] != -1]
|
||||||
set report_fanout [expr [lsearch $fields "fanout*"] != -1]
|
set report_fanout [expr [lsearch $fields "fanout*"] != -1]
|
||||||
|
set report_src_attr [expr [lsearch $fields "src_attr*"] != -1]
|
||||||
} else {
|
} else {
|
||||||
set report_input_pin 0
|
set report_input_pin 0
|
||||||
set report_cap 0
|
set report_cap 0
|
||||||
set report_net 0
|
set report_net 0
|
||||||
set report_slew 0
|
set report_slew 0
|
||||||
set report_fanout 0
|
set report_fanout 0
|
||||||
|
set report_src_attr 0
|
||||||
}
|
}
|
||||||
set_report_path_fields $report_input_pin $report_net \
|
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)]
|
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_net,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout)
|
bool report_fanout,
|
||||||
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
report_path_->setReportFields(report_input_pin, report_net, report_cap,
|
report_path_->setReportFields(report_input_pin, report_net, report_cap,
|
||||||
report_slew, report_fanout);
|
report_slew, report_fanout, report_src_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportField *
|
ReportField *
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ protected:
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
ArcDelay arc_delay,
|
ArcDelay arc_delay,
|
||||||
|
|
@ -254,6 +255,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
PathVertex *from_path,
|
||||||
|
const Arrival &,
|
||||||
Edge *,
|
Edge *,
|
||||||
TimingArc *,
|
TimingArc *,
|
||||||
ArcDelay ,
|
ArcDelay ,
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ proc run_test_plain { test cmd_file log_file } {
|
||||||
cleanse_logfile $test $log_file
|
cleanse_logfile $test $log_file
|
||||||
return "ERROR $error"
|
return "ERROR $error"
|
||||||
}
|
}
|
||||||
|
file delete $run_file
|
||||||
cleanse_logfile $test $log_file
|
cleanse_logfile $test $log_file
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ record_sta_tests {
|
||||||
get_filter
|
get_filter
|
||||||
get_noargs
|
get_noargs
|
||||||
get_objrefs
|
get_objrefs
|
||||||
|
report_checks_src_attr
|
||||||
}
|
}
|
||||||
|
|
||||||
define_test_group fast [group_tests all]
|
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
|
# 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
|
read_verilog verilog_attribute.v
|
||||||
link_design counter
|
link_design counter
|
||||||
create_clock -name clk [get_ports clk] -period 50
|
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" *)
|
(* src = "synthesis/tests/counter.v:18.14-18.19" *)
|
||||||
input reset;
|
input reset;
|
||||||
input in;
|
input in;
|
||||||
|
(* bottom_bound = 1'sh0 *)
|
||||||
(* src = "synthesis/tests/counter.v:22.3-28.6", attr1 = "test_attr1", attr2 = "test_attr2" *)
|
(* src = "synthesis/tests/counter.v:22.3-28.6", attr1 = "test_attr1", attr2 = "test_attr2" *)
|
||||||
sky130_fd_sc_hd__dfrtp_1 _1415_ (
|
sky130_fd_sc_hd__dfrtp_1 _1415_ (
|
||||||
.CLK(clk),
|
.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);
|
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
||||||
return CONSTANT;
|
return CONSTANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
{SIGN}?{UNSIGNED_NUMBER}?"'"[oO][0-7_xz]+ {
|
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[oO][0-7_xz]+ {
|
||||||
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
||||||
return CONSTANT;
|
return CONSTANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
{SIGN}?{UNSIGNED_NUMBER}?"'"[dD][0-9_]+ {
|
{SIGN}?{UNSIGNED_NUMBER}?"'"[sS]?[dD][0-9_]+ {
|
||||||
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
||||||
return CONSTANT;
|
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);
|
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
||||||
return CONSTANT;
|
return CONSTANT;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,31 +41,35 @@ public:
|
||||||
CellSeq *remove_cells,
|
CellSeq *remove_cells,
|
||||||
FILE *stream,
|
FILE *stream,
|
||||||
Network *network);
|
Network *network);
|
||||||
void writeModule(Instance *inst);
|
void writeModules();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void writePorts(Cell *cell);
|
void writeModule(const Instance *inst);
|
||||||
void writePortDcls(Cell *cell);
|
InstanceSeq findHierChildren();
|
||||||
void writeWireDcls(Instance *inst);
|
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);
|
const char *verilogPortDir(PortDirection *dir);
|
||||||
void writeChildren(Instance *inst);
|
void writeChildren(const Instance *inst);
|
||||||
void writeChild(Instance *child);
|
void writeChild(const Instance *child);
|
||||||
void writeInstPin(Instance *inst,
|
void writeInstPin(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_port);
|
bool &first_port);
|
||||||
void writeInstBusPin(Instance *inst,
|
void writeInstBusPin(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_port);
|
bool &first_port);
|
||||||
void writeInstBusPinBit(Instance *inst,
|
void writeInstBusPinBit(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_member);
|
bool &first_member);
|
||||||
void writeAssigns(Instance *inst);
|
void writeAssigns(const Instance *inst);
|
||||||
|
|
||||||
int findUnconnectedNetCount();
|
int findUnconnectedNetCount(const Instance *inst);
|
||||||
int findNCcount(Instance *inst);
|
int findChildNCcount(const Instance *child);
|
||||||
int findChildNCcount(Instance *child);
|
int findPortNCcount(const Instance *inst,
|
||||||
int findPortNCcount(Instance *inst,
|
const Port *port);
|
||||||
Port *port);
|
|
||||||
|
|
||||||
const char *filename_;
|
const char *filename_;
|
||||||
bool sort_;
|
bool sort_;
|
||||||
|
|
@ -73,9 +77,6 @@ protected:
|
||||||
CellSet remove_cells_;
|
CellSet remove_cells_;
|
||||||
FILE *stream_;
|
FILE *stream_;
|
||||||
Network *network_;
|
Network *network_;
|
||||||
|
|
||||||
CellSet written_cells_;
|
|
||||||
Vector<Instance*> pending_children_;
|
|
||||||
int unconnected_net_index_;
|
int unconnected_net_index_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -91,7 +92,7 @@ writeVerilog(const char *filename,
|
||||||
if (stream) {
|
if (stream) {
|
||||||
VerilogWriter writer(filename, sort, include_pwr_gnd,
|
VerilogWriter writer(filename, sort, include_pwr_gnd,
|
||||||
remove_cells, stream, network);
|
remove_cells, stream, network);
|
||||||
writer.writeModule(network->topInstance());
|
writer.writeModules();
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -111,7 +112,6 @@ VerilogWriter::VerilogWriter(const char *filename,
|
||||||
remove_cells_(network),
|
remove_cells_(network),
|
||||||
stream_(stream),
|
stream_(stream),
|
||||||
network_(network),
|
network_(network),
|
||||||
written_cells_(network),
|
|
||||||
unconnected_net_index_(1)
|
unconnected_net_index_(1)
|
||||||
{
|
{
|
||||||
if (remove_cells) {
|
if (remove_cells) {
|
||||||
|
|
@ -121,7 +121,54 @@ VerilogWriter::VerilogWriter(const char *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
Cell *cell = network_->cell(inst);
|
||||||
fprintf(stream_, "module %s (",
|
fprintf(stream_, "module %s (",
|
||||||
|
|
@ -134,22 +181,10 @@ VerilogWriter::writeModule(Instance *inst)
|
||||||
writeChildren(inst);
|
writeChildren(inst);
|
||||||
writeAssigns(inst);
|
writeAssigns(inst);
|
||||||
fprintf(stream_, "endmodule\n");
|
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
|
void
|
||||||
VerilogWriter::writePorts(Cell *cell)
|
VerilogWriter::writePorts(const Cell *cell)
|
||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
CellPortIterator *port_iter = network_->portIterator(cell);
|
CellPortIterator *port_iter = network_->portIterator(cell);
|
||||||
|
|
@ -170,7 +205,7 @@ VerilogWriter::writePorts(Cell *cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writePortDcls(Cell *cell)
|
VerilogWriter::writePortDcls(const Cell *cell)
|
||||||
{
|
{
|
||||||
CellPortIterator *port_iter = network_->portIterator(cell);
|
CellPortIterator *port_iter = network_->portIterator(cell);
|
||||||
while (port_iter->hasNext()) {
|
while (port_iter->hasNext()) {
|
||||||
|
|
@ -228,7 +263,7 @@ VerilogWriter::verilogPortDir(PortDirection *dir)
|
||||||
typedef std::pair<int, int> BusIndexRange;
|
typedef std::pair<int, int> BusIndexRange;
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeWireDcls(Instance *inst)
|
VerilogWriter::writeWireDcls(const Instance *inst)
|
||||||
{
|
{
|
||||||
Cell *cell = network_->cell(inst);
|
Cell *cell = network_->cell(inst);
|
||||||
char escape = network_->pathEscape();
|
char escape = network_->pathEscape();
|
||||||
|
|
@ -268,22 +303,19 @@ VerilogWriter::writeWireDcls(Instance *inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wire net dcls for writeInstBusPinBit.
|
// Wire net dcls for writeInstBusPinBit.
|
||||||
int nc_count = findUnconnectedNetCount();
|
int nc_count = findUnconnectedNetCount(inst);
|
||||||
for (int i = 1; i < nc_count + 1; i++)
|
for (int i = 1; i < nc_count + 1; i++)
|
||||||
fprintf(stream_, " wire _NC%d;\n", i);
|
fprintf(stream_, " wire _NC%d;\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeChildren(Instance *inst)
|
VerilogWriter::writeChildren(const Instance *inst)
|
||||||
{
|
{
|
||||||
Vector<Instance*> children;
|
Vector<Instance*> children;
|
||||||
InstanceChildIterator *child_iter = network_->childIterator(inst);
|
InstanceChildIterator *child_iter = network_->childIterator(inst);
|
||||||
while (child_iter->hasNext()) {
|
while (child_iter->hasNext()) {
|
||||||
Instance *child = child_iter->next();
|
Instance *child = child_iter->next();
|
||||||
children.push_back(child);
|
children.push_back(child);
|
||||||
if (network_->isHierarchical(child)) {
|
|
||||||
pending_children_.push_back(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
delete child_iter;
|
delete child_iter;
|
||||||
|
|
||||||
|
|
@ -298,7 +330,7 @@ VerilogWriter::writeChildren(Instance *inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeChild(Instance *child)
|
VerilogWriter::writeChild(const Instance *child)
|
||||||
{
|
{
|
||||||
Cell *child_cell = network_->cell(child);
|
Cell *child_cell = network_->cell(child);
|
||||||
if (!remove_cells_.hasKey(child_cell)) {
|
if (!remove_cells_.hasKey(child_cell)) {
|
||||||
|
|
@ -325,8 +357,8 @@ VerilogWriter::writeChild(Instance *child)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeInstPin(Instance *inst,
|
VerilogWriter::writeInstPin(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_port)
|
bool &first_port)
|
||||||
{
|
{
|
||||||
Pin *pin = network_->findPin(inst, port);
|
Pin *pin = network_->findPin(inst, port);
|
||||||
|
|
@ -348,8 +380,8 @@ VerilogWriter::writeInstPin(Instance *inst,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeInstBusPin(Instance *inst,
|
VerilogWriter::writeInstBusPin(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_port)
|
bool &first_port)
|
||||||
{
|
{
|
||||||
if (!first_port)
|
if (!first_port)
|
||||||
|
|
@ -382,8 +414,8 @@ VerilogWriter::writeInstBusPin(Instance *inst,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VerilogWriter::writeInstBusPinBit(Instance *inst,
|
VerilogWriter::writeInstBusPinBit(const Instance *inst,
|
||||||
Port *port,
|
const Port *port,
|
||||||
bool &first_member)
|
bool &first_member)
|
||||||
{
|
{
|
||||||
Pin *pin = network_->findPin(inst, port);
|
Pin *pin = network_->findPin(inst, port);
|
||||||
|
|
@ -405,12 +437,13 @@ VerilogWriter::writeInstBusPinBit(Instance *inst,
|
||||||
// Use an assign statement to alias the net when it is connected to
|
// Use an assign statement to alias the net when it is connected to
|
||||||
// multiple output ports.
|
// multiple output ports.
|
||||||
void
|
void
|
||||||
VerilogWriter::writeAssigns(Instance *inst)
|
VerilogWriter::writeAssigns(const Instance *inst)
|
||||||
{
|
{
|
||||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||||
while (pin_iter->hasNext()) {
|
while (pin_iter->hasNext()) {
|
||||||
Pin *pin = pin_iter->next();
|
Pin *pin = pin_iter->next();
|
||||||
Term *term = network_->term(pin);
|
Term *term = network_->term(pin);
|
||||||
|
if (term) {
|
||||||
Net *net = network_->net(term);
|
Net *net = network_->net(term);
|
||||||
Port *port = network_->port(pin);
|
Port *port = network_->port(pin);
|
||||||
if (port
|
if (port
|
||||||
|
|
@ -429,21 +462,14 @@ VerilogWriter::writeAssigns(Instance *inst)
|
||||||
net_vname.c_str());
|
net_vname.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
delete pin_iter;
|
delete pin_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Walk the hierarch counting unconnected nets used to connect to
|
|
||||||
// bus ports with concatenation.
|
|
||||||
int
|
int
|
||||||
VerilogWriter::findUnconnectedNetCount()
|
VerilogWriter::findUnconnectedNetCount(const Instance *inst)
|
||||||
{
|
|
||||||
return findNCcount(network_->topInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
VerilogWriter::findNCcount(Instance *inst)
|
|
||||||
{
|
{
|
||||||
int nc_count = 0;
|
int nc_count = 0;
|
||||||
InstanceChildIterator *child_iter = network_->childIterator(inst);
|
InstanceChildIterator *child_iter = network_->childIterator(inst);
|
||||||
|
|
@ -456,7 +482,7 @@ VerilogWriter::findNCcount(Instance *inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
VerilogWriter::findChildNCcount(Instance *child)
|
VerilogWriter::findChildNCcount(const Instance *child)
|
||||||
{
|
{
|
||||||
int nc_count = 0;
|
int nc_count = 0;
|
||||||
Cell *child_cell = network_->cell(child);
|
Cell *child_cell = network_->cell(child);
|
||||||
|
|
@ -473,8 +499,8 @@ VerilogWriter::findChildNCcount(Instance *child)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
VerilogWriter::findPortNCcount(Instance *inst,
|
VerilogWriter::findPortNCcount(const Instance *inst,
|
||||||
Port *port)
|
const Port *port)
|
||||||
{
|
{
|
||||||
int nc_count = 0;
|
int nc_count = 0;
|
||||||
LibertyPort *lib_port = network_->libertyPort(port);
|
LibertyPort *lib_port = network_->libertyPort(port);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue