commit
fbfc705282
|
|
@ -61,8 +61,8 @@ compiled locally. Derivative works are supported as long as they
|
||||||
adhere to the GPL license requirements. However, OpenSTA is not
|
adhere to the GPL license requirements. However, OpenSTA is not
|
||||||
supported by a public community of developers as many other open
|
supported by a public community of developers as many other open
|
||||||
source projects are. The copyright and develpment are exclusive to
|
source projects are. The copyright and develpment are exclusive to
|
||||||
Parallax Software. OpenSTA does not solicit or accept external code
|
Parallax Software. Contributors must signing the Contributor License
|
||||||
contributions.
|
Agreement (doc/CLA.txt) when submitting pull requests.
|
||||||
|
|
||||||
Removing copyright and license notices from OpenSTA sources (or any
|
Removing copyright and license notices from OpenSTA sources (or any
|
||||||
other open source project for that matter) is illegal. This should be
|
other open source project for that matter) is illegal. This should be
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,21 @@ Naming conventions
|
||||||
|
|
||||||
directory - lowercase (directory)
|
directory - lowercase (directory)
|
||||||
filename - corresponding class name without prefix (Filename)
|
filename - corresponding class name without prefix (Filename)
|
||||||
class - capitalized (ClassName)
|
class - upper camel case (ClassName)
|
||||||
member function - lowercase/capitalized (memberFunction)
|
member function - upper camel case (memberFunction)
|
||||||
member variable - lowercase/underscore/trailing underscore (member_variable_)
|
member variable - snake case with trailing underscore (member_variable_)
|
||||||
Trailing underscore prevents conflict with accessor
|
Trailing underscore prevents conflict with accessor
|
||||||
member function name.
|
member function name.
|
||||||
function - lowercase/capitalized (functionName)
|
function - lower camel case (functionName)
|
||||||
comments - use capitalized sentences that end with periods
|
comments - use capitalized sentences that end with periods
|
||||||
|
|
||||||
C++ code files should use a .cc file extension
|
C++ code files should use a .cc file extension
|
||||||
C++ header files should use a .hh file extension
|
C++ header files should use a .hh file extension
|
||||||
|
|
||||||
Use ifdef/define's to protect headers from being read more than once.
|
Use pragmas to protect headers from being read more than once instead of
|
||||||
Name the define variable the same as the header in uppercase.
|
ifdef/define.
|
||||||
For example, for Clock.hh
|
|
||||||
|
|
||||||
#ifndef STA_CLOCK_H
|
#pragma once
|
||||||
#define STA_CLOCK_H
|
|
||||||
...
|
|
||||||
#endif
|
|
||||||
|
|
||||||
In general it is better to for class variables to use pointers to
|
In general it is better to for class variables to use pointers to
|
||||||
objects of other classes rather than embedding the instance directly.
|
objects of other classes rather than embedding the instance directly.
|
||||||
|
|
@ -35,22 +31,23 @@ where Directory is the capitalized name of the sub-directory.
|
||||||
Place comments describing public functions and classes in header files
|
Place comments describing public functions and classes in header files
|
||||||
rather than code files because a consumer is more likely to have
|
rather than code files because a consumer is more likely to have
|
||||||
access to the header and that is the first place they will look.
|
access to the header and that is the first place they will look.
|
||||||
Comments for private functions can be in the source file.
|
|
||||||
|
|
||||||
The return type of a function should be on the line before the
|
The return type of a function should be on the line before the
|
||||||
function name. Spaces should be added after commas in the argument
|
function name. Arguments should be on separate lines to make it easier
|
||||||
list. Split the function arguments to fit on one line. For example:
|
to remove or add them without having to reformat the lines as they
|
||||||
|
change length.
|
||||||
|
|
||||||
return_type
|
return_type
|
||||||
function(type1 arg1, type2, arg2)
|
function(type1 arg1,
|
||||||
|
type2 arg2)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Functions should be less than one screen long. Break long functions
|
Functions should be less than one screen long. Break long functions
|
||||||
up into smaller ones. Lines should be less than 80 characters long.
|
up into smaller ones. Lines should be less than 90 characters long.
|
||||||
|
|
||||||
Try to avoid assignments inside `if'-conditions. For example, don't
|
Avoid assignments inside `if'-conditions. For example, don't write
|
||||||
write this:
|
this:
|
||||||
|
|
||||||
if ((foo = (char *) malloc (sizeof *foo)) == 0)
|
if ((foo = (char *) malloc (sizeof *foo)) == 0)
|
||||||
fatal ("virtual memory exhausted");
|
fatal ("virtual memory exhausted");
|
||||||
|
|
@ -102,8 +99,8 @@ Don't declare class variables as const. It means any downstream code
|
||||||
that accesses the member cannot modify it, which is overly
|
that accesses the member cannot modify it, which is overly
|
||||||
restrictive.
|
restrictive.
|
||||||
|
|
||||||
Never use [] to lookup a map value because it creates a key/null value
|
Avoid using [] to lookup a map value because it creates a key/null value
|
||||||
pair if the lookup fails. Use sta::Map::findKey instead.
|
pair if the lookup fails. Use map::find or sta::Map::findKey instead.
|
||||||
|
|
||||||
Avoid nested classes/enums because SWIG has trouble with them.
|
Avoid nested classes/enums because SWIG has trouble with them.
|
||||||
|
|
||||||
|
|
@ -127,24 +124,6 @@ cmd unknown keyword option
|
||||||
cmd unknown
|
cmd unknown
|
||||||
sdf pin not found
|
sdf pin not found
|
||||||
|
|
||||||
................................................................
|
|
||||||
|
|
||||||
if configure.ac changes
|
|
||||||
autoconf
|
|
||||||
|
|
||||||
if Makefile.am changes
|
|
||||||
automake
|
|
||||||
|
|
||||||
Adding a new source file
|
|
||||||
Add header and source to source_dir/Makefile.am
|
|
||||||
cd source_dir; make clean
|
|
||||||
|
|
||||||
Adding a new source directory
|
|
||||||
Add to configure.ac STA_SUBDIRS, AC_CONFIG_FILES
|
|
||||||
bootstrap
|
|
||||||
configure
|
|
||||||
make
|
|
||||||
|
|
||||||
................................................................
|
................................................................
|
||||||
Swig notes
|
Swig notes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -276,10 +276,19 @@ Graph::makeWireEdgesFromPin(const Pin *drvr_pin,
|
||||||
{
|
{
|
||||||
// Find all drivers and loads on the net to avoid N*M run time
|
// Find all drivers and loads on the net to avoid N*M run time
|
||||||
// for large fanin/fanout nets.
|
// for large fanin/fanout nets.
|
||||||
PinSeq loads, drvrs;
|
PinSeq drvrs, loads;
|
||||||
FindNetDrvrLoads visitor(drvr_pin, visited_drvrs, loads, drvrs, network_);
|
FindNetDrvrLoads visitor(drvr_pin, visited_drvrs, loads, drvrs, network_);
|
||||||
network_->visitConnectedPins(drvr_pin, visitor);
|
network_->visitConnectedPins(drvr_pin, visitor);
|
||||||
|
|
||||||
|
if (isIsolatedNet(drvrs, loads)) {
|
||||||
|
for (auto drvr_pin : drvrs) {
|
||||||
|
visited_drvrs.insert(drvr_pin);
|
||||||
|
debugPrint(debug_, "graph", 1, "ignoring isolated driver %s",
|
||||||
|
network_->pathName(drvr_pin));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto drvr_pin : drvrs) {
|
for (auto drvr_pin : drvrs) {
|
||||||
for (auto load_pin : loads) {
|
for (auto load_pin : loads) {
|
||||||
if (drvr_pin != load_pin)
|
if (drvr_pin != load_pin)
|
||||||
|
|
@ -288,6 +297,35 @@ Graph::makeWireEdgesFromPin(const Pin *drvr_pin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for nets with bidirect drivers that have no fanin or
|
||||||
|
// fanout. One example of these nets are bidirect pad ring pins
|
||||||
|
// are connected together but have no function but are marked
|
||||||
|
// as signal nets.
|
||||||
|
// These nets tickle N^2 behaviors that have no function.
|
||||||
|
bool
|
||||||
|
Graph::isIsolatedNet(PinSeq &drvrs,
|
||||||
|
PinSeq &loads) const
|
||||||
|
{
|
||||||
|
if (drvrs.size() < 10)
|
||||||
|
return false;
|
||||||
|
// Check that all drivers have no fanin.
|
||||||
|
for (auto drvr_pin : drvrs) {
|
||||||
|
Vertex *drvr_vertex = pinDrvrVertex(drvr_pin);
|
||||||
|
if (network_->isTopLevelPort(drvr_pin)
|
||||||
|
|| drvr_vertex->hasFanin())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check for fanout on the load pins.
|
||||||
|
for (auto load_pin : loads) {
|
||||||
|
Vertex *load_vertex = pinLoadVertex(load_pin);
|
||||||
|
if (load_vertex->hasFanout()
|
||||||
|
|| load_vertex->hasChecks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Graph::makeWireEdgesToPin(const Pin *to_pin)
|
Graph::makeWireEdgesToPin(const Pin *to_pin)
|
||||||
{
|
{
|
||||||
|
|
@ -536,7 +574,7 @@ Graph::makeArrivals(Vertex *vertex,
|
||||||
uint32_t count)
|
uint32_t count)
|
||||||
{
|
{
|
||||||
if (vertex->arrivals() != arrival_null)
|
if (vertex->arrivals() != arrival_null)
|
||||||
debugPrint(debug_, "leaks", 617, "arrival leak");
|
debugPrint(debug_, "graph", 1, "arrival leak");
|
||||||
Arrival *arrivals;
|
Arrival *arrivals;
|
||||||
ArrivalId id;
|
ArrivalId id;
|
||||||
{
|
{
|
||||||
|
|
@ -569,7 +607,7 @@ Graph::makeRequireds(Vertex *vertex,
|
||||||
uint32_t count)
|
uint32_t count)
|
||||||
{
|
{
|
||||||
if (vertex->requireds() != arrival_null)
|
if (vertex->requireds() != arrival_null)
|
||||||
debugPrint(debug_, "leaks", 617, "required leak");
|
debugPrint(debug_, "graph", 1, "required leak");
|
||||||
Required *requireds;
|
Required *requireds;
|
||||||
ArrivalId id;
|
ArrivalId id;
|
||||||
{
|
{
|
||||||
|
|
@ -1281,6 +1319,18 @@ Vertex::setIsDisabledConstraint(bool disabled)
|
||||||
is_disabled_constraint_ = disabled;
|
is_disabled_constraint_ = disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Vertex::hasFanin() const
|
||||||
|
{
|
||||||
|
return in_edges_ != edge_id_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Vertex::hasFanout() const
|
||||||
|
{
|
||||||
|
return out_edges_ != edge_id_null;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vertex::setHasChecks(bool has_checks)
|
Vertex::setHasChecks(bool has_checks)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ public:
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
Slew &drvr_slew); // __attribute__ ((deprecated));
|
Slew &drvr_slew); // __attribute__ ((deprecated));
|
||||||
|
|
||||||
// Find gate delays and slews for parallel gates.
|
// Find gate delays and slews for parallel gates.
|
||||||
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
|
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,8 @@ protected:
|
||||||
void makePinVertices(const Instance *inst);
|
void makePinVertices(const Instance *inst);
|
||||||
void makeWireEdgesFromPin(const Pin *drvr_pin,
|
void makeWireEdgesFromPin(const Pin *drvr_pin,
|
||||||
PinSet &visited_drvrs);
|
PinSet &visited_drvrs);
|
||||||
|
bool isIsolatedNet(PinSeq &drvrs,
|
||||||
|
PinSeq &loads) const;
|
||||||
void makeWireEdges();
|
void makeWireEdges();
|
||||||
virtual void makeInstDrvrWireEdges(const Instance *inst,
|
virtual void makeInstDrvrWireEdges(const Instance *inst,
|
||||||
PinSet &visited_drvrs);
|
PinSet &visited_drvrs);
|
||||||
|
|
@ -289,6 +291,8 @@ public:
|
||||||
Level level() const { return level_; }
|
Level level() const { return level_; }
|
||||||
void setLevel(Level level);
|
void setLevel(Level level);
|
||||||
bool isRoot() const{ return level_ == 0; }
|
bool isRoot() const{ return level_ == 0; }
|
||||||
|
bool hasFanin() const;
|
||||||
|
bool hasFanout() const;
|
||||||
LevelColor color() const { return static_cast<LevelColor>(color_); }
|
LevelColor color() const { return static_cast<LevelColor>(color_); }
|
||||||
void setColor(LevelColor color);
|
void setColor(LevelColor color);
|
||||||
ArrivalId arrivals() { return arrivals_; }
|
ArrivalId arrivals() { return arrivals_; }
|
||||||
|
|
|
||||||
|
|
@ -796,14 +796,20 @@ public:
|
||||||
void setDriverWaveform(DriverWaveform *driver_waveform,
|
void setDriverWaveform(DriverWaveform *driver_waveform,
|
||||||
const RiseFall *rf);
|
const RiseFall *rf);
|
||||||
void setClkTreeDelay(const TableModel *model,
|
void setClkTreeDelay(const TableModel *model,
|
||||||
const RiseFall *rf,
|
const RiseFall *from_rf,
|
||||||
|
const RiseFall *to_rf,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
|
// Should be deprecated.
|
||||||
float clkTreeDelay(float in_slew,
|
float clkTreeDelay(float in_slew,
|
||||||
const RiseFall *rf,
|
const RiseFall *from_rf,
|
||||||
|
const MinMax *min_max) const;
|
||||||
|
float clkTreeDelay(float in_slew,
|
||||||
|
const RiseFall *from_rf,
|
||||||
|
const RiseFall *to_rf,
|
||||||
const MinMax *min_max) const;
|
const MinMax *min_max) const;
|
||||||
// Assumes input slew of 0.0.
|
// Assumes input slew of 0.0.
|
||||||
RiseFallMinMax clkTreeDelays() const;
|
RiseFallMinMax clkTreeDelays() const;
|
||||||
RiseFallMinMax clockTreePathDelays() const; // __attribute__ ((deprecated))
|
RiseFallMinMax clockTreePathDelays() const; // __attribute__ ((deprecated));
|
||||||
|
|
||||||
static bool equiv(const LibertyPort *port1,
|
static bool equiv(const LibertyPort *port1,
|
||||||
const LibertyPort *port2);
|
const LibertyPort *port2);
|
||||||
|
|
@ -846,7 +852,7 @@ protected:
|
||||||
ReceiverModelPtr receiver_model_;
|
ReceiverModelPtr receiver_model_;
|
||||||
DriverWaveform *driver_waveform_[RiseFall::index_count];
|
DriverWaveform *driver_waveform_[RiseFall::index_count];
|
||||||
// Redundant with clock_tree_path_delay timing arcs but faster to access.
|
// Redundant with clock_tree_path_delay timing arcs but faster to access.
|
||||||
const TableModel *clk_tree_delay_[RiseFall::index_count][MinMax::index_count];
|
const TableModel *clk_tree_delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
||||||
|
|
||||||
unsigned int min_pulse_width_exists_:RiseFall::index_count;
|
unsigned int min_pulse_width_exists_:RiseFall::index_count;
|
||||||
bool min_period_exists_:1;
|
bool min_period_exists_:1;
|
||||||
|
|
|
||||||
|
|
@ -1896,7 +1896,7 @@ void
|
||||||
LibertyCell::ensureVoltageWaveforms()
|
LibertyCell::ensureVoltageWaveforms()
|
||||||
{
|
{
|
||||||
if (!have_voltage_waveforms_) {
|
if (!have_voltage_waveforms_) {
|
||||||
float vdd = 0.0;
|
float vdd = 0;
|
||||||
bool vdd_exists;
|
bool vdd_exists;
|
||||||
liberty_library_->supplyVoltage("VDD", vdd, vdd_exists);
|
liberty_library_->supplyVoltage("VDD", vdd, vdd_exists);
|
||||||
if (!vdd_exists || vdd == 0.0)
|
if (!vdd_exists || vdd == 0.0)
|
||||||
|
|
@ -2001,9 +2001,11 @@ LibertyPort::LibertyPort(LibertyCell *cell,
|
||||||
liberty_port_ = this;
|
liberty_port_ = this;
|
||||||
min_pulse_width_[RiseFall::riseIndex()] = 0.0;
|
min_pulse_width_[RiseFall::riseIndex()] = 0.0;
|
||||||
min_pulse_width_[RiseFall::fallIndex()] = 0.0;
|
min_pulse_width_[RiseFall::fallIndex()] = 0.0;
|
||||||
for (auto rf_index : RiseFall::rangeIndex()) {
|
for (auto from_rf_index : RiseFall::rangeIndex()) {
|
||||||
for (auto mm_index : MinMax::rangeIndex())
|
for (auto to_rf_index : RiseFall::rangeIndex()) {
|
||||||
clk_tree_delay_[rf_index][mm_index] = nullptr;
|
for (auto mm_index : MinMax::rangeIndex())
|
||||||
|
clk_tree_delay_[from_rf_index][to_rf_index][mm_index] = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2607,12 +2609,15 @@ RiseFallMinMax
|
||||||
LibertyPort::clkTreeDelays() const
|
LibertyPort::clkTreeDelays() const
|
||||||
{
|
{
|
||||||
RiseFallMinMax delays;
|
RiseFallMinMax delays;
|
||||||
for (const RiseFall *rf : RiseFall::range()) {
|
for (const RiseFall *from_rf : RiseFall::range()) {
|
||||||
for (const MinMax *min_max : MinMax::range()) {
|
for (const RiseFall *to_rf : RiseFall::range()) {
|
||||||
const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()];
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
if (model) {
|
const TableModel *model =
|
||||||
float delay = model->findValue(0.0, 0.0, 0.0);
|
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()];
|
||||||
delays.setValue(rf, min_max, delay);
|
if (model) {
|
||||||
|
float delay = model->findValue(0.0, 0.0, 0.0);
|
||||||
|
delays.setValue(from_rf, min_max, delay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2624,7 +2629,21 @@ LibertyPort::clkTreeDelay(float in_slew,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max) const
|
const MinMax *min_max) const
|
||||||
{
|
{
|
||||||
const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()];
|
const TableModel *model = clk_tree_delay_[rf->index()][rf->index()][min_max->index()];
|
||||||
|
if (model)
|
||||||
|
return model->findValue(in_slew, 0.0, 0.0);
|
||||||
|
else
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
LibertyPort::clkTreeDelay(float in_slew,
|
||||||
|
const RiseFall *from_rf,
|
||||||
|
const RiseFall *to_rf,
|
||||||
|
const MinMax *min_max) const
|
||||||
|
{
|
||||||
|
const TableModel *model =
|
||||||
|
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()];
|
||||||
if (model)
|
if (model)
|
||||||
return model->findValue(in_slew, 0.0, 0.0);
|
return model->findValue(in_slew, 0.0, 0.0);
|
||||||
else
|
else
|
||||||
|
|
@ -2633,10 +2652,11 @@ LibertyPort::clkTreeDelay(float in_slew,
|
||||||
|
|
||||||
void
|
void
|
||||||
LibertyPort::setClkTreeDelay(const TableModel *model,
|
LibertyPort::setClkTreeDelay(const TableModel *model,
|
||||||
const RiseFall *rf,
|
const RiseFall *from_rf,
|
||||||
|
const RiseFall *to_rf,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
clk_tree_delay_[rf->index()][min_max->index()] = model;
|
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()] = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -642,9 +642,27 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
||||||
for (auto to_rf : RiseFall::range()) {
|
for (auto to_rf : RiseFall::range()) {
|
||||||
TimingModel *model = attrs->model(to_rf);
|
TimingModel *model = attrs->model(to_rf);
|
||||||
if (model) {
|
if (model) {
|
||||||
makeTimingArc(arc_set, nullptr, to_rf->asTransition(), model);
|
|
||||||
const GateTableModel *gate_model = dynamic_cast<GateTableModel *>(model);
|
const GateTableModel *gate_model = dynamic_cast<GateTableModel *>(model);
|
||||||
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, min_max);
|
RiseFall *opp_rf = to_rf->opposite();
|
||||||
|
switch (attrs->timingSense()) {
|
||||||
|
case TimingSense::positive_unate:
|
||||||
|
makeTimingArc(arc_set, to_rf, to_rf, model);
|
||||||
|
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, to_rf, min_max);
|
||||||
|
break;
|
||||||
|
case TimingSense::negative_unate:
|
||||||
|
makeTimingArc(arc_set, opp_rf, to_rf, model);
|
||||||
|
to_port->setClkTreeDelay(gate_model->delayModel(), opp_rf, to_rf, min_max);
|
||||||
|
break;
|
||||||
|
case TimingSense::non_unate:
|
||||||
|
case TimingSense::unknown:
|
||||||
|
makeTimingArc(arc_set, to_rf, to_rf, model);
|
||||||
|
makeTimingArc(arc_set, opp_rf, to_rf, model);
|
||||||
|
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, to_rf, min_max);
|
||||||
|
to_port->setClkTreeDelay(gate_model->delayModel(), opp_rf, to_rf, min_max);
|
||||||
|
break;
|
||||||
|
case TimingSense::none:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arc_set;
|
return arc_set;
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,13 @@ public:
|
||||||
float &lib_clk_delay,
|
float &lib_clk_delay,
|
||||||
float &latency,
|
float &latency,
|
||||||
PathVertex &path,
|
PathVertex &path,
|
||||||
bool &exists);
|
bool &exists) const;
|
||||||
void latency(const RiseFall *src_rf,
|
void latency(const RiseFall *src_rf,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
// Return values.
|
// Return values.
|
||||||
float &delay,
|
float &delay,
|
||||||
bool &exists);
|
bool &exists) const;
|
||||||
static float latency(PathVertex *clk_path,
|
static float latency(PathVertex *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
void setLatency(const RiseFall *src_rf,
|
void setLatency(const RiseFall *src_rf,
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ ClkDelays::delay(const RiseFall *src_rf,
|
||||||
float &lib_clk_delay,
|
float &lib_clk_delay,
|
||||||
float &latency,
|
float &latency,
|
||||||
PathVertex &path,
|
PathVertex &path,
|
||||||
bool &exists)
|
bool &exists) const
|
||||||
{
|
{
|
||||||
int src_rf_index = src_rf->index();
|
int src_rf_index = src_rf->index();
|
||||||
int end_rf_index = end_rf->index();
|
int end_rf_index = end_rf->index();
|
||||||
|
|
@ -213,7 +213,7 @@ ClkDelays::latency(const RiseFall *src_rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
// Return values.
|
// Return values.
|
||||||
float &latency,
|
float &latency,
|
||||||
bool &exists)
|
bool &exists) const
|
||||||
{
|
{
|
||||||
int src_rf_index = src_rf->index();
|
int src_rf_index = src_rf->index();
|
||||||
int end_rf_index = end_rf->index();
|
int end_rf_index = end_rf->index();
|
||||||
|
|
|
||||||
|
|
@ -168,9 +168,8 @@ MakeTimingModel::findArea()
|
||||||
while (leaf_iter->hasNext()) {
|
while (leaf_iter->hasNext()) {
|
||||||
const Instance *inst = leaf_iter->next();
|
const Instance *inst = leaf_iter->next();
|
||||||
const LibertyCell *cell = network_->libertyCell(inst);
|
const LibertyCell *cell = network_->libertyCell(inst);
|
||||||
if (cell) {
|
if (cell)
|
||||||
area += cell->area();
|
area += cell->area();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
delete leaf_iter;
|
delete leaf_iter;
|
||||||
return area;
|
return area;
|
||||||
|
|
@ -546,30 +545,8 @@ MakeTimingModel::findClkInsertionDelays()
|
||||||
for (const Clock *clk : *clks) {
|
for (const Clock *clk : *clks) {
|
||||||
ClkDelays delays = sta_->findClkDelays(clk);
|
ClkDelays delays = sta_->findClkDelays(clk);
|
||||||
for (const MinMax *min_max : MinMax::range()) {
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
TimingArcAttrsPtr attrs = nullptr;
|
makeClkTreePaths(lib_port, min_max, TimingSense::positive_unate, delays);
|
||||||
for (const RiseFall *clk_rf : RiseFall::range()) {
|
makeClkTreePaths(lib_port, min_max, TimingSense::negative_unate, delays);
|
||||||
float delay = min_max->initValue();
|
|
||||||
for (const RiseFall *end_rf : RiseFall::range()) {
|
|
||||||
PathVertex clk_path;
|
|
||||||
float insertion, delay1, lib_clk_delay, latency;
|
|
||||||
bool exists;
|
|
||||||
delays.delay(clk_rf, end_rf, min_max, insertion, delay1,
|
|
||||||
lib_clk_delay, latency, clk_path, exists);
|
|
||||||
if (exists)
|
|
||||||
delay = min_max->minMax(delay, delayAsFloat(delay1));
|
|
||||||
}
|
|
||||||
TimingModel *model = makeGateModelScalar(delay, clk_rf);
|
|
||||||
if (attrs == nullptr)
|
|
||||||
attrs = std::make_shared<TimingArcAttrs>();
|
|
||||||
attrs->setModel(clk_rf, model);
|
|
||||||
}
|
|
||||||
if (attrs)
|
|
||||||
attrs->setTimingSense(TimingSense::positive_unate);
|
|
||||||
TimingRole *role = (min_max == MinMax::min())
|
|
||||||
? TimingRole::clockTreePathMin()
|
|
||||||
: TimingRole::clockTreePathMax();
|
|
||||||
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role,
|
|
||||||
min_max, attrs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -579,6 +556,38 @@ MakeTimingModel::findClkInsertionDelays()
|
||||||
delete port_iter;
|
delete port_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port,
|
||||||
|
const MinMax *min_max,
|
||||||
|
TimingSense sense,
|
||||||
|
const ClkDelays &delays)
|
||||||
|
{
|
||||||
|
TimingArcAttrsPtr attrs = nullptr;
|
||||||
|
for (const RiseFall *clk_rf : RiseFall::range()) {
|
||||||
|
const RiseFall *end_rf = (sense == TimingSense::positive_unate)
|
||||||
|
? clk_rf
|
||||||
|
: clk_rf->opposite();
|
||||||
|
PathVertex clk_path;
|
||||||
|
float insertion, delay, lib_clk_delay, latency;
|
||||||
|
bool exists;
|
||||||
|
delays.delay(clk_rf, end_rf, min_max, insertion, delay,
|
||||||
|
lib_clk_delay, latency, clk_path, exists);
|
||||||
|
if (exists) {
|
||||||
|
TimingModel *model = makeGateModelScalar(delay, end_rf);
|
||||||
|
if (attrs == nullptr)
|
||||||
|
attrs = std::make_shared<TimingArcAttrs>();
|
||||||
|
attrs->setModel(end_rf, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attrs) {
|
||||||
|
attrs->setTimingSense(sense);
|
||||||
|
TimingRole *role = (min_max == MinMax::min())
|
||||||
|
? TimingRole::clockTreePathMin()
|
||||||
|
: TimingRole::clockTreePathMax();
|
||||||
|
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, min_max, attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LibertyPort *
|
LibertyPort *
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,10 @@ private:
|
||||||
void findTimingFromInput(Port *input_port);
|
void findTimingFromInput(Port *input_port);
|
||||||
void findClkedOutputPaths();
|
void findClkedOutputPaths();
|
||||||
void findClkInsertionDelays();
|
void findClkInsertionDelays();
|
||||||
|
void makeClkTreePaths(LibertyPort *lib_port,
|
||||||
|
const MinMax *min_max,
|
||||||
|
TimingSense sense,
|
||||||
|
const ClkDelays &delays);
|
||||||
void findOutputDelays(const RiseFall *input_rf,
|
void findOutputDelays(const RiseFall *input_rf,
|
||||||
OutputPinDelays &output_pin_delays);
|
OutputPinDelays &output_pin_delays);
|
||||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue