Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2024-07-01 16:22:09 -07:00
commit 1c7f022cd0
24 changed files with 1933 additions and 234 deletions

View File

@ -80,6 +80,7 @@ set(STA_SOURCE
dcalc/LumpedCapDelayCalc.cc dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc dcalc/NetCaps.cc
dcalc/ParallelDelayCalc.cc dcalc/ParallelDelayCalc.cc
dcalc/PrimaDelayCalc.cc
dcalc/UnitDelayCalc.cc dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc graph/DelayFloat.cc

View File

@ -24,6 +24,7 @@
#include "ArnoldiDelayCalc.hh" #include "ArnoldiDelayCalc.hh"
#include "CcsCeffDelayCalc.hh" #include "CcsCeffDelayCalc.hh"
#include "CcsSimDelayCalc.hh" #include "CcsSimDelayCalc.hh"
#include "PrimaDelayCalc.hh"
namespace sta { namespace sta {
@ -41,6 +42,7 @@ registerDelayCalcs()
registerDelayCalc("arnoldi", makeArnoldiDelayCalc); registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
registerDelayCalc("ccs_ceff", makeCcsCeffDelayCalc); registerDelayCalc("ccs_ceff", makeCcsCeffDelayCalc);
registerDelayCalc("ccs_sim", makeCcsSimDelayCalc); registerDelayCalc("ccs_sim", makeCcsSimDelayCalc);
registerDelayCalc("prima", makePrimaDelayCalc);
} }
void void

View File

@ -21,6 +21,7 @@
#include "Sta.hh" #include "Sta.hh"
#include "ArcDelayCalc.hh" #include "ArcDelayCalc.hh"
#include "dcalc/ArcDcalcWaveforms.hh" #include "dcalc/ArcDcalcWaveforms.hh"
#include "dcalc/PrimaDelayCalc.hh"
%} %}
@ -133,4 +134,16 @@ ccs_load_waveform(const Pin *in_pin,
return Table1(); 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 %} // inline

1131
dcalc/PrimaDelayCalc.cc Normal file

File diff suppressed because it is too large Load Diff

263
dcalc/PrimaDelayCalc.hh Normal file
View File

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

View File

@ -15,15 +15,15 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # 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 The STA is built in C++ with heavy use of STL (Standard Template
Libraries). It also uses the zlib library to read compressed Verilog, Libraries). It also uses the zlib library to read compressed Liberty,
SDF, SPF, and SPEF files. Verilog, SDF, SPF, and SPEF files.
The sub-directories of the STA code are: The sub-directories of the STA code are:
doc doc
Documentation files. Documentation files.
util util
Basic utilities. Basic utilities.
liberty liberty
Liberty timing library classes and file reader. Liberty timing library classes and file reader.
network network
@ -33,7 +33,7 @@ verilog
graph graph
Timing graph built from network and library cell timing arcs. Timing graph built from network and library cell timing arcs.
sdc sdc
SDC timing constraint classes. SDC timing constraint classes.
sdf sdf
SDF reader, writer and annotator. SDF reader, writer and annotator.
dcalc dcalc
@ -42,7 +42,7 @@ search
Search engine used to annotate the graph with arrival, required times Search engine used to annotate the graph with arrival, required times
and find timing check slacks. and find timing check slacks.
parasitics parasitics
Parasitics API, Spef and Spf readers. Parasitics API, Spef and Spf readers.
app app
Interface between Tcl and STA (built with SWIG). Interface between Tcl and STA (built with SWIG).
Main program definition. Main program definition.
@ -60,45 +60,45 @@ STA API
------- -------
Major components of the STA such as the network, timing graph, sdc, 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. contains an instance of each of these components.
The Sta class defines the bulk of the externally visible API used by The Sta class defines the bulk of the externally visible API used by
the Tcl interface, and coordinates operations that involve multiple 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 the Tcl command interpreter, the Sta passes the declaration on to the
Sdc component and tells the Search component to invalidate all arrival Sdc component and tells the Search component to invalidate all arrival
and required times. and required times.
Applications should call functions defined by the Sta class rather 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 by the components will get you in trouble unless you understand them
in detail. For example, telling the delay calculator to recompute the in detail. For example, telling the delay calculator to recompute the
delays leaves the arrival times that depend on them wrong. Always delays leaves the arrival times that depend on them wrong. Always
remember that the Sta coordinates the components. remember that the Sta coordinates the components.
In general, objects passed as arguments to Sta functions that are In general, objects passed as arguments to Sta functions that are
constructors become "owned" by the STA and should not be deleted by 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 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 arguments are copied by the Sta functions before they are retained in
STA data structures. STA data structures.
In many cases the major components contain pointers to other 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 components that makes initialization of pointers to the components
easier. easier.
An STA with modified behavior can be built by defining classes derived An STA with modified behavior can be built by defining classes derived
from the component classes and overloading some of the member from the component classes and overloading some of the member
functions (which may have to be modified to be virtual). Components functions (which may have to be modified to be virtual). Components
are created by Sta::makeComponents(). The Sta::makeComponents() are created by Sta::makeComponents(). The Sta::makeComponents()
function in turn calls each of the Sta::make<Component> component function in turn calls each of the Sta::make<Component> component
constructors. These constructors can be overloaded by redefining them constructors. These constructors can be overloaded by redefining them
in a class derived from Sta. Because the components refer to each in a class derived from Sta. Because the components refer to each
other, Sta::updateComponentsState() must be called to notify the other, Sta::updateComponentsState() must be called to notify the
components if any of them are changed after creation. components if any of them are changed after creation.
The file liberty/LibertyExt.cc contains an example that shows how the The file liberty/LibertyExt.cc contains an example that shows how the
liberty reader is replaced with a custom one on the Sta object. liberty reader is replaced with a custom one on the Sta object.
@ -121,19 +121,16 @@ Utilities
--------- ---------
The most significant utilities are the Vector, Map and Set templated 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 these classes is to provide Java-like iterators that can be passed
around as one object. STL iterators require the container to be around as one object. STL iterators require the container to be
useful. Iterators uniformly use the hasNext() function to test to see useful. Iterators uniformly use the hasNext() function to test to see
if there is another member and next() to access the next iteration if there is another member and next() to access the next iteration
member. 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. 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 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 encapsulated by functions in the the ReportTcl class. Printing inside
the STA is directed to the Tcl channels so that it appears with the the STA is directed to the Tcl channels so that it appears with the
Tcl interpreter output. Tcl interpreter output.
@ -142,21 +139,22 @@ Network
------- -------
The network API is the key to making the STA a timing engine that can 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 efficiently communicate with external network data structures without
the overhead of making and maintaining a copying of it. the overhead of making and maintaining a copying of it.
The network API encapsulates both library and netlist accessors. The network API encapsulates both library and netlist accessors.
Libraries are composed of cells that have ports the define connections Libraries are composed of cells that have ports that define connections
to the cell. Netlists are built out of cell instances, pins and nets. to the cell. Netlists are built out of cell instances, pins and nets.
The ConcreteLibrary and ConcreteNetwork classes are used by the STA The ConcreteLibrary and ConcreteNetwork classes are used by the STA
netlist readers. These class definitions are to support a stand alone netlist readers (notibly Verilog). These class definitions are to
STA that does not depend on external netlist data structures. 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 External network data structures are interfaced to the STA by casting
pointers to network object across the interface. The external objects pointers to network objects across the interface. The external objects
do not have to be derived from STA network base classes. The network do not have to be derived from STA network base classes. The network
API functions are typically very thin functions that cast the STA API functions are typically very thin functions that cast the STA
network types to the external class types and call the corresponding network types to the external class types and call the corresponding
external network database accessor. 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 iterators are provided for the expanded and unexpanded set of cell
ports. ports.
Network instances are calls of cells in the design hierarchy. Both Network instances are calls of cells in the design hierarchy. Both
hierarchcial and leaf instances are in the network. Hierarchical hierarchcial and leaf instances are in the network. Hierarchical
instances have children instances at the next lower hierarchy level. 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 of the hierarchy is a top level instance that has instances for the
top level netlist. If a cell has multiple instances the entire top level netlist. If a cell has multiple instances the entire
sub-tree of hierarchy is repeated in the network. This "unfolded" sub-tree of hierarchy is repeated in the network. This "unfolded"
network representation allows optimization to specialize instances of 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 one sub-tree for each hierarchical block means that all copies must
have identical sub-trees, preventing optimations that specialize the have identical sub-trees, preventing optimations that specialize the
contents. contents.
Pins are a connection between an instance and a net corresponding to a 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 (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. in the network that are the top level inputs and outputs.
Nets connect together a group of pins. Both hierarchical and leaf Nets connect together a group of pins. Both hierarchical and leaf
pins are on a net. Nets can connect pins on multiple levels of pins are on a net. Nets can connect pins on multiple levels of
hierarchy. hierarchy.
The network objects inside the STA are always pointers to instances of The network objects inside the STA are always pointers to instances of
undefined class objects. The implementation and definition of the undefined class objects. The implementation and definition of the
network objects themselves is never visible inside the STA. The network objects themselves is never visible inside the STA. The
network API is implemented as an adapter that performs all operations network API is implemented as an adapter that performs all operations
on all network objects. There is one network adapter instance used by on all network objects. There is one network adapter instance used by
all STA code. For example, to find the cell of an instance all STA code. For example, to find the cell of an instance
Cell *cell = network->cell(instance); Cell *cell = network->cell(instance);
The network adapter returns iterators for looping over groups of 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. children of the top level instance.
Instance *top_instance = network->topInstance(); 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 An adapter to a network database is built by defining a class derived
from the base class Network, or NetworkEdit if it supports incremental from the base class Network, or NetworkEdit if it supports incremental
editing operations. network/ConcreteNetwork.cc and oa/OaNetwork.cc editing operations. network/ConcreteNetwork.cc is a example of
are sample network adapters. 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 A network adaptor to interface to an external network database must
define the virtual functions of the Network class (about 45 define the virtual functions of the Network class (about 45
functions). The external network objects do not have to use any STA functions). The external network objects do not have to use any STA
network objects as base classes or even be C++ objects. These network network objects as base classes or even be C++ objects. These network
adapter functions should cast the network object pointers to the adapter functions should cast the network object pointers to the
underlying network object. underlying network object.
@ -231,8 +232,7 @@ functions to find corresponding liberty objects.
virtual LibertyPort *libertyPort(Port *port) const; virtual LibertyPort *libertyPort(Port *port) const;
The NetworkLiberty class provides implementations of the first two The NetworkLiberty class provides implementations of the first two
functions for derived network classes. The OaNetwork class shows an functions for derived network classes.
implentation that uses the NetworkLiberty class.
If the network adapter implements the NetworkEdit API the following If the network adapter implements the NetworkEdit API the following
TCL commands are supported: TCL commands are supported:
@ -253,13 +253,13 @@ Liberty
------- -------
The liberty timing library reader builds classes that are derived from 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 port classes, there are classes to represent timing arcs, timing
models, wireload models, operating conditions, and scale factors for models, wireload models, operating conditions, and scale factors for
derating timing data. derating timing data.
Timing arcs are grouped into sets of arcs between a pair of cell 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. and output; one for a rising output and another for a falling output.
The timing arcs are: 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 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 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: in this arc set:
S f -> Z r S f -> Z r
@ -283,19 +283,19 @@ in this arc set:
S r -> Z f S r -> Z f
The liberty file reader can be customized to read attributes that are 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 Graph
----- -----
The timing graph is the central data structure used by the delay The timing graph is the central data structure used by the delay
calculation and search algorithms. It is annotated with timing arc calculation and search algorithms. It is annotated with timing arc
delay values and slews (from SDF or a delay calculator). A forward delay values and slews (from SDF or a delay calculator). A forward
search annotates the graph with arrival times, and a backward search search annotates the graph with arrival times, and a backward search
annotates required times. annotates required times.
The graph is composed of vertices and edges. Each pin in the design 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 has a vertex. Bidirect pins have two vertices, one for its use as an
input and another for its use as an output. input and another for its use as an output.
The Network adapter supplies functions to find and set the index 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 pointer to the vertex used for a bidirectional pin driver is kept in
a map owned by the Graph class. a map owned by the Graph class.
Edges in the graph connect vertices. The pins connected together by a 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 net have wire edges between the pin vertices. Timing arc sets in the
leaf instance timing models have corresponding edges in the graph leaf instance timing models have corresponding edges in the graph
between pins on the instance. between pins on the instance.
The Graph class constructor option slew_tr_count is used to prevent 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 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 delay values. This is useful if an external delay calculator is used
to annotate delays on the graph. In this case the Graph functions to annotate delays on the graph. In this case the Graph functions
arcDelay and wireDelay should be overloaded to return delay values arcDelay and wireDelay should be overloaded to return delay values
stored outside of the STA. stored outside of the STA.
@ -347,93 +347,89 @@ Delay Calculation
----------------- -----------------
The graph is annotated with arc delay values and slews (also known as The graph is annotated with arc delay values and slews (also known as
transition times) by the graph delay calculator and the SDF reader. transition times) by the graph delay calculator or the SDF reader.
The GraphDelayCalc class seeds slews and arrival times from SDC The GraphDelayCalc class seeds slews from SDC constraints and uses a
constraints and uses a breadth first search to visit each gate output breadth first search to visit each gate output pin. The GraphDelayCalc
pin. The GraphDelayCalc then calls a timing arc delay calculator for then calls a timing arc delay calculator for each timing arc and
each timing arc and annotates the graph arc delays and vertex slews. annotates the graph arc delays and vertex slews.
The delay calculator is architeched to support multiple delay 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 analysis point (class DcalcAnalysisPt) that specifies the operating
conditions and parasitics used to find the delays. conditions and parasitics used to find the delays.
The ArcDelayCalc class defines the API used by the GraphDelayCalc to The ArcDelayCalc class defines the API used by the GraphDelayCalc to
calculate the gate delay, driver slew, load delays and load slews 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: 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 LumpedCapArcDelayCalc - Liberty table models using lumped capacitive
load (RSPF pi model total capacitance). Wire delays are zero. 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.
DmpCeffElmoreDelayCalc - RSPF (Driver Pi model with elmore interconnect 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: model as described in the following paper:
"Performance Computation for Precharacterized CMOS Gates with RC Loads", "Performance Computation for Precharacterized CMOS Gates with RC Loads",
Florentin Dartu, Noel Menezes and Lawrence Pileggi, IEEE Transactions Florentin Dartu, Noel Menezes and Lawrence Pileggi, IEEE Transactions
on Computer-Aided Design of Integrated Circuits and Systems, Vol 15, No 5, on Computer-Aided Design of Integrated Circuits and Systems, Vol 15, No 5,
May 1996. May 1996.
Wire delays are computed by applying the driver waveform to Wire delays are computed by applying the driver waveform to
the RSPF dependent source and solving the RC network. the RSPF dependent source and solving the RC network.
DmpCeffTwoPoleDelayCalc - Driver Pi model with two pole interconnect DmpCeffTwoPoleDelayCalc - Driver Pi model with two pole interconnect
delays and effective capacitance as in DmpCeffElmoreDelayCalc. delays and effective capacitance as in DmpCeffElmoreDelayCalc.
Other delay calculators can be interfaced by defining a class based on Other delay calculators can be interfaced by defining a class based on
ArcDelayCalc and using the registerDelayCalc function to register it 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. function can be used to set the delay calculator at run time.
Search Search
------ ------
A breadth first forward search is used to find arrival times at graph A breadth first forward search is used to find arrival times at graph
vertices. Vertices are annotated with instances of the Event class to vertices. Vertices are annotated with instances of the Event class to
record signal arrival and required times. As each vertex is visited record signal arrival and required times. As each vertex is visited
in the forward search its required time is found using If the vertex 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 is constrained by setup or hold timing checks, min/max path delay
exceptions or gated timing checks its required time is found from the exceptions or gated timing checks its required time is found from the
SDC. The slack is the difference between the vertex required time and SDC. The slack is the difference between the vertex required time and
arrival time. If the vertex is constrained it is scheduled for a arrival time. If the vertex is constrained it is scheduled for a
breadth first backward search to propagate required times to the fanin 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 used for each clock edge and exception set that cause a vertex to
change. change.
Arrival, required and slack calculations are incremental using a level 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 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 for any vertex with a lower/higher logic level when the
arrival/required time is requested. arrival/required time is requested.
Clock arrival times are found before data arrival times by Clock arrival times are found before data arrival times by
Search::findClkArrivals(). Clock arrival times now include insertion Search::findClkArrivals(). Clock arrival times include insertion delay
delay (source latency). (source latency).
When an incremental netlist change is made (for instance, changing the When an incremental netlist change is made (for instance, changing the
drive strengh of a gate with swap_cell), the STA incrementally updates drive strengh of a gate with swap_cell), the STA incrementally updates
delay calculation, arrival times, required times and slacks. Because delay calculation, arrival times, required times and slacks. Because
gate delay is only weakly dependent on slew (transition time), the gate delay is only weakly dependent on slew, the effect of the change
effect of the change will diminish in gates downstream of the change. will diminish in gates downstream of the change. The STA uses a
The STA uses a tolerance on the gate delays to determine when to stop tolerance on the gate delays to determine when to stop propagating the
propagating the change. The tolerance is set using the change. The tolerance is set using the
Sta::setIncrementalDelayTolerance function. Sta::setIncrementalDelayTolerance function.
void Sta::setIncrementalDelayTolerance(float tol); void Sta::setIncrementalDelayTolerance(float tol);
The tolerance is a percentage (0.0:1.0) change in delay that causes The tolerance is a percentage (0.0:1.0) change in delay that causes
downstream delays to be recomputed during incremental delay downstream delays to be recomputed during incremental delay
calculation. The default value is 0.0 for maximum accuracy and calculation. The default value is 0.0 for maximum accuracy and
slowest incremental speed. The delay calculation will not recompute slowest incremental speed. The delay calculation will not recompute
delays for downstream gates when the change in the gate delay is less 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 any gate delay changes, so increasing the tolerance can significantly
reduce incremental timing run time. 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) 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. code from the description file.
All user interface code is written in Tcl. SDC argument parsing and All commands are written in Tcl. SDC argument parsing and checking is
checking is done with Tcl procedures that call a SWIG interface done with Tcl procedures that call a SWIG interface function.
function. All reporting commands are written in Tcl so they can be
easily customized.
The Tcl 'sta' namespace is used to segregate internal STA functions 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. are exported to the global Tcl namespace.
A lot of the internal STA state can be accessed from Tcl to make A lot of the internal STA state can be accessed from Tcl to make
debugging a lot easier. Some debugging commands require a namespace debugging a easier. Some debugging commands require a namespace
qualifier because they are not intended for casual users. Some qualifier because they are not intended for casual users. Some
examples are shown below. examples are shown below.
sta::report_arrival sta::report_arrival
@ -473,21 +467,10 @@ examples are shown below.
sta::network_leaf_pin_count sta::network_leaf_pin_count
Additionally, many of the STA network and graph objects themselvs are Additionally, many of the STA network and graph objects themselvs are
exposed to Tcl using SWIG. These Tcl objects have methods for exposed to Tcl using SWIG. These Tcl objects have methods for
inspecting them. Examples of how to use these methods can be found in inspecting them. Examples of how to use these methods can be found in
the tcl/Graph.tcl and tcl/Network.tcl files. 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 Architecture alternatives for using the STA Engine
-------------------------------------------------- --------------------------------------------------
@ -496,15 +479,15 @@ an application.
* STA with TCL application * STA with TCL application
The simplest example is an application written in TCL. The The simplest example is an application written in TCL. The application
application calls STA commands and primitives defined in /tcl and calls STA commands and primitives defined in the swig c++/tcl
tcl/StaTcl.i. A stand-alone STA executable is built and a TCL file interface. A stand-alone STA executable is built and a TCL file that
that defines the application is included as part of the STA by defines the application is included as part of the STA by modifying
modifying app/Makefile.am to add the TCL file to app/TclInitVar.cc. CMakeLists.txt to add the TCL file to app/TclInitVar.cc.
The user calls STA commands to read design files (liberty, verilog, The user calls STA commands to read design files (liberty, verilog,
SDF, parasitics) to define and link the design. The user defines SDC 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. commands.
A simple gate sizer is an example of an application that can be built 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 * STA with C++ application
The application is built by adding C++ files to the /app directory and 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 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 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. TCL files to TclInitVar.cc.
The user calls STA commands to read design files (liberty, verilog, The user calls STA commands to read design files (liberty, verilog,
SDF, parasitics) to define and link the design. The user defines SDC 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. commands.
* C++ application without native Network data structures linking STA libraries * 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. app/StaMain.cc.
The application must link and instanciate a TCL interpreter to read 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 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. that can be read by calling TCL commands or Sta class member functions.
Liberty files that define the leaf cells used in the design. Liberty files that define the leaf cells used in the design.
Read using the read_liberty command or by calling Sta::readLibertyFile(). 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 command or by calling readVerilogFile() (see verilog/Verilog.i
read_verilog). read_verilog).
@ -561,7 +544,7 @@ Sta::deleteInstance() to edit the network.
The application defines a Network adapter (described above) so that The application defines a Network adapter (described above) so that
the STA can use the native network data structures without duplicating 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 that defines the makeNetwork() member function to build an instance of
the network adapter. 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. data structures that the STA accesses through the Network adapter.
The application must link and instanciate a TCL interpreter to read 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 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. 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. SDC commands to define timing constraints.
Defined using SDC commands in the TCL interpreter, or sourced 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. Parasitics used by delay calculation.
Read using the read_parasitics command, Sta::readParasitics(), or Read using the read_parasitics command, Sta::readParasitics(), or

View File

@ -764,6 +764,8 @@ public:
// Is the clock for timing checks. // Is the clock for timing checks.
bool isCheckClk() const { return is_check_clk_; } bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_clk); void setIsCheckClk(bool is_clk);
bool isPad() const { return is_pad_; }
void setIsPad(bool is_pad);
RiseFall *pulseClkTrigger() const { return pulse_clk_trigger_; } RiseFall *pulseClkTrigger() const { return pulse_clk_trigger_; }
// Rise for high, fall for low. // Rise for high, fall for low.
RiseFall *pulseClkSense() const { return pulse_clk_sense_; } RiseFall *pulseClkSense() const { return pulse_clk_sense_; }
@ -863,6 +865,7 @@ protected:
bool level_shifter_data_:1; bool level_shifter_data_:1;
bool is_switch_:1; bool is_switch_:1;
bool is_disabled_constraint_:1; bool is_disabled_constraint_:1;
bool is_pad_:1;
private: private:
friend class LibertyLibrary; friend class LibertyLibrary;

View File

@ -269,6 +269,7 @@ public:
protected: protected:
void makeWireloadNetworkWorst(Parasitic *parasitic, void makeWireloadNetworkWorst(Parasitic *parasitic,
const Pin *drvr_pin, const Pin *drvr_pin,
const Net *net,
float wireload_cap, float wireload_cap,
float wireload_res, float wireload_res,
float fanout); float fanout);

View File

@ -1996,7 +1996,8 @@ LibertyPort::LibertyPort(LibertyCell *cell,
isolation_cell_enable_(false), isolation_cell_enable_(false),
level_shifter_data_(false), level_shifter_data_(false),
is_switch_(false), is_switch_(false),
is_disabled_constraint_(false) is_disabled_constraint_(false),
is_pad_(false)
{ {
liberty_port_ = this; liberty_port_ = this;
min_pulse_width_[RiseFall::riseIndex()] = 0.0; min_pulse_width_[RiseFall::riseIndex()] = 0.0;
@ -2472,6 +2473,12 @@ LibertyPort::setIsDisabledConstraint(bool is_disabled)
is_disabled_constraint_ = is_disabled; is_disabled_constraint_ = is_disabled;
} }
void
LibertyPort::setIsPad(bool is_pad)
{
is_pad_ = is_pad;
}
LibertyPort * LibertyPort *
LibertyPort::cornerPort(const Corner *corner, LibertyPort::cornerPort(const Corner *corner,
const MinMax *min_max) const MinMax *min_max)

View File

@ -297,6 +297,7 @@ LibertyReader::defineVisitors()
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse); defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
defineAttrVisitor("is_macro_cell", &LibertyReader::visitIsMacro); defineAttrVisitor("is_macro_cell", &LibertyReader::visitIsMacro);
defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory); defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory);
defineAttrVisitor("pad_cell", &LibertyReader::visitIsPadCell);
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad); defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
defineAttrVisitor("is_clock_cell", &LibertyReader::visitIsClockCell); defineAttrVisitor("is_clock_cell", &LibertyReader::visitIsClockCell);
defineAttrVisitor("is_level_shifter", &LibertyReader::visitIsLevelShifter); defineAttrVisitor("is_level_shifter", &LibertyReader::visitIsLevelShifter);
@ -2887,13 +2888,13 @@ LibertyReader::visitIsMemory(LibertyAttr *attr)
} }
void void
LibertyReader::visitIsPad(LibertyAttr *attr) LibertyReader::visitIsPadCell(LibertyAttr *attr)
{ {
if (cell_) { if (cell_) {
bool is_pad, exists; bool pad_cell, exists;
getAttrBool(attr, is_pad, exists); getAttrBool(attr, pad_cell, exists);
if (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 void
LibertyReader::visitCapacitance(LibertyAttr *attr) LibertyReader::visitCapacitance(LibertyAttr *attr)
{ {

View File

@ -187,6 +187,7 @@ public:
virtual void visitDontUse(LibertyAttr *attr); virtual void visitDontUse(LibertyAttr *attr);
virtual void visitIsMacro(LibertyAttr *attr); virtual void visitIsMacro(LibertyAttr *attr);
virtual void visitIsMemory(LibertyAttr *attr); virtual void visitIsMemory(LibertyAttr *attr);
virtual void visitIsPadCell(LibertyAttr *attr);
virtual void visitIsPad(LibertyAttr *attr); virtual void visitIsPad(LibertyAttr *attr);
virtual void visitIsClockCell(LibertyAttr *attr); virtual void visitIsClockCell(LibertyAttr *attr);
virtual void visitIsLevelShifter(LibertyAttr *attr); virtual void visitIsLevelShifter(LibertyAttr *attr);

View File

@ -203,7 +203,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
const MinMax *min_max, const MinMax *min_max,
const ParasiticAnalysisPt *ap) const ParasiticAnalysisPt *ap)
{ {
Net *net = network_->net(drvr_pin); const Net *net = findParasiticNet(drvr_pin);
Parasitic *parasitic = makeParasiticNetwork(net, false, ap); Parasitic *parasitic = makeParasiticNetwork(net, false, ap);
const OperatingConditions *op_cond = sdc_->operatingConditions(min_max); const OperatingConditions *op_cond = sdc_->operatingConditions(min_max);
float wireload_cap, wireload_res; float wireload_cap, wireload_res;
@ -214,7 +214,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
tree = op_cond->wireloadTree(); tree = op_cond->wireloadTree();
switch (tree) { switch (tree) {
case WireloadTree::worst_case: case WireloadTree::worst_case:
makeWireloadNetworkWorst(parasitic, drvr_pin, wireload_cap, makeWireloadNetworkWorst(parasitic, drvr_pin, net, wireload_cap,
wireload_res, fanout); wireload_res, fanout);
break; break;
case WireloadTree::balanced: case WireloadTree::balanced:
@ -235,12 +235,12 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
void void
Parasitics::makeWireloadNetworkWorst(Parasitic *parasitic, Parasitics::makeWireloadNetworkWorst(Parasitic *parasitic,
const Pin *drvr_pin, const Pin *drvr_pin,
const Net *net,
float wireload_cap, float wireload_cap,
float wireload_res, float wireload_res,
float /* fanout */) float /* fanout */)
{ {
ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_);
Net *net = network_->net(drvr_pin);
size_t resistor_index = 1; size_t resistor_index = 1;
ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0, network_); ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0, network_);
makeResistor(parasitic, resistor_index++, wireload_res, drvr_node, load_node); makeResistor(parasitic, resistor_index++, wireload_res, drvr_node, load_node);

View File

@ -19,8 +19,10 @@
#include <cmath> // abs #include <cmath> // abs
#include <algorithm> #include <algorithm>
#include "Fuzzy.hh"
#include "Report.hh" #include "Report.hh"
#include "Debug.hh" #include "Debug.hh"
#include "DispatchQueue.hh"
#include "Units.hh" #include "Units.hh"
#include "TimingArc.hh" #include "TimingArc.hh"
#include "Liberty.hh" #include "Liberty.hh"
@ -53,17 +55,20 @@ public:
void operator=(const ClkSkew &clk_skew); void operator=(const ClkSkew &clk_skew);
PathVertex *srcPath() { return &src_path_; } PathVertex *srcPath() { return &src_path_; }
PathVertex *tgtPath() { return &tgt_path_; } PathVertex *tgtPath() { return &tgt_path_; }
float srcLatency(StaState *sta); float srcLatency(const StaState *sta);
float tgtLatency(StaState *sta); float tgtLatency(const StaState *sta);
float srcInternalClkLatency(StaState *sta); float srcInternalClkLatency(const StaState *sta);
float tgtInternalClkLatency(StaState *sta); float tgtInternalClkLatency(const StaState *sta);
Crpr crpr(StaState *sta); Crpr crpr(const StaState *sta);
float uncertainty(StaState *sta); float uncertainty(const StaState *sta);
float skew() const { return skew_; } float skew() const { return skew_; }
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkew &clk_skew2,
const StaState *sta);
private: private:
float clkTreeDelay(PathVertex &clk_path, float clkTreeDelay(PathVertex &clk_path,
StaState *sta); const StaState *sta);
PathVertex src_path_; PathVertex src_path_;
PathVertex tgt_path_; PathVertex tgt_path_;
@ -109,7 +114,7 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
} }
float float
ClkSkew::srcLatency(StaState *sta) ClkSkew::srcLatency(const StaState *sta)
{ {
Arrival src_arrival = src_path_.arrival(sta); Arrival src_arrival = src_path_.arrival(sta);
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time() return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time()
@ -117,13 +122,13 @@ ClkSkew::srcLatency(StaState *sta)
} }
float float
ClkSkew::srcInternalClkLatency(StaState *sta) ClkSkew::srcInternalClkLatency(const StaState *sta)
{ {
return clkTreeDelay(src_path_, sta); return clkTreeDelay(src_path_, sta);
} }
float float
ClkSkew::tgtLatency(StaState *sta) ClkSkew::tgtLatency(const StaState *sta)
{ {
Arrival tgt_arrival = tgt_path_.arrival(sta); Arrival tgt_arrival = tgt_path_.arrival(sta);
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time() return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time()
@ -131,14 +136,14 @@ ClkSkew::tgtLatency(StaState *sta)
} }
float float
ClkSkew::tgtInternalClkLatency(StaState *sta) ClkSkew::tgtInternalClkLatency(const StaState *sta)
{ {
return clkTreeDelay(tgt_path_, sta); return clkTreeDelay(tgt_path_, sta);
} }
float float
ClkSkew::clkTreeDelay(PathVertex &clk_path, ClkSkew::clkTreeDelay(PathVertex &clk_path,
StaState *sta) const StaState *sta)
{ {
if (include_internal_latency_) { if (include_internal_latency_) {
const Vertex *vertex = clk_path.vertex(sta); const Vertex *vertex = clk_path.vertex(sta);
@ -154,14 +159,14 @@ ClkSkew::clkTreeDelay(PathVertex &clk_path,
} }
Crpr Crpr
ClkSkew::crpr(StaState *sta) ClkSkew::crpr(const StaState *sta)
{ {
CheckCrpr *check_crpr = sta->search()->checkCrpr(); CheckCrpr *check_crpr = sta->search()->checkCrpr();
return check_crpr->checkCrpr(&src_path_, &tgt_path_); return check_crpr->checkCrpr(&src_path_, &tgt_path_);
} }
float float
ClkSkew::uncertainty(StaState *sta) ClkSkew::uncertainty(const StaState *sta)
{ {
TimingRole *check_role = (src_path_.minMax(sta) == SetupHold::max()) TimingRole *check_role = (src_path_.minMax(sta) == SetupHold::max())
? TimingRole::setup() ? TimingRole::setup()
@ -171,10 +176,27 @@ ClkSkew::uncertainty(StaState *sta)
check_role, 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) : ClkSkews::ClkSkews(StaState *sta) :
StaState(sta) StaState(sta),
fanout_pred_(sta)
{ {
} }
@ -275,54 +297,86 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
bool include_internal_latency) bool include_internal_latency)
{ {
ClkSkewMap skews; 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) for (const Clock *clk : clks)
clk_set.insert(clk); clk_set_.insert(clk);
for (Vertex *src_vertex : *graph_->regClkVertices()) { if (thread_count_ > 1) {
if (hasClkPaths(src_vertex, clk_set)) { std::vector<ClkSkewMap> partial_skews(thread_count_, skews);
VertexOutEdgeIterator edge_iter(src_vertex, graph_); for (Vertex *src_vertex : *graph_->regClkVertices()) {
while (edge_iter.hasNext()) { if (hasClkPaths(src_vertex)) {
Edge *edge = edge_iter.next(); dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) {
if (edge->role()->genericRole() == TimingRole::regClkToQ()) { findClkSkewFrom(src_vertex, partial_skews[i]);
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);
}
} }
} }
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; return skews;
} }
bool bool
ClkSkews::hasClkPaths(Vertex *vertex, ClkSkews::hasClkPaths(Vertex *vertex)
ConstClockSet &clks)
{ {
VertexPathIterator path_iter(vertex, this); VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) { while (path_iter.hasNext()) {
PathVertex *path = path_iter.next(); PathVertex *path = path_iter.next();
const Clock *path_clk = path->clock(this); 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 true;
} }
return false; 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 void
ClkSkews::findClkSkewFrom(Vertex *src_vertex, ClkSkews::findClkSkewFrom(Vertex *src_vertex,
Vertex *q_vertex, Vertex *q_vertex,
const RiseFallBoth *src_rf, const RiseFallBoth *src_rf,
ConstClockSet &clk_set,
const Corner *corner,
const SetupHold *setup_hold,
bool include_internal_latency,
ClkSkewMap &skews) ClkSkewMap &skews)
{ {
VertexSet endpoints = findFanout(q_vertex); VertexSet endpoints = findFanout(q_vertex);
@ -332,18 +386,16 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
Edge *edge = edge_iter.next(); Edge *edge = edge_iter.next();
TimingRole *role = edge->role(); TimingRole *role = edge->role();
if (role->isTimingCheck() if (role->isTimingCheck()
&& ((setup_hold == SetupHold::max() && ((setup_hold_ == SetupHold::max()
&& role->genericRole() == TimingRole::setup()) && role->genericRole() == TimingRole::setup())
|| ((setup_hold == SetupHold::min() || ((setup_hold_ == SetupHold::min()
&& role->genericRole() == TimingRole::hold())))) { && role->genericRole() == TimingRole::hold())))) {
Vertex *tgt_vertex = edge->from(graph_); Vertex *tgt_vertex = edge->from(graph_);
const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge();
const RiseFallBoth *tgt_rf = tgt_rf1 const RiseFallBoth *tgt_rf = tgt_rf1
? tgt_rf1->asRiseFallBoth() ? tgt_rf1->asRiseFallBoth()
: RiseFallBoth::riseFall(); : RiseFallBoth::riseFall();
findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, skews);
clk_set, corner, setup_hold,
include_internal_latency, skews);
} }
} }
} }
@ -354,24 +406,20 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
const RiseFallBoth *src_rf, const RiseFallBoth *src_rf,
Vertex *tgt_vertex, Vertex *tgt_vertex,
const RiseFallBoth *tgt_rf, const RiseFallBoth *tgt_rf,
ConstClockSet &clk_set,
const Corner *corner,
const SetupHold *setup_hold,
bool include_internal_latency,
ClkSkewMap &skews) ClkSkewMap &skews)
{ {
Unit *time_unit = units_->timeUnit(); 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); VertexPathIterator src_iter(src_vertex, this);
while (src_iter.hasNext()) { while (src_iter.hasNext()) {
PathVertex *src_path = src_iter.next(); PathVertex *src_path = src_iter.next();
const Clock *src_clk = src_path->clock(this); const Clock *src_clk = src_path->clock(this);
if (src_rf->matches(src_path->transition(this)) if (src_rf->matches(src_path->transition(this))
&& src_path->minMax(this) == setup_hold && src_path->minMax(this) == setup_hold_
&& clk_set.find(src_clk) != clk_set.end()) { && clk_set_.find(src_clk) != clk_set_.end()) {
Corner *src_corner = src_path->pathAnalysisPt(this)->corner(); Corner *src_corner = src_path->pathAnalysisPt(this)->corner();
if (corner == nullptr if (corner_ == nullptr
|| src_corner == corner) { || src_corner == corner_) {
VertexPathIterator tgt_iter(tgt_vertex, this); VertexPathIterator tgt_iter(tgt_vertex, this);
while (tgt_iter.hasNext()) { while (tgt_iter.hasNext()) {
PathVertex *tgt_path = tgt_iter.next(); PathVertex *tgt_path = tgt_iter.next();
@ -381,7 +429,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
&& tgt_rf->matches(tgt_path->transition(this)) && tgt_rf->matches(tgt_path->transition(this))
&& tgt_path->minMax(this) == tgt_min_max && tgt_path->minMax(this) == tgt_min_max
&& tgt_path->pathAnalysisPt(this)->corner() == src_corner) { && 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]; ClkSkew &clk_skew = skews[src_clk];
debugPrint(debug_, "clk_skew", 2, debugPrint(debug_, "clk_skew", 2,
"%s %s %s -> %s %s %s crpr = %s skew = %s", "%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: VertexSet endpoints(graph_);
FanOutSrchPred(const StaState *sta); UnorderedSet<Vertex*> visited;
virtual bool searchThru(Edge *edge); 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) : FanOutSrchPred::FanOutSrchPred(const StaState *sta) :
SearchPred1(sta) SearchPred1(sta)
@ -426,25 +500,4 @@ FanOutSrchPred::searchThru(Edge *edge)
|| role == TimingRole::tristateDisable()); || 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 } // namespace

View File

@ -18,18 +18,28 @@
#include <map> #include <map>
#include "UnorderedSet.hh"
#include "SdcClass.hh" #include "SdcClass.hh"
#include "StaState.hh" #include "StaState.hh"
#include "Transition.hh" #include "Transition.hh"
#include "SearchClass.hh" #include "SearchClass.hh"
#include "SearchPred.hh"
#include "PathVertex.hh" #include "PathVertex.hh"
namespace sta { namespace sta {
class ClkSkew; class ClkSkew;
class SearchPred;
typedef std::map<const Clock*, ClkSkew> ClkSkewMap; 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. // Find and report clock skews between source/target registers.
class ClkSkews : public StaState class ClkSkews : public StaState
{ {
@ -51,28 +61,30 @@ protected:
const Corner *corner, const Corner *corner,
const SetupHold *setup_hold, const SetupHold *setup_hold,
bool include_internal_latency); bool include_internal_latency);
bool hasClkPaths(Vertex *vertex, bool hasClkPaths(Vertex *vertex);
ConstClockSet &clks); void findClkSkewFrom(Vertex *src_vertex,
ClkSkewMap &skews);
void findClkSkewFrom(Vertex *src_vertex, void findClkSkewFrom(Vertex *src_vertex,
Vertex *q_vertex, Vertex *q_vertex,
const RiseFallBoth *src_rf, const RiseFallBoth *src_rf,
ConstClockSet &clk_set,
const Corner *corner,
const SetupHold *setup_hold,
bool include_internal_latency,
ClkSkewMap &skews); ClkSkewMap &skews);
void findClkSkew(Vertex *src_vertex, void findClkSkew(Vertex *src_vertex,
const RiseFallBoth *src_rf, const RiseFallBoth *src_rf,
Vertex *tgt_vertex, Vertex *tgt_vertex,
const RiseFallBoth *tgt_rf, const RiseFallBoth *tgt_rf,
ConstClockSet &clk_set,
const Corner *corner,
const SetupHold *setup_hold,
bool include_internal_latency,
ClkSkewMap &skews); ClkSkewMap &skews);
VertexSet findFanout(Vertex *from); VertexSet findFanout(Vertex *from);
void findFanout1(Vertex *from,
UnorderedSet<Vertex*> &visited,
VertexSet &endpoints);
void reportClkSkew(ClkSkew &clk_skew, void reportClkSkew(ClkSkew &clk_skew,
int digits); int digits);
ConstClockSet clk_set_;
const Corner *corner_;
const SetupHold *setup_hold_;
bool include_internal_latency_;
FanOutSrchPred fanout_pred_;
}; };
} // namespace } // namespace

View File

@ -246,7 +246,8 @@ GenClkMasterSearchPred::searchThru(Edge *edge)
const Sdc *sdc = sta_->sdc(); const Sdc *sdc = sta_->sdc();
TimingRole *role = edge->role(); TimingRole *role = edge->role();
// Propagate clocks through constants. // Propagate clocks through constants.
return !(edge->isDisabledLoop() return !(edge->role()->isTimingCheck()
|| edge->isDisabledLoop()
|| edge->isDisabledConstraint() || edge->isDisabledConstraint()
// Constants disable edge cond expression. // Constants disable edge cond expression.
|| edge->isDisabledCond() || edge->isDisabledCond()

View File

@ -359,6 +359,8 @@ Sta::updateComponentsState()
if (check_timing_) if (check_timing_)
check_timing_->copyState(this); check_timing_->copyState(this);
clk_network_->copyState(this); clk_network_->copyState(this);
if (clk_skews_)
clk_skews_->copyState(this);
if (power_) if (power_)
power_->copyState(this); power_->copyState(this);
} }

BIN
test/asap7_seq.lib.gz Normal file

Binary file not shown.

BIN
test/asap7_simple.lib.gz Normal file

Binary file not shown.

51
test/prima3.ok Normal file
View File

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

13
test/prima3.tcl Normal file
View File

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

135
test/reg1_asap7.spef Normal file
View File

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

11
test/reg1_asap7.v Normal file
View File

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

View File

@ -123,6 +123,7 @@ record_example_tests {
record_sta_tests { record_sta_tests {
ccs_sim1 ccs_sim1
prima3
verilog_attribute verilog_attribute
} }

View File

@ -35,6 +35,7 @@ DispatchQueue::terminateThreads()
threads_[i].join(); threads_[i].join();
} }
} }
quit_ = false;
} }
void void