%module sta %{ // OpenSTA, Static Timing Analyzer // Copyright (c) 2019, Parallax Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . //////////////////////////////////////////////////////////////// // // Most of the TCL SWIG interface code is in this file. This and any // optional interface code is %included into a final interface file // used by the application. // // Define TCL methods for each network object. This works despite the // fact that the underlying implementation does not have class methods // corresponding to the TCL methods defined here. // // Note the function name changes from sta naming convention // (lower/capitalize) to TCL naming convention (lower/underscore). // //////////////////////////////////////////////////////////////// #include #include "Machine.hh" #include "StaConfig.hh" // STA_VERSION #include "Stats.hh" #include "Report.hh" #include "Error.hh" #include "StringUtil.hh" #include "PatternMatch.hh" #include "MinMax.hh" #include "Fuzzy.hh" #include "PortDirection.hh" #include "FuncExpr.hh" #include "Units.hh" #include "MinMax.hh" #include "Transition.hh" #include "TimingRole.hh" #include "TimingArc.hh" #include "EquivCells.hh" #include "Liberty.hh" #include "Network.hh" #include "Clock.hh" #include "PortDelay.hh" #include "ExceptionPath.hh" #include "Sdc.hh" #include "Graph.hh" #include "Parasitics.hh" #include "Wireload.hh" #include "DelayCalc.hh" #include "DcalcAnalysisPt.hh" #include "Corner.hh" #include "Tag.hh" #include "PathVertex.hh" #include "PathRef.hh" #include "PathExpanded.hh" #include "PathEnd.hh" #include "PathGroup.hh" #include "CheckTiming.hh" #include "CheckMinPulseWidths.hh" #include "Levelize.hh" #include "Bfs.hh" #include "Search.hh" #include "SearchPred.hh" #include "PathAnalysisPt.hh" #include "ReportPath.hh" #include "Power.hh" #include "Property.hh" #include "WritePathSpice.hh" #include "Sta.hh" namespace sta { //////////////////////////////////////////////////////////////// // // C++ helper functions used by the interface functions. // These are not visible in the TCL API. // //////////////////////////////////////////////////////////////// typedef Vector LibrarySeq; typedef CellSeq TmpCellSeq; typedef LibertyCellSeq TmpLibertyCellSeq; typedef PortSeq TmpPortSeq; typedef LibertyPortSeq TmpLibertyPortSeq; typedef PinSet TmpPinSet; typedef PinSeq TmpPinSeq; typedef InstanceSeq TmpInstanceSeq; typedef InstanceSet TmpInstanceSet; typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator; typedef FloatSeq TmpFloatSeq; typedef string TmpString; typedef Set StringSet; typedef MinMaxAll MinMaxAllNull; typedef ClockSet TmpClockSet; typedef StringSeq TmpStringSeq; class CmdErrorNetworkNotLinked : public StaException { public: virtual const char *what() const throw() { return "Error: no network has been linked."; } }; class CmdErrorNetworkNotEditable : public StaException { public: virtual const char *what() const throw() { return "Error: network does not support edits."; } }; // Get the network for commands. Network * cmdNetwork() { return Sta::sta()->cmdNetwork(); } // Make sure the network has been read and linked. // Throwing an error means the caller doesn't have to check the result. Network * cmdLinkedNetwork() { Network *network = cmdNetwork(); if (network->isLinked()) return network; else { throw CmdErrorNetworkNotLinked(); return nullptr; } } // Make sure an editable network has been read and linked. NetworkEdit * cmdEditNetwork() { Network *network = cmdLinkedNetwork(); if (network->isEditable()) return dynamic_cast(network); else { throw CmdErrorNetworkNotEditable(); return nullptr; } } // Get the graph for commands. // Throw to cmd level on failure. Graph * cmdGraph() { cmdLinkedNetwork(); return Sta::sta()->ensureGraph(); } // These should be templated, but Sun's compiler can't deal with // an explicit template instantiation (ie, the arglist is the same // for all these functions). Adding a dummy argument of the return // type is not sufficient because then it chokes on the call to // SWIG_ConvertPtr because it is declared extern "C". PortSeq * TclListSeqPort(Tcl_Obj * const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { PortSeq *seq = new PortSeq; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Port, false); seq->push_back(reinterpret_cast(obj)); } return seq; } else return nullptr; } PinSeq * TclListSeqPin(Tcl_Obj * const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { PinSeq *seq = new PinSeq; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Pin, false); seq->push_back(reinterpret_cast(obj)); } return seq; } else return nullptr; } InstanceSeq * TclListSeqInstance(Tcl_Obj * const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { InstanceSeq *seq = new InstanceSeq; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Instance, false); seq->push_back(reinterpret_cast(obj)); } return seq; } else return nullptr; } ExceptionThruSeq * TclListSeqExceptionThru(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK && argc > 0) { ExceptionThruSeq *seq = new ExceptionThruSeq; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_ExceptionThru, false); seq->push_back(reinterpret_cast(obj)); } return seq; } else return nullptr; } PortSet * TclListSetPort(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { PortSet *set = new PortSet; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Port, false); set->insert(reinterpret_cast(obj)); } return set; } else return nullptr; } PinSet * TclListSetPin(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { PinSet *set = new PinSet; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Pin, false); set->insert(reinterpret_cast(obj)); } return set; } else return nullptr; } ClockSet * TclListSetClock(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { ClockSet *set = new ClockSet; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Clock, false); set->insert(reinterpret_cast(obj)); } return set; } else return nullptr; } InstanceSet * TclListSetInstance(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { InstanceSet *set = new InstanceSet; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Instance, false); set->insert(reinterpret_cast(obj)); } return set; } else return nullptr; } NetSet * TclListSetNet(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { NetSet *set = new NetSet; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Net, false); set->insert(reinterpret_cast(obj)); } return set; } else return nullptr; } StringSet * TclListSetConstChar(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { StringSet *set = new StringSet; for (int i = 0; i < argc; i++) { int length; const char *str = Tcl_GetStringFromObj(argv[i], &length); set->insert(str); } return set; } else return nullptr; } StringSeq * TclListSeqConstChar(Tcl_Obj *const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { StringSeq *seq = new StringSeq; for (int i = 0; i < argc; i++) { int length; const char *str = Tcl_GetStringFromObj(argv[i], &length); seq->push_back(str); } return seq; } else return nullptr; } EdgeSeq * TclListSeqEdge(Tcl_Obj * const source, Tcl_Interp *interp) { int argc; Tcl_Obj **argv; if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { EdgeSeq *seq = new EdgeSeq; for (int i = 0; i < argc; i++) { void *obj; // Ignore returned TCL_ERROR because can't get swig_type_info. SWIG_ConvertPtr(argv[i], &obj, SWIGTYPE_p_Edge, false); seq->push_back(reinterpret_cast(obj)); } return seq; } else return nullptr; } //////////////////////////////////////////////////////////////// TmpPinSet * findStartpoints() { PinSet *pins = new PinSet; VertexPinCollector visitor(pins); Sta::sta()->visitStartpoints(&visitor); return pins; } TmpPinSet * findEndpoints() { PinSet *pins = new PinSet; VertexPinCollector visitor(pins); Sta::sta()->visitEndpoints(&visitor); return pins; } void pushPowerResultFloats(PowerResult &power, TmpFloatSeq *floats) { floats->push_back(power.internal()); floats->push_back(power.switching()); floats->push_back(power.leakage()); floats->push_back(power.total()); } //////////////////////////////////////////////////////////////// void tclError(Tcl_Interp *interp, const char *msg, const char *arg) { char *error = stringPrint(msg, arg); Tcl_SetResult(interp, error, TCL_VOLATILE); stringDelete(error); } void objectListNext(const char *list, const char *type, // Return values. bool &type_match, const char *&next) { // Default return values (failure). type_match = false; next = nullptr; // _hexaddress_p_type const char *s = list; char ch = *s++; if (ch == '_') { while (*s && isxdigit(*s)) s++; if ((s - list - 1) == sizeof(void*) * 2 && *s && *s++ == '_' && *s && *s++ == 'p' && *s && *s++ == '_') { const char *t = type; while (*s && *s != ' ') { if (*s != *t) return; s++; t++; } type_match = true; if (*s) next = s + 1; else next = nullptr; } } } } // namespace using namespace sta; %} //////////////////////////////////////////////////////////////// // // SWIG type definitions. // //////////////////////////////////////////////////////////////// // String that is deleted after crossing over to tcland. %typemap(out) TmpString* { string *str = $1; if (str) { // String is volatile because it is deleted. Tcl_SetResult(interp, const_cast(str->c_str()), TCL_VOLATILE); delete str; } else Tcl_SetResult(interp, nullptr, TCL_STATIC); } %typemap(in) StringSeq* { $1 = TclListSeqConstChar($input, interp); } %typemap(out) StringSeq* { StringSeq *strs = $1; Tcl_Obj *list = Tcl_NewListObj(0, nullptr); StringSeq::Iterator str_iter(strs); while (str_iter.hasNext()) { const char *str = str_iter.next(); Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } %typemap(out) TmpStringSeq* { StringSeq *strs = $1; Tcl_Obj *list = Tcl_NewListObj(0, nullptr); StringSeq::Iterator str_iter(strs); while (str_iter.hasNext()) { const char *str = str_iter.next(); Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); delete strs; } %typemap(out) Library* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibraryIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyLibraryIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Cell* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) CellSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); CellSeq *cells = $1; CellSeq::Iterator cell_iter(cells); while (cell_iter.hasNext()) { Cell *cell = cell_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_Cell, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } %typemap(out) TmpCellSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); CellSeq *cells = $1; CellSeq::Iterator cell_iter(cells); while (cell_iter.hasNext()) { Cell *cell = cell_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_Cell, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); delete cells; } %typemap(out) LibertyCellSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); LibertyCellSeq *cells = $1; LibertyCellSeq::Iterator cell_iter(cells); while (cell_iter.hasNext()) { LibertyCell *cell = cell_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_LibertyCell, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } %typemap(out) TmpLibertyCellSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); LibertyCellSeq *cells = $1; LibertyCellSeq::Iterator cell_iter(cells); while (cell_iter.hasNext()) { LibertyCell *cell = cell_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_LibertyCell, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); delete cells; } %typemap(out) CellPortIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyCellPortIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Port* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(in) PortSet* { $1 = TclListSetPort($input, interp); } %typemap(in) PortSeq* { $1 = TclListSeqPort($input, interp); } %typemap(out) TmpPortSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); TmpPortSeq *ports = $1; TmpPortSeq::Iterator port_iter(ports); while (port_iter.hasNext()) { Port *port = port_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(port, SWIGTYPE_p_Port, false); Tcl_ListObjAppendElement(interp, list, obj); } delete ports; Tcl_SetObjResult(interp, list); } %typemap(out) TmpLibertyPortSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); TmpLibertyPortSeq *ports = $1; TmpLibertyPortSeq::Iterator port_iter(ports); while (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(port, SWIGTYPE_p_LibertyPort, false); Tcl_ListObjAppendElement(interp, list, obj); } delete ports; Tcl_SetObjResult(interp, list); } %typemap(out) TmpPinSet* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PinSet *pins = $1; PinSet::Iterator pin_iter(pins); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false); Tcl_ListObjAppendElement(interp, list, obj); } delete pins; Tcl_SetObjResult(interp, list); } %typemap(out) TmpPinSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PinSeq *pins = $1; PinSeq::Iterator pin_iter(pins); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false); Tcl_ListObjAppendElement(interp, list, obj); } delete pins; Tcl_SetObjResult(interp, list); } %typemap(out) PortMemberIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyCell* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyPort* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyPortMemberIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, SWIGTYPE_p_LibertyPortMemberIterator, false); Tcl_SetObjResult(interp, obj); } %typemap(out) TimingArc* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Wireload* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) WireloadSelection* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(in) Transition* { int length; const char *arg = Tcl_GetStringFromObj($input, &length); Transition *tr = Transition::find(arg); if (tr == nullptr) { Tcl_SetResult(interp,const_cast("Error: transition not found."), TCL_STATIC); return TCL_ERROR; } else $1 = tr; } %typemap(out) Transition* { Transition *tr = $1; const char *str = ""; if (tr) str = tr->asString(); Tcl_SetResult(interp, const_cast(str), TCL_STATIC); } %typemap(in) TransRiseFall* { int length; const char *arg = Tcl_GetStringFromObj($input, &length); TransRiseFall *tr = TransRiseFall::find(arg); if (tr == nullptr) { Tcl_SetResult(interp,const_cast("Error: unknown transition name."), TCL_STATIC); return TCL_ERROR; } $1 = tr; } %typemap(out) TransRiseFall* { const TransRiseFall *tr = $1; const char *str = ""; if (tr) str = tr->asString(); Tcl_SetResult(interp, const_cast(str), TCL_STATIC); } %typemap(in) TransRiseFallBoth* { int length; const char *arg = Tcl_GetStringFromObj($input, &length); TransRiseFallBoth *tr = TransRiseFallBoth::find(arg); if (tr == nullptr) { Tcl_SetResult(interp,const_cast("Error: unknown transition name."), TCL_STATIC); return TCL_ERROR; } $1 = tr; } %typemap(out) TransRiseFallBoth* { TransRiseFallBoth *tr = $1; const char *str = ""; if (tr) str = tr->asString(); Tcl_SetResult(interp, const_cast(str), TCL_STATIC); } %typemap(in) TimingRole* { int length; const char *arg = Tcl_GetStringFromObj($input, &length); TimingRole *role = TimingRole::find(arg); if (role) $1 = TimingRole::find(arg); else { Tcl_SetResult(interp,const_cast("Error: unknown timing role."), TCL_STATIC); return TCL_ERROR; } } %typemap(out) TimingRole* { Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); } %typemap(in) LogicValue { int length; const char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "0") || stringEq(arg, "zero")) $1 = LogicValue::zero; else if (stringEq(arg, "1") || stringEq(arg, "one")) $1 = LogicValue::one; else if (stringEq(arg, "X")) $1 = LogicValue::unknown; else if (stringEq(arg, "rise") || stringEq(arg, "rising")) $1 = LogicValue::rise; else if (stringEq(arg, "fall") || stringEq(arg, "falling")) $1 = LogicValue::fall; else { Tcl_SetResult(interp,const_cast("Error: unknown logic value."), TCL_STATIC); return TCL_ERROR; } } %typemap(in) AnalysisType { int length; const char *arg = Tcl_GetStringFromObj($input, &length); if (stringEqual(arg, "single")) $1 = AnalysisType::single; else if (stringEqual(arg, "bc_wc")) $1 = AnalysisType::bc_wc; else if (stringEq(arg, "on_chip_variation")) $1 = AnalysisType::ocv; else { Tcl_SetResult(interp,const_cast("Error: unknown analysis type."), TCL_STATIC); return TCL_ERROR; } } %typemap(out) Instance* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(in) InstanceSeq* { $1 = TclListSeqInstance($input, interp); } %typemap(out) TmpInstanceSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); TmpInstanceSeq *insts = $1; TmpInstanceSeq::Iterator inst_iter(insts); while (inst_iter.hasNext()) { Instance *inst = inst_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(inst, SWIGTYPE_p_Instance,false); Tcl_ListObjAppendElement(interp, list, obj); } delete insts; Tcl_SetObjResult(interp, list); } %typemap(out) InstanceChildIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LeafInstanceIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) InstancePinIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) InstanceNetIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Pin* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) PinSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PinSeq *pins = $1; PinSeq::Iterator pin_iter(pins); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false); Tcl_ListObjAppendElement(interp, list, obj); } delete pins; Tcl_SetObjResult(interp, list); } %typemap(out) Net* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) NetSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); NetSeq *nets = $1; NetSeq::Iterator net_iter(nets); while (net_iter.hasNext()) { Net *net = net_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(net, SWIGTYPE_p_Net, false); Tcl_ListObjAppendElement(interp, list, obj); } delete nets; Tcl_SetObjResult(interp, list); } %typemap(out) NetPinIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) NetTermIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) NetConnectedPinIterator* { Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) PinConnectedPinIterator* { Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Clock* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ClockSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); ClockSeq *clks = $1; ClockSeq::Iterator clk_iter(clks); while (clk_iter.hasNext()) { Clock *clk = clk_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); Tcl_ListObjAppendElement(interp, list, obj); } delete clks; Tcl_SetObjResult(interp, list); } %typemap(out) ClockIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ClockPinIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1,$1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ClockEdge* { Tcl_Obj *obj = SWIG_NewInstanceObj($1,$1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(in) FloatSeq* { int argc; Tcl_Obj **argv; FloatSeq *floats = nullptr; if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { if (argc) floats = new FloatSeq; for (int i = 0; i < argc; i++) { char *arg = Tcl_GetString(argv[i]); double value; if (Tcl_GetDouble(interp, arg, &value) == TCL_OK) floats->push_back(static_cast(value)); else { delete floats; tclError(interp, "Error: %s is not a floating point number.", arg); return TCL_ERROR; } } } $1 = floats; } %typemap(out) FloatSeq* { FloatSeq *floats = $1; Tcl_Obj *list = Tcl_NewListObj(0, nullptr); if (floats) { for (unsigned i = 0; i < floats->size(); i++) { Tcl_Obj *obj = Tcl_NewDoubleObj((*floats)[i]); Tcl_ListObjAppendElement(interp, list, obj); } } Tcl_SetObjResult(interp, list); } %typemap(out) TmpFloatSeq* { FloatSeq *floats = $1; Tcl_Obj *list = Tcl_NewListObj(0, nullptr); if (floats) { for (unsigned i = 0; i < floats->size(); i++) { Tcl_Obj *obj = Tcl_NewDoubleObj((*floats)[i]); Tcl_ListObjAppendElement(interp, list, obj); } delete floats; } Tcl_SetObjResult(interp, list); } %typemap(in) IntSeq* { int argc; Tcl_Obj **argv; IntSeq *ints = nullptr; if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { if (argc) ints = new IntSeq; for (int i = 0; i < argc; i++) { char *arg = Tcl_GetString(argv[i]); int value; if (Tcl_GetInt(interp, arg, &value) == TCL_OK) ints->push_back(value); else { delete ints; tclError(interp, "Error: %s is not an integer.", arg); return TCL_ERROR; } } } $1 = ints; } %typemap(in) MinMax* { int length; char *arg = Tcl_GetStringFromObj($input, &length); MinMax *min_max = MinMax::find(arg); if (min_max) $1 = min_max; else { tclError(interp, "Error: %s not min or max.", arg); return TCL_ERROR; } } %typemap(out) MinMax* { Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); } %typemap(out) MinMax* { Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); } %typemap(in) MinMaxAll* { int length; char *arg = Tcl_GetStringFromObj($input, &length); MinMaxAll *min_max = MinMaxAll::find(arg); if (min_max) $1 = min_max; else { tclError(interp, "Error: %s not min, max or min_max.", arg); return TCL_ERROR; } } %typemap(in) MinMaxAllNull* { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEqual(arg, "NULL")) $1 = nullptr; else { MinMaxAll *min_max = MinMaxAll::find(arg); if (min_max) $1 = min_max; else { tclError(interp, "Error: %s not min, max or min_max.", arg); return TCL_ERROR; } } } %typemap(out) MinMaxAll* { Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); } // SetupHold is typedef'd to MinMax. %typemap(in) SetupHold* { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEqual(arg, "hold") || stringEqual(arg, "min")) $1 = MinMax::min(); else if (stringEqual(arg, "setup") || stringEqual(arg, "max")) $1 = MinMax::max(); else { tclError(interp, "Error: %s not setup, hold, min or max.", arg); return TCL_ERROR; } } // SetupHoldAll is typedef'd to MinMaxAll. %typemap(in) SetupHoldAll* { int length; char *arg = Tcl_GetStringFromObj($input, &length); MinMaxAll *min_max = MinMaxAll::find(arg); if (min_max) $1 = min_max; else { tclError(interp, "Error: %s not min, max or min_max.", arg); return TCL_ERROR; } } // EarlyLate is typedef'd to MinMax. %typemap(in) EarlyLate* { int length; char *arg = Tcl_GetStringFromObj($input, &length); EarlyLate *early_late = EarlyLate::find(arg); if (early_late) $1 = early_late; else { tclError(interp, "Error: %s not early/min or late/max.", arg); return TCL_ERROR; } } // EarlyLateAll is typedef'd to MinMaxAll. %typemap(in) EarlyLateAll* { int length; char *arg = Tcl_GetStringFromObj($input, &length); EarlyLateAll *early_late = EarlyLateAll::find(arg); if (early_late) $1 = early_late; else { tclError(interp, "Error: %s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } %typemap(in) TimingDerateType { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "net_delay")) $1 = TimingDerateType::net_delay; else if (stringEq(arg, "cell_delay")) $1 = TimingDerateType::cell_delay; else if (stringEq(arg, "cell_check")) $1 = TimingDerateType::cell_check; else { tclError(interp, "Error: %s not clk or data.", arg); return TCL_ERROR; } } %typemap(in) PathClkOrData { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "clk")) $1 = PathClkOrData::clk; else if (stringEq(arg, "data")) $1 = PathClkOrData::data; else { tclError(interp, "Error: %s not clk or data.", arg); return TCL_ERROR; } } %typemap(in) ReportSortBy { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "group")) $1 = sort_by_group; else if (stringEq(arg, "slack")) $1 = sort_by_slack; else { tclError(interp, "Error: %s not group or slack.", arg); return TCL_ERROR; } } %typemap(in) ReportPathFormat { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "full")) $1 = ReportPathFormat::full; else if (stringEq(arg, "full_clock")) $1 = ReportPathFormat::full_clock; else if (stringEq(arg, "full_clock_expanded")) $1 = ReportPathFormat::full_clock_expanded; else if (stringEq(arg, "short")) $1 = ReportPathFormat::shorter; else if (stringEq(arg, "end")) $1 = ReportPathFormat::endpoint; else if (stringEq(arg, "summary")) $1 = ReportPathFormat::summary; else if (stringEq(arg, "slack_only")) $1 = ReportPathFormat::slack_only; else { tclError(interp, "Error: unknown path type %s.", arg); return TCL_ERROR; } } %typemap(in) PinSeq* { $1 = TclListSeqPin($input, interp); } %typemap(in) PinSet* { $1 = TclListSetPin($input, interp); } %typemap(out) PinSet* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); const PinSet *pins = $1; if (pins) { PinSet::ConstIterator pin_iter(pins); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false); Tcl_ListObjAppendElement(interp, list, obj); } } Tcl_SetObjResult(interp, list); } %typemap(in) ClockSet* { $1 = TclListSetClock($input, interp); } %typemap(out) ClockSet* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); const ClockSet *clks = $1; if (clks) { ClockSet::ConstIterator clk_iter(clks); while (clk_iter.hasNext()) { Clock *clk = clk_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); Tcl_ListObjAppendElement(interp, list, obj); } } Tcl_SetObjResult(interp, list); } %typemap(out) TmpClockSet* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); const ClockSet *clks = $1; if (clks) { ClockSet::ConstIterator clk_iter(clks); while (clk_iter.hasNext()) { Clock *clk = clk_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); Tcl_ListObjAppendElement(interp, list, obj); } delete clks; } Tcl_SetObjResult(interp, list); } %typemap(in) InstanceSet* { $1 = TclListSetInstance($input, interp); } %typemap(out) TmpInstanceSet* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); InstanceSet *insts = $1; InstanceSet::Iterator inst_iter(insts); while (inst_iter.hasNext()) { Instance *inst = inst_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(inst, SWIGTYPE_p_Instance,false); Tcl_ListObjAppendElement(interp, list, obj); } delete insts; Tcl_SetObjResult(interp, list); } %typemap(in) NetSet* { $1 = TclListSetNet($input, interp); } %typemap(in) ExceptionThruSeq* { $1 = TclListSeqExceptionThru($input, interp); } %typemap(out) Vertex* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) Vertex** { int i = 0; Tcl_ResetResult(interp); Tcl_Obj *list = Tcl_NewListObj(0, nullptr); while ($1[i]) { Tcl_Obj *obj = SWIG_NewInstanceObj($1[i], SWIGTYPE_p_Vertex,false); Tcl_ListObjAppendElement(interp, list, obj); i++; } Tcl_SetObjResult(interp, list); } %typemap(in) EdgeSeq* { $1 = TclListSeqEdge($input, interp); } %typemap(out) Edge* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) EdgeSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); EdgeSeq *edges = $1; EdgeSeq::Iterator edge_iter(edges); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(edge, SWIGTYPE_p_Edge, false); Tcl_ListObjAppendElement(interp, list, obj); } delete edges; Tcl_SetObjResult(interp, list); } %typemap(out) VertexIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) VertexInEdgeIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) VertexOutEdgeIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) TimingArcSetArcIterator* { Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) LibertyCellTimingArcSetIterator* { Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) CheckErrorSeq & { Tcl_Obj *error_list = Tcl_NewListObj(0, nullptr); CheckErrorSeq *check_errors = $1; CheckErrorSeq::Iterator check_iter(check_errors); while (check_iter.hasNext()) { CheckError *error = check_iter.next(); Tcl_Obj *string_list = Tcl_NewListObj(0, nullptr); CheckError::Iterator string_iter(error); while (string_iter.hasNext()) { const char *str = string_iter.next(); size_t str_len = strlen(str); Tcl_Obj *obj = Tcl_NewStringObj(const_cast(str), static_cast(str_len)); Tcl_ListObjAppendElement(interp, string_list, obj); } Tcl_ListObjAppendElement(interp, error_list, string_list); } Tcl_SetObjResult(interp, error_list); } %typemap(out) PathEnd* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) PathEndSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); const PathEndSeq *path_ends = $1; PathEndSeq::ConstIterator end_iter(path_ends); while (end_iter.hasNext()) { PathEnd *path_end = end_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(path_end, SWIGTYPE_p_PathEnd, false); Tcl_ListObjAppendElement(interp, list, obj); } // Delete the PathEndSeq, not the ends. delete path_ends; Tcl_SetObjResult(interp, list); } %typemap(out) MinPulseWidthCheckSeqIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) PathRefSeq* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PathRefSeq *paths = $1; PathRefSeq::Iterator path_iter(paths); while (path_iter.hasNext()) { PathRef *path = &path_iter.next(); PathRef *copy = new PathRef(path); Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } %typemap(out) MinPulseWidthCheck* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) MinPulseWidthCheckSeq & { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) MinPulseWidthCheckSeqIterator & { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) VertexPathIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) SlowDrvrIterator* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ExceptionFrom* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ExceptionTo* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) ExceptionThru* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) OperatingConditions* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(in) ReduceParasiticsTo { int length; char *arg = Tcl_GetStringFromObj($input, &length); if (stringEq(arg, "pi_elmore")) $1 = ReduceParasiticsTo::pi_elmore; else if (stringEq(arg, "pi_pole_residue2")) $1 = ReduceParasiticsTo::pi_pole_residue2; else if (stringEq(arg, "none")) $1 = ReduceParasiticsTo::none; else { tclError(interp, "Error: %s pi_elmore, pi_pole_residue2, or none.", arg); return TCL_ERROR; } } %typemap(out) Arrival { Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); } %typemap(out) Required { Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); } %typemap(out) Slack { Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); } %typemap(out) ArcDelay { Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); } %typemap(out) Slew { Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); } %typemap(in) PathGroupNameSet* { $1 = TclListSetConstChar($input, interp); } %typemap(in) StringSet* { $1 = TclListSetConstChar($input, interp); } %typemap(out) Corner* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); } %typemap(out) PropertyValue { PropertyValue value = $1; switch (value.type()) { case PropertyValue::Type::type_none: Tcl_SetResult(interp, const_cast(""), TCL_STATIC); break; case PropertyValue::Type::type_string: Tcl_SetResult(interp, const_cast(value.stringValue()), TCL_VOLATILE); break; case PropertyValue::Type::type_float: { char *float_string = stringPrint("%.5f", value.floatValue()); Tcl_SetResult(interp, float_string, TCL_VOLATILE); stringDelete(float_string); } break; case PropertyValue::Type::type_instance: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.instance(), SWIGTYPE_p_Instance, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_pin: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.pin(), SWIGTYPE_p_Pin, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_pins: { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PinSeq *pins = value.pins(); PinSeq::Iterator pin_iter(pins); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } break; case PropertyValue::Type::type_net: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.net(), SWIGTYPE_p_Net, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_liberty_cell: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyCell(), SWIGTYPE_p_LibertyCell, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_liberty_library: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyLibrary(), SWIGTYPE_p_LibertyLibrary, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_library: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.library(), SWIGTYPE_p_Library, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_cell: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.cell(), SWIGTYPE_p_Cell, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_clk: { Tcl_Obj *obj = SWIG_NewInstanceObj(value.clock(), SWIGTYPE_p_Clock, false); Tcl_SetObjResult(interp, obj); } break; case PropertyValue::Type::type_clks: { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); ClockSeq *clks = value.clocks(); ClockSeq::Iterator clk_iter(clks); while (clk_iter.hasNext()) { Clock *clk = clk_iter.next(); Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } break; case PropertyValue::Type::type_path_refs: { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); PathRefSeq *paths = value.pathRefs(); PathRefSeq::Iterator path_iter(paths); while (path_iter.hasNext()) { PathRef &path = path_iter.next(); PathRef *copy = new PathRef(path); Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); Tcl_ListObjAppendElement(interp, list, obj); } Tcl_SetObjResult(interp, list); } break; } } //////////////////////////////////////////////////////////////// // // Empty class definitions to make swig happy. // Private constructor/destructor so swig doesn't emit them. // //////////////////////////////////////////////////////////////// class Library { private: Library(); ~Library(); }; class LibraryIterator { private: LibraryIterator(); ~LibraryIterator(); }; class Cell { private: Cell(); ~Cell(); }; class CellPortIterator { private: CellPortIterator(); ~CellPortIterator(); }; class LibertyCellPortIterator { private: LibertyCellPortIterator(); ~LibertyCellPortIterator(); }; class Port { private: Port(); ~Port(); }; class PortMemberIterator { private: PortMemberIterator(); ~PortMemberIterator(); }; class LibertyLibrary { private: LibertyLibrary(); ~LibertyLibrary(); }; class LibertyLibraryIterator { private: LibertyLibraryIterator(); ~LibertyLibraryIterator(); }; class LibertyCell { private: LibertyCell(); ~LibertyCell(); }; class LibertyPort { private: LibertyPort(); ~LibertyPort(); }; class LibertyPortMemberIterator { private: LibertyPortMemberIterator(); ~LibertyPortMemberIterator(); }; class TimingArcSet { private: TimingArcSet(); ~TimingArcSet(); }; class LibertyCellTimingArcSetIterator { private: LibertyCellTimingArcSetIterator(); ~LibertyCellTimingArcSetIterator(); }; class TimingArcSetArcIterator { private: TimingArcSetArcIterator(); ~TimingArcSetArcIterator(); }; class TimingArc { private: TimingArc(); ~TimingArc(); }; class Wireload { private: Wireload(); ~Wireload(); }; class WireloadSelection { private: WireloadSelection(); ~WireloadSelection(); }; class Transition { private: Transition(); ~Transition(); }; class Instance { private: Instance(); ~Instance(); }; class Pin { private: Pin(); ~Pin(); }; class Term { private: Term(); ~Term(); }; class InstanceChildIterator { private: InstanceChildIterator(); ~InstanceChildIterator(); }; class InstancePinIterator { private: InstancePinIterator(); ~InstancePinIterator(); }; class InstanceNetIterator { private: InstanceNetIterator(); ~InstanceNetIterator(); }; class LeafInstanceIterator { private: LeafInstanceIterator(); ~LeafInstanceIterator(); }; class Net { private: Net(); ~Net(); }; class NetPinIterator { private: NetPinIterator(); ~NetPinIterator(); }; class NetTermIterator { private: NetTermIterator(); ~NetTermIterator(); }; class NetConnectedPinIterator { private: NetConnectedPinIterator(); ~NetConnectedPinIterator(); }; class PinConnectedPinIterator { private: PinConnectedPinIterator(); ~PinConnectedPinIterator(); }; class Clock { private: Clock(); ~Clock(); }; class ClockIterator { private: ClockIterator(); ~ClockIterator(); }; class ClockPinIterator { private: ClockPinIterator(); ~ClockPinIterator(); }; class ClockEdge { private: ClockEdge(); ~ClockEdge(); }; class Vertex { private: Vertex(); ~Vertex(); }; class Edge { private: Edge(); ~Edge(); }; class VertexIterator { private: VertexIterator(); ~VertexIterator(); }; class VertexInEdgeIterator { private: VertexInEdgeIterator(); ~VertexInEdgeIterator(); }; class VertexOutEdgeIterator { private: VertexOutEdgeIterator(); ~VertexOutEdgeIterator(); }; class PathRef { private: PathRef(); ~PathRef(); }; class PathEnd { private: PathEnd(); ~PathEnd(); }; class MinPulseWidthCheck { private: MinPulseWidthCheck(); ~MinPulseWidthCheck(); }; class MinPulseWidthCheckSeq { private: MinPulseWidthCheckSeq(); ~MinPulseWidthCheckSeq(); }; class MinPulseWidthCheckSeqIterator { private: MinPulseWidthCheckSeqIterator(); ~MinPulseWidthCheckSeqIterator(); }; class VertexPathIterator { private: VertexPathIterator(); ~VertexPathIterator(); }; class SlowDrvrIterator { private: SlowDrvrIterator(); ~SlowDrvrIterator(); }; class ExceptionFrom { private: ExceptionFrom(); ~ExceptionFrom(); }; class ExceptionThru { private: ExceptionThru(); ~ExceptionThru(); }; class ExceptionTo { private: ExceptionTo(); ~ExceptionTo(); }; class OperatingConditions { private: OperatingConditions(); ~OperatingConditions(); }; class Corner { private: Corner(); ~Corner(); }; //////////////////////////////////////////////////////////////// // // C++ functions visible as TCL functions. // //////////////////////////////////////////////////////////////// %inline %{ float float_inf = INF; int group_count_max = PathGroup::group_count_max; const char * version() { return STA_VERSION; } void redirect_file_begin(const char *filename) { Sta::sta()->report()->redirectFileBegin(filename); } void redirect_file_append_begin(const char *filename) { Sta::sta()->report()->redirectFileAppendBegin(filename); } void redirect_file_end() { Sta::sta()->report()->redirectFileEnd(); } void redirect_string_begin() { Sta::sta()->report()->redirectStringBegin(); } const char * redirect_string_end() { return Sta::sta()->report()->redirectStringEnd(); } void log_begin(const char *filename) { Sta::sta()->report()->logBegin(filename); } void log_end() { Sta::sta()->report()->logEnd(); } void set_debug(const char *what, int level) { Sta::sta()->setDebugLevel(what, level); } bool is_object(const char *obj) { // _hexaddress_p_type const char *s = obj; char ch = *s++; if (ch != '_') return false; while (*s && isxdigit(*s)) s++; if ((s - obj - 1) == sizeof(void*) * 2 && *s && *s++ == '_' && *s && *s++ == 'p' && *s && *s++ == '_') { while (*s && *s != ' ') s++; return *s == '\0'; } else return false; } // Assumes is_object is true. const char * object_type(const char *obj) { return &obj[1 + sizeof(void*) * 2 + 3]; } bool is_object_list(const char *list, const char *type) { const char *s = list; while (s) { bool type_match; const char *next; objectListNext(s, type, type_match, next); if (type_match) s = next; else return false; } return true; } void set_rise_fall_short_names(const char *rise_short_name, const char *fall_short_name) { TransRiseFall::rise()->setShortName(rise_short_name); TransRiseFall::fall()->setShortName(fall_short_name); TransRiseFallBoth::rise()->setShortName(rise_short_name); TransRiseFallBoth::fall()->setShortName(fall_short_name); Transition::rise()->setName(rise_short_name); Transition::fall()->setName(fall_short_name); } const char * rise_short_name() { return TransRiseFall::rise()->shortName(); } const char * fall_short_name() { return TransRiseFall::fall()->shortName(); } bool pin_is_constrained(Pin *pin) { return Sta::sta()->sdc()->isConstrained(pin); } bool instance_is_constrained(Instance *inst) { return Sta::sta()->sdc()->isConstrained(inst); } bool net_is_constrained(Net *net) { return Sta::sta()->sdc()->isConstrained(net); } bool clk_thru_tristate_enabled() { return Sta::sta()->clkThruTristateEnabled(); } void set_clk_thru_tristate_enabled(bool enabled) { Sta::sta()->setClkThruTristateEnabled(enabled); } bool network_is_linked() { return Sta::sta()->cmdNetwork()->isLinked(); } void set_path_divider(char divider) { cmdNetwork()->setPathDivider(divider); } void set_current_instance(Instance *inst) { Sta::sta()->setCurrentInstance(inst); } bool read_liberty_cmd(char *filename, Corner *corner, const MinMaxAll *min_max, bool infer_latches) { LibertyLibrary *lib = Sta::sta()->readLiberty(filename, corner, min_max, infer_latches); return (lib != nullptr); } bool set_min_library_cmd(char *min_filename, char *max_filename) { return Sta::sta()->setMinLibrary(min_filename, max_filename); } Library * find_library(const char *name) { return cmdNetwork()->findLibrary(name); } LibraryIterator * library_iterator() { return cmdNetwork()->libraryIterator(); } LibertyLibrary * find_liberty(const char *name) { return cmdNetwork()->findLiberty(name); } LibertyLibraryIterator * liberty_library_iterator() { return cmdNetwork()->libertyLibraryIterator(); } LibertyCell * find_liberty_cell(const char *name) { return cmdNetwork()->findLibertyCell(name); } TmpCellSeq * find_cells_matching(const char *pattern, bool regexp, bool nocase) { Network *network = cmdNetwork(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); TmpCellSeq *cells = new TmpCellSeq; LibraryIterator *lib_iter = network->libraryIterator(); while (lib_iter->hasNext()) { Library *lib = lib_iter->next(); network->findCellsMatching(lib, &matcher, cells); } delete lib_iter; return cells; } bool cells_equiv_ports(LibertyCell *cell1, LibertyCell *cell2) { 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) { if (stringEq(namespc, "sdc")) Sta::sta()->setCmdNamespace(CmdNamespace::sdc); else if (stringEq(namespc, "sta")) Sta::sta()->setCmdNamespace(CmdNamespace::sta); else internalError("unknown namespace"); } bool link_design_cmd(const char *top_cell_name) { return Sta::sta()->linkDesign(top_cell_name); } bool link_make_black_boxes() { return Sta::sta()->linkMakeBlackBoxes(); } void set_link_make_black_boxes(bool make) { Sta::sta()->setLinkMakeBlackBoxes(make); } Instance * top_instance() { return cmdLinkedNetwork()->topInstance(); } const char * liberty_port_direction(const LibertyPort *port) { return port->direction()->name(); } const char * port_direction(const Port *port) { return cmdLinkedNetwork()->direction(port)->name(); } const char * pin_direction(const Pin *pin) { return cmdLinkedNetwork()->direction(pin)->name(); } TmpPortSeq * find_ports_matching(const char *pattern, bool regexp, bool nocase) { Network *network = cmdLinkedNetwork(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); Cell *top_cell = network->cell(network->topInstance()); PortSeq ports1; network->findPortsMatching(top_cell, &matcher, &ports1); // Expand bus/bundle ports. TmpPortSeq *ports = new TmpPortSeq; PortSeq::Iterator port_iter(ports1); while (port_iter.hasNext()) { Port *port = port_iter.next(); if (network->isBus(port) || network->isBundle(port)) { PortMemberIterator *member_iter = network->memberIterator(port); while (member_iter->hasNext()) { Port *member = member_iter->next(); ports->push_back(member); } delete member_iter; } else ports->push_back(port); } return ports; } TmpPinSeq * find_port_pins_matching(const char *pattern, bool regexp, bool nocase) { Network *network = cmdLinkedNetwork(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); PortSeq ports; Instance *top_inst = network->topInstance(); Cell *top_cell = network->cell(top_inst); network->findPortsMatching(top_cell, &matcher, &ports); TmpPinSeq *pins = new TmpPinSeq; PortSeq::Iterator port_iter(ports); while (port_iter.hasNext()) { Port *port = port_iter.next(); if (network->isBus(port) || network->isBundle(port)) { PortMemberIterator *member_iter = network->memberIterator(port); while (member_iter->hasNext()) { Port *member = member_iter->next(); Pin *pin = network->findPin(top_inst, member); if (pin) pins->push_back(pin); } delete member_iter; } else { Pin *pin = network->findPin(top_inst, port); if (pin) pins->push_back(pin); } } return pins; } Pin * find_pin(const char *path_name) { return cmdLinkedNetwork()->findPin(path_name); } TmpPinSeq * find_pins_matching(const char *pattern, bool regexp, bool nocase) { Sta *sta = Sta::sta(); Network *network = cmdLinkedNetwork(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); Instance *current_instance = sta->currentInstance(); TmpPinSeq *pins = new TmpPinSeq; network->findPinsMatching(current_instance, &matcher, pins); return pins; } TmpPinSeq * find_pins_hier_matching(const char *pattern, bool regexp, bool nocase) { Sta *sta = Sta::sta(); Network *network = cmdLinkedNetwork(); Instance *current_instance = sta->currentInstance(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); TmpPinSeq *pins = new TmpPinSeq; network->findPinsHierMatching(current_instance, &matcher, pins); return pins; } Instance * find_instance(char *path_name) { return cmdLinkedNetwork()->findInstance(path_name); } TmpInstanceSeq * network_leaf_instances() { InstanceSeq *insts = new InstanceSeq; LeafInstanceIterator *iter = cmdLinkedNetwork()->leafInstanceIterator(); while (iter->hasNext()) { Instance *inst = iter->next(); insts->push_back(inst); } delete iter; return insts; } TmpInstanceSeq * find_instances_matching(const char *pattern, bool regexp, bool nocase) { Sta *sta = Sta::sta(); Instance *current_instance = sta->currentInstance(); PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp()); TmpInstanceSeq *insts = new InstanceSeq; cmdLinkedNetwork()->findInstancesMatching(current_instance, &matcher, insts); return insts; } TmpInstanceSeq * find_instances_hier_matching(const char *pattern, bool regexp, bool nocase) { Sta *sta = Sta::sta(); Network *network = cmdLinkedNetwork(); Instance *current_instance = sta->currentInstance(); PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp()); TmpInstanceSeq *insts = new InstanceSeq; network->findInstancesHierMatching(current_instance, &matcher, insts); return insts; } TmpInstanceSet * find_register_instances(ClockSet *clks, const TransRiseFallBoth *clk_tr, bool edge_triggered, bool latches) { cmdLinkedNetwork(); InstanceSet *insts = Sta::sta()->findRegisterInstances(clks, clk_tr, edge_triggered, latches); delete clks; return insts; } TmpPinSet * find_register_data_pins(ClockSet *clks, const TransRiseFallBoth *clk_tr, bool edge_triggered, bool latches) { cmdLinkedNetwork(); PinSet *pins = Sta::sta()->findRegisterDataPins(clks, clk_tr, edge_triggered, latches); delete clks; return pins; } TmpPinSet * find_register_clk_pins(ClockSet *clks, const TransRiseFallBoth *clk_tr, bool edge_triggered, bool latches) { cmdLinkedNetwork(); PinSet *pins = Sta::sta()->findRegisterClkPins(clks, clk_tr, edge_triggered, latches); delete clks; return pins; } TmpPinSet * find_register_async_pins(ClockSet *clks, const TransRiseFallBoth *clk_tr, bool edge_triggered, bool latches) { cmdLinkedNetwork(); PinSet *pins = Sta::sta()->findRegisterAsyncPins(clks, clk_tr, edge_triggered, latches); delete clks; return pins; } TmpPinSet * find_register_output_pins(ClockSet *clks, const TransRiseFallBoth *clk_tr, bool edge_triggered, bool latches) { cmdLinkedNetwork(); PinSet *pins = Sta::sta()->findRegisterOutputPins(clks, clk_tr, edge_triggered, latches); delete clks; return pins; } Net * find_net(char *path_name) { return cmdLinkedNetwork()->findNet(path_name); } NetSeq * find_nets_matching(const char *pattern, bool regexp, bool nocase) { Network *network = cmdLinkedNetwork(); Instance *current_instance = Sta::sta()->currentInstance(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); NetSeq *nets = new NetSeq; network->findNetsMatching(current_instance, &matcher, nets); return nets; } NetSeq * find_nets_hier_matching(const char *pattern, bool regexp, bool nocase) { Network *network = cmdLinkedNetwork(); Instance *current_instance = Sta::sta()->currentInstance(); PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); NetSeq *nets = new NetSeq; network->findNetsHierMatching(current_instance, &matcher, nets); return nets; } TmpPortSeq * filter_ports(const char *property, const char *op, const char *pattern, PortSeq *ports) { Sta *sta = Sta::sta(); TmpPortSeq *filtered_ports = new TmpPortSeq; PortSeq::Iterator port_iter(ports); bool exact_match = stringEq(op, "=="); while (port_iter.hasNext()) { Port *port = port_iter.next(); PropertyValue value(getProperty(port, property, sta)); const char *prop = value.stringValue(); if (prop && ((exact_match && stringEq(prop, pattern)) || (!exact_match && patternMatch(pattern, prop)))) filtered_ports->push_back(port); } delete ports; return filtered_ports; } TmpInstanceSeq * filter_insts(const char *property, const char *op, const char *pattern, InstanceSeq *insts) { Sta *sta = Sta::sta(); cmdLinkedNetwork(); TmpInstanceSeq *filtered_insts = new TmpInstanceSeq; TmpInstanceSeq::Iterator inst_iter(insts); bool exact_match = stringEq(op, "=="); while (inst_iter.hasNext()) { Instance *inst = inst_iter.next(); PropertyValue value(getProperty(inst, property, sta)); const char *prop = value.stringValue(); if (prop && ((exact_match && stringEq(prop, pattern)) || (!exact_match && patternMatch(pattern, prop)))) filtered_insts->push_back(inst); } delete insts; return filtered_insts; } PinSeq * filter_pins(const char *property, const char *op, const char *pattern, PinSeq *pins) { Sta *sta = Sta::sta(); PinSeq *filtered_pins = new PinSeq; PinSeq::Iterator pin_iter(pins); bool exact_match = stringEq(op, "=="); while (pin_iter.hasNext()) { Pin *pin = pin_iter.next(); PropertyValue value(getProperty(pin, property, sta)); const char *prop = value.stringValue(); if (prop && ((exact_match && stringEq(prop, pattern)) || (!exact_match && patternMatch(pattern, prop)))) filtered_pins->push_back(pin); } delete pins; return filtered_pins; } PropertyValue pin_property(const Pin *pin, const char *property) { cmdGraph(); return getProperty(pin, property, Sta::sta()); } PropertyValue instance_property(const Instance *inst, const char *property) { cmdGraph(); return getProperty(inst, property, Sta::sta()); } PropertyValue net_property(const Net *net, const char *property) { cmdGraph(); return getProperty(net, property, Sta::sta()); } PropertyValue port_property(const Port *port, const char *property) { cmdGraph(); return getProperty(port, property, Sta::sta()); } PropertyValue liberty_cell_property(const LibertyCell *cell, const char *property) { return getProperty(cell, property, Sta::sta()); } PropertyValue cell_property(const Cell *cell, const char *property) { return getProperty(cell, property, Sta::sta()); } PropertyValue liberty_port_property(const LibertyPort *port, const char *property) { return getProperty(port, property, Sta::sta()); } PropertyValue library_property(const Library *lib, const char *property) { return getProperty(lib, property, Sta::sta()); } PropertyValue liberty_library_property(const LibertyLibrary *lib, const char *property) { return getProperty(lib, property, Sta::sta()); } PropertyValue edge_property(Edge *edge, const char *property) { cmdGraph(); return getProperty(edge, property, Sta::sta()); } PropertyValue clock_property(Clock *clk, const char *property) { cmdLinkedNetwork(); return getProperty(clk, property, Sta::sta()); } PropertyValue path_end_property(PathEnd *end, const char *property) { cmdLinkedNetwork(); return getProperty(end, property, Sta::sta()); } PropertyValue path_ref_property(PathRef *path, const char *property) { cmdLinkedNetwork(); return getProperty(path, property, Sta::sta()); } PropertyValue timing_arc_set_property(TimingArcSet *arc_set, const char *property) { cmdLinkedNetwork(); return getProperty(arc_set, property, Sta::sta()); } LeafInstanceIterator * leaf_instance_iterator() { return cmdLinkedNetwork()->leafInstanceIterator(); } //////////////////////////////////////////////////////////////// void define_corners_cmd(StringSet *corner_names) { Sta *sta = Sta::sta(); sta->makeCorners(corner_names); delete corner_names; } Corner * cmd_corner() { return Sta::sta()->cmdCorner(); } void set_cmd_corner(Corner *corner) { Sta::sta()->setCmdCorner(corner); } Corner * find_corner(const char *corner_name) { return Sta::sta()->findCorner(corner_name); } bool multi_corner() { return Sta::sta()->multiCorner(); } //////////////////////////////////////////////////////////////// void set_analysis_type_cmd(const char *analysis_type) { AnalysisType type; if (stringEq(analysis_type, "single")) type = AnalysisType::single; else if (stringEq(analysis_type, "bc_wc")) type = AnalysisType::bc_wc; else if (stringEq(analysis_type, "on_chip_variation")) type = AnalysisType::ocv; else { internalError("unknown analysis type"); type = AnalysisType::single; } Sta::sta()->setAnalysisType(type); } OperatingConditions * operating_conditions(const MinMax *min_max) { return Sta::sta()->operatingConditions(min_max); } void set_operating_conditions_cmd(OperatingConditions *op_cond, const MinMaxAll *min_max) { Sta::sta()->setOperatingConditions(op_cond, min_max); } EdgeSeq * filter_timing_arcs(const char *property, const char *op, const char *pattern, EdgeSeq *edges) { Sta *sta = Sta::sta(); EdgeSeq *filtered_edges = new EdgeSeq; EdgeSeq::Iterator edge_iter(edges); bool exact_match = stringEq(op, "=="); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); PropertyValue value(getProperty(edge, property, sta)); const char *prop = value.stringValue(); if (prop && ((exact_match && stringEq(prop, pattern)) || (!exact_match && patternMatch(pattern, prop)))) filtered_edges->push_back(edge); } delete edges; return filtered_edges; } const char * operating_condition_analysis_type() { switch (Sta::sta()->sdc()->analysisType()){ case AnalysisType::single: return "single"; case AnalysisType::bc_wc: return "bc_wc"; case AnalysisType::ocv: return "on_chip_variation"; } // Prevent warnings from lame compilers. return "?"; } void set_instance_pvt(Instance *inst, const MinMaxAll *min_max, float process, float voltage, float temperature) { cmdLinkedNetwork(); Pvt *pvt = new Pvt(process, voltage, temperature); Sta::sta()->setPvt(inst, min_max, pvt); } float port_ext_pin_cap(Port *port, const TransRiseFall *tr, const MinMax *min_max) { cmdLinkedNetwork(); return Sta::sta()->portExtPinCap(port, tr, min_max); } void set_port_pin_cap(Port *port, const TransRiseFallBoth *tr, const MinMaxAll *min_max, float cap) { Sta::sta()->setPortExtPinCap(port, tr, min_max, cap); } float port_ext_wire_cap(Port *port, const TransRiseFall *tr, const MinMax *min_max) { cmdLinkedNetwork(); return Sta::sta()->portExtWireCap(port, tr, min_max); } void set_port_wire_cap(Port *port, bool subtract_pin_cap, const TransRiseFallBoth *tr, const MinMaxAll *min_max, float cap) { Sta::sta()->setPortExtWireCap(port, subtract_pin_cap, tr, min_max, cap); } int port_ext_fanout(Port *port, const MinMax *min_max) { cmdLinkedNetwork(); return Sta::sta()->portExtFanout(port, min_max); } void set_port_ext_fanout_cmd(Port *port, int fanout, const MinMaxAll *min_max) { Sta::sta()->setPortExtFanout(port, fanout, min_max); } void set_net_wire_cap(Net *net, bool subtract_pin_cap, Corner *corner, const MinMaxAll *min_max, float cap) { Sta::sta()->setNetWireCap(net, subtract_pin_cap, corner, min_max, cap); } void set_wire_load_mode_cmd(const char *mode_name) { WireloadMode mode = stringWireloadMode(mode_name); if (mode == WireloadMode::unknown) internalError("unknown wire load mode"); else Sta::sta()->setWireloadMode(mode); } void set_net_resistance(Net *net, const MinMaxAll *min_max, float res) { Sta::sta()->setResistance(net, min_max, res); } void set_wire_load_cmd(Wireload *wireload, const MinMaxAll *min_max) { Sta::sta()->setWireload(wireload, min_max); } void set_wire_load_selection_group_cmd(WireloadSelection *selection, const MinMaxAll *min_max) { Sta::sta()->setWireloadSelection(selection, min_max); } void make_clock(const char *name, PinSet *pins, bool add_to_pins, float period, FloatSeq *waveform, char *comment) { cmdLinkedNetwork(); Sta::sta()->makeClock(name, pins, add_to_pins, period, waveform, comment); } void make_generated_clock(const char *name, PinSet *pins, bool add_to_pins, Pin *src_pin, Clock *master_clk, Pin *pll_out, Pin *pll_fdbk, int divide_by, int multiply_by, float duty_cycle, bool invert, bool combinational, IntSeq *edges, FloatSeq *edge_shifts, char *comment) { cmdLinkedNetwork(); Sta::sta()->makeGeneratedClock(name, pins, add_to_pins, src_pin, master_clk, pll_out, pll_fdbk, divide_by, multiply_by, duty_cycle, invert, combinational, edges, edge_shifts, comment); } void remove_clock_cmd(Clock *clk) { cmdLinkedNetwork(); Sta::sta()->removeClock(clk); } void set_propagated_clock_cmd(Clock *clk) { cmdLinkedNetwork(); Sta::sta()->setPropagatedClock(clk); } void set_propagated_clock_pin_cmd(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->setPropagatedClock(pin); } void unset_propagated_clock_cmd(Clock *clk) { cmdLinkedNetwork(); Sta::sta()->removePropagatedClock(clk); } void unset_propagated_clock_pin_cmd(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->removePropagatedClock(pin); } void set_clock_slew_cmd(Clock *clk, const TransRiseFallBoth *tr, const MinMaxAll *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setClockSlew(clk, tr, min_max, slew); } void unset_clock_slew_cmd(Clock *clk) { cmdLinkedNetwork(); Sta::sta()->removeClockSlew(clk); } void set_clock_latency_cmd(Clock *clk, Pin *pin, const TransRiseFallBoth *tr, MinMaxAll *min_max, float delay) { cmdLinkedNetwork(); Sta::sta()->setClockLatency(clk, pin, tr, min_max, delay); } void set_clock_insertion_cmd(Clock *clk, Pin *pin, const TransRiseFallBoth *tr, const MinMaxAll *min_max, const EarlyLateAll *early_late, float delay) { cmdLinkedNetwork(); Sta::sta()->setClockInsertion(clk, pin, tr, min_max, early_late, delay); } void unset_clock_latency_cmd(Clock *clk, Pin *pin) { cmdLinkedNetwork(); Sta::sta()->removeClockLatency(clk, pin); } void unset_clock_insertion_cmd(Clock *clk, Pin *pin) { cmdLinkedNetwork(); Sta::sta()->removeClockInsertion(clk, pin); } void set_clock_uncertainty_clk(Clock *clk, const SetupHoldAll *setup_hold, float uncertainty) { cmdLinkedNetwork(); Sta::sta()->setClockUncertainty(clk, setup_hold, uncertainty); } void unset_clock_uncertainty_clk(Clock *clk, const SetupHoldAll *setup_hold) { cmdLinkedNetwork(); Sta::sta()->removeClockUncertainty(clk, setup_hold); } void set_clock_uncertainty_pin(Pin *pin, const MinMaxAll *min_max, float uncertainty) { cmdLinkedNetwork(); Sta::sta()->setClockUncertainty(pin, min_max, uncertainty); } void unset_clock_uncertainty_pin(Pin *pin, const MinMaxAll *min_max) { cmdLinkedNetwork(); Sta::sta()->removeClockUncertainty(pin, min_max); } void set_inter_clock_uncertainty(Clock *from_clk, const TransRiseFallBoth *from_tr, Clock *to_clk, const TransRiseFallBoth *to_tr, const MinMaxAll *min_max, float uncertainty) { cmdLinkedNetwork(); Sta::sta()->setClockUncertainty(from_clk, from_tr, to_clk, to_tr, min_max, uncertainty); } void unset_inter_clock_uncertainty(Clock *from_clk, const TransRiseFallBoth *from_tr, Clock *to_clk, const TransRiseFallBoth *to_tr, const MinMaxAll *min_max) { cmdLinkedNetwork(); Sta::sta()->removeClockUncertainty(from_clk, from_tr, to_clk, to_tr, min_max); } void set_clock_gating_check_cmd(const TransRiseFallBoth *tr, const SetupHold *setup_hold, float margin) { Sta::sta()->setClockGatingCheck(tr, setup_hold, margin); } void set_clock_gating_check_clk_cmd(Clock *clk, const TransRiseFallBoth *tr, const SetupHold *setup_hold, float margin) { Sta::sta()->setClockGatingCheck(clk, tr, setup_hold, margin); } void set_clock_gating_check_pin_cmd(Pin *pin, const TransRiseFallBoth *tr, const SetupHold *setup_hold, float margin, LogicValue active_value) { Sta::sta()->setClockGatingCheck(pin, tr, setup_hold, margin, active_value); } void set_clock_gating_check_instance_cmd(Instance *inst, const TransRiseFallBoth *tr, const SetupHold *setup_hold, float margin, LogicValue active_value) { Sta::sta()->setClockGatingCheck(inst, tr, setup_hold, margin, active_value); } void set_data_check_cmd(Pin *from, const TransRiseFallBoth *from_tr, Pin *to, const TransRiseFallBoth *to_tr, Clock *clk, const SetupHold *setup_hold, float margin) { Sta::sta()->setDataCheck(from, from_tr, to, to_tr, clk, setup_hold, margin); } void unset_data_check_cmd(Pin *from, const TransRiseFallBoth *from_tr, Pin *to, const TransRiseFallBoth *to_tr, Clock *clk, const SetupHold *setup_hold) { Sta::sta()->removeDataCheck(from, from_tr, to, to_tr, clk, setup_hold); } void set_input_delay_cmd(Pin *pin, TransRiseFallBoth *tr, Clock *clk, TransRiseFall *clk_tr, Pin *ref_pin, bool source_latency_included, bool network_latency_included, MinMaxAll *min_max, bool add, float delay) { cmdLinkedNetwork(); Sta::sta()->setInputDelay(pin, tr, clk, clk_tr, ref_pin, source_latency_included, network_latency_included, min_max, add, delay); } void unset_input_delay_cmd(Pin *pin, TransRiseFallBoth *tr, Clock *clk, TransRiseFall *clk_tr, MinMaxAll *min_max) { cmdLinkedNetwork(); Sta::sta()->removeInputDelay(pin, tr, clk, clk_tr, min_max); } void set_output_delay_cmd(Pin *pin, const TransRiseFallBoth *tr, Clock *clk, const TransRiseFall *clk_tr, Pin *ref_pin, bool source_latency_included, bool network_latency_included, const MinMaxAll *min_max, bool add, float delay) { cmdLinkedNetwork(); Sta::sta()->setOutputDelay(pin, tr, clk, clk_tr, ref_pin, source_latency_included, network_latency_included, min_max, add, delay); } void unset_output_delay_cmd(Pin *pin, TransRiseFallBoth *tr, Clock *clk, TransRiseFall *clk_tr, MinMaxAll *min_max) { cmdLinkedNetwork(); Sta::sta()->removeOutputDelay(pin, tr, clk, clk_tr, min_max); } void disable_cell(LibertyCell *cell, LibertyPort *from, LibertyPort *to) { cmdLinkedNetwork(); Sta::sta()->disable(cell, from, to); } void unset_disable_cell(LibertyCell *cell, LibertyPort *from, LibertyPort *to) { cmdLinkedNetwork(); Sta::sta()->removeDisable(cell, from, to); } void disable_lib_port(LibertyPort *port) { cmdLinkedNetwork(); Sta::sta()->disable(port); } void unset_disable_lib_port(LibertyPort *port) { cmdLinkedNetwork(); Sta::sta()->removeDisable(port); } void disable_port(Port *port) { cmdLinkedNetwork(); Sta::sta()->disable(port); } void unset_disable_port(Port *port) { cmdLinkedNetwork(); Sta::sta()->removeDisable(port); } void disable_instance(Instance *instance, LibertyPort *from, LibertyPort *to) { cmdLinkedNetwork(); Sta::sta()->disable(instance, from, to); } void unset_disable_instance(Instance *instance, LibertyPort *from, LibertyPort *to) { cmdLinkedNetwork(); Sta::sta()->removeDisable(instance, from, to); } void disable_pin(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->disable(pin); } void unset_disable_pin(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->removeDisable(pin); } void disable_edge(Edge *edge) { cmdLinkedNetwork(); Sta::sta()->disable(edge); } void unset_disable_edge(Edge *edge) { cmdLinkedNetwork(); Sta::sta()->removeDisable(edge); } void disable_timing_arc_set(TimingArcSet *arc_set) { cmdLinkedNetwork(); Sta::sta()->disable(arc_set); } void unset_disable_timing_arc_set(TimingArcSet *arc_set) { cmdLinkedNetwork(); Sta::sta()->removeDisable(arc_set); } void disable_clock_gating_check_inst(Instance *inst) { cmdLinkedNetwork(); Sta::sta()->disableClockGatingCheck(inst); } void disable_clock_gating_check_pin(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->disableClockGatingCheck(pin); } void unset_disable_clock_gating_check_inst(Instance *inst) { cmdLinkedNetwork(); Sta::sta()->removeDisableClockGatingCheck(inst); } void unset_disable_clock_gating_check_pin(Pin *pin) { cmdLinkedNetwork(); Sta::sta()->removeDisableClockGatingCheck(pin); } void make_false_path(ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, const MinMaxAll *min_max, const char *comment) { cmdLinkedNetwork(); Sta::sta()->makeFalsePath(from, thrus, to, min_max, comment); } void make_multicycle_path(ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, const MinMaxAll *min_max, bool use_end_clk, int path_multiplier, const char *comment) { cmdLinkedNetwork(); Sta::sta()->makeMulticyclePath(from, thrus, to, min_max, use_end_clk, path_multiplier, comment); } void make_path_delay(ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, const MinMax *min_max, bool ignore_clk_latency, float delay, const char *comment) { cmdLinkedNetwork(); Sta::sta()->makePathDelay(from, thrus, to, min_max, ignore_clk_latency, delay, comment); } void reset_path_cmd(ExceptionFrom * from, ExceptionThruSeq *thrus, ExceptionTo *to, const MinMaxAll *min_max) { cmdLinkedNetwork(); Sta::sta()->resetPath(from, thrus, to, min_max); // from/to and thru are owned and deleted by the caller. // ExceptionThruSeq thrus arg is made by TclListSeqExceptionThru // in the swig converter so it is deleted here. delete thrus; } void make_group_path(const char *name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, const char *comment) { cmdLinkedNetwork(); if (name[0] == '\0') name = nullptr; Sta::sta()->makeGroupPath(name, is_default, from, thrus, to, comment); } bool is_path_group_name(const char *name) { cmdLinkedNetwork(); return Sta::sta()->isGroupPathName(name); } ExceptionFrom * make_exception_from(PinSet *from_pins, ClockSet *from_clks, InstanceSet *from_insts, const TransRiseFallBoth *from_tr) { cmdLinkedNetwork(); return Sta::sta()->makeExceptionFrom(from_pins, from_clks, from_insts, from_tr); } void delete_exception_from(ExceptionFrom *from) { Sta::sta()->deleteExceptionFrom(from); } void check_exception_from_pins(ExceptionFrom *from, const char *file, int line) { Sta::sta()->checkExceptionFromPins(from, file, line); } ExceptionThru * make_exception_thru(PinSet *pins, NetSet *nets, InstanceSet *insts, const TransRiseFallBoth *tr) { cmdLinkedNetwork(); return Sta::sta()->makeExceptionThru(pins, nets, insts, tr); } void delete_exception_thru(ExceptionThru *thru) { Sta::sta()->deleteExceptionThru(thru); } ExceptionTo * make_exception_to(PinSet *to_pins, ClockSet *to_clks, InstanceSet *to_insts, const TransRiseFallBoth *tr, TransRiseFallBoth *end_tr) { cmdLinkedNetwork(); return Sta::sta()->makeExceptionTo(to_pins, to_clks, to_insts, tr, end_tr); } void delete_exception_to(ExceptionTo *to) { Sta::sta()->deleteExceptionTo(to); } void check_exception_to_pins(ExceptionTo *to, const char *file, int line) { Sta::sta()->checkExceptionToPins(to, file, line); } void set_input_slew_cmd(Port *port, const TransRiseFallBoth *tr, const MinMaxAll *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setInputSlew(port, tr, min_max, slew); } void set_drive_cell_cmd(LibertyLibrary *library, LibertyCell *cell, Port *port, LibertyPort *from_port, float from_slew_rise, float from_slew_fall, LibertyPort *to_port, const TransRiseFallBoth *tr, const MinMaxAll *min_max) { float from_slews[TransRiseFall::index_count]; from_slews[TransRiseFall::riseIndex()] = from_slew_rise; from_slews[TransRiseFall::fallIndex()] = from_slew_fall; Sta::sta()->setDriveCell(library, cell, port, from_port, from_slews, to_port, tr, min_max); } void set_drive_resistance_cmd(Port *port, const TransRiseFallBoth *tr, const MinMaxAll *min_max, float res) { cmdLinkedNetwork(); Sta::sta()->setDriveResistance(port, tr, min_max, res); } void set_slew_limit_clk(Clock *clk, const TransRiseFallBoth *tr, PathClkOrData clk_data, const MinMax *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setSlewLimit(clk, tr, clk_data, min_max, slew); } void set_slew_limit_port(Port *port, const MinMax *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setSlewLimit(port, min_max, slew); } void set_slew_limit_pin(Pin *pin, const MinMax *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setSlewLimit(pin, min_max, slew); } void set_slew_limit_cell(Cell *cell, const MinMax *min_max, float slew) { cmdLinkedNetwork(); Sta::sta()->setSlewLimit(cell, min_max, slew); } void set_port_capacitance_limit(Port *port, const MinMax *min_max, float cap) { Sta::sta()->setCapacitanceLimit(port, min_max, cap); } void set_pin_capacitance_limit(Pin *pin, const MinMax *min_max, float cap) { Sta::sta()->setCapacitanceLimit(pin, min_max, cap); } void set_cell_capacitance_limit(Cell *cell, const MinMax *min_max, float cap) { Sta::sta()->setCapacitanceLimit(cell, min_max, cap); } void set_latch_borrow_limit_pin(Pin *pin, float limit) { Sta::sta()->setLatchBorrowLimit(pin, limit); } void set_latch_borrow_limit_inst(Instance *inst, float limit) { Sta::sta()->setLatchBorrowLimit(inst, limit); } void set_latch_borrow_limit_clk(Clock *clk, float limit) { Sta::sta()->setLatchBorrowLimit(clk, limit); } void set_min_pulse_width_global(const TransRiseFallBoth *tr, float min_width) { Sta::sta()->setMinPulseWidth(tr, min_width); } void set_min_pulse_width_pin(Pin *pin, const TransRiseFallBoth *tr, float min_width) { Sta::sta()->setMinPulseWidth(pin, tr, min_width); } void set_min_pulse_width_clk(Clock *clk, const TransRiseFallBoth *tr, float min_width) { Sta::sta()->setMinPulseWidth(clk, tr, min_width); } void set_min_pulse_width_inst(Instance *inst, const TransRiseFallBoth *tr, float min_width) { Sta::sta()->setMinPulseWidth(inst, tr, min_width); } void set_max_area_cmd(float area) { Sta::sta()->setMaxArea(area); } void set_port_fanout_limit(Port *port, const MinMax *min_max, float fanout) { Sta::sta()->setFanoutLimit(port, min_max, fanout); } void set_cell_fanout_limit(Cell *cell, const MinMax *min_max, float fanout) { Sta::sta()->setFanoutLimit(cell, min_max, fanout); } void set_logic_value_cmd(Pin *pin, LogicValue value) { Sta::sta()->setLogicValue(pin, value); } void set_case_analysis_cmd(Pin *pin, LogicValue value) { Sta::sta()->setCaseAnalysis(pin, value); } void unset_case_analysis_cmd(Pin *pin) { Sta::sta()->removeCaseAnalysis(pin); } void set_timing_derate_cmd(TimingDerateType type, PathClkOrData clk_data, const TransRiseFallBoth *tr, const EarlyLate *early_late, float derate) { Sta::sta()->setTimingDerate(type, clk_data, tr, early_late, derate); } void set_timing_derate_net_cmd(const Net *net, PathClkOrData clk_data, const TransRiseFallBoth *tr, const EarlyLate *early_late, float derate) { Sta::sta()->setTimingDerate(net, clk_data, tr, early_late, derate); } void set_timing_derate_inst_cmd(const Instance *inst, TimingDerateType type, PathClkOrData clk_data, const TransRiseFallBoth *tr, const EarlyLate *early_late, float derate) { Sta::sta()->setTimingDerate(inst, type, clk_data, tr, early_late, derate); } void set_timing_derate_cell_cmd(const LibertyCell *cell, TimingDerateType type, PathClkOrData clk_data, const TransRiseFallBoth *tr, const EarlyLate *early_late, float derate) { Sta::sta()->setTimingDerate(cell, type, clk_data, tr, early_late, derate); } void unset_timing_derate_cmd() { Sta::sta()->unsetTimingDerate(); } ClockIterator * clock_iterator() { return new ClockIterator(Sta::sta()->sdc()); } Clock * find_clock(const char *name) { cmdLinkedNetwork(); return Sta::sta()->sdc()->findClock(name); } bool is_clock_src(const Pin *pin) { return Sta::sta()->isClockSrc(pin); } Clock * default_arrival_clock() { return Sta::sta()->sdc()->defaultArrivalClock(); } ClockSeq * find_clocks_matching(const char *pattern, bool regexp, bool nocase) { cmdLinkedNetwork(); ClockSeq *clks = new ClockSeq; Sta *sta = Sta::sta(); Sdc *sdc = sta->sdc(); PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp()); sdc->findClocksMatching(&matcher, clks); return clks; } void update_generated_clks() { cmdLinkedNetwork(); Sta::sta()->updateGeneratedClks(); } bool pin_is_clock(const Pin *pin) { Sta *sta = Sta::sta(); Graph *graph = sta->graph(); Search *search = sta->search(); Vertex *vertex, *bidirect_drvr_vertex; graph->pinVertices(pin, vertex, bidirect_drvr_vertex); return search->isClock(vertex); } bool pin_is_genclk_src(const Pin *pin) { Sta *sta = Sta::sta(); Graph *graph = sta->graph(); Search *search = sta->search(); Vertex *vertex, *bidirect_drvr_vertex; graph->pinVertices(pin, vertex, bidirect_drvr_vertex); return search->isGenClkSrc(vertex); } // format_unit functions print with fixed digits and suffix. // Pass value arg as string to support NaNs. const char * format_time(const char *value, int digits) { float value1 = strtof(value, nullptr); return Sta::sta()->units()->timeUnit()->asString(value1, digits); } const char * format_capacitance(const char *value, int digits) { float value1 = strtof(value, nullptr); return Sta::sta()->units()->capacitanceUnit()->asString(value1, digits); } const char * format_resistance(const char *value, int digits) { float value1 = strtof(value, nullptr); return Sta::sta()->units()->resistanceUnit()->asString(value1, digits); } const char * format_voltage(const char *value, int digits) { float value1 = strtof(value, nullptr); return Sta::sta()->units()->voltageUnit()->asString(value1, digits); } const char * format_power(const char *value, int digits) { float value1 = strtof(value, nullptr); return Sta::sta()->units()->powerUnit()->asString(value1, digits); } // Unit converstion from sta unit to user interface and visa versa. double time_ui_sta(double value) { return value * Sta::sta()->units()->timeUnit()->scale(); } double time_sta_ui(double value) { return value / Sta::sta()->units()->timeUnit()->scale(); } double capacitance_ui_sta(double value) { return value * Sta::sta()->units()->capacitanceUnit()->scale(); } double capacitance_sta_ui(double value) { return value / Sta::sta()->units()->capacitanceUnit()->scale(); } double resistance_ui_sta(double value) { return value * Sta::sta()->units()->resistanceUnit()->scale(); } double resistance_sta_ui(double value) { return value / Sta::sta()->units()->resistanceUnit()->scale(); } double voltage_ui_sta(double value) { return value * Sta::sta()->units()->voltageUnit()->scale(); } double voltage_sta_ui(double value) { return value / Sta::sta()->units()->voltageUnit()->scale(); } double current_ui_sta(double value) { return value * Sta::sta()->units()->currentUnit()->scale(); } double current_sta_ui(double value) { return value / Sta::sta()->units()->currentUnit()->scale(); } double power_ui_sta(double value) { return value * Sta::sta()->units()->powerUnit()->scale(); } double power_sta_ui(double value) { return value / Sta::sta()->units()->powerUnit()->scale(); } VertexIterator * vertex_iterator() { return new VertexIterator(cmdGraph()); } void set_arc_delay(Edge *edge, TimingArc *arc, const Corner *corner, const MinMaxAll *min_max, float delay) { cmdGraph(); Sta::sta()->setArcDelay(edge, arc, corner, min_max, delay); } void set_annotated_slew(Vertex *vertex, const Corner *corner, const MinMaxAll *min_max, const TransRiseFallBoth *tr, float slew) { cmdGraph(); Sta::sta()->setAnnotatedSlew(vertex, corner, min_max, tr, slew); } // Remove all delay and slew annotations. void remove_delay_slew_annotations() { cmdGraph(); Sta::sta()->removeDelaySlewAnnotations(); } CheckErrorSeq & check_timing_cmd(bool no_input_delay, bool no_output_delay, bool reg_multiple_clks, bool reg_no_clks, bool unconstrained_endpoints, bool loops, bool generated_clks) { cmdLinkedNetwork(); return Sta::sta()->checkTiming(no_input_delay, no_output_delay, reg_multiple_clks, reg_no_clks, unconstrained_endpoints, loops, generated_clks); } bool crpr_enabled() { return Sta::sta()->crprEnabled(); } void set_crpr_enabled(bool enabled) { return Sta::sta()->setCrprEnabled(enabled); } const char * crpr_mode() { switch (Sta::sta()->crprMode()) { case CrprMode::same_transition: return "same_transition"; case CrprMode::same_pin: return "same_pin"; default: return ""; } } void set_crpr_mode(const char *mode) { if (stringEq(mode, "same_pin")) Sta::sta()->setCrprMode(CrprMode::same_pin); else if (stringEq(mode, "same_transition")) Sta::sta()->setCrprMode(CrprMode::same_transition); else internalError("unknown common clk pessimism mode."); } bool pocv_enabled() { return Sta::sta()->pocvEnabled(); } void set_pocv_enabled(bool enabled) { #if !SSTA if (enabled) Sta::sta()->report()->error("POCV support requires compilation with SSTA=1.\n"); #endif return Sta::sta()->setPocvEnabled(enabled); } float pocv_sigma_factor() { return Sta::sta()->sigmaFactor(); } void set_pocv_sigma_factor(float factor) { Sta::sta()->setSigmaFactor(factor); } bool propagate_gated_clock_enable() { return Sta::sta()->propagateGatedClockEnable(); } void set_propagate_gated_clock_enable(bool enable) { Sta::sta()->setPropagateGatedClockEnable(enable); } bool preset_clr_arcs_enabled() { return Sta::sta()->presetClrArcsEnabled(); } void set_preset_clr_arcs_enabled(bool enable) { Sta::sta()->setPresetClrArcsEnabled(enable); } bool cond_default_arcs_enabled() { return Sta::sta()->condDefaultArcsEnabled(); } void set_cond_default_arcs_enabled(bool enabled) { Sta::sta()->setCondDefaultArcsEnabled(enabled); } bool bidirect_inst_paths_enabled() { return Sta::sta()->bidirectInstPathsEnabled(); } void set_bidirect_inst_paths_enabled(bool enabled) { Sta::sta()->setBidirectInstPathsEnabled(enabled); } bool bidirect_net_paths_enabled() { return Sta::sta()->bidirectNetPathsEnabled(); } void set_bidirect_net_paths_enabled(bool enabled) { Sta::sta()->setBidirectNetPathsEnabled(enabled); } bool recovery_removal_checks_enabled() { return Sta::sta()->recoveryRemovalChecksEnabled(); } void set_recovery_removal_checks_enabled(bool enabled) { Sta::sta()->setRecoveryRemovalChecksEnabled(enabled); } bool gated_clk_checks_enabled() { return Sta::sta()->gatedClkChecksEnabled(); } void set_gated_clk_checks_enabled(bool enabled) { Sta::sta()->setGatedClkChecksEnabled(enabled); } bool dynamic_loop_breaking() { return Sta::sta()->dynamicLoopBreaking(); } void set_dynamic_loop_breaking(bool enable) { Sta::sta()->setDynamicLoopBreaking(enable); } bool use_default_arrival_clock() { return Sta::sta()->useDefaultArrivalClock(); } void set_use_default_arrival_clock(bool enable) { return Sta::sta()->setUseDefaultArrivalClock(enable); } bool propagate_all_clocks() { return Sta::sta()->propagateAllClocks(); } void set_propagate_all_clocks(bool prop) { Sta::sta()->setPropagateAllClocks(prop); } //////////////////////////////////////////////////////////////// PathEndSeq * find_path_ends(ExceptionFrom *from, ExceptionThruSeq *thrus, ExceptionTo *to, bool unconstrained, Corner *corner, const MinMaxAll *delay_min_max, int group_count, int endpoint_count, bool unique_pins, float slack_min, float slack_max, bool sort_by_slack, PathGroupNameSet *groups, bool setup, bool hold, bool recovery, bool removal, bool clk_gating_setup, bool clk_gating_hold) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); PathEndSeq *ends = sta->findPathEnds(from, thrus, to, unconstrained, corner, delay_min_max, group_count, endpoint_count, unique_pins, slack_min, slack_max, sort_by_slack, groups->size() ? groups : nullptr, setup, hold, recovery, removal, clk_gating_setup, clk_gating_hold); delete groups; return ends; } void report_path_end_header() { Sta::sta()->reportPathEndHeader(); } void report_path_end_footer() { Sta::sta()->reportPathEndFooter(); } void report_path_end(PathEnd *end) { Sta::sta()->reportPathEnd(end); } void report_path_end2(PathEnd *end, PathEnd *prev_end) { Sta::sta()->reportPathEnd(end, prev_end); } void set_report_path_format(ReportPathFormat format) { Sta::sta()->setReportPathFormat(format); } void set_report_path_field_order(StringSeq *field_names) { Sta::sta()->setReportPathFieldOrder(field_names); delete field_names; } void set_report_path_fields(bool report_input_pin, bool report_net, bool report_cap, bool report_slew) { Sta::sta()->setReportPathFields(report_input_pin, report_net, report_cap, report_slew); } void set_report_path_field_properties(const char *field_name, const char *title, int width, bool left_justify) { Sta *sta = Sta::sta(); ReportField *field = sta->findReportPathField(field_name); if (field) field->setProperties(title, width, left_justify); else sta->report()->print("Error: unknown report path field %s\n", field_name); } void set_report_path_field_width(const char *field_name, int width) { Sta *sta = Sta::sta(); ReportField *field = sta->findReportPathField(field_name); if (field) field->setWidth(width); else sta->report()->print("Error: unknown report path field %s\n", field_name); } void set_report_path_digits(int digits) { Sta::sta()->setReportPathDigits(digits); } void set_report_path_no_split(bool no_split) { Sta::sta()->setReportPathNoSplit(no_split); } void delete_path_ref(PathRef *path) { delete path; } void remove_constraints() { Sta::sta()->removeConstraints(); } void report_path_cmd(PathRef *path) { Sta::sta()->reportPath(path); } void report_clk_skew(ClockSet *clks, const Corner *corner, const SetupHold *setup_hold, int digits) { cmdLinkedNetwork(); Sta::sta()->reportClkSkew(clks, corner, setup_hold, digits); delete clks; } TmpPinSet * startpoints() { return findStartpoints(); } TmpPinSet * endpoints() { return findEndpoints(); } TmpPinSet * group_path_pins(const char *group_path_name) { Sta *sta = Sta::sta(); Sdc *sdc = sta->sdc(); if (sdc->isGroupPathName(group_path_name)) return sta->findGroupPathPins(group_path_name); else return nullptr; } //////////////////////////////////////////////////////////////// MinPulseWidthCheckSeq & min_pulse_width_violations(const Corner *corner) { cmdLinkedNetwork(); return Sta::sta()->minPulseWidthViolations(corner); } MinPulseWidthCheckSeq & min_pulse_width_check_pins(PinSeq *pins, const Corner *corner) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); MinPulseWidthCheckSeq &checks = sta->minPulseWidthChecks(pins, corner); delete pins; return checks; } MinPulseWidthCheckSeq & min_pulse_width_checks(const Corner *corner) { cmdLinkedNetwork(); return Sta::sta()->minPulseWidthChecks(corner); } MinPulseWidthCheck * min_pulse_width_check_slack(const Corner *corner) { cmdLinkedNetwork(); return Sta::sta()->minPulseWidthSlack(corner); } void report_mpw_checks(MinPulseWidthCheckSeq *checks, bool verbose) { Sta::sta()->reportMpwChecks(checks, verbose); } void report_mpw_check(MinPulseWidthCheck *check, bool verbose) { Sta::sta()->reportMpwCheck(check, verbose); } //////////////////////////////////////////////////////////////// MinPeriodCheckSeq & min_period_violations() { cmdLinkedNetwork(); return Sta::sta()->minPeriodViolations(); } MinPeriodCheck * min_period_check_slack() { cmdLinkedNetwork(); return Sta::sta()->minPeriodSlack(); } void report_min_period_checks(MinPeriodCheckSeq *checks, bool verbose) { Sta::sta()->reportChecks(checks, verbose); } void report_min_period_check(MinPeriodCheck *check, bool verbose) { Sta::sta()->reportCheck(check, verbose); } //////////////////////////////////////////////////////////////// MaxSkewCheckSeq & max_skew_violations() { cmdLinkedNetwork(); return Sta::sta()->maxSkewViolations(); } MaxSkewCheck * max_skew_check_slack() { cmdLinkedNetwork(); return Sta::sta()->maxSkewSlack(); } void report_max_skew_checks(MaxSkewCheckSeq *checks, bool verbose) { Sta::sta()->reportChecks(checks, verbose); } void report_max_skew_check(MaxSkewCheck *check, bool verbose) { Sta::sta()->reportCheck(check, verbose); } //////////////////////////////////////////////////////////////// void find_timing_cmd(bool full) { cmdLinkedNetwork(); Sta::sta()->updateTiming(full); } void find_requireds() { cmdLinkedNetwork(); Sta::sta()->findRequireds(); } void find_delays() { cmdLinkedNetwork(); Sta::sta()->findDelays(); } Slack total_negative_slack_cmd(const MinMax *min_max) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); return sta->totalNegativeSlack(min_max); } Slack total_negative_slack_corner_cmd(const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); return sta->totalNegativeSlack(corner, min_max); } Slack worst_slack(const MinMax *min_max) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); Slack worst_slack; Vertex *worst_vertex; sta->worstSlack(min_max, worst_slack, worst_vertex); return worst_slack; } Vertex * worst_slack_vertex(const MinMax *min_max) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); Slack worst_slack; Vertex *worst_vertex; sta->worstSlack(min_max, worst_slack, worst_vertex); return worst_vertex;; } Slack worst_slack_corner(const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); Slack worst_slack; Vertex *worst_vertex; sta->worstSlack(corner, min_max, worst_slack, worst_vertex); return worst_slack; } PathRef * vertex_worst_arrival_path(Vertex *vertex, const MinMax *min_max) { Sta *sta = Sta::sta(); PathRef path; sta->vertexWorstArrivalPath(vertex, min_max, path); if (!path.isNull()) return new PathRef(path); else return nullptr; } PathRef * vertex_worst_arrival_path_tr(Vertex *vertex, const TransRiseFall *tr, MinMax *min_max) { Sta *sta = Sta::sta(); PathRef path; sta->vertexWorstArrivalPath(vertex, tr, min_max, path); if (!path.isNull()) return new PathRef(path); else return nullptr; } PathRef * vertex_worst_slack_path(Vertex *vertex, const MinMax *min_max) { Sta *sta = Sta::sta(); PathRef path; sta->vertexWorstSlackPath(vertex, min_max, path); if (!path.isNull()) return new PathRef(path); else return nullptr; } TmpString * report_delay_calc_cmd(Edge *edge, TimingArc *arc, const Corner *corner, const MinMax *min_max, int digits) { cmdLinkedNetwork(); return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); } Pin * pin_min_slew_limit_slack(const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); return Sta::sta()->pinMinSlewLimitSlack(corner, min_max); } PinSeq * pin_slew_limit_violations(const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); return Sta::sta()->pinSlewLimitViolations(corner, min_max); } void report_slew_limit_short_header() { Sta::sta()->reportSlewLimitShortHeader(); } void report_slew_limit_short(Pin *pin, const Corner *corner, const MinMax *min_max) { Sta::sta()->reportSlewLimitShort(pin, corner, min_max); } void report_slew_limit_verbose(Pin *pin, const Corner *corner, const MinMax *min_max) { Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max); } //////////////////////////////////////////////////////////////// TmpFloatSeq * design_power(const Corner *corner) { cmdLinkedNetwork(); PowerResult total, sequential, combinational, macro, pad; Sta::sta()->power(corner, total, sequential, combinational, macro, pad); FloatSeq *floats = new FloatSeq; pushPowerResultFloats(total, floats); pushPowerResultFloats(sequential, floats); pushPowerResultFloats(combinational, floats); pushPowerResultFloats(macro, floats); pushPowerResultFloats(pad, floats); return floats; } TmpFloatSeq * instance_power(Instance *inst, const Corner *corner) { cmdLinkedNetwork(); PowerResult power; Sta::sta()->power(inst, corner, power); FloatSeq *floats = new FloatSeq; floats->push_back(power.internal()); floats->push_back(power.switching()); floats->push_back(power.leakage()); floats->push_back(power.total()); return floats; } float power_default_signal_toggle_rate() { return Sta::sta()->power()->defaultSignalToggleRate(); } void set_power_default_signal_toggle_rate(float rate) { return Sta::sta()->power()->setDefaultSignalToggleRate(rate); } //////////////////////////////////////////////////////////////// EdgeSeq * disabled_edges_sorted() { cmdLinkedNetwork(); return Sta::sta()->disabledEdgesSorted(); } void write_sdc_cmd(const char *filename, bool compatible, bool no_timestamp, int digits) { cmdLinkedNetwork(); Sta::sta()->writeSdc(filename, compatible, no_timestamp, digits); } void write_path_spice_cmd(PathRef *path, const char *spice_filename, const char *subckt_filename, const char *lib_subckt_filename, const char *model_filename, const char *power_name, const char *gnd_name) { Sta *sta = Sta::sta(); writePathSpice(path, spice_filename, subckt_filename, lib_subckt_filename, model_filename, power_name, gnd_name, sta); } bool liberty_supply_exists(const char *supply_name) { auto network = Sta::sta()->network(); auto lib = network->defaultLibertyLibrary(); return lib && lib->supplyExists(supply_name); } float unit_scale(const char *unit_name) { Unit *unit = Sta::sta()->units()->find(unit_name); if (unit) return unit->scale(); else return 1.0F; } bool fuzzy_equal(float value1, float value2) { return fuzzyEqual(value1, value2); } char pin_sim_logic_value(const Pin *pin) { return logicValueString(Sta::sta()->simLogicValue(pin)); } char pin_case_logic_value(const Pin *pin) { Sta *sta = Sta::sta(); Sdc *sdc = sta->sdc(); LogicValue value = LogicValue::unknown; bool exists; sdc->caseLogicValue(pin, value, exists); return logicValueString(value); } char pin_logic_value(const Pin *pin) { Sta *sta = Sta::sta(); Sdc *sdc = sta->sdc(); LogicValue value = LogicValue::unknown; bool exists; sdc->logicValue(pin, value, exists); return logicValueString(value); } SlowDrvrIterator * slow_driver_iterator() { return Sta::sta()->slowDrvrIterator(); } bool timing_arc_disabled(Edge *edge, TimingArc *arc) { Graph *graph = Sta::sta()->graph(); return !searchThru(edge, arc, graph); } ClockGroups * make_clock_groups(const char *name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, bool allow_paths, const char *comment) { return Sta::sta()->makeClockGroups(name, logically_exclusive, physically_exclusive, asynchronous, allow_paths, comment); } void clock_groups_make_group(ClockGroups *clk_groups, ClockSet *clks) { Sta::sta()->makeClockGroup(clk_groups, clks); } void unset_clock_groups_logically_exclusive(const char *name) { Sta::sta()->removeClockGroupsLogicallyExclusive(name); } void unset_clock_groups_physically_exclusive(const char *name) { Sta::sta()->removeClockGroupsPhysicallyExclusive(name); } void unset_clock_groups_asynchronous(const char *name) { Sta::sta()->removeClockGroupsAsynchronous(name); } // Debugging function. bool same_clk_group(Clock *clk1, Clock *clk2) { Sta *sta = Sta::sta(); Sdc *sdc = sta->sdc(); return sdc->sameClockGroupExplicit(clk1, clk2); } void set_clock_sense_cmd(PinSet *pins, ClockSet *clks, bool positive, bool negative, bool stop_propagation) { ClockSense sense; if (positive) sense = ClockSense::positive; else if (negative) sense = ClockSense::negative; else if (stop_propagation) sense = ClockSense::stop; else internalError("unknown clock sense"); Sta::sta()->setClockSense(pins, clks, sense); } bool timing_role_is_check(TimingRole *role) { return role->isTimingCheck(); } //////////////////////////////////////////////////////////////// TmpPinSet * find_fanin_pins(PinSeq *to, bool flat, bool startpoints_only, int inst_levels, int pin_levels, bool thru_disabled, bool thru_constants) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); PinSet *fanin = sta->findFaninPins(to, flat, startpoints_only, inst_levels, pin_levels, thru_disabled, thru_constants); delete to; return fanin; } TmpInstanceSet * find_fanin_insts(PinSeq *to, bool flat, bool startpoints_only, int inst_levels, int pin_levels, bool thru_disabled, bool thru_constants) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); InstanceSet *fanin = sta->findFaninInstances(to, flat, startpoints_only, inst_levels, pin_levels, thru_disabled, thru_constants); delete to; return fanin; } TmpPinSet * find_fanout_pins(PinSeq *from, bool flat, bool endpoints_only, int inst_levels, int pin_levels, bool thru_disabled, bool thru_constants) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); PinSet *fanout = sta->findFanoutPins(from, flat, endpoints_only, inst_levels, pin_levels, thru_disabled, thru_constants); delete from; return fanout; } TmpInstanceSet * find_fanout_insts(PinSeq *from, bool flat, bool endpoints_only, int inst_levels, int pin_levels, bool thru_disabled, bool thru_constants) { cmdLinkedNetwork(); Sta *sta = Sta::sta(); InstanceSet *fanout = sta->findFanoutInstances(from, flat, endpoints_only, inst_levels, pin_levels, thru_disabled, thru_constants); delete from; return fanout; } TmpPinSet * net_load_pins(Net *net) { Network *network = cmdLinkedNetwork(); PinSet *pins = new PinSet; NetConnectedPinIterator *pin_iter = network->connectedPinIterator(net); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); if (network->isLoad(pin)) pins->insert(pin); } delete pin_iter; return pins; } TmpPinSet * net_driver_pins(Net *net) { Network *network = cmdLinkedNetwork(); PinSet *pins = new PinSet; NetConnectedPinIterator *pin_iter = network->connectedPinIterator(net); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); if (network->isDriver(pin)) pins->insert(pin); } delete pin_iter; return pins; } //////////////////////////////////////////////////////////////// void report_loops() { Sta *sta = Sta::sta(); Network *network = cmdLinkedNetwork(); Graph *graph = cmdGraph(); Report *report = sta->report(); GraphLoopSeq *loops = sta->graphLoops(); GraphLoopSeq::Iterator loop_iter(loops); while (loop_iter.hasNext()) { GraphLoop *loop = loop_iter.next(); loop->report(report, network, graph); report->print("\n"); } } // Includes top instance. int network_instance_count() { Network *network = cmdNetwork(); return network->instanceCount(); } int network_pin_count() { Network *network = cmdNetwork(); return network->pinCount(); } int network_net_count() { Network *network = cmdNetwork(); return network->netCount(); } int network_leaf_instance_count() { Network *network = cmdNetwork(); return network->leafInstanceCount(); } int network_leaf_pin_count() { Network *network = cmdNetwork(); return network->leafPinCount(); } int graph_vertex_count() { return cmdGraph()->vertexCount(); } int graph_edge_count() { return cmdGraph()->edgeCount(); } int graph_arc_count() { return cmdGraph()->arcCount(); } int tag_group_count() { return Sta::sta()->tagGroupCount(); } void report_tag_groups() { Sta::sta()->search()->reportTagGroups(); } void report_tag_arrivals_cmd(Vertex *vertex) { Sta::sta()->search()->reportArrivals(vertex); } void report_arrival_count_histogram() { Sta::sta()->search()->reportArrivalCountHistogram(); } int tag_count() { return Sta::sta()->tagCount(); } void report_tags() { Sta::sta()->search()->reportTags(); } void report_clk_infos() { Sta::sta()->search()->reportClkInfos(); } int clk_info_count() { return Sta::sta()->clkInfoCount(); } int arrival_count() { return Sta::sta()->arrivalCount(); } void delete_all_memory() { deleteAllMemory(); } Tcl_Interp * tcl_interp() { return Sta::sta()->tclInterp(); } // Initialize sta after delete_all_memory. void init_sta() { initSta(); } void clear_sta() { Sta::sta()->clear(); } void make_sta(Tcl_Interp *interp) { Sta *sta = new Sta; Sta::setSta(sta); sta->makeComponents(); sta->setTclInterp(interp); } void clear_network() { Sta *sta = Sta::sta(); sta->network()->clear(); } // Elapsed run time (in seconds). double elapsed_run_time() { return elapsedRunTime(); } // User run time (in seconds). double user_run_time() { return userRunTime(); } // User run time (in seconds). unsigned long cputime() { return static_cast(userRunTime() + .5); } // Peak memory usage in bytes. unsigned long mem() { return memoryUsage(); } int processor_count() { return processorCount(); } int thread_count() { return Sta::sta()->threadCount(); } void set_thread_count(int count) { Sta::sta()->setThreadCount(count); } void arrivals_invalid() { Sta *sta = Sta::sta(); sta->arrivalsInvalid(); } %} // inline //////////////////////////////////////////////////////////////// // // Object Methods // //////////////////////////////////////////////////////////////// %extend Library { Cell * find_cell(const char *name) { return cmdNetwork()->findCell(self, name); } TmpCellSeq * find_cells_matching(const char *pattern, bool regexp, bool nocase) { PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); TmpCellSeq *cells = new TmpCellSeq; cmdNetwork()->findCellsMatching(self, &matcher, cells); return cells; } } // Library methods %extend LibertyLibrary { LibertyCell * find_liberty_cell(const char *name) { return self->findLibertyCell(name); } TmpLibertyCellSeq * find_liberty_cells_matching(const char *pattern, bool regexp, bool nocase) { PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); // TmpLibertyCellSeq deletes temporary CellSeq after conversion to tcl list. TmpLibertyCellSeq *cells = new TmpLibertyCellSeq; self->findLibertyCellsMatching(&matcher, cells); return cells; } Wireload * find_wireload(const char *model_name) { return self->findWireload(model_name); } WireloadSelection * find_wireload_selection(const char *selection_name) { return self->findWireloadSelection(selection_name); } OperatingConditions * find_operating_conditions(const char *op_cond_name) { return self->findOperatingConditions(op_cond_name); } OperatingConditions * default_operating_conditions() { return self->defaultOperatingConditions(); } } // LibertyLibrary methods %extend LibraryIterator { bool has_next() { return self->hasNext(); } Library *next() { return self->next(); } void finish() { delete self; } } // LibraryIterator methods %extend LibertyLibraryIterator { bool has_next() { return self->hasNext(); } LibertyLibrary *next() { return self->next(); } void finish() { delete self; } } // LibertyLibraryIterator methods %extend Cell { Library *library() { return cmdNetwork()->library(self); } LibertyCell *liberty_cell() { return cmdNetwork()->libertyCell(self); } bool is_leaf() { return cmdNetwork()->isLeaf(self); } CellPortIterator * port_iterator() { return cmdNetwork()->portIterator(self); } Port * find_port(const char *name) { return cmdNetwork()->findPort(self, name); } TmpPortSeq * find_ports_matching(const char *pattern, bool regexp, bool nocase) { PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); TmpPortSeq *ports = new TmpPortSeq; cmdNetwork()->findPortsMatching(self, &matcher, ports); return ports; } } // Cell methods %extend LibertyCell { bool is_leaf() { return self->isLeaf(); } LibertyLibrary *liberty_library() { return self->libertyLibrary(); } Cell *cell() { return reinterpret_cast(self); } LibertyPort * find_liberty_port(const char *name) { return self->findLibertyPort(name); } TmpLibertyPortSeq * find_liberty_ports_matching(const char *pattern, bool regexp, bool nocase) { PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp()); TmpLibertyPortSeq *ports = new TmpLibertyPortSeq; self->findLibertyPortsMatching(&matcher, ports); return ports; } LibertyCellPortIterator * liberty_port_iterator() { return new LibertyCellPortIterator(self); } LibertyCellTimingArcSetIterator * timing_arc_set_iterator() { return new LibertyCellTimingArcSetIterator(self); } } // LibertyCell methods %extend CellPortIterator { bool has_next() { return self->hasNext(); } Port *next() { return self->next(); } void finish() { delete self; } } // CellPortIterator methods %extend LibertyCellPortIterator { bool has_next() { return self->hasNext(); } LibertyPort *next() { return self->next(); } void finish() { delete self; } } // LibertyCellPortIterator methods %extend Port { const char *bus_name() { return cmdNetwork()->busName(self); } Cell *cell() { return cmdNetwork()->cell(self); } LibertyPort *liberty_port() { return cmdNetwork()->libertyPort(self); } bool is_bus() { return cmdNetwork()->isBus(self); } PortMemberIterator * member_iterator() { return cmdNetwork()->memberIterator(self); } } // Port methods %extend LibertyPort { const char *bus_name() { return self->busName(); } Cell *cell() { return self->cell(); } bool is_bus() { return self->isBus(); } LibertyPortMemberIterator * member_iterator() { return new LibertyPortMemberIterator(self); } const char * function() { FuncExpr *func = self->function(); if (func) return func->asString(); else return nullptr; } const char * tristate_enable() { FuncExpr *enable = self->tristateEnable(); if (enable) return enable->asString(); else return nullptr; } float capacitance(const TransRiseFall *tr, const MinMax *min_max) { Sta *sta = Sta::sta(); OperatingConditions *op_cond = sta->operatingConditions(min_max); return self->capacitance(tr, min_max, op_cond, op_cond); } } // LibertyPort methods %extend OperatingConditions { float process() { return self->process(); } float voltage() { return self->voltage(); } float temperature() { return self->temperature(); } } %extend PortMemberIterator { bool has_next() { return self->hasNext(); } Port *next() { return self->next(); } void finish() { delete self; } } // PortMemberIterator methods %extend LibertyPortMemberIterator { bool has_next() { return self->hasNext(); } LibertyPort *next() { return self->next(); } void finish() { delete self; } } // LibertyPortMemberIterator methods %extend TimingArcSet { LibertyPort *from() { return self->from(); } LibertyPort *to() { return self->to(); } TimingRole *role() { return self->role(); } const char *sdf_cond() { return self->sdfCond(); } const char * full_name() { const char *from = self->from()->name(); const char *to = self->to()->name(); const char *cell_name = self->libertyCell()->name(); return stringPrintTmp("%s %s -> %s", cell_name, from, to); } } // TimingArcSet methods %extend LibertyCellTimingArcSetIterator { bool has_next() { return self->hasNext(); } TimingArcSet *next() { return self->next(); } void finish() { delete self; } } %extend TimingArc { LibertyPort *from() { return self->from(); } LibertyPort *to() { return self->to(); } Transition *from_trans() { return self->fromTrans(); } const char *from_trans_name() { return self->fromTrans()->asRiseFall()->name(); } Transition *to_trans() { return self->toTrans(); } const char *to_trans_name() { return self->toTrans()->asRiseFall()->name(); } TimingRole *role() { return self->role(); } } // TimingArc methods %extend TimingArcSetArcIterator { bool has_next() { return self->hasNext(); } TimingArc *next() { return self->next(); } void finish() { delete self; } } %extend Instance { Instance *parent() { return cmdLinkedNetwork()->parent(self); } Cell *cell() { return cmdLinkedNetwork()->cell(self); } LibertyCell *liberty_cell() { return cmdLinkedNetwork()->libertyCell(self); } bool is_leaf() { return cmdLinkedNetwork()->isLeaf(self); } InstanceChildIterator * child_iterator() { return cmdLinkedNetwork()->childIterator(self); } InstancePinIterator * pin_iterator() { return cmdLinkedNetwork()->pinIterator(self); } InstanceNetIterator * net_iterator() { return cmdLinkedNetwork()->netIterator(self); } Pin * find_pin(const char *name) { return cmdLinkedNetwork()->findPin(self, name); } } // Instance methods %extend InstanceChildIterator { bool has_next() { return self->hasNext(); } Instance *next() { return self->next(); } void finish() { delete self; } } // InstanceChildIterator methods %extend LeafInstanceIterator { bool has_next() { return self->hasNext(); } Instance *next() { return self->next(); } void finish() { delete self; } } // LeafInstanceIterator methods %extend InstancePinIterator { bool has_next() { return self->hasNext(); } Pin *next() { return self->next(); } void finish() { delete self; } } // InstancePinIterator methods %extend InstanceNetIterator { bool has_next() { return self->hasNext(); } Net *next() { return self->next(); } void finish() { delete self; } } // InstanceNetIterator methods %extend Pin { const char *port_name() { return cmdLinkedNetwork()->portName(self); } Instance *instance() { return cmdLinkedNetwork()->instance(self); } Net *net() { return cmdLinkedNetwork()->net(self); } Port *port() { return cmdLinkedNetwork()->port(self); } Term *term() { return cmdLinkedNetwork()->term(self); } LibertyPort *liberty_port() { return cmdLinkedNetwork()->libertyPort(self); } bool is_driver() { return cmdLinkedNetwork()->isDriver(self); } bool is_load() { return cmdLinkedNetwork()->isLoad(self); } bool is_leaf() { return cmdLinkedNetwork()->isLeaf(self); } bool is_hierarchical() { return cmdLinkedNetwork()->isHierarchical(self); } bool is_top_level_port() { return cmdLinkedNetwork()->isTopLevelPort(self); } PinConnectedPinIterator *connected_pin_iterator() { return cmdLinkedNetwork()->connectedPinIterator(self); } Vertex ** vertices() { Vertex *vertex, *vertex_bidirect_drvr; static Vertex *vertices[3]; cmdGraph()->pinVertices(self, vertex, vertex_bidirect_drvr); vertices[0] = vertex; vertices[1] = vertex_bidirect_drvr; vertices[2] = nullptr; return vertices; } float capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return pin_cap + wire_cap; } float pin_capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return pin_cap; } float wire_capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return wire_cap; } } // Pin methods %extend PinConnectedPinIterator { bool has_next() { return self->hasNext(); } Pin *next() { return self->next(); } void finish() { delete self; } } // PinConnectedPinIterator methods %extend Term { Net *net() { return cmdLinkedNetwork()->net(self); } Pin *pin() { return cmdLinkedNetwork()->pin(self); } } // Term methods %extend Net { Instance *instance() { return cmdLinkedNetwork()->instance(self); } Net *highest_connected_net() { return cmdLinkedNetwork()->highestConnectedNet(self); } NetPinIterator *pin_iterator() { return cmdLinkedNetwork()->pinIterator(self);} NetTermIterator *term_iterator() {return cmdLinkedNetwork()->termIterator(self);} NetConnectedPinIterator *connected_pin_iterator() { return cmdLinkedNetwork()->connectedPinIterator(self); } bool is_power() { return cmdLinkedNetwork()->isPower(self);} bool is_ground() { return cmdLinkedNetwork()->isGround(self);} float capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return pin_cap + wire_cap; } float pin_capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return pin_cap; } float wire_capacitance(const TransRiseFall *tr, const Corner *corner, const MinMax *min_max) { cmdLinkedNetwork(); float pin_cap, wire_cap; Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap); return wire_cap; } TmpPortSeq * ports() { Network *network = cmdLinkedNetwork(); PortSeq *ports = new PortSeq; if (network->isTopInstance(network->instance(self))) { NetTermIterator *term_iter = network->termIterator(self); while (term_iter->hasNext()) { Term *term = term_iter->next(); Port *port = network->port(network->pin(term)); ports->push_back(port); } delete term_iter; } return ports; } } // Net methods %extend NetPinIterator { bool has_next() { return self->hasNext(); } Pin *next() { return self->next(); } void finish() { delete self; } } // NetPinIterator methods %extend NetTermIterator { bool has_next() { return self->hasNext(); } Term *next() { return self->next(); } void finish() { delete self; } } // NetTermIterator methods %extend NetConnectedPinIterator { bool has_next() { return self->hasNext(); } Pin *next() { return self->next(); } void finish() { delete self; } } // NetConnectedPinIterator methods %extend Clock { float period() { return self->period(); } FloatSeq *waveform() { return self->waveform(); } float time(TransRiseFall *tr) { return self->edge(tr)->time(); } ClockPinIterator *pin_iterator() { return new ClockPinIterator(self); } bool is_generated() { return self->isGenerated(); } bool waveform_valid() { return self->waveformValid(); } bool is_virtual() { return self->isVirtual(); } bool is_propagated() { return self->isPropagated(); } PinSet *sources() { return self->pins(); } float slew(const TransRiseFall *tr, const MinMax *min_max) { return self->slew(tr, min_max); } } %extend ClockEdge { Clock *clock() { return self->clock(); } TransRiseFall *transition() { return self->transition(); } float time() { return self->time(); } } %extend ClockIterator { bool has_next() { return self->hasNext(); } Clock *next() { return self->next(); } void finish() { delete self; } } %extend ClockPinIterator { bool has_next() { return self->hasNext(); } Pin *next() { return self->next(); } void finish() { delete self; } } %extend Vertex { Pin *pin() { return self->pin(); } bool is_bidirect_driver() { return self->isBidirectDriver(); } int level() { return Sta::sta()->vertexLevel(self); } int tag_group_index() { return self->tagGroupIndex(); } TmpFloatSeq * slews(TransRiseFall *tr) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; DcalcAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { DcalcAnalysisPt *dcalc_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->vertexSlew(self, tr, dcalc_ap))); } return floats; } Slew slew(const TransRiseFall *tr, const MinMax *min_max) { Sta *sta = Sta::sta(); return sta->vertexSlew(self, tr, min_max); } VertexOutEdgeIterator * out_edge_iterator() { return new VertexOutEdgeIterator(self, Sta::sta()->graph()); } VertexInEdgeIterator * in_edge_iterator() { return new VertexInEdgeIterator(self, Sta::sta()->graph()); } TmpFloatSeq * arrivals_clk(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge, path_ap))); } return floats; } TmpStringSeq * arrivals_clk_delays(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr, int digits) { Sta *sta = Sta::sta(); StringSeq *arrivals = new StringSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); arrivals->push_back(delayAsString(sta->vertexArrival(self, tr, clk_edge, path_ap), sta, digits)); } return arrivals; } TmpFloatSeq * requireds_clk(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->vertexRequired(self, tr, clk_edge, path_ap))); } return floats; } TmpStringSeq * requireds_clk_delays(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr, int digits) { Sta *sta = Sta::sta(); StringSeq *requireds = new StringSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); requireds->push_back(delayAsString(sta->vertexRequired(self, tr, clk_edge, path_ap), sta, digits)); } return requireds; } TmpFloatSeq * slacks(TransRiseFall *tr) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, path_ap))); } return floats; } // Slack with respect to a clock rise/fall edge. TmpFloatSeq * slacks_clk(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge, path_ap))); } return floats; } TmpStringSeq * slacks_clk_delays(const TransRiseFall *tr, Clock *clk, const TransRiseFall *clk_tr, int digits) { Sta *sta = Sta::sta(); StringSeq *slacks = new StringSeq; const ClockEdge *clk_edge = nullptr; if (clk) clk_edge = clk->edge(clk_tr); PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); slacks->push_back(delayAsString(sta->vertexSlack(self, tr, clk_edge, path_ap), sta, digits)); } return slacks; } VertexPathIterator * path_iterator(const TransRiseFall *tr, const MinMax *min_max) { return Sta::sta()->vertexPathIterator(self, tr, min_max); } bool has_downstream_clk_pin() { return self->hasDownstreamClkPin(); } bool is_clock() { Sta *sta = Sta::sta(); Search *search = sta->search(); return search->isClock(self); } } // Vertex methods %extend Edge { Vertex *from() { return self->from(Sta::sta()->graph()); } Vertex *to() { return self->to(Sta::sta()->graph()); } Pin *from_pin() { return self->from(Sta::sta()->graph())->pin(); } Pin *to_pin() { return self->to(Sta::sta()->graph())->pin(); } TimingRole *role() { return self->role(); } const char *sense() { return timingSenseString(self->sense()); } TimingArcSetArcIterator * timing_arc_iterator() { return new TimingArcSetArcIterator(self->timingArcSet()); } bool is_disabled_loop() { return Sta::sta()->isDisabledLoop(self); } bool is_disabled_constraint() { return Sta::sta()->isDisabledConstraint(self);} bool is_disabled_constant() { return Sta::sta()->isDisabledConstant(self); } bool is_disabled_cond_default() { return Sta::sta()->isDisabledCondDefault(self); } TmpPinSet * disabled_constant_pins() { return Sta::sta()->disabledConstantPins(self); } bool is_disabled_bidirect_inst_path() { return Sta::sta()->isDisabledBidirectInstPath(self); } bool is_disabled_bidirect_net_path() { return Sta::sta()->isDisabledBidirectNetPath(self); } bool is_disabled_preset_clear() { return Sta::sta()->isDisabledPresetClr(self); } const char * sim_timing_sense(){return timingSenseString(Sta::sta()->simTimingSense(self));} TmpFloatSeq * arc_delays(TimingArc *arc) { Sta *sta = Sta::sta(); TmpFloatSeq *floats = new FloatSeq; DcalcAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { DcalcAnalysisPt *dcalc_ap = ap_iter.next(); floats->push_back(delayAsFloat(sta->arcDelay(self, arc, dcalc_ap))); } return floats; } TmpStringSeq * arc_delay_strings(TimingArc *arc, int digits) { Sta *sta = Sta::sta(); StringSeq *delays = new StringSeq; DcalcAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { DcalcAnalysisPt *dcalc_ap = ap_iter.next(); delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap), sta, digits)); } return delays; } bool delay_annotated(TimingArc *arc, const Corner *corner, const MinMax *min_max) { DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); return Sta::sta()->arcDelayAnnotated(self, arc, dcalc_ap); } float arc_delay(TimingArc *arc, const Corner *corner, const MinMax *min_max) { DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap)); } const char * cond() { FuncExpr *cond = self->timingArcSet()->cond(); if (cond) return cond->asString(); else return nullptr; } const char * mode_name() { return self->timingArcSet()->modeName(); } const char * mode_value() { return self->timingArcSet()->modeValue(); } const char * latch_d_to_q_en() { if (self->role() == TimingRole::latchDtoQ()) { Sta *sta = Sta::sta(); const Network *network = sta->cmdNetwork(); const Graph *graph = sta->graph(); Pin *from_pin = self->from(graph)->pin(); Instance *inst = network->instance(from_pin); LibertyCell *lib_cell = network->libertyCell(inst); TimingArcSet *d_q_set = self->timingArcSet(); LibertyPort *enable_port; FuncExpr *enable_func; TransRiseFall *enable_tr; lib_cell->latchEnable(d_q_set, enable_port, enable_func, enable_tr); const char *en_name = enable_port->name(); return stringPrintTmp("%s %s", en_name, enable_tr->asString()); } return ""; } } // Edge methods %extend VertexIterator { bool has_next() { return self->hasNext(); } Vertex *next() { return self->next(); } void finish() { delete self; } } %extend VertexInEdgeIterator { bool has_next() { return self->hasNext(); } Edge *next() { return self->next(); } void finish() { delete self; } } %extend VertexOutEdgeIterator { bool has_next() { return self->hasNext(); } Edge *next() { return self->next(); } void finish() { delete self; } } %extend PathEnd { bool is_unconstrained() { return self->isUnconstrained(); } bool is_check() { return self->isCheck(); } bool is_latch_check() { return self->isLatchCheck(); } bool is_data_check() { return self->isDataCheck(); } bool is_output_delay() { return self->isOutputDelay(); } bool is_path_delay() { return self->isPathDelay(); } bool is_gated_clock() { return self->isGatedClock(); } Vertex *vertex() { return self->vertex(Sta::sta()); } PathRef *path() { return &self->pathRef(); } TransRiseFall *end_transition() { return const_cast(self->path()->transition(Sta::sta())); } Slack slack() { return self->slack(Sta::sta()); } ArcDelay margin() { return self->margin(Sta::sta()); } Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); } Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); } TimingRole *check_role() { return self->checkRole(Sta::sta()); } MinMax *min_max() { return const_cast(self->minMax(Sta::sta())); } float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); } Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); } Arrival source_clk_insertion_delay() { return self->sourceClkInsertionDelay(Sta::sta()); } Clock *target_clk() { return self->targetClk(Sta::sta()); } ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); } Path *target_clk_path() { return self->targetClkPath(); } float target_clk_time() { return self->targetClkTime(Sta::sta()); } float target_clk_offset() { return self->targetClkOffset(Sta::sta()); } float target_clk_mcp_adjustment() { return self->targetClkMcpAdjustment(Sta::sta()); } Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); } Arrival target_clk_insertion_delay() { return self->targetClkInsertionDelay(Sta::sta()); } float target_clk_uncertainty() { return self->targetNonInterClkUncertainty(Sta::sta()); } float inter_clk_uncertainty() { return self->interClkUncertainty(Sta::sta()); } Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); } bool path_delay_margin_is_external() { return self->pathDelayMarginIsExternal();} Crpr common_clk_pessimism() { return self->commonClkPessimism(Sta::sta()); } TransRiseFall *target_clk_end_trans() { return const_cast(self->targetClkEndTrans(Sta::sta())); } } %extend MinPulseWidthCheckSeqIterator { bool has_next() { return self->hasNext(); } MinPulseWidthCheck *next() { return self->next(); } void finish() { delete self; } } // MinPulseWidthCheckSeqIterator methods %extend PathRef { float arrival() { Sta *sta = Sta::sta(); return delayAsFloat(self->arrival(sta)); } float required() { Sta *sta = Sta::sta(); return delayAsFloat(self->required(sta)); } float slack() { Sta *sta = Sta::sta(); return delayAsFloat(self->slack(sta)); } Pin * pin() { Sta *sta = Sta::sta(); return self->pin(sta); } const char * tag() { Sta *sta = Sta::sta(); return self->tag(sta)->asString(sta); } // mea_opt3 TmpPinSeq * pins() { Sta *sta = Sta::sta(); PinSeq *pins = new PinSeq; PathRef path1(self); while (!path1.isNull()) { pins->push_back(path1.vertex(sta)->pin()); PathRef prev_path; path1.prevPath(sta, prev_path); path1.init(prev_path); } return pins; } } %extend VertexPathIterator { bool has_next() { return self->hasNext(); } PathRef * next() { Path *path = self->next(); return new PathRef(path); } void finish() { delete self; } } %extend SlowDrvrIterator { bool has_next() { return self->hasNext(); } Instance *next() { return self->next(); } void finish() { delete self->container(); delete self; } } %extend Corner { const char *name() { return self->name(); } } // Local Variables: // mode:c++ // End: