diff --git a/README.md b/README.md index 3c6bd4b0..6d5b0dad 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/doc/CodingGuidelines.txt b/doc/CodingGuidelines.txt index 80ea0eee..1c6f8dce 100644 --- a/doc/CodingGuidelines.txt +++ b/doc/CodingGuidelines.txt @@ -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 diff --git a/graph/Graph.cc b/graph/Graph.cc index c24d69ca..3ce7aec6 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -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) { diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index eb56da6f..b1dabe55 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -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, diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index eb53b2e7..593e0f2f 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -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(color_); } void setColor(LevelColor color); ArrivalId arrivals() { return arrivals_; } diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 30d3a02e..1d6e16c6 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -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; diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 7e52064e..e486915c 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -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; } //////////////////////////////////////////////////////////////// diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index dac8d59b..39a1f1b8 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -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(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; diff --git a/search/ClkDelays.hh b/search/ClkDelays.hh index 3aadfa88..003b705c 100644 --- a/search/ClkDelays.hh +++ b/search/ClkDelays.hh @@ -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, diff --git a/search/ClkLatency.cc b/search/ClkLatency.cc index 9e2e91a4..8c9c90ce 100644 --- a/search/ClkLatency.cc +++ b/search/ClkLatency.cc @@ -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(); diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index 04bf5c92..bacdaeea 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -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(); - 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(); + 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 * diff --git a/search/MakeTimingModelPvt.hh b/search/MakeTimingModelPvt.hh index da5f15b8..e7587f6f 100644 --- a/search/MakeTimingModelPvt.hh +++ b/search/MakeTimingModelPvt.hh @@ -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,