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
supported by a public community of developers as many other open
source projects are. The copyright and develpment are exclusive to
Parallax Software. OpenSTA does not solicit or accept external code
contributions.
Parallax Software. Contributors must signing the Contributor License
Agreement (doc/CLA.txt) when submitting pull requests.
Removing copyright and license notices from OpenSTA sources (or any
other open source project for that matter) is illegal. This should be

View File

@ -2,25 +2,21 @@ Naming conventions
directory - lowercase (directory)
filename - corresponding class name without prefix (Filename)
class - capitalized (ClassName)
member function - lowercase/capitalized (memberFunction)
member variable - lowercase/underscore/trailing underscore (member_variable_)
class - upper camel case (ClassName)
member function - upper camel case (memberFunction)
member variable - snake case with trailing underscore (member_variable_)
Trailing underscore prevents conflict with accessor
member function name.
function - lowercase/capitalized (functionName)
function - lower camel case (functionName)
comments - use capitalized sentences that end with periods
C++ code files should use a .cc file extension
C++ header files should use a .hh file extension
Use ifdef/define's to protect headers from being read more than once.
Name the define variable the same as the header in uppercase.
For example, for Clock.hh
Use pragmas to protect headers from being read more than once instead of
ifdef/define.
#ifndef STA_CLOCK_H
#define STA_CLOCK_H
...
#endif
#pragma once
In general it is better to for class variables to use pointers to
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
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.
Comments for private functions can be in the source file.
The return type of a function should be on the line before the
function name. Spaces should be added after commas in the argument
list. Split the function arguments to fit on one line. For example:
function name. Arguments should be on separate lines to make it easier
to remove or add them without having to reformat the lines as they
change length.
return_type
function(type1 arg1, type2, arg2)
function(type1 arg1,
type2 arg2)
{
}
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
write this:
Avoid assignments inside `if'-conditions. For example, don't write
this:
if ((foo = (char *) malloc (sizeof *foo)) == 0)
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
restrictive.
Never use [] to lookup a map value because it creates a key/null value
pair if the lookup fails. Use sta::Map::findKey instead.
Avoid using [] to lookup a map value because it creates a key/null value
pair if the lookup fails. Use map::find or sta::Map::findKey instead.
Avoid nested classes/enums because SWIG has trouble with them.
@ -127,24 +124,6 @@ cmd unknown keyword option
cmd unknown
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

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
// for large fanin/fanout nets.
PinSeq loads, drvrs;
PinSeq drvrs, loads;
FindNetDrvrLoads visitor(drvr_pin, visited_drvrs, loads, drvrs, network_);
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 load_pin : loads) {
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
Graph::makeWireEdgesToPin(const Pin *to_pin)
{
@ -536,7 +574,7 @@ Graph::makeArrivals(Vertex *vertex,
uint32_t count)
{
if (vertex->arrivals() != arrival_null)
debugPrint(debug_, "leaks", 617, "arrival leak");
debugPrint(debug_, "graph", 1, "arrival leak");
Arrival *arrivals;
ArrivalId id;
{
@ -569,7 +607,7 @@ Graph::makeRequireds(Vertex *vertex,
uint32_t count)
{
if (vertex->requireds() != arrival_null)
debugPrint(debug_, "leaks", 617, "required leak");
debugPrint(debug_, "graph", 1, "required leak");
Required *requireds;
ArrivalId id;
{
@ -1281,6 +1319,18 @@ Vertex::setIsDisabledConstraint(bool 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
Vertex::setHasChecks(bool has_checks)
{

View File

@ -180,7 +180,7 @@ public:
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew); // __attribute__ ((deprecated));
Slew &drvr_slew); // __attribute__ ((deprecated));
// Find gate delays and slews for parallel gates.
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,

View File

@ -221,6 +221,8 @@ protected:
void makePinVertices(const Instance *inst);
void makeWireEdgesFromPin(const Pin *drvr_pin,
PinSet &visited_drvrs);
bool isIsolatedNet(PinSeq &drvrs,
PinSeq &loads) const;
void makeWireEdges();
virtual void makeInstDrvrWireEdges(const Instance *inst,
PinSet &visited_drvrs);
@ -289,6 +291,8 @@ public:
Level level() const { return level_; }
void setLevel(Level level);
bool isRoot() const{ return level_ == 0; }
bool hasFanin() const;
bool hasFanout() const;
LevelColor color() const { return static_cast<LevelColor>(color_); }
void setColor(LevelColor color);
ArrivalId arrivals() { return arrivals_; }

View File

@ -796,14 +796,20 @@ public:
void setDriverWaveform(DriverWaveform *driver_waveform,
const RiseFall *rf);
void setClkTreeDelay(const TableModel *model,
const RiseFall *rf,
const RiseFall *from_rf,
const RiseFall *to_rf,
const MinMax *min_max);
// Should be deprecated.
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;
// Assumes input slew of 0.0.
RiseFallMinMax clkTreeDelays() const;
RiseFallMinMax clockTreePathDelays() const; // __attribute__ ((deprecated))
RiseFallMinMax clockTreePathDelays() const; // __attribute__ ((deprecated));
static bool equiv(const LibertyPort *port1,
const LibertyPort *port2);
@ -846,7 +852,7 @@ protected:
ReceiverModelPtr receiver_model_;
DriverWaveform *driver_waveform_[RiseFall::index_count];
// 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;
bool min_period_exists_:1;

View File

@ -1896,7 +1896,7 @@ void
LibertyCell::ensureVoltageWaveforms()
{
if (!have_voltage_waveforms_) {
float vdd = 0.0;
float vdd = 0;
bool vdd_exists;
liberty_library_->supplyVoltage("VDD", vdd, vdd_exists);
if (!vdd_exists || vdd == 0.0)
@ -2001,9 +2001,11 @@ LibertyPort::LibertyPort(LibertyCell *cell,
liberty_port_ = this;
min_pulse_width_[RiseFall::riseIndex()] = 0.0;
min_pulse_width_[RiseFall::fallIndex()] = 0.0;
for (auto rf_index : RiseFall::rangeIndex()) {
for (auto mm_index : MinMax::rangeIndex())
clk_tree_delay_[rf_index][mm_index] = nullptr;
for (auto from_rf_index : RiseFall::rangeIndex()) {
for (auto to_rf_index : RiseFall::rangeIndex()) {
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
{
RiseFallMinMax delays;
for (const RiseFall *rf : RiseFall::range()) {
for (const MinMax *min_max : MinMax::range()) {
const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()];
if (model) {
float delay = model->findValue(0.0, 0.0, 0.0);
delays.setValue(rf, min_max, delay);
for (const RiseFall *from_rf : RiseFall::range()) {
for (const RiseFall *to_rf : RiseFall::range()) {
for (const MinMax *min_max : MinMax::range()) {
const TableModel *model =
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()];
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 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)
return model->findValue(in_slew, 0.0, 0.0);
else
@ -2633,10 +2652,11 @@ LibertyPort::clkTreeDelay(float in_slew,
void
LibertyPort::setClkTreeDelay(const TableModel *model,
const RiseFall *rf,
const RiseFall *from_rf,
const RiseFall *to_rf,
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()) {
TimingModel *model = attrs->model(to_rf);
if (model) {
makeTimingArc(arc_set, nullptr, to_rf->asTransition(), 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;

View File

@ -36,13 +36,13 @@ public:
float &lib_clk_delay,
float &latency,
PathVertex &path,
bool &exists);
bool &exists) const;
void latency(const RiseFall *src_rf,
const RiseFall *end_rf,
const MinMax *min_max,
// Return values.
float &delay,
bool &exists);
bool &exists) const;
static float latency(PathVertex *clk_path,
StaState *sta);
void setLatency(const RiseFall *src_rf,

View File

@ -194,7 +194,7 @@ ClkDelays::delay(const RiseFall *src_rf,
float &lib_clk_delay,
float &latency,
PathVertex &path,
bool &exists)
bool &exists) const
{
int src_rf_index = src_rf->index();
int end_rf_index = end_rf->index();
@ -213,7 +213,7 @@ ClkDelays::latency(const RiseFall *src_rf,
const MinMax *min_max,
// Return values.
float &latency,
bool &exists)
bool &exists) const
{
int src_rf_index = src_rf->index();
int end_rf_index = end_rf->index();

View File

@ -168,9 +168,8 @@ MakeTimingModel::findArea()
while (leaf_iter->hasNext()) {
const Instance *inst = leaf_iter->next();
const LibertyCell *cell = network_->libertyCell(inst);
if (cell) {
if (cell)
area += cell->area();
}
}
delete leaf_iter;
return area;
@ -546,30 +545,8 @@ MakeTimingModel::findClkInsertionDelays()
for (const Clock *clk : *clks) {
ClkDelays delays = sta_->findClkDelays(clk);
for (const MinMax *min_max : MinMax::range()) {
TimingArcAttrsPtr attrs = nullptr;
for (const RiseFall *clk_rf : RiseFall::range()) {
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);
makeClkTreePaths(lib_port, min_max, TimingSense::positive_unate, delays);
makeClkTreePaths(lib_port, min_max, TimingSense::negative_unate, delays);
}
}
}
@ -579,6 +556,38 @@ MakeTimingModel::findClkInsertionDelays()
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 *

View File

@ -64,6 +64,10 @@ private:
void findTimingFromInput(Port *input_port);
void findClkedOutputPaths();
void findClkInsertionDelays();
void makeClkTreePaths(LibertyPort *lib_port,
const MinMax *min_max,
TimingSense sense,
const ClkDelays &delays);
void findOutputDelays(const RiseFall *input_rf,
OutputPinDelays &output_pin_delays);
void makeSetupHoldTimingArcs(const Pin *input_pin,