Merge remote-tracking branch 'parallax/master'
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
commit
1c7f022cd0
|
|
@ -80,6 +80,7 @@ set(STA_SOURCE
|
|||
dcalc/LumpedCapDelayCalc.cc
|
||||
dcalc/NetCaps.cc
|
||||
dcalc/ParallelDelayCalc.cc
|
||||
dcalc/PrimaDelayCalc.cc
|
||||
dcalc/UnitDelayCalc.cc
|
||||
|
||||
graph/DelayFloat.cc
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "ArnoldiDelayCalc.hh"
|
||||
#include "CcsCeffDelayCalc.hh"
|
||||
#include "CcsSimDelayCalc.hh"
|
||||
#include "PrimaDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
@ -41,6 +42,7 @@ registerDelayCalcs()
|
|||
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
|
||||
registerDelayCalc("ccs_ceff", makeCcsCeffDelayCalc);
|
||||
registerDelayCalc("ccs_sim", makeCcsSimDelayCalc);
|
||||
registerDelayCalc("prima", makePrimaDelayCalc);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "Sta.hh"
|
||||
#include "ArcDelayCalc.hh"
|
||||
#include "dcalc/ArcDcalcWaveforms.hh"
|
||||
#include "dcalc/PrimaDelayCalc.hh"
|
||||
|
||||
%}
|
||||
|
||||
|
|
@ -133,4 +134,16 @@ ccs_load_waveform(const Pin *in_pin,
|
|||
return Table1();
|
||||
}
|
||||
|
||||
void
|
||||
set_prima_reduce_order(size_t order)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
Sta *sta = Sta::sta();
|
||||
PrimaDelayCalc *dcalc = dynamic_cast<PrimaDelayCalc*>(sta->arcDelayCalc());
|
||||
if (dcalc) {
|
||||
dcalc->setPrimaReduceOrder(order);
|
||||
sta->delaysInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
%} // inline
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,263 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <Eigen/SparseCore>
|
||||
#include <Eigen/SparseLU>
|
||||
|
||||
#include "Map.hh"
|
||||
#include "LumpedCapDelayCalc.hh"
|
||||
#include "ArcDcalcWaveforms.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class ArcDelayCalc;
|
||||
class StaState;
|
||||
class Corner;
|
||||
|
||||
using std::vector;
|
||||
using std::array;
|
||||
using Eigen::MatrixXd;
|
||||
using Eigen::MatrixXcd;
|
||||
using Eigen::VectorXd;
|
||||
using Eigen::SparseMatrix;
|
||||
using Eigen::Index;
|
||||
using std::map;
|
||||
|
||||
typedef Map<const Pin*, size_t, PinIdLess> PinNodeMap;
|
||||
typedef Map<const ParasiticNode*, size_t> NodeIndexMap;
|
||||
typedef Map<const Pin*, size_t> PortIndexMap;
|
||||
typedef SparseMatrix<double> MatrixSd;
|
||||
typedef Map<const Pin*, VectorXd, PinIdLess> PinLMap;
|
||||
typedef map<const Pin*, FloatSeq, PinIdLess> WatchPinValuesMap;
|
||||
|
||||
typedef Table1 Waveform;
|
||||
|
||||
ArcDelayCalc *
|
||||
makePrimaDelayCalc(StaState *sta);
|
||||
|
||||
class PrimaDelayCalc : public DelayCalcBase,
|
||||
public ArcDcalcWaveforms
|
||||
{
|
||||
public:
|
||||
PrimaDelayCalc(StaState *sta);
|
||||
PrimaDelayCalc(const PrimaDelayCalc &dcalc);
|
||||
~PrimaDelayCalc();
|
||||
ArcDelayCalc *copy() override;
|
||||
void copyState(const StaState *sta) override;
|
||||
void setPrimaReduceOrder(size_t order);
|
||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
ArcDcalcResult inputPortDelay(const Pin *drvr_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const LoadPinIndexMap &load_pin_index_map,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||
const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *parasitic,
|
||||
const LoadPinIndexMap &load_pin_index_map,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
|
||||
float load_cap,
|
||||
const LoadPinIndexMap &load_pin_index_map,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
string reportGateDelay(const Pin *drvr_pin,
|
||||
const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *parasitic,
|
||||
const LoadPinIndexMap &load_pin_index_map,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
int digits) override;
|
||||
|
||||
// Record waveform for drvr/load pin.
|
||||
void watchPin(const Pin *pin);
|
||||
void clearWatchPins();
|
||||
PinSeq watchPins() const;
|
||||
Waveform watchWaveform(const Pin *pin);
|
||||
|
||||
Waveform inputWaveform(const Pin *in_pin,
|
||||
const RiseFall *in_rf,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max) override;
|
||||
Waveform drvrWaveform(const Pin *in_pin,
|
||||
const RiseFall *in_rf,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *drvr_rf,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max) override;
|
||||
Waveform loadWaveform(const Pin *in_pin,
|
||||
const RiseFall *in_rf,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *drvr_rf,
|
||||
const Pin *load_pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max) override;
|
||||
|
||||
protected:
|
||||
ArcDcalcResultSeq tableDcalcResults(float load_cap);
|
||||
void simulate();
|
||||
void simulate1(const MatrixSd &G,
|
||||
const MatrixSd &C,
|
||||
const MatrixXd &B,
|
||||
const VectorXd &x_init,
|
||||
const MatrixXd &x_to_v,
|
||||
const size_t order);
|
||||
double maxTime();
|
||||
double timeStep();
|
||||
float driverResistance();
|
||||
void updateCeffIdrvr();
|
||||
void initSim();
|
||||
void findLoads();
|
||||
void findNodeCount();
|
||||
void setOrder();
|
||||
void initCeffIdrvr();
|
||||
void setXinit();
|
||||
void stampEqns();
|
||||
void stampConductance(size_t n1,
|
||||
double g);
|
||||
void stampConductance(size_t n1,
|
||||
size_t n2,
|
||||
double g);
|
||||
void stampCapacitance(size_t n1,
|
||||
double cap);
|
||||
void stampCapacitance(size_t n1,
|
||||
size_t n2,
|
||||
double cap);
|
||||
float pinCapacitance(ParasiticNode *node);
|
||||
void setPortCurrents();
|
||||
void measureThresholds(double time);
|
||||
double voltage(const Pin *pin);
|
||||
double voltage(size_t node_idx);
|
||||
double voltagePrev(size_t node_idx);
|
||||
bool loadWaveformsFinished();
|
||||
ArcDcalcResultSeq dcalcResults();
|
||||
|
||||
void recordWaveformStep(double time);
|
||||
void makeWaveforms(const Pin *in_pin,
|
||||
const RiseFall *in_rf,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *drvr_rf,
|
||||
const Pin *load_pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void primaReduce();
|
||||
void primaReduce2();
|
||||
|
||||
void reportMatrix(const char *name,
|
||||
MatrixSd &matrix);
|
||||
void reportMatrix(const char *name,
|
||||
MatrixXd &matrix);
|
||||
void reportMatrix(const char *name,
|
||||
VectorXd &matrix);
|
||||
void reportVector(const char *name,
|
||||
vector<double> &matrix);
|
||||
void reportMatrix(MatrixSd &matrix);
|
||||
void reportMatrix(MatrixXd &matrix);
|
||||
void reportMatrix(VectorXd &matrix);
|
||||
void reportVector(vector<double> &matrix);
|
||||
|
||||
ArcDcalcArgSeq *dcalc_args_;
|
||||
size_t drvr_count_;
|
||||
float load_cap_;
|
||||
const DcalcAnalysisPt *dcalc_ap_;
|
||||
const Parasitic *parasitic_network_;
|
||||
const RiseFall *drvr_rf_;
|
||||
const LoadPinIndexMap *load_pin_index_map_;
|
||||
|
||||
PinNodeMap pin_node_map_; // Parasitic pin -> array index
|
||||
NodeIndexMap node_index_map_; // Parasitic node -> array index
|
||||
vector<OutputWaveforms*> output_waveforms_;
|
||||
double resistance_sum_;
|
||||
|
||||
vector<double> node_capacitances_;
|
||||
bool includes_pin_caps_;
|
||||
float coupling_cap_multiplier_;
|
||||
|
||||
size_t node_count_; // Parasitic network node count
|
||||
size_t port_count_; // aka drvr_count_
|
||||
size_t order_; // node_count_ + port_count_
|
||||
|
||||
// MNA node eqns
|
||||
// G*x(t) + C*x'(t) = B*u(t)
|
||||
MatrixSd G_;
|
||||
MatrixSd C_;
|
||||
MatrixXd B_;
|
||||
VectorXd x_init_;
|
||||
VectorXd u_;
|
||||
|
||||
// Prima reduced MNA eqns
|
||||
size_t prima_order_;
|
||||
MatrixXd Vq_;
|
||||
MatrixSd Gq_;
|
||||
MatrixSd Cq_;
|
||||
MatrixXd Bq_;
|
||||
VectorXd xq_init_;
|
||||
|
||||
// Node voltages.
|
||||
VectorXd v_; // voltage[node_idx]
|
||||
VectorXd v_prev_;
|
||||
|
||||
// Indexed by driver index.
|
||||
vector<double> ceff_;
|
||||
vector<double> drvr_current_;
|
||||
|
||||
double time_step_;
|
||||
double time_step_prev_;
|
||||
|
||||
// Waveform recording.
|
||||
bool make_waveforms_;
|
||||
const Pin *waveform_drvr_pin_;
|
||||
const Pin *waveform_load_pin_;
|
||||
FloatSeq drvr_voltages_;
|
||||
FloatSeq load_voltages_;
|
||||
WatchPinValuesMap watch_pin_values_;
|
||||
FloatSeq times_;
|
||||
|
||||
float vdd_;
|
||||
float vth_;
|
||||
float vl_;
|
||||
float vh_;
|
||||
|
||||
static constexpr size_t threshold_vl = 0;
|
||||
static constexpr size_t threshold_vth = 1;
|
||||
static constexpr size_t threshold_vh = 2;
|
||||
static constexpr size_t measure_threshold_count_ = 3;
|
||||
typedef array<double, measure_threshold_count_> ThresholdTimes;
|
||||
// Vl Vth Vh
|
||||
ThresholdTimes measure_thresholds_;
|
||||
// Indexed by node number.
|
||||
vector<ThresholdTimes> threshold_times_;
|
||||
|
||||
// Delay calculator to use when ccs waveforms are missing from liberty.
|
||||
ArcDelayCalc *table_dcalc_;
|
||||
|
||||
using ArcDelayCalc::reduceParasitic;
|
||||
};
|
||||
|
||||
} // namespacet
|
||||
243
doc/StaApi.txt
243
doc/StaApi.txt
|
|
@ -15,8 +15,8 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
The STA is built in C++ with heavy use of STL (Standard Template
|
||||
Libraries). It also uses the zlib library to read compressed Verilog,
|
||||
SDF, SPF, and SPEF files.
|
||||
Libraries). It also uses the zlib library to read compressed Liberty,
|
||||
Verilog, SDF, SPF, and SPEF files.
|
||||
|
||||
The sub-directories of the STA code are:
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ search
|
|||
Search engine used to annotate the graph with arrival, required times
|
||||
and find timing check slacks.
|
||||
parasitics
|
||||
Parasitics API, Spef and Spf readers.
|
||||
Parasitics API, Spef and Spf readers.
|
||||
app
|
||||
Interface between Tcl and STA (built with SWIG).
|
||||
Main program definition.
|
||||
|
|
@ -60,43 +60,43 @@ STA API
|
|||
-------
|
||||
|
||||
Major components of the STA such as the network, timing graph, sdc,
|
||||
and search are implemented as separate classes. The Sta class
|
||||
and search are implemented as separate classes. The Sta class
|
||||
contains an instance of each of these components.
|
||||
|
||||
The Sta class defines the bulk of the externally visible API used by
|
||||
the Tcl interface, and coordinates operations that involve multiple
|
||||
components. For example, when a false path command is entered into
|
||||
components. For example, when a false path command is entered into
|
||||
the Tcl command interpreter, the Sta passes the declaration on to the
|
||||
Sdc component and tells the Search component to invalidate all arrival
|
||||
and required times.
|
||||
|
||||
Applications should call functions defined by the Sta class rather
|
||||
than functions defined by the components. Calling functions defined
|
||||
than functions defined by the components. Calling functions defined
|
||||
by the components will get you in trouble unless you understand them
|
||||
in detail. For example, telling the delay calculator to recompute the
|
||||
delays leaves the arrival times that depend on them wrong. Always
|
||||
in detail. For example, telling the delay calculator to recompute the
|
||||
delays leaves the arrival times that depend on them wrong. Always
|
||||
remember that the Sta coordinates the components.
|
||||
|
||||
In general, objects passed as arguments to Sta functions that are
|
||||
constructors become "owned" by the STA and should not be deleted by
|
||||
the caller. For example, a set of pins passed into
|
||||
the caller. For example, a set of pins passed into
|
||||
Sta::makeExceptionFrom are used in the resulting object (rather than
|
||||
copied into another set). On the other hand, strings passed as
|
||||
copied into another set). On the other hand, strings passed as
|
||||
arguments are copied by the Sta functions before they are retained in
|
||||
STA data structures.
|
||||
|
||||
In many cases the major components contain pointers to other
|
||||
components. The StaState class is a simple container for these
|
||||
components. The StaState class is a simple container for these
|
||||
components that makes initialization of pointers to the components
|
||||
easier.
|
||||
|
||||
An STA with modified behavior can be built by defining classes derived
|
||||
from the component classes and overloading some of the member
|
||||
functions (which may have to be modified to be virtual). Components
|
||||
are created by Sta::makeComponents(). The Sta::makeComponents()
|
||||
functions (which may have to be modified to be virtual). Components
|
||||
are created by Sta::makeComponents(). The Sta::makeComponents()
|
||||
function in turn calls each of the Sta::make<Component> component
|
||||
constructors. These constructors can be overloaded by redefining them
|
||||
in a class derived from Sta. Because the components refer to each
|
||||
constructors. These constructors can be overloaded by redefining them
|
||||
in a class derived from Sta. Because the components refer to each
|
||||
other, Sta::updateComponentsState() must be called to notify the
|
||||
components if any of them are changed after creation.
|
||||
|
||||
|
|
@ -121,19 +121,16 @@ Utilities
|
|||
---------
|
||||
|
||||
The most significant utilities are the Vector, Map and Set templated
|
||||
classes built on top the respective STL classes. The main point of
|
||||
classes built on top the respective STL classes. The main point of
|
||||
these classes is to provide Java-like iterators that can be passed
|
||||
around as one object. STL iterators require the container to be
|
||||
useful. Iterators uniformly use the hasNext() function to test to see
|
||||
around as one object. STL iterators require the container to be
|
||||
useful. Iterators uniformly use the hasNext() function to test to see
|
||||
if there is another member and next() to access the next iteration
|
||||
member.
|
||||
|
||||
Most printing is done in Tcl rather than the STA C++ code. Some
|
||||
errors and warnings are reported by the STA in C++
|
||||
|
||||
All printing done by the STA core is done using the Report class API.
|
||||
The report class supports output redirection to a file and logging to
|
||||
a file. The Tcl interpreter prints to "channels" that are
|
||||
a file. The Tcl interpreter prints to "channels" that are
|
||||
encapsulated by functions in the the ReportTcl class. Printing inside
|
||||
the STA is directed to the Tcl channels so that it appears with the
|
||||
Tcl interpreter output.
|
||||
|
|
@ -142,21 +139,22 @@ Network
|
|||
-------
|
||||
|
||||
The network API is the key to making the STA a timing engine that can
|
||||
be bolted onto another application. This API allows the STA to
|
||||
be bolted onto another application. This API allows the STA to
|
||||
efficiently communicate with external network data structures without
|
||||
the overhead of making and maintaining a copying of it.
|
||||
|
||||
The network API encapsulates both library and netlist accessors.
|
||||
Libraries are composed of cells that have ports the define connections
|
||||
to the cell. Netlists are built out of cell instances, pins and nets.
|
||||
Libraries are composed of cells that have ports that define connections
|
||||
to the cell. Netlists are built out of cell instances, pins and nets.
|
||||
|
||||
The ConcreteLibrary and ConcreteNetwork classes are used by the STA
|
||||
netlist readers. These class definitions are to support a stand alone
|
||||
STA that does not depend on external netlist data structures.
|
||||
netlist readers (notibly Verilog). These class definitions are to
|
||||
support a stand alone STA that does not depend on external netlist
|
||||
data structures.
|
||||
|
||||
External network data structures are interfaced to the STA by casting
|
||||
pointers to network object across the interface. The external objects
|
||||
do not have to be derived from STA network base classes. The network
|
||||
pointers to network objects across the interface. The external objects
|
||||
do not have to be derived from STA network base classes. The network
|
||||
API functions are typically very thin functions that cast the STA
|
||||
network types to the external class types and call the corresponding
|
||||
external network database accessor.
|
||||
|
|
@ -165,40 +163,40 @@ Bus ports are expanded into ports for each bit in the bus, and
|
|||
iterators are provided for the expanded and unexpanded set of cell
|
||||
ports.
|
||||
|
||||
Network instances are calls of cells in the design hierarchy. Both
|
||||
hierarchcial and leaf instances are in the network. Hierarchical
|
||||
Network instances are calls of cells in the design hierarchy. Both
|
||||
hierarchcial and leaf instances are in the network. Hierarchical
|
||||
instances have children instances at the next lower hierarchy level.
|
||||
Leaf instances have liberty cells with timing model data. At the top
|
||||
Leaf instances have liberty cells with timing model data. At the top
|
||||
of the hierarchy is a top level instance that has instances for the
|
||||
top level netlist. If a cell has multiple instances the entire
|
||||
sub-tree of hierarchy is repeated in the network. This "unfolded"
|
||||
top level netlist. If a cell has multiple instances the entire
|
||||
sub-tree of hierarchy is repeated in the network. This "unfolded"
|
||||
network representation allows optimization to specialize instances of
|
||||
a hierarchical block. A "folded" network representation that has only
|
||||
a hierarchical block. A "folded" network representation that has only
|
||||
one sub-tree for each hierarchical block means that all copies must
|
||||
have identical sub-trees, preventing optimations that specialize the
|
||||
contents.
|
||||
|
||||
Pins are a connection between an instance and a net corresponding to a
|
||||
port. For bus ports each bit in the bus has a corresponding pin
|
||||
port. For bus ports each bit in the bus has a corresponding pin
|
||||
(library iterators can be used to find the pins that correspond to all
|
||||
of the bits in a bus). Ports on the top level instance also have pins
|
||||
of the bits in a bus). Ports on the top level instance also have pins
|
||||
in the network that are the top level inputs and outputs.
|
||||
|
||||
Nets connect together a group of pins. Both hierarchical and leaf
|
||||
pins are on a net. Nets can connect pins on multiple levels of
|
||||
Nets connect together a group of pins. Both hierarchical and leaf
|
||||
pins are on a net. Nets can connect pins on multiple levels of
|
||||
hierarchy.
|
||||
|
||||
The network objects inside the STA are always pointers to instances of
|
||||
undefined class objects. The implementation and definition of the
|
||||
network objects themselves is never visible inside the STA. The
|
||||
undefined class objects. The implementation and definition of the
|
||||
network objects themselves is never visible inside the STA. The
|
||||
network API is implemented as an adapter that performs all operations
|
||||
on all network objects. There is one network adapter instance used by
|
||||
all STA code. For example, to find the cell of an instance
|
||||
on all network objects. There is one network adapter instance used by
|
||||
all STA code. For example, to find the cell of an instance
|
||||
|
||||
Cell *cell = network->cell(instance);
|
||||
|
||||
The network adapter returns iterators for looping over groups of
|
||||
network objects. For example, the following code iterates over the
|
||||
network objects. For example, the following code iterates over the
|
||||
children of the top level instance.
|
||||
|
||||
Instance *top_instance = network->topInstance();
|
||||
|
|
@ -211,13 +209,16 @@ children of the top level instance.
|
|||
|
||||
An adapter to a network database is built by defining a class derived
|
||||
from the base class Network, or NetworkEdit if it supports incremental
|
||||
editing operations. network/ConcreteNetwork.cc and oa/OaNetwork.cc
|
||||
are sample network adapters.
|
||||
editing operations. network/ConcreteNetwork.cc is a example of
|
||||
a network adapter the supports hierarchy. An example of a network adapter
|
||||
for a flat DEF based netlist, see
|
||||
https://github.com/The-OpenROAD-Project/OpenROAD/blob/master/src/dbSta/include/db_sta/dbNetwork.hh,
|
||||
https://github.com/The-OpenROAD-Project/OpenROAD/blob/master/src/dbSta/src/dbNetwork.cc.
|
||||
|
||||
A network adaptor to interface to an external network database must
|
||||
define the virtual functions of the Network class (about 45
|
||||
functions). The external network objects do not have to use any STA
|
||||
network objects as base classes or even be C++ objects. These network
|
||||
functions). The external network objects do not have to use any STA
|
||||
network objects as base classes or even be C++ objects. These network
|
||||
adapter functions should cast the network object pointers to the
|
||||
underlying network object.
|
||||
|
||||
|
|
@ -231,8 +232,7 @@ functions to find corresponding liberty objects.
|
|||
virtual LibertyPort *libertyPort(Port *port) const;
|
||||
|
||||
The NetworkLiberty class provides implementations of the first two
|
||||
functions for derived network classes. The OaNetwork class shows an
|
||||
implentation that uses the NetworkLiberty class.
|
||||
functions for derived network classes.
|
||||
|
||||
If the network adapter implements the NetworkEdit API the following
|
||||
TCL commands are supported:
|
||||
|
|
@ -253,13 +253,13 @@ Liberty
|
|||
-------
|
||||
|
||||
The liberty timing library reader builds classes that are derived from
|
||||
the concrete library classes. In addition to the library, cell and
|
||||
the concrete library classes. In addition to the library, cell and
|
||||
port classes, there are classes to represent timing arcs, timing
|
||||
models, wireload models, operating conditions, and scale factors for
|
||||
derating timing data.
|
||||
|
||||
Timing arcs are grouped into sets of arcs between a pair of cell
|
||||
ports. For example, a buffer has two timing arcs between the input
|
||||
ports. For example, a buffer has two timing arcs between the input
|
||||
and output; one for a rising output and another for a falling output.
|
||||
The timing arcs are:
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ Similarly, an inverter has two negative-unate timing arcs.
|
|||
|
||||
On the other hand, a multiplexor, has a non-unate path from the select
|
||||
input to the output because a rise or fall change on the input can
|
||||
cause the output to either rise or fall. There are four timing arcs
|
||||
cause the output to either rise or fall. There are four timing arcs
|
||||
in this arc set:
|
||||
|
||||
S f -> Z r
|
||||
|
|
@ -283,19 +283,19 @@ in this arc set:
|
|||
S r -> Z f
|
||||
|
||||
The liberty file reader can be customized to read attributes that are
|
||||
not used by the STA. See liberty/LibertyExt.cc for an example.
|
||||
not used by the STA. See liberty/LibertyExt.cc for an example.
|
||||
|
||||
Graph
|
||||
-----
|
||||
|
||||
The timing graph is the central data structure used by the delay
|
||||
calculation and search algorithms. It is annotated with timing arc
|
||||
delay values and slews (from SDF or a delay calculator). A forward
|
||||
calculation and search algorithms. It is annotated with timing arc
|
||||
delay values and slews (from SDF or a delay calculator). A forward
|
||||
search annotates the graph with arrival times, and a backward search
|
||||
annotates required times.
|
||||
|
||||
The graph is composed of vertices and edges. Each pin in the design
|
||||
has a vertex. Bidirect pins have two vertices, one for its use as an
|
||||
The graph is composed of vertices and edges. Each pin in the design
|
||||
has a vertex. Bidirect pins have two vertices, one for its use as an
|
||||
input and another for its use as an output.
|
||||
|
||||
The Network adapter supplies functions to find and set the index
|
||||
|
|
@ -310,16 +310,16 @@ compared to storing the value in the pin structure.
|
|||
A pointer to the vertex used for a bidirectional pin driver is kept in
|
||||
a map owned by the Graph class.
|
||||
|
||||
Edges in the graph connect vertices. The pins connected together by a
|
||||
net have wire edges between the pin vertices. Timing arc sets in the
|
||||
Edges in the graph connect vertices. The pins connected together by a
|
||||
net have wire edges between the pin vertices. Timing arc sets in the
|
||||
leaf instance timing models have corresponding edges in the graph
|
||||
between pins on the instance.
|
||||
|
||||
The Graph class constructor option slew_tr_count is used to prevent
|
||||
the grpah from reserving memory to store slews. Similarly, if the
|
||||
the grpah from reserving memory to store slews. Similarly, if the
|
||||
have_arc_delays option is false no memory is reserved for storing arc
|
||||
delay values. This is useful if an external delay calculator is used
|
||||
to annotate delays on the graph. In this case the Graph functions
|
||||
delay values. This is useful if an external delay calculator is used
|
||||
to annotate delays on the graph. In this case the Graph functions
|
||||
arcDelay and wireDelay should be overloaded to return delay values
|
||||
stored outside of the STA.
|
||||
|
||||
|
|
@ -347,33 +347,29 @@ Delay Calculation
|
|||
-----------------
|
||||
|
||||
The graph is annotated with arc delay values and slews (also known as
|
||||
transition times) by the graph delay calculator and the SDF reader.
|
||||
The GraphDelayCalc class seeds slews and arrival times from SDC
|
||||
constraints and uses a breadth first search to visit each gate output
|
||||
pin. The GraphDelayCalc then calls a timing arc delay calculator for
|
||||
each timing arc and annotates the graph arc delays and vertex slews.
|
||||
transition times) by the graph delay calculator or the SDF reader.
|
||||
The GraphDelayCalc class seeds slews from SDC constraints and uses a
|
||||
breadth first search to visit each gate output pin. The GraphDelayCalc
|
||||
then calls a timing arc delay calculator for each timing arc and
|
||||
annotates the graph arc delays and vertex slews.
|
||||
|
||||
The delay calculator is architeched to support multiple delay
|
||||
calculation results. Each result has an associated delay calculation
|
||||
calculation results. Each result has an associated delay calculation
|
||||
analysis point (class DcalcAnalysisPt) that specifies the operating
|
||||
conditions and parasitics used to find the delays.
|
||||
|
||||
The ArcDelayCalc class defines the API used by the GraphDelayCalc to
|
||||
calculate the gate delay, driver slew, load delays and load slews
|
||||
driven by a timing arc. The following delay calculation algorithms
|
||||
driven by a timing arc. The following delay calculation algorithms
|
||||
are defined in the dcalc directory:
|
||||
|
||||
UnitDelayCalc - All gate delays are 1. Wire delays are zero.
|
||||
UnitDelayCalc - All gate delays are 1. Wire delays are zero.
|
||||
|
||||
LumpedCapArcDelayCalc - Liberty table models using lumped capacitive
|
||||
load (RSPF pi model total capacitance). Wire delays are zero.
|
||||
|
||||
SimpleRCArcDelayCalc - Liberty table models using lumped capacitive
|
||||
load (RSPF pi model total capacitance). Wire delays are the RSPF
|
||||
elmore delay.
|
||||
load (RSPF pi model total capacitance). Wire delays are zero.
|
||||
|
||||
DmpCeffElmoreDelayCalc - RSPF (Driver Pi model with elmore interconnect
|
||||
delays) delay calculator. Liberty table models using effective capacitive
|
||||
delays) delay calculator. Liberty table models using effective capacitive
|
||||
model as described in the following paper:
|
||||
"Performance Computation for Precharacterized CMOS Gates with RC Loads",
|
||||
Florentin Dartu, Noel Menezes and Lawrence Pileggi, IEEE Transactions
|
||||
|
|
@ -387,53 +383,53 @@ are defined in the dcalc directory:
|
|||
|
||||
Other delay calculators can be interfaced by defining a class based on
|
||||
ArcDelayCalc and using the registerDelayCalc function to register it
|
||||
for the "set_delay_calculator" Tcl command. The Sta::setArcDelayCalc
|
||||
for the "set_delay_calculator" Tcl command. The Sta::setArcDelayCalc
|
||||
function can be used to set the delay calculator at run time.
|
||||
|
||||
Search
|
||||
------
|
||||
|
||||
A breadth first forward search is used to find arrival times at graph
|
||||
vertices. Vertices are annotated with instances of the Event class to
|
||||
record signal arrival and required times. As each vertex is visited
|
||||
vertices. Vertices are annotated with instances of the Event class to
|
||||
record signal arrival and required times. As each vertex is visited
|
||||
in the forward search its required time is found using If the vertex
|
||||
is constrained by setup or hold timing checks, min/max path delay
|
||||
exceptions or gated timing checks its required time is found from the
|
||||
SDC. The slack is the difference between the vertex required time and
|
||||
arrival time. If the vertex is constrained it is scheduled for a
|
||||
SDC. The slack is the difference between the vertex required time and
|
||||
arrival time. If the vertex is constrained it is scheduled for a
|
||||
breadth first backward search to propagate required times to the fanin
|
||||
vertices. Separate events (and hence arrival and required times) are
|
||||
vertices. Separate events (and hence arrival and required times) are
|
||||
used for each clock edge and exception set that cause a vertex to
|
||||
change.
|
||||
|
||||
Arrival, required and slack calculations are incremental using a level
|
||||
based "lazy evaluation" algorithm. The first time arrival/required
|
||||
based "lazy evaluation" algorithm. The first time arrival/required
|
||||
times are found for a vertex the arrival/required times are propagated
|
||||
to/from the vertex's logic level. After that no search is required
|
||||
to/from the vertex's logic level. After that no search is required
|
||||
for any vertex with a lower/higher logic level when the
|
||||
arrival/required time is requested.
|
||||
|
||||
Clock arrival times are found before data arrival times by
|
||||
Search::findClkArrivals(). Clock arrival times now include insertion
|
||||
delay (source latency).
|
||||
Search::findClkArrivals(). Clock arrival times include insertion delay
|
||||
(source latency).
|
||||
|
||||
When an incremental netlist change is made (for instance, changing the
|
||||
drive strengh of a gate with swap_cell), the STA incrementally updates
|
||||
delay calculation, arrival times, required times and slacks. Because
|
||||
gate delay is only weakly dependent on slew (transition time), the
|
||||
effect of the change will diminish in gates downstream of the change.
|
||||
The STA uses a tolerance on the gate delays to determine when to stop
|
||||
propagating the change. The tolerance is set using the
|
||||
delay calculation, arrival times, required times and slacks. Because
|
||||
gate delay is only weakly dependent on slew, the effect of the change
|
||||
will diminish in gates downstream of the change. The STA uses a
|
||||
tolerance on the gate delays to determine when to stop propagating the
|
||||
change. The tolerance is set using the
|
||||
Sta::setIncrementalDelayTolerance function.
|
||||
|
||||
void Sta::setIncrementalDelayTolerance(float tol);
|
||||
|
||||
The tolerance is a percentage (0.0:1.0) change in delay that causes
|
||||
downstream delays to be recomputed during incremental delay
|
||||
calculation. The default value is 0.0 for maximum accuracy and
|
||||
slowest incremental speed. The delay calculation will not recompute
|
||||
calculation. The default value is 0.0 for maximum accuracy and
|
||||
slowest incremental speed. The delay calculation will not recompute
|
||||
delays for downstream gates when the change in the gate delay is less
|
||||
than the tolerance. Required times must be recomputed backward from
|
||||
than the tolerance. Required times must be recomputed backward from
|
||||
any gate delay changes, so increasing the tolerance can significantly
|
||||
reduce incremental timing run time.
|
||||
|
||||
|
|
@ -441,21 +437,19 @@ Tcl Interface
|
|||
-------------
|
||||
|
||||
The interface from Tcl to C++ is written in a SWIG (www.swig.org)
|
||||
interface description (tcl/StaTcl.i). SWIG generates the interface
|
||||
interface description (tcl/StaTcl.i). SWIG generates the interface
|
||||
code from the description file.
|
||||
|
||||
All user interface code is written in Tcl. SDC argument parsing and
|
||||
checking is done with Tcl procedures that call a SWIG interface
|
||||
function. All reporting commands are written in Tcl so they can be
|
||||
easily customized.
|
||||
All commands are written in Tcl. SDC argument parsing and checking is
|
||||
done with Tcl procedures that call a SWIG interface function.
|
||||
|
||||
The Tcl 'sta' namespace is used to segregate internal STA functions
|
||||
from the global Tcl namespace. All user visible STA and SDC commands
|
||||
from the global Tcl namespace. All user visible STA and SDC commands
|
||||
are exported to the global Tcl namespace.
|
||||
|
||||
A lot of the internal STA state can be accessed from Tcl to make
|
||||
debugging a lot easier. Some debugging commands require a namespace
|
||||
qualifier because they are not intended for casual users. Some
|
||||
debugging a easier. Some debugging commands require a namespace
|
||||
qualifier because they are not intended for casual users. Some
|
||||
examples are shown below.
|
||||
|
||||
sta::report_arrival
|
||||
|
|
@ -473,21 +467,10 @@ examples are shown below.
|
|||
sta::network_leaf_pin_count
|
||||
|
||||
Additionally, many of the STA network and graph objects themselvs are
|
||||
exposed to Tcl using SWIG. These Tcl objects have methods for
|
||||
inspecting them. Examples of how to use these methods can be found in
|
||||
exposed to Tcl using SWIG. These Tcl objects have methods for
|
||||
inspecting them. Examples of how to use these methods can be found in
|
||||
the tcl/Graph.tcl and tcl/Network.tcl files.
|
||||
|
||||
Optional Components
|
||||
-------------------
|
||||
Optional components that are not included in the standard distribution are:
|
||||
|
||||
Edif netlist reader
|
||||
OpenAccess netlist and parasitics interface
|
||||
Verific netlist interface
|
||||
Budgeter
|
||||
Interface Logic Model (ILM) generation
|
||||
Arnoldi reduced order delay calculation
|
||||
|
||||
Architecture alternatives for using the STA Engine
|
||||
--------------------------------------------------
|
||||
|
||||
|
|
@ -496,15 +479,15 @@ an application.
|
|||
|
||||
* STA with TCL application
|
||||
|
||||
The simplest example is an application written in TCL. The
|
||||
application calls STA commands and primitives defined in /tcl and
|
||||
tcl/StaTcl.i. A stand-alone STA executable is built and a TCL file
|
||||
that defines the application is included as part of the STA by
|
||||
modifying app/Makefile.am to add the TCL file to app/TclInitVar.cc.
|
||||
The simplest example is an application written in TCL. The application
|
||||
calls STA commands and primitives defined in the swig c++/tcl
|
||||
interface. A stand-alone STA executable is built and a TCL file that
|
||||
defines the application is included as part of the STA by modifying
|
||||
CMakeLists.txt to add the TCL file to app/TclInitVar.cc.
|
||||
|
||||
The user calls STA commands to read design files (liberty, verilog,
|
||||
SDF, parasitics) to define and link the design. The user defines SDC
|
||||
commands or sources an SDC file. The user calls the application's TCL
|
||||
commands or sources an SDC file. The user calls the application's TCL
|
||||
commands.
|
||||
|
||||
A simple gate sizer is an example of an application that can be built
|
||||
|
|
@ -515,15 +498,15 @@ or insert buffers.
|
|||
* STA with C++ application
|
||||
|
||||
The application is built by adding C++ files to the /app directory and
|
||||
modifying app/Makefile.am to include them in the executable. Interface
|
||||
modifying CMakeLists.txt to include them in the executable. Interface
|
||||
commands between C++ and TCL are put in a SWIG .i file in the /app
|
||||
directory and modifying app/StaApp.i to include them. TCL commands are
|
||||
added to the STA by modifying app/Makefile.am to add the application's
|
||||
added to the STA by modifying CMakeLists.txt to add the application's
|
||||
TCL files to TclInitVar.cc.
|
||||
|
||||
The user calls STA commands to read design files (liberty, verilog,
|
||||
SDF, parasitics) to define and link the design. The user defines SDC
|
||||
commands or sources an SDC file. The user calls the application's TCL
|
||||
commands or sources an SDC file. The user calls the application's TCL
|
||||
commands.
|
||||
|
||||
* C++ application without native Network data structures linking STA libraries
|
||||
|
|
@ -533,14 +516,14 @@ calls STA initialization functions like staMain() defined in
|
|||
app/StaMain.cc.
|
||||
|
||||
The application must link and instanciate a TCL interpreter to read
|
||||
SDC commands like staMain(). The application can choose to expose the TCL
|
||||
SDC commands like staMain(). The application can choose to expose the TCL
|
||||
interpreter to the user or not. The STA depends on the following data
|
||||
that can be read by calling TCL commands or Sta class member functions.
|
||||
|
||||
Liberty files that define the leaf cells used in the design.
|
||||
Read using the read_liberty command or by calling Sta::readLibertyFile().
|
||||
|
||||
Verilog files that define the netlist. Read using the read_verilog
|
||||
Verilog files that define the netlist. Read using the read_verilog
|
||||
command or by calling readVerilogFile() (see verilog/Verilog.i
|
||||
read_verilog).
|
||||
|
||||
|
|
@ -561,7 +544,7 @@ Sta::deleteInstance() to edit the network.
|
|||
|
||||
The application defines a Network adapter (described above) so that
|
||||
the STA can use the native network data structures without duplicating
|
||||
them for the STA. The application defines a class built on class Sta
|
||||
them in the STA. The application defines a class built on class Sta
|
||||
that defines the makeNetwork() member function to build an instance of
|
||||
the network adapter.
|
||||
|
||||
|
|
@ -571,7 +554,7 @@ app/StaMain.cc. The application reads the netlist and builds network
|
|||
data structures that the STA accesses through the Network adapter.
|
||||
|
||||
The application must link and instanciate a TCL interpreter to read
|
||||
SDC commands like staMain(). The application can choose to expose the TCL
|
||||
SDC commands like staMain(). The application can choose to expose the TCL
|
||||
interpreter to the user or not. The STA depends on the following data
|
||||
that can be read by calling TCL commands or Sta class member functions.
|
||||
|
||||
|
|
@ -580,7 +563,7 @@ Read using the read_liberty command or by calling Sta::readLibertyFile.
|
|||
|
||||
SDC commands to define timing constraints.
|
||||
Defined using SDC commands in the TCL interpreter, or sourced
|
||||
from a file using Tcl_Eval(sta::tclInterp()).
|
||||
from a file using sta::sourceTclFile.
|
||||
|
||||
Parasitics used by delay calculation.
|
||||
Read using the read_parasitics command, Sta::readParasitics(), or
|
||||
|
|
|
|||
|
|
@ -764,6 +764,8 @@ public:
|
|||
// Is the clock for timing checks.
|
||||
bool isCheckClk() const { return is_check_clk_; }
|
||||
void setIsCheckClk(bool is_clk);
|
||||
bool isPad() const { return is_pad_; }
|
||||
void setIsPad(bool is_pad);
|
||||
RiseFall *pulseClkTrigger() const { return pulse_clk_trigger_; }
|
||||
// Rise for high, fall for low.
|
||||
RiseFall *pulseClkSense() const { return pulse_clk_sense_; }
|
||||
|
|
@ -863,6 +865,7 @@ protected:
|
|||
bool level_shifter_data_:1;
|
||||
bool is_switch_:1;
|
||||
bool is_disabled_constraint_:1;
|
||||
bool is_pad_:1;
|
||||
|
||||
private:
|
||||
friend class LibertyLibrary;
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ public:
|
|||
protected:
|
||||
void makeWireloadNetworkWorst(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
const Net *net,
|
||||
float wireload_cap,
|
||||
float wireload_res,
|
||||
float fanout);
|
||||
|
|
|
|||
|
|
@ -1996,7 +1996,8 @@ LibertyPort::LibertyPort(LibertyCell *cell,
|
|||
isolation_cell_enable_(false),
|
||||
level_shifter_data_(false),
|
||||
is_switch_(false),
|
||||
is_disabled_constraint_(false)
|
||||
is_disabled_constraint_(false),
|
||||
is_pad_(false)
|
||||
{
|
||||
liberty_port_ = this;
|
||||
min_pulse_width_[RiseFall::riseIndex()] = 0.0;
|
||||
|
|
@ -2472,6 +2473,12 @@ LibertyPort::setIsDisabledConstraint(bool is_disabled)
|
|||
is_disabled_constraint_ = is_disabled;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::setIsPad(bool is_pad)
|
||||
{
|
||||
is_pad_ = is_pad;
|
||||
}
|
||||
|
||||
LibertyPort *
|
||||
LibertyPort::cornerPort(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ LibertyReader::defineVisitors()
|
|||
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
|
||||
defineAttrVisitor("is_macro_cell", &LibertyReader::visitIsMacro);
|
||||
defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory);
|
||||
defineAttrVisitor("pad_cell", &LibertyReader::visitIsPadCell);
|
||||
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
|
||||
defineAttrVisitor("is_clock_cell", &LibertyReader::visitIsClockCell);
|
||||
defineAttrVisitor("is_level_shifter", &LibertyReader::visitIsLevelShifter);
|
||||
|
|
@ -2887,13 +2888,13 @@ LibertyReader::visitIsMemory(LibertyAttr *attr)
|
|||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsPad(LibertyAttr *attr)
|
||||
LibertyReader::visitIsPadCell(LibertyAttr *attr)
|
||||
{
|
||||
if (cell_) {
|
||||
bool is_pad, exists;
|
||||
getAttrBool(attr, is_pad, exists);
|
||||
bool pad_cell, exists;
|
||||
getAttrBool(attr, pad_cell, exists);
|
||||
if (exists)
|
||||
cell_->setIsPad(is_pad);
|
||||
cell_->setIsPad(pad_cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3358,6 +3359,19 @@ LibertyReader::visitClock(LibertyAttr *attr)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsPad(LibertyAttr *attr)
|
||||
{
|
||||
if (ports_) {
|
||||
bool is_pad, exists;
|
||||
getAttrBool(attr, is_pad, exists);
|
||||
if (exists) {
|
||||
for (LibertyPort *port : *ports_)
|
||||
port->setIsPad(is_pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitCapacitance(LibertyAttr *attr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ public:
|
|||
virtual void visitDontUse(LibertyAttr *attr);
|
||||
virtual void visitIsMacro(LibertyAttr *attr);
|
||||
virtual void visitIsMemory(LibertyAttr *attr);
|
||||
virtual void visitIsPadCell(LibertyAttr *attr);
|
||||
virtual void visitIsPad(LibertyAttr *attr);
|
||||
virtual void visitIsClockCell(LibertyAttr *attr);
|
||||
virtual void visitIsLevelShifter(LibertyAttr *attr);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
|
|||
const MinMax *min_max,
|
||||
const ParasiticAnalysisPt *ap)
|
||||
{
|
||||
Net *net = network_->net(drvr_pin);
|
||||
const Net *net = findParasiticNet(drvr_pin);
|
||||
Parasitic *parasitic = makeParasiticNetwork(net, false, ap);
|
||||
const OperatingConditions *op_cond = sdc_->operatingConditions(min_max);
|
||||
float wireload_cap, wireload_res;
|
||||
|
|
@ -214,7 +214,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
|
|||
tree = op_cond->wireloadTree();
|
||||
switch (tree) {
|
||||
case WireloadTree::worst_case:
|
||||
makeWireloadNetworkWorst(parasitic, drvr_pin, wireload_cap,
|
||||
makeWireloadNetworkWorst(parasitic, drvr_pin, net, wireload_cap,
|
||||
wireload_res, fanout);
|
||||
break;
|
||||
case WireloadTree::balanced:
|
||||
|
|
@ -235,12 +235,12 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
|
|||
void
|
||||
Parasitics::makeWireloadNetworkWorst(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
const Net *net,
|
||||
float wireload_cap,
|
||||
float wireload_res,
|
||||
float /* fanout */)
|
||||
{
|
||||
ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_);
|
||||
Net *net = network_->net(drvr_pin);
|
||||
size_t resistor_index = 1;
|
||||
ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0, network_);
|
||||
makeResistor(parasitic, resistor_index++, wireload_res, drvr_node, load_node);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@
|
|||
#include <cmath> // abs
|
||||
#include <algorithm>
|
||||
|
||||
#include "Fuzzy.hh"
|
||||
#include "Report.hh"
|
||||
#include "Debug.hh"
|
||||
#include "DispatchQueue.hh"
|
||||
#include "Units.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "Liberty.hh"
|
||||
|
|
@ -53,17 +55,20 @@ public:
|
|||
void operator=(const ClkSkew &clk_skew);
|
||||
PathVertex *srcPath() { return &src_path_; }
|
||||
PathVertex *tgtPath() { return &tgt_path_; }
|
||||
float srcLatency(StaState *sta);
|
||||
float tgtLatency(StaState *sta);
|
||||
float srcInternalClkLatency(StaState *sta);
|
||||
float tgtInternalClkLatency(StaState *sta);
|
||||
Crpr crpr(StaState *sta);
|
||||
float uncertainty(StaState *sta);
|
||||
float srcLatency(const StaState *sta);
|
||||
float tgtLatency(const StaState *sta);
|
||||
float srcInternalClkLatency(const StaState *sta);
|
||||
float tgtInternalClkLatency(const StaState *sta);
|
||||
Crpr crpr(const StaState *sta);
|
||||
float uncertainty(const StaState *sta);
|
||||
float skew() const { return skew_; }
|
||||
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
|
||||
ClkSkew &clk_skew2,
|
||||
const StaState *sta);
|
||||
|
||||
private:
|
||||
float clkTreeDelay(PathVertex &clk_path,
|
||||
StaState *sta);
|
||||
const StaState *sta);
|
||||
|
||||
PathVertex src_path_;
|
||||
PathVertex tgt_path_;
|
||||
|
|
@ -109,7 +114,7 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
|
|||
}
|
||||
|
||||
float
|
||||
ClkSkew::srcLatency(StaState *sta)
|
||||
ClkSkew::srcLatency(const StaState *sta)
|
||||
{
|
||||
Arrival src_arrival = src_path_.arrival(sta);
|
||||
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time()
|
||||
|
|
@ -117,13 +122,13 @@ ClkSkew::srcLatency(StaState *sta)
|
|||
}
|
||||
|
||||
float
|
||||
ClkSkew::srcInternalClkLatency(StaState *sta)
|
||||
ClkSkew::srcInternalClkLatency(const StaState *sta)
|
||||
{
|
||||
return clkTreeDelay(src_path_, sta);
|
||||
}
|
||||
|
||||
float
|
||||
ClkSkew::tgtLatency(StaState *sta)
|
||||
ClkSkew::tgtLatency(const StaState *sta)
|
||||
{
|
||||
Arrival tgt_arrival = tgt_path_.arrival(sta);
|
||||
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time()
|
||||
|
|
@ -131,14 +136,14 @@ ClkSkew::tgtLatency(StaState *sta)
|
|||
}
|
||||
|
||||
float
|
||||
ClkSkew::tgtInternalClkLatency(StaState *sta)
|
||||
ClkSkew::tgtInternalClkLatency(const StaState *sta)
|
||||
{
|
||||
return clkTreeDelay(tgt_path_, sta);
|
||||
}
|
||||
|
||||
float
|
||||
ClkSkew::clkTreeDelay(PathVertex &clk_path,
|
||||
StaState *sta)
|
||||
const StaState *sta)
|
||||
{
|
||||
if (include_internal_latency_) {
|
||||
const Vertex *vertex = clk_path.vertex(sta);
|
||||
|
|
@ -154,14 +159,14 @@ ClkSkew::clkTreeDelay(PathVertex &clk_path,
|
|||
}
|
||||
|
||||
Crpr
|
||||
ClkSkew::crpr(StaState *sta)
|
||||
ClkSkew::crpr(const StaState *sta)
|
||||
{
|
||||
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
||||
return check_crpr->checkCrpr(&src_path_, &tgt_path_);
|
||||
}
|
||||
|
||||
float
|
||||
ClkSkew::uncertainty(StaState *sta)
|
||||
ClkSkew::uncertainty(const StaState *sta)
|
||||
{
|
||||
TimingRole *check_role = (src_path_.minMax(sta) == SetupHold::max())
|
||||
? TimingRole::setup()
|
||||
|
|
@ -171,10 +176,27 @@ ClkSkew::uncertainty(StaState *sta)
|
|||
check_role, sta);
|
||||
}
|
||||
|
||||
bool
|
||||
ClkSkew::srcTgtPathNameLess(ClkSkew &clk_skew1,
|
||||
ClkSkew &clk_skew2,
|
||||
const StaState *sta)
|
||||
{
|
||||
Network *network = sta->sdcNetwork();
|
||||
const char *src_path1 = network->pathName(clk_skew1.srcPath()->pin(sta));
|
||||
const char *src_path2 = network->pathName(clk_skew2.srcPath()->pin(sta));
|
||||
const char *tgt_path1 = network->pathName(clk_skew1.tgtPath()->pin(sta));
|
||||
const char *tgt_path2 = network->pathName(clk_skew2.tgtPath()->pin(sta));
|
||||
return stringLess(src_path1, src_path2)
|
||||
|| (stringEqual(src_path1, src_path2)
|
||||
&& stringEqual(tgt_path1, tgt_path2));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
ClkSkews::ClkSkews(StaState *sta) :
|
||||
StaState(sta)
|
||||
StaState(sta),
|
||||
fanout_pred_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -275,54 +297,86 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
|
|||
bool include_internal_latency)
|
||||
{
|
||||
ClkSkewMap skews;
|
||||
corner_ = corner;
|
||||
setup_hold_ = setup_hold;
|
||||
include_internal_latency_ = include_internal_latency;
|
||||
|
||||
ConstClockSet clk_set;
|
||||
clk_set_.clear();
|
||||
for (const Clock *clk : clks)
|
||||
clk_set.insert(clk);
|
||||
clk_set_.insert(clk);
|
||||
|
||||
for (Vertex *src_vertex : *graph_->regClkVertices()) {
|
||||
if (hasClkPaths(src_vertex, clk_set)) {
|
||||
VertexOutEdgeIterator edge_iter(src_vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
if (edge->role()->genericRole() == TimingRole::regClkToQ()) {
|
||||
Vertex *q_vertex = edge->to(graph_);
|
||||
const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge();
|
||||
const RiseFallBoth *src_rf = rf
|
||||
? rf->asRiseFallBoth()
|
||||
: RiseFallBoth::riseFall();
|
||||
findClkSkewFrom(src_vertex, q_vertex, src_rf, clk_set,
|
||||
corner, setup_hold, include_internal_latency,
|
||||
skews);
|
||||
}
|
||||
if (thread_count_ > 1) {
|
||||
std::vector<ClkSkewMap> partial_skews(thread_count_, skews);
|
||||
for (Vertex *src_vertex : *graph_->regClkVertices()) {
|
||||
if (hasClkPaths(src_vertex)) {
|
||||
dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) {
|
||||
findClkSkewFrom(src_vertex, partial_skews[i]);
|
||||
});
|
||||
}
|
||||
}
|
||||
dispatch_queue_->finishTasks();
|
||||
|
||||
// Reduce skews from each register source.
|
||||
for (size_t i = 0; i < partial_skews.size(); i++) {
|
||||
for (auto clk_skew_itr : partial_skews[i]) {
|
||||
const Clock *clk = clk_skew_itr.first;
|
||||
auto partial_skew = clk_skew_itr.second;
|
||||
auto ins = skews.insert(std::make_pair(clk, partial_skew));
|
||||
if (!ins.second) {
|
||||
ClkSkew &final_skew = ins.first->second;
|
||||
if (abs(partial_skew.skew()) > abs(final_skew.skew())
|
||||
|| (fuzzyEqual(abs(partial_skew.skew()), abs(final_skew.skew()))
|
||||
// Break ties based on source/target path names.
|
||||
&& ClkSkew::srcTgtPathNameLess(partial_skew, final_skew, this)))
|
||||
final_skew = partial_skew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Vertex *src_vertex : *graph_->regClkVertices()) {
|
||||
if (hasClkPaths(src_vertex))
|
||||
findClkSkewFrom(src_vertex, skews);
|
||||
}
|
||||
}
|
||||
return skews;
|
||||
}
|
||||
|
||||
bool
|
||||
ClkSkews::hasClkPaths(Vertex *vertex,
|
||||
ConstClockSet &clks)
|
||||
ClkSkews::hasClkPaths(Vertex *vertex)
|
||||
{
|
||||
VertexPathIterator path_iter(vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
PathVertex *path = path_iter.next();
|
||||
const Clock *path_clk = path->clock(this);
|
||||
if (clks.find(path_clk) != clks.end())
|
||||
if (clk_set_.find(path_clk) != clk_set_.end())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ClkSkews::findClkSkewFrom(Vertex *src_vertex,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
VertexOutEdgeIterator edge_iter(src_vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
if (edge->role()->genericRole() == TimingRole::regClkToQ()) {
|
||||
Vertex *q_vertex = edge->to(graph_);
|
||||
const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge();
|
||||
const RiseFallBoth *src_rf = rf
|
||||
? rf->asRiseFallBoth()
|
||||
: RiseFallBoth::riseFall();
|
||||
findClkSkewFrom(src_vertex, q_vertex, src_rf, skews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClkSkews::findClkSkewFrom(Vertex *src_vertex,
|
||||
Vertex *q_vertex,
|
||||
const RiseFallBoth *src_rf,
|
||||
ConstClockSet &clk_set,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
bool include_internal_latency,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
VertexSet endpoints = findFanout(q_vertex);
|
||||
|
|
@ -332,18 +386,16 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
|
|||
Edge *edge = edge_iter.next();
|
||||
TimingRole *role = edge->role();
|
||||
if (role->isTimingCheck()
|
||||
&& ((setup_hold == SetupHold::max()
|
||||
&& ((setup_hold_ == SetupHold::max()
|
||||
&& role->genericRole() == TimingRole::setup())
|
||||
|| ((setup_hold == SetupHold::min()
|
||||
|| ((setup_hold_ == SetupHold::min()
|
||||
&& role->genericRole() == TimingRole::hold())))) {
|
||||
Vertex *tgt_vertex = edge->from(graph_);
|
||||
const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge();
|
||||
const RiseFallBoth *tgt_rf = tgt_rf1
|
||||
? tgt_rf1->asRiseFallBoth()
|
||||
: RiseFallBoth::riseFall();
|
||||
findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf,
|
||||
clk_set, corner, setup_hold,
|
||||
include_internal_latency, skews);
|
||||
findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, skews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,24 +406,20 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
|||
const RiseFallBoth *src_rf,
|
||||
Vertex *tgt_vertex,
|
||||
const RiseFallBoth *tgt_rf,
|
||||
ConstClockSet &clk_set,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
bool include_internal_latency,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
Unit *time_unit = units_->timeUnit();
|
||||
const SetupHold *tgt_min_max = setup_hold->opposite();
|
||||
const SetupHold *tgt_min_max = setup_hold_->opposite();
|
||||
VertexPathIterator src_iter(src_vertex, this);
|
||||
while (src_iter.hasNext()) {
|
||||
PathVertex *src_path = src_iter.next();
|
||||
const Clock *src_clk = src_path->clock(this);
|
||||
if (src_rf->matches(src_path->transition(this))
|
||||
&& src_path->minMax(this) == setup_hold
|
||||
&& clk_set.find(src_clk) != clk_set.end()) {
|
||||
&& src_path->minMax(this) == setup_hold_
|
||||
&& clk_set_.find(src_clk) != clk_set_.end()) {
|
||||
Corner *src_corner = src_path->pathAnalysisPt(this)->corner();
|
||||
if (corner == nullptr
|
||||
|| src_corner == corner) {
|
||||
if (corner_ == nullptr
|
||||
|| src_corner == corner_) {
|
||||
VertexPathIterator tgt_iter(tgt_vertex, this);
|
||||
while (tgt_iter.hasNext()) {
|
||||
PathVertex *tgt_path = tgt_iter.next();
|
||||
|
|
@ -381,7 +429,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
|||
&& tgt_rf->matches(tgt_path->transition(this))
|
||||
&& tgt_path->minMax(this) == tgt_min_max
|
||||
&& tgt_path->pathAnalysisPt(this)->corner() == src_corner) {
|
||||
ClkSkew probe(src_path, tgt_path, include_internal_latency, this);
|
||||
ClkSkew probe(src_path, tgt_path, include_internal_latency_, this);
|
||||
ClkSkew &clk_skew = skews[src_clk];
|
||||
debugPrint(debug_, "clk_skew", 2,
|
||||
"%s %s %s -> %s %s %s crpr = %s skew = %s",
|
||||
|
|
@ -403,12 +451,38 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
|||
}
|
||||
}
|
||||
|
||||
class FanOutSrchPred : public SearchPred1
|
||||
VertexSet
|
||||
ClkSkews::findFanout(Vertex *from)
|
||||
{
|
||||
public:
|
||||
FanOutSrchPred(const StaState *sta);
|
||||
virtual bool searchThru(Edge *edge);
|
||||
};
|
||||
VertexSet endpoints(graph_);
|
||||
UnorderedSet<Vertex*> visited;
|
||||
findFanout1(from, visited, endpoints);
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
void
|
||||
ClkSkews::findFanout1(Vertex *from,
|
||||
UnorderedSet<Vertex*> &visited,
|
||||
VertexSet &endpoints)
|
||||
{
|
||||
visited.insert(from);
|
||||
if (from->hasChecks())
|
||||
endpoints.insert(from);
|
||||
if (fanout_pred_.searchFrom(from)) {
|
||||
VertexOutEdgeIterator edge_iter(from, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to = edge->to(graph_);
|
||||
if (fanout_pred_.searchThru(edge)
|
||||
&& fanout_pred_.searchTo(to)
|
||||
// Do not revisit downstream fanout cones.
|
||||
&& visited.insert(to).second)
|
||||
findFanout1(to, visited, endpoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
FanOutSrchPred::FanOutSrchPred(const StaState *sta) :
|
||||
SearchPred1(sta)
|
||||
|
|
@ -426,25 +500,4 @@ FanOutSrchPred::searchThru(Edge *edge)
|
|||
|| role == TimingRole::tristateDisable());
|
||||
}
|
||||
|
||||
VertexSet
|
||||
ClkSkews::findFanout(Vertex *from)
|
||||
{
|
||||
debugPrint(debug_, "fanout", 1, "%s",
|
||||
from->name(sdc_network_));
|
||||
VertexSet endpoints(graph_);
|
||||
FanOutSrchPred pred(this);
|
||||
BfsFwdIterator fanout_iter(BfsIndex::other, &pred, this);
|
||||
fanout_iter.enqueue(from);
|
||||
while (fanout_iter.hasNext()) {
|
||||
Vertex *fanout = fanout_iter.next();
|
||||
if (fanout->hasChecks()) {
|
||||
debugPrint(debug_, "fanout", 1, " endpoint %s",
|
||||
fanout->name(sdc_network_));
|
||||
endpoints.insert(fanout);
|
||||
}
|
||||
fanout_iter.enqueueAdjacentVertices(fanout);
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -18,18 +18,28 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
#include "UnorderedSet.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Transition.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "SearchPred.hh"
|
||||
#include "PathVertex.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class ClkSkew;
|
||||
class SearchPred;
|
||||
|
||||
typedef std::map<const Clock*, ClkSkew> ClkSkewMap;
|
||||
|
||||
class FanOutSrchPred : public SearchPred1
|
||||
{
|
||||
public:
|
||||
FanOutSrchPred(const StaState *sta);
|
||||
virtual bool searchThru(Edge *edge);
|
||||
};
|
||||
|
||||
// Find and report clock skews between source/target registers.
|
||||
class ClkSkews : public StaState
|
||||
{
|
||||
|
|
@ -51,28 +61,30 @@ protected:
|
|||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
bool include_internal_latency);
|
||||
bool hasClkPaths(Vertex *vertex,
|
||||
ConstClockSet &clks);
|
||||
bool hasClkPaths(Vertex *vertex);
|
||||
void findClkSkewFrom(Vertex *src_vertex,
|
||||
ClkSkewMap &skews);
|
||||
void findClkSkewFrom(Vertex *src_vertex,
|
||||
Vertex *q_vertex,
|
||||
const RiseFallBoth *src_rf,
|
||||
ConstClockSet &clk_set,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
bool include_internal_latency,
|
||||
ClkSkewMap &skews);
|
||||
void findClkSkew(Vertex *src_vertex,
|
||||
const RiseFallBoth *src_rf,
|
||||
Vertex *tgt_vertex,
|
||||
const RiseFallBoth *tgt_rf,
|
||||
ConstClockSet &clk_set,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
bool include_internal_latency,
|
||||
ClkSkewMap &skews);
|
||||
VertexSet findFanout(Vertex *from);
|
||||
void findFanout1(Vertex *from,
|
||||
UnorderedSet<Vertex*> &visited,
|
||||
VertexSet &endpoints);
|
||||
void reportClkSkew(ClkSkew &clk_skew,
|
||||
int digits);
|
||||
|
||||
ConstClockSet clk_set_;
|
||||
const Corner *corner_;
|
||||
const SetupHold *setup_hold_;
|
||||
bool include_internal_latency_;
|
||||
FanOutSrchPred fanout_pred_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -246,7 +246,8 @@ GenClkMasterSearchPred::searchThru(Edge *edge)
|
|||
const Sdc *sdc = sta_->sdc();
|
||||
TimingRole *role = edge->role();
|
||||
// Propagate clocks through constants.
|
||||
return !(edge->isDisabledLoop()
|
||||
return !(edge->role()->isTimingCheck()
|
||||
|| edge->isDisabledLoop()
|
||||
|| edge->isDisabledConstraint()
|
||||
// Constants disable edge cond expression.
|
||||
|| edge->isDisabledCond()
|
||||
|
|
|
|||
|
|
@ -359,6 +359,8 @@ Sta::updateComponentsState()
|
|||
if (check_timing_)
|
||||
check_timing_->copyState(this);
|
||||
clk_network_->copyState(this);
|
||||
if (clk_skews_)
|
||||
clk_skews_->copyState(this);
|
||||
if (power_)
|
||||
power_->copyState(this);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,51 @@
|
|||
Warning: asap7_simple.lib.gz line 71510, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 71986, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 72462, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 72938, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 73414, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 74830, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 71029, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 71505, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 71981, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 72457, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 72933, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 73409, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 73885, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 82276, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 83692, when attribute inside table model.
|
||||
Warning: asap7_simple.lib.gz line 81795, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 82271, timing group from output port.
|
||||
Warning: asap7_simple.lib.gz line 82747, timing group from output port.
|
||||
Startpoint: r2 (rising edge-triggered flip-flop clocked by clk)
|
||||
Endpoint: r3 (rising edge-triggered flip-flop clocked by clk)
|
||||
Path Group: clk
|
||||
Path Type: max
|
||||
|
||||
Slew Delay Time Description
|
||||
----------------------------------------------------------------
|
||||
0.00 0.00 0.00 clock clk (rise edge)
|
||||
0.00 0.00 clock source latency
|
||||
10.00 0.00 0.00 ^ clk2 (in)
|
||||
48.15 12.04 12.04 ^ r2/CLK (DFFHQx4_ASAP7_75t_R)
|
||||
38.97 90.82 102.86 ^ r2/Q (DFFHQx4_ASAP7_75t_R)
|
||||
59.28 16.50 119.36 ^ u1/A (BUFx2_ASAP7_75t_R)
|
||||
70.25 51.69 171.05 ^ u1/Y (BUFx2_ASAP7_75t_R)
|
||||
83.74 18.32 189.37 ^ u2/B (AND2x2_ASAP7_75t_R)
|
||||
72.19 60.76 250.13 ^ u2/Y (AND2x2_ASAP7_75t_R)
|
||||
85.61 18.34 268.46 ^ r3/D (DFFHQx4_ASAP7_75t_R)
|
||||
268.46 data arrival time
|
||||
|
||||
0.00 500.00 500.00 clock clk (rise edge)
|
||||
0.00 500.00 clock source latency
|
||||
10.00 0.00 500.00 ^ clk3 (in)
|
||||
47.52 11.84 511.84 ^ r3/CLK (DFFHQx4_ASAP7_75t_R)
|
||||
0.00 511.84 clock reconvergence pessimism
|
||||
-14.89 496.95 library setup time
|
||||
496.95 data required time
|
||||
----------------------------------------------------------------
|
||||
496.95 data required time
|
||||
-268.46 data arrival time
|
||||
----------------------------------------------------------------
|
||||
228.48 slack (MET)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# prima reg1 asap7
|
||||
read_liberty asap7_invbuf.lib.gz
|
||||
read_liberty asap7_seq.lib.gz
|
||||
read_liberty asap7_simple.lib.gz
|
||||
read_verilog reg1_asap7.v
|
||||
link_design top
|
||||
create_clock -name clk -period 500 {clk1 clk2 clk3}
|
||||
set_input_delay -clock clk 1 {in1 in2}
|
||||
set_input_transition 10 {in1 in2 clk1 clk2 clk3}
|
||||
set_propagated_clock {clk1 clk2 clk3}
|
||||
read_spef reg1_asap7.spef
|
||||
sta::set_delay_calculator prima
|
||||
report_checks -fields {input_pins slew} -format full_clock
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
*SPEF "IEEE 1481-1998"
|
||||
*DESIGN "reg1"
|
||||
*DATE "Fri Nov 20 13:23:00 2002"
|
||||
*VENDOR "Parallax Software, Inc"
|
||||
*PROGRAM "Handjob"
|
||||
*VERSION "1.0.1c"
|
||||
*DESIGN_FLOW "MISSING_NETS"
|
||||
*DIVIDER /
|
||||
*DELIMITER :
|
||||
*BUS_DELIMITER [ ]
|
||||
*T_UNIT 1.0 PS
|
||||
*C_UNIT 1.0 FF
|
||||
*R_UNIT 1.0 KOHM
|
||||
*L_UNIT 1.0 UH
|
||||
|
||||
*POWER_NETS VDD
|
||||
*GROUND_NETS VSS
|
||||
|
||||
*PORTS
|
||||
in1 I
|
||||
in2 I
|
||||
clk1 I
|
||||
clk2 I
|
||||
clk3 I
|
||||
out O
|
||||
|
||||
*D_NET in1 13.4
|
||||
*CONN
|
||||
*P in1 I
|
||||
*I r1:D I *L .0036
|
||||
*CAP
|
||||
1 in1 6.7
|
||||
2 r1:D 6.7
|
||||
*RES
|
||||
3 in1 r1:D 2.42
|
||||
*END
|
||||
|
||||
*D_NET in2 13.4
|
||||
*CONN
|
||||
*P in2 I
|
||||
*I r2:D I *L .0036
|
||||
*CAP
|
||||
1 in2 6.7
|
||||
2 r2:D 6.7
|
||||
*RES
|
||||
3 in2 r2:D 2.42
|
||||
*END
|
||||
|
||||
*D_NET clk1 13.4
|
||||
*CONN
|
||||
*P clk1 I
|
||||
*I r1:CLK I *L .0036
|
||||
*CAP
|
||||
1 clk1 6.7
|
||||
2 r1:CLK 6.7
|
||||
*RES
|
||||
3 clk1 r1:CLK 2.42
|
||||
*END
|
||||
|
||||
*D_NET clk2 13.4
|
||||
*CONN
|
||||
*P clk2 I
|
||||
*I r2:CLK I *L .0036
|
||||
*CAP
|
||||
1 clk2 6.7
|
||||
2 r2:CLK 6.7
|
||||
*RES
|
||||
3 clk2 r2:CLK 2.42
|
||||
*END
|
||||
|
||||
*D_NET clk3 13.4
|
||||
*CONN
|
||||
*P clk3 I
|
||||
*I r3:CLK I *L .0036
|
||||
*CAP
|
||||
1 clk3 6.7
|
||||
2 r3:CLK 6.7
|
||||
*RES
|
||||
3 clk3 r3:CLK 2.42
|
||||
*END
|
||||
|
||||
*D_NET r1q 13.4
|
||||
*CONN
|
||||
*I r1:Q O
|
||||
*I u2:A I *L .0086
|
||||
*CAP
|
||||
1 r1:Q 6.7
|
||||
2 u2:A 6.7
|
||||
*RES
|
||||
3 r1:Q u2:A 2.42
|
||||
*END
|
||||
|
||||
*D_NET r2q 13.4
|
||||
*CONN
|
||||
*I r2:Q O
|
||||
*I u1:A I *L .0086
|
||||
*CAP
|
||||
1 r2:Q 6.7
|
||||
2 u1:A 6.7
|
||||
*RES
|
||||
3 r2:Q u1:A 2.42
|
||||
*END
|
||||
|
||||
*D_NET u1z 13.4
|
||||
*CONN
|
||||
*I u1:Y O
|
||||
*I u2:B I *L .0086
|
||||
*CAP
|
||||
1 u1:Y 6.7
|
||||
2 u2:B 6.7
|
||||
*RES
|
||||
3 u1:Y u2:B 2.42
|
||||
*END
|
||||
|
||||
*D_NET u2z 13.4
|
||||
*CONN
|
||||
*I u2:Y O
|
||||
*I r3:D I *L .0086
|
||||
*CAP
|
||||
1 u2:Y 6.7
|
||||
2 r3:D 6.7
|
||||
*RES
|
||||
3 u2:Y r3:D 2.42
|
||||
*END
|
||||
|
||||
*D_NET out 13.4
|
||||
*CONN
|
||||
*I r3:Q O
|
||||
*P out O
|
||||
*CAP
|
||||
1 r3:Q 6.7
|
||||
2 out 6.7
|
||||
*RES
|
||||
3 r3:Q out 2.42
|
||||
*END
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
module top (in1, in2, clk1, clk2, clk3, out);
|
||||
input in1, in2, clk1, clk2, clk3;
|
||||
output out;
|
||||
wire r1q, r2q, u1z, u2z;
|
||||
|
||||
DFFHQx4_ASAP7_75t_R r1 (.D(in1), .CLK(clk1), .Q(r1q));
|
||||
DFFHQx4_ASAP7_75t_R r2 (.D(in2), .CLK(clk2), .Q(r2q));
|
||||
BUFx2_ASAP7_75t_R u1 (.A(r2q), .Y(u1z));
|
||||
AND2x2_ASAP7_75t_R u2 (.A(r1q), .B(u1z), .Y(u2z));
|
||||
DFFHQx4_ASAP7_75t_R r3 (.D(u2z), .CLK(clk3), .Q(out));
|
||||
endmodule // top
|
||||
|
|
@ -123,6 +123,7 @@ record_example_tests {
|
|||
|
||||
record_sta_tests {
|
||||
ccs_sim1
|
||||
prima3
|
||||
verilog_attribute
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ DispatchQueue::terminateThreads()
|
|||
threads_[i].join();
|
||||
}
|
||||
}
|
||||
quit_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Reference in New Issue