Merge pull request #233 from The-OpenROAD-Project/up

Upstream merge
This commit is contained in:
Matt Liberty 2024-03-06 20:46:36 -08:00 committed by GitHub
commit fbfc705282
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 183 additions and 93 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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_; }

View File

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

View File

@ -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;
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

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

View File

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

View File

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

View File

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

View File

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