From 6a194ef6ee79aea22266cd926ad18190e9f6df7d Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sat, 25 May 2019 17:08:53 -0700 Subject: [PATCH] LibertyCell::higherDrive(), slowerDrive() --- CMakeLists.txt | 2 +- app/StaApp.i | 14 +++--- liberty/EquivCells.cc | 34 ++++++++++---- liberty/EquivCells.hh | 10 ++-- liberty/Liberty.cc | 36 +++++++++------ liberty/Liberty.hh | 99 ++++++++++++++++++++++------------------ liberty/LibertyReader.cc | 1 + search/Property.cc | 6 ++- search/Sta.cc | 2 +- search/Sta.hh | 2 +- tcl/StaTcl.i | 10 ++-- 11 files changed, 124 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28f362ee..9cd2f3b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -626,7 +626,7 @@ add_flex_bison_dependency(SdfLex SdfParser) include(FindSWIG) add_custom_command(OUTPUT ${STA_HOME}/app/StaApp_wrap.cc - COMMAND ${SWIG_EXECUTABLE} -tcl8 -c++ -namespace -prefix sta -o ${STA_HOME}/app/StaApp_wrap.cc ${STA_HOME}/app/StaApp.i + COMMAND ${SWIG_EXECUTABLE} -tcl8 -c++ -namespace -prefix sta -I${STA_HOME}/tcl -I${STA_HOME}/sdf -I${STA_HOME}/dcalc -I${STA_HOME}/parasitics -I${STA_HOME}/verilog -o ${STA_HOME}/app/StaApp_wrap.cc ${STA_HOME}/app/StaApp.i COMMAND ${STA_HOME}/etc/SwigCleanup.tcl ${STA_HOME}/app/StaApp_wrap.cc WORKING_DIRECTORY ${STA_HOME} DEPENDS ${STA_SWIG_FILES} diff --git a/app/StaApp.i b/app/StaApp.i index 68f32cd7..f38c4697 100644 --- a/app/StaApp.i +++ b/app/StaApp.i @@ -16,10 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -%include "../tcl/StaException.i" -%include "../tcl/StaTcl.i" -%include "../verilog/Verilog.i" -%include "../tcl/NetworkEdit.i" -%include "../sdf/Sdf.i" -%include "../dcalc/DelayCalc.i" -%include "../parasitics/Parasitics.i" +%include "StaException.i" +%include "StaTcl.i" +%include "Verilog.i" +%include "NetworkEdit.i" +%include "Sdf.i" +%include "DelayCalc.i" +%include "Parasitics.i" diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index e11caffa..b7cfc107 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -15,6 +15,7 @@ // along with this program. If not, see . #include "Machine.hh" +#include "UnorderedMap.hh" #include "PortDirection.hh" #include "Transition.hh" #include "MinMax.hh" @@ -28,14 +29,16 @@ namespace sta { -typedef Map > LibertyCellHashMap; +typedef UnorderedMap LibertyCellHashMap; typedef Set LibertyCellSeqSet; static LibertyCellEquivMap * findEquivCells1(const LibertyLibrary *library); static void +deleteEquivCellMap(LibertyCellEquivMap *equiv_map); +static void sortCellEquivs(LibertyCellEquivMap *cell_equivs); -float +static float cellDriveResistance(const LibertyCell *cell); static unsigned @@ -55,15 +58,19 @@ static bool equivCellSequentials(const LibertyCell *cell1, const LibertyCell *cell2); -LibertyCellEquivMap * -makeEquivCellMap(const LibertyLibrary *library) +void +findEquivCells(const LibertyLibrary *library) { + // Build a map from each cell in the library to a group (CellSeq) of + // cells with equivalent functionality. LibertyCellEquivMap *cell_equivs = findEquivCells1(library); + // Sort by drive strength. sortCellEquivs(cell_equivs); - return cell_equivs; + deleteEquivCellMap(cell_equivs); } -void +// Delete the LibertyCellEquivMap returned by makeEquivCellMap. +static void deleteEquivCellMap(LibertyCellEquivMap *equiv_map) { // Multiple cells can point to the same cell sequence, so collect @@ -147,14 +154,21 @@ sortCellEquivs(LibertyCellEquivMap *cell_equivs) while (equivs_iter.hasNext()) { LibertyCellSeq *equivs = equivs_iter.next(); sort(equivs, CellDriveResistanceLess()); + LibertyCell *lower = nullptr; + LibertyCellSeq::Iterator cell_iter(equivs); + while (cell_iter.hasNext()) { + LibertyCell *cell = cell_iter.next(); + if (lower) { + lower->setHigherDrive(cell); + cell->setLowerDrive(lower); + } + lower = cell; + } } } // Use the worst "drive" for all the timing arcs in the cell. -// Note that this function can NOT be static for sun's compiler to -// be happy with using it in a sort predicate (presumably because the -// template functions are compiled outside the scope of this file). -float +static float cellDriveResistance(const LibertyCell *cell) { float max_drive = 0.0; diff --git a/liberty/EquivCells.hh b/liberty/EquivCells.hh index 63aa5ea9..2b831052 100644 --- a/liberty/EquivCells.hh +++ b/liberty/EquivCells.hh @@ -22,14 +22,10 @@ namespace sta { -// Build a map from each cell in the library to a group (CellSeq) of -// cells with equivalent functionality, sorted by drive strength. -LibertyCellEquivMap * -makeEquivCellMap(const LibertyLibrary *library); - -// Delete the LibertyCellEquivMap returned by makeEquivCellMap. +// Find equivalent cells, sort by drive strength and +// and set cell->higherDrive/lowerDrive. void -deleteEquivCellMap(LibertyCellEquivMap *equiv_map); +findEquivCells(const LibertyLibrary *library); // Predicate that is true when the ports, functions, sequentials and // timing arcs match. diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 5a267ba8..8f474a72 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -82,7 +82,6 @@ LibertyLibrary::LibertyLibrary(const char *name, default_wire_load_mode_(WireloadMode::unknown), default_wire_load_selection_(nullptr), default_operating_conditions_(nullptr), - equiv_cell_map_(nullptr), ocv_arc_depth_(0.0), default_ocv_derate_(nullptr) { @@ -123,8 +122,6 @@ LibertyLibrary::~LibertyLibrary() operating_conditions_.deleteContents(); wireloads_.deleteContents(); wire_load_selections_.deleteContents(); - if (equiv_cell_map_) - deleteEquivCellMap(equiv_cell_map_); delete units_; ocv_derate_map_.deleteContents(); @@ -500,15 +497,6 @@ LibertyLibrary::setDefaultOutputPinRes(const TransRiseFall *tr, default_output_pin_res_.setValue(tr, value); } -LibertyCellSeq * -LibertyLibrary::findEquivCells(LibertyCell *cell) -{ - if (equiv_cell_map_ == nullptr) - equiv_cell_map_ = makeEquivCellMap(this); - LibertyCellSeq *equivs = equiv_cell_map_->findKey(cell); - return equivs; -} - void LibertyLibrary::addWireload(Wireload *wireload) { @@ -748,6 +736,12 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1, } } +void +LibertyLibrary::finish() +{ + findEquivCells(this); +} + //////////////////////////////////////////////////////////////// float @@ -849,7 +843,9 @@ LibertyCell::LibertyCell(LibertyLibrary *library, ocv_derate_(nullptr), is_disabled_constraint_(false), leakage_power_(0.0), - leakage_power_exists_(false) + leakage_power_exists_(false), + higher_drive_(nullptr), + lower_drive_(nullptr) { } @@ -1388,6 +1384,20 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell, //////////////////////////////////////////////////////////////// +void +LibertyCell::setHigherDrive(LibertyCell *cell) +{ + higher_drive_ = cell; +} + +void +LibertyCell::setLowerDrive(LibertyCell *cell) +{ + lower_drive_ = cell; +} + +//////////////////////////////////////////////////////////////// + float LibertyCell::ocvArcDepth() const { diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index fb603ecc..a0620e49 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -223,7 +223,6 @@ public: float slewDerateFromLibrary() const; void setSlewDerateFromLibrary(float derate); - LibertyCellSeq *findEquivCells(LibertyCell *cell); Units *units() { return units_; } const Units *units() const { return units_; } @@ -279,6 +278,7 @@ public: bool link, int ap_index, Report *report); + void finish(); protected: float degradeWireSlew(const LibertyCell *cell, @@ -322,7 +322,6 @@ protected: WireloadSelectionMap wire_load_selections_; OperatingConditionsMap operating_conditions_; OperatingConditions *default_operating_conditions_; - LibertyCellEquivMap *equiv_cell_map_; float ocv_arc_depth_; OcvDerate *default_ocv_derate_; OcvDerateMap ocv_derate_map_; @@ -391,9 +390,6 @@ public: void setScaleFactors(ScaleFactors *scale_factors); ModeDef *makeModeDef(const char *name); ModeDef *findModeDef(const char *name); - // Add scaled cell after it is complete. - void addScaledCell(OperatingConditions *op_cond, - LibertyCell *scaled_cell); float area() const { return area_; } void setArea(float area); @@ -410,15 +406,6 @@ public: bool isClockGateOther() const; bool isClockGate() const; void setClockGateType(ClockGateType type); - virtual unsigned addTimingArcSet(TimingArcSet *set); - void addTimingArcAttrs(TimingArcAttrs *attrs); - virtual void addInternalPower(InternalPower *power); - void addInternalPowerAttrs(InternalPowerAttrs *attrs); - virtual void addLeakagePower(LeakagePower *power); - // Call after cell is finished being constructed. - virtual void finish(bool infer_latches, - Report *report, - Debug *debug); // Internal to LibertyCellTimingArcSetIterator. TimingArcSetSeq *timingArcSets(const LibertyPort *from, const LibertyPort *to) const; @@ -427,13 +414,44 @@ public: TimingArcSet *findTimingArcSet(TimingArcSet *key) const; TimingArcSet *findTimingArcSet(unsigned arc_set_index) const; bool hasTimingArcs(LibertyPort *port) const; + InternalPowerSeq *internalPowers() { return &internal_powers_; } LeakagePowerSeq *leakagePowers() { return &leakage_powers_; } void leakagePower(// Return values. float &leakage, bool &exists) const; bool leakagePowerEx() const { return leakage_power_exists_; } + bool hasSequentials() const; + // Find the sequential with the output connected to an (internal) port. + Sequential *outputPortSequential(LibertyPort *port); + + // Find bus declaration local to this cell. + BusDcl *findBusDcl(const char *name) const; + // True when TimingArcSetBuilder::makeRegLatchArcs infers register + // timing arcs. + bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; } + TestCell *testCell() const { return test_cell_; } + bool isLatchData(LibertyPort *port); + void latchEnable(TimingArcSet *arc_set, + // Return values. + LibertyPort *&enable_port, + FuncExpr *&enable_func, + TransRiseFall *&enable_tr) const; + TransRiseFall *latchCheckEnableTrans(TimingArcSet *check_set); + bool isDisabledConstraint() const { return is_disabled_constraint_; } + LibertyCell *cornerCell(int ap_index); + + // AOCV + float ocvArcDepth() const; + OcvDerate *ocvDerate() const; + OcvDerate *findOcvDerate(const char *derate_name); + + // Next higher/lower drive equivalent cells. + LibertyCell *higherDrive() const { return higher_drive_; } + LibertyCell *lowerDrive() const { return lower_drive_; } + + // Build helpers. void makeSequential(int size, bool is_register, FuncExpr *clk, @@ -444,40 +462,31 @@ public: LogicValue clr_preset_out_inv, LibertyPort *output, LibertyPort *output_inv); - // Find the sequential with the output connected to an (internal) port. - Sequential *outputPortSequential(LibertyPort *port); - // Find bus declaration local to this cell. - BusDcl *findBusDcl(const char *name) const; void addBusDcl(BusDcl *bus_dcl); - // True when TimingArcSetBuilder::makeRegLatchArcs infers register - // timing arcs. - bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; } - void setHasInferedRegTimingArcs(bool infered); - TestCell *testCell() const { return test_cell_; } + // Add scaled cell after it is complete. + void addScaledCell(OperatingConditions *op_cond, + LibertyCell *scaled_cell); + virtual unsigned addTimingArcSet(TimingArcSet *set); + void addTimingArcAttrs(TimingArcAttrs *attrs); + virtual void addInternalPower(InternalPower *power); + void addInternalPowerAttrs(InternalPowerAttrs *attrs); + virtual void addLeakagePower(LeakagePower *power); + void setLeakagePower(float leakage); + void setOcvArcDepth(float depth); + void setOcvDerate(OcvDerate *derate); + void addOcvDerate(OcvDerate *derate); + void addPgPort(LibertyPgPort *pg_port); void setTestCell(TestCell *test); - bool isLatchData(LibertyPort *port); - void latchEnable(TimingArcSet *arc_set, - // Return values. - LibertyPort *&enable_port, - FuncExpr *&enable_func, - TransRiseFall *&enable_tr) const; - TransRiseFall *latchCheckEnableTrans(TimingArcSet *check_set); - bool isDisabledConstraint() const { return is_disabled_constraint_; } + void setHasInferedRegTimingArcs(bool infered); void setIsDisabledConstraint(bool is_disabled); - LibertyCell *cornerCell(int ap_index); void setCornerCell(LibertyCell *corner_cell, int ap_index); - void setLeakagePower(float leakage); - - // AOCV - float ocvArcDepth() const; - void setOcvArcDepth(float depth); - OcvDerate *ocvDerate() const; - void setOcvDerate(OcvDerate *derate); - OcvDerate *findOcvDerate(const char *derate_name); - void addOcvDerate(OcvDerate *derate); - - void addPgPort(LibertyPgPort *pg_port); + // Call after cell is finished being constructed. + virtual void finish(bool infer_latches, + Report *report, + Debug *debug); + void setHigherDrive(LibertyCell *cell); + void setLowerDrive(LibertyCell *cell); protected: virtual void addPort(ConcretePort *port); @@ -511,7 +520,6 @@ protected: bool interface_timing_; ClockGateType clock_gate_type_; TimingArcSetSeq timing_arc_sets_; - // Used to find matching arc sets in equivalent cells. TimingArcSetMap timing_arc_set_map_; LibertyPortPairTimingArcMap port_timing_arc_set_map_; LibertyPortTimingArcMap timing_arc_set_from_map_; @@ -542,6 +550,9 @@ protected: float leakage_power_; bool leakage_power_exists_; LibertyPgPortMap pg_port_map_; + // Next higher/lower drive equivalent cells. + LibertyCell *higher_drive_; + LibertyCell *lower_drive_; private: DISALLOW_COPY_AND_ASSIGN(LibertyCell); diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 67550600..90a90f1f 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -578,6 +578,7 @@ void LibertyReader::endLibrary(LibertyGroup *group) { endLibraryAttrs(group); + library_->finish(); } void diff --git a/search/Property.cc b/search/Property.cc index dee21fb7..14ca66ee 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -509,6 +509,10 @@ getProperty(const LibertyCell *cell, return PropertyValue(cell->filename()); else if (stringEqual(property, "library")) return PropertyValue(cell->libertyLibrary()); + else if (stringEqual(property, "higher_drive")) + return PropertyValue(cell->higherDrive()); + else if (stringEqual(property, "lower_drive")) + return PropertyValue(cell->lowerDrive()); else throw PropertyUnknown("liberty cell", property); } @@ -706,7 +710,7 @@ pinSlewProperty(const Pin *pin, const MinMax *min_max, Sta *sta) { - auto graph = sta->graph(); + auto graph = sta->ensureGraph(); Vertex *vertex, *bidirect_drvr_vertex; graph->pinVertices(pin, vertex, bidirect_drvr_vertex); Slew slew = min_max->initValue(); diff --git a/search/Sta.cc b/search/Sta.cc index 381b92ad..017e6af9 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -3214,7 +3214,7 @@ Sta::setArcDelay(Edge *edge, TimingArc *arc, const Corner *corner, const MinMaxAll *min_max, - float delay) + ArcDelay delay) { MinMaxIterator mm_iter(min_max); while (mm_iter.hasNext()) { diff --git a/search/Sta.hh b/search/Sta.hh index 95df50be..d5093cc2 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -705,7 +705,7 @@ public: TimingArc *arc, const Corner *corner, const MinMaxAll *min_max, - float delay); + ArcDelay delay); // Set annotated slew on a vertex for delay calculation. void setAnnotatedSlew(Vertex *vertex, const Corner *corner, diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 42ad15f7..3737886e 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -2275,13 +2275,6 @@ cells_equiv_ports(LibertyCell *cell1, return equivCellPorts(cell1, cell2); } -LibertyCellSeq * -find_equiv_cells(LibertyCell *cell) -{ - LibertyLibrary *library = cell->libertyLibrary(); - return library->findEquivCells(cell); -} - void set_cmd_namespace_cmd(const char *namespc) { @@ -2652,6 +2645,7 @@ PropertyValue pin_property(const Pin *pin, const char *property) { + cmdLinkedNetwork(); return getProperty(pin, property, Sta::sta()); } @@ -2659,6 +2653,7 @@ PropertyValue instance_property(const Instance *inst, const char *property) { + cmdLinkedNetwork(); return getProperty(inst, property, Sta::sta()); } @@ -2666,6 +2661,7 @@ PropertyValue net_property(const Net *net, const char *property) { + cmdLinkedNetwork(); return getProperty(net, property, Sta::sta()); }