2025-01-17 20:15:00 +01:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, Parallax Software, Inc.
|
2025-01-17 20:15:00 +01:00
|
|
|
//
|
|
|
|
|
// 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 <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
//
|
|
|
|
|
// The origin of this software must not be misrepresented; you must not
|
|
|
|
|
// claim that you wrote the original software.
|
|
|
|
|
//
|
|
|
|
|
// Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
|
//
|
|
|
|
|
// This notice may not be removed or altered from any source distribution.
|
2025-01-17 20:15:00 +01:00
|
|
|
|
|
|
|
|
#include "TclTypeHelpers.hh"
|
|
|
|
|
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "Sta.hh"
|
|
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
StringSet *
|
|
|
|
|
tclListSetConstChar(Tcl_Obj *const source,
|
|
|
|
|
Tcl_Interp *interp)
|
|
|
|
|
{
|
|
|
|
|
Tcl_Size 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)
|
|
|
|
|
{
|
|
|
|
|
Tcl_Size 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StdStringSet *
|
|
|
|
|
tclListSetStdString(Tcl_Obj *const source,
|
|
|
|
|
Tcl_Interp *interp)
|
|
|
|
|
{
|
|
|
|
|
Tcl_Size argc;
|
|
|
|
|
Tcl_Obj **argv;
|
|
|
|
|
|
|
|
|
|
if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) {
|
|
|
|
|
StdStringSet *set = new StdStringSet;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
tclArgError(Tcl_Interp *interp,
|
|
|
|
|
const char *msg,
|
|
|
|
|
const char *arg)
|
|
|
|
|
{
|
|
|
|
|
// Swig does not add try/catch around arg parsing so this cannot use Report::error.
|
|
|
|
|
string error_msg = "Error: ";
|
|
|
|
|
error_msg += msg;
|
|
|
|
|
char *error = stringPrint(error_msg.c_str(), 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Tcl_Obj *
|
|
|
|
|
tclArcDcalcArg(ArcDcalcArg &gate,
|
|
|
|
|
Tcl_Interp *interp)
|
|
|
|
|
{
|
|
|
|
|
Sta *sta = Sta::sta();
|
|
|
|
|
const Network *network = sta->network();
|
|
|
|
|
const Instance *drvr = network->instance(gate.drvrPin());
|
|
|
|
|
const TimingArc *arc = gate.arc();
|
|
|
|
|
|
|
|
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
|
|
|
Tcl_Obj *obj;
|
|
|
|
|
|
|
|
|
|
const char *inst_name = network->pathName(drvr);
|
|
|
|
|
obj = Tcl_NewStringObj(inst_name, strlen(inst_name));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
const char *from_name = arc->from()->name();
|
|
|
|
|
obj = Tcl_NewStringObj(from_name, strlen(from_name));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
const char *from_edge = arc->fromEdge()->asString();
|
|
|
|
|
obj = Tcl_NewStringObj(from_edge, strlen(from_edge));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
const char *to_name = arc->to()->name();
|
|
|
|
|
obj = Tcl_NewStringObj(to_name, strlen(to_name));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
const char *to_edge = arc->toEdge()->asString();
|
|
|
|
|
obj = Tcl_NewStringObj(to_edge, strlen(to_edge));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
const char *input_delay = delayAsString(gate.inputDelay(), sta, 3);
|
|
|
|
|
obj = Tcl_NewStringObj(input_delay, strlen(input_delay));
|
|
|
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArcDcalcArg
|
|
|
|
|
arcDcalcArgTcl(Tcl_Obj *obj,
|
|
|
|
|
Tcl_Interp *interp)
|
|
|
|
|
{
|
|
|
|
|
Sta *sta = Sta::sta();
|
|
|
|
|
sta->ensureGraph();
|
|
|
|
|
int list_argc;
|
|
|
|
|
Tcl_Obj **list_argv;
|
|
|
|
|
if (Tcl_ListObjGetElements(interp, obj, &list_argc, &list_argv) == TCL_OK) {
|
|
|
|
|
const char *input_delay = "0.0";
|
|
|
|
|
int length;
|
|
|
|
|
if (list_argc == 6)
|
|
|
|
|
input_delay = Tcl_GetStringFromObj(list_argv[5], &length);
|
|
|
|
|
if (list_argc == 5 || list_argc == 6) {
|
|
|
|
|
return makeArcDcalcArg(Tcl_GetStringFromObj(list_argv[0], &length),
|
|
|
|
|
Tcl_GetStringFromObj(list_argv[1], &length),
|
|
|
|
|
Tcl_GetStringFromObj(list_argv[2], &length),
|
|
|
|
|
Tcl_GetStringFromObj(list_argv[3], &length),
|
|
|
|
|
Tcl_GetStringFromObj(list_argv[4], &length),
|
|
|
|
|
input_delay, sta);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sta->report()->warn(2140, "Delay calc arg requires 5 or 6 args.");
|
|
|
|
|
}
|
|
|
|
|
return ArcDcalcArg();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|