diff --git a/CMakeLists.txt b/CMakeLists.txt index 91eb4d86..a0088607 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -700,12 +700,14 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${STA_HOME}/app) # Note executable and lib name cannot be the same because # on osx something is case insensitive. Using STA for the # lib name results in "No rule to make target ../depend. -add_executable(sta app/Main.cc) +add_executable(sta app/Main.cc ${STA_WRAP}) + target_link_libraries(sta OpenSTA ${TCL_LIB} ${CUDD_LIB} ) + if (ZLIB_FOUND) target_link_libraries(sta ${ZLIB_LIBRARIES}) endif() diff --git a/app/Main.cc b/app/Main.cc index c884275b..f7f927b9 100644 --- a/app/Main.cc +++ b/app/Main.cc @@ -15,32 +15,58 @@ // along with this program. If not, see . #include +#include #include "Machine.hh" #include "StaConfig.hh" // STA_VERSION #include "StringUtil.hh" #include "Sta.hh" #include "StaMain.hh" + +namespace sta { +extern const char *tcl_inits[]; +} + using sta::stringEq; +using sta::findCmdLineFlag; using sta::Sta; -using sta::staMain; -using sta::showUsage; +using sta::initSta; +using sta::evalTclInit; +using sta::stringPrintTmp; +using sta::sourceTclFile; +using sta::parseThreadsArg; +using sta::tcl_inits; // Swig uses C linkage for init functions. extern "C" { extern int Sta_Init(Tcl_Interp *interp); } -namespace sta { -extern const char *tcl_inits[]; -} +static int cmd_argc; +static char **cmd_argv; +static const char *init_filename = ".sta"; + +static void +showUsage(const char *prog, + const char *init_filename); +static int +tclAppInit(Tcl_Interp *interp); +static int +staTclAppInit(int argc, + char *argv[], + const char *init_filename, + Tcl_Interp *interp); +static void +initStaApp(int argc, + char *argv[], + Tcl_Interp *interp); int main(int argc, char *argv[]) { if (argc == 2 && stringEq(argv[1], "-help")) { - showUsage(argv[0]); + showUsage(argv[0], init_filename); return 0; } else if (argc == 2 && stringEq(argv[1], "-version")) { @@ -48,8 +74,102 @@ main(int argc, return 0; } else { - Sta *sta = new Sta; - staMain(sta, argc, argv, ".sta", Sta_Init, sta::tcl_inits); + // Set argc to 1 so Tcl_Main doesn't source any files. + // Tcl_Main never returns. +#if 0 + // It should be possible to pass argc/argv to staTclAppInit with + // a closure but I couldn't get the signature to match Tcl_AppInitProc. + Tcl_Main(1, argv, [=](Tcl_Interp *interp) + { sta::staTclAppInit(argc, argv, interp); + return 1; + }); +#else + // Workaround. + cmd_argc = argc; + cmd_argv = argv; + Tcl_Main(1, argv, tclAppInit); +#endif return 0; } } + +static int +tclAppInit(Tcl_Interp *interp) +{ + return staTclAppInit(cmd_argc, cmd_argv, init_filename, interp); +} + +// Tcl init executed inside Tcl_Main. +static int +staTclAppInit(int argc, + char *argv[], + const char *init_filename, + Tcl_Interp *interp) +{ + // source init.tcl + Tcl_Init(interp); + + initStaApp(argc, argv, interp); + + if (!findCmdLineFlag(argc, argv, "-no_splash")) + Tcl_Eval(interp, "sta::show_splash"); + + if (!findCmdLineFlag(argc, argv, "-no_init")) { + char *init_path = stringPrintTmp("[file join $env(HOME) %s]", + init_filename); + sourceTclFile(init_path, true, true, interp); + } + + bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit"); + + if (argc > 2 || + (argc > 1 && argv[1][0] == '-')) + showUsage(argv[0], init_filename); + else { + if (argc == 2) { + char *cmd_file = argv[1]; + if (cmd_file) { + sourceTclFile(cmd_file, false, false, interp); + if (exit_after_cmd_file) + exit(EXIT_SUCCESS); + } + } + } + return TCL_OK; +} + +static void +initStaApp(int argc, + char *argv[], + Tcl_Interp *interp) +{ + initSta(); + Sta *sta = new Sta; + Sta::setSta(sta); + sta->makeComponents(); + sta->setTclInterp(interp); + int thread_count = parseThreadsArg(argc, argv); + sta->setThreadCount(thread_count); + + // Define swig TCL commands. + Sta_Init(interp); + // Eval encoded sta TCL sources. + evalTclInit(interp, tcl_inits); + // Import exported commands from sta namespace to global namespace. + Tcl_Eval(interp, "sta::define_sta_cmds"); + Tcl_Eval(interp, "namespace import sta::*"); +} + +static void +showUsage(const char *prog, + const char *init_filename) +{ + printf("Usage: %s [-help] [-version] [-no_init] [-exit] cmd_file\n", prog); + printf(" -help show help and exit\n"); + printf(" -version show version and exit\n"); + printf(" -no_init do not read %s init file\n", init_filename); + printf(" -threads count|max use count threads\n"); + printf(" -no_splash do not show the license splash at startup\n"); + printf(" -exit exit after reading cmd_file\n"); + printf(" cmd_file source cmd_file\n"); +} diff --git a/app/StaMain.cc b/app/StaMain.cc index 2d96ae24..5b49f134 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -24,37 +24,6 @@ namespace sta { -typedef sta::Vector SwigInitFuncSeq; - -// "Arguments" passed to staTclAppInit. -static int sta_argc; -static char **sta_argv; -static const char *sta_init_filename; -static const char **sta_tcl_inits; -static SwigInitFunc sta_swig_init; - -void -staMain(Sta *sta, - int argc, - char *argv[], - const char *init_filename, - SwigInitFunc swig_init, - const char *tcl_inits[]) -{ - initSta(); - - Sta::setSta(sta); - sta->makeComponents(); - - int thread_count = parseThreadsArg(argc, argv); - sta->setThreadCount(thread_count); - - staSetupAppInit(argc, argv, init_filename, swig_init, tcl_inits); - // Set argc to 1 so Tcl_Main doesn't source any files. - // Tcl_Main never returns. - Tcl_Main(1, argv, staTclAppInit); -} - int parseThreadsArg(int &argc, char *argv[]) @@ -71,71 +40,6 @@ parseThreadsArg(int &argc, return 1; } -// Set globals to pass to staTclAppInit. -void -staSetupAppInit(int argc, - char *argv[], - const char *init_filename, - SwigInitFunc swig_init, - const char *tcl_inits[]) -{ - sta_argc = argc; - sta_argv = argv; - sta_init_filename = init_filename; - sta_tcl_inits = tcl_inits; - sta_swig_init = swig_init; -} - -// Tcl init executed inside Tcl_Main. -int -staTclAppInit(Tcl_Interp *interp) -{ - int argc = sta_argc; - char **argv = sta_argv; - - // source init.tcl - Tcl_Init(interp); - - // Define swig commands. - sta_swig_init(interp); - - Sta *sta = Sta::sta(); - sta->setTclInterp(interp); - - // Eval encoded sta TCL sources. - evalTclInit(interp, sta_tcl_inits); - - if (!findCmdLineFlag(argc, argv, "-no_splash")) - Tcl_Eval(interp, "sta::show_splash"); - - // Import exported commands from sta namespace to global namespace. - Tcl_Eval(interp, "sta::define_sta_cmds"); - Tcl_Eval(interp, "namespace import sta::*"); - - if (!findCmdLineFlag(argc, argv, "-no_init")) { - char *init_path = stringPrintTmp("[file join $env(HOME) %s]", - sta_init_filename); - sourceTclFile(init_path, true, true, interp); - } - - bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit"); - - if (argc > 2 || - (argc > 1 && argv[1][0] == '-')) - showUsage(argv[0]); - else { - if (argc == 2) { - char *cmd_file = argv[1]; - if (cmd_file) { - sourceTclFile(cmd_file, false, false, interp); - if (exit_after_cmd_file) - exit(EXIT_SUCCESS); - } - } - } - return TCL_OK; -} - bool findCmdLineFlag(int &argc, char *argv[], @@ -220,17 +124,4 @@ evalTclInit(Tcl_Interp *interp, delete [] unencoded; } -void -showUsage(const char * prog) -{ - printf("Usage: %s [-help] [-version] [-no_init] [-exit] cmd_file\n", prog); - printf(" -help show help and exit\n"); - printf(" -version show version and exit\n"); - printf(" -no_init do not read .sta init file\n"); - printf(" -threads count|max use count threads\n"); - printf(" -no_splash do not show the license splash at startup\n"); - printf(" -exit exit after reading cmd_file\n"); - printf(" cmd_file source cmd_file\n"); -} - } // namespace diff --git a/app/StaMain.hh b/app/StaMain.hh index a9fa2d1c..2b188e89 100644 --- a/app/StaMain.hh +++ b/app/StaMain.hh @@ -22,28 +22,20 @@ struct Tcl_Interp; namespace sta { class Sta; -typedef int (*SwigInitFunc)(Tcl_Interp *); - -// The swig_init function is called to define the swig interface -// functions to the tcl interpreter. -void -staMain(Sta *sta, - int argc, - char *argv[], - const char *init_filename, - SwigInitFunc swig_init, - const char *tcl_inits[]); - -// Set arguments passed to staTclAppInit inside the tcl interpreter. -void -staSetupAppInit(int argc, - char *argv[], - const char *init_filename, - SwigInitFunc swig_init, - const char *tcl_inits[]); +// Parse command line argument int -staTclAppInit(Tcl_Interp *interp); +staTclAppInit(int argc, + char *argv[], + const char *init_filename, + Tcl_Interp *interp); + +// Sta initialization. +// Makes the Sta object and registers TCL commands. +void +initSta(int argc, + char *argv[], + Tcl_Interp *interp); // TCL init files are encoded into the string init using the three // digit decimal equivalent for each ascii character. This function @@ -63,8 +55,6 @@ findCmdLineKey(int &argc, char *argv[], const char *key); -void -showUsage(const char *prog); int parseThreadsArg(int &argc, char *argv[]); diff --git a/network/ConcreteLibrary.cc b/network/ConcreteLibrary.cc index 059e104f..eea5ec4c 100644 --- a/network/ConcreteLibrary.cc +++ b/network/ConcreteLibrary.cc @@ -117,6 +117,7 @@ ConcreteCell::ConcreteCell(ConcreteLibrary *library, name_(stringCopy(name)), filename_(stringCopy(filename)), liberty_cell_(nullptr), + ext_cell_(nullptr), port_bit_count_(0), is_leaf_(is_leaf) { @@ -145,6 +146,12 @@ ConcreteCell::setLibertyCell(LibertyCell *cell) liberty_cell_ = cell; } +void +ConcreteCell::setExtCell(void *ext_cell) +{ + ext_cell_ = ext_cell; +} + ConcretePort * ConcreteCell::makePort(const char *name) { @@ -437,6 +444,7 @@ ConcretePort::ConcretePort(ConcreteCell *cell, cell_(cell), direction_(PortDirection::unknown()), liberty_port_(nullptr), + ext_port_(nullptr), pin_index_(-1), is_bundle_(is_bundle), is_bus_(is_bus), @@ -468,6 +476,12 @@ ConcretePort::setLibertyPort(LibertyPort *port) liberty_port_ = port; } +void +ConcretePort::setExtPort(void *port) +{ + ext_port_ = port; +} + const char * ConcretePort::busName() const { diff --git a/network/ConcreteLibrary.hh b/network/ConcreteLibrary.hh index 906b135c..18ecd8db 100644 --- a/network/ConcreteLibrary.hh +++ b/network/ConcreteLibrary.hh @@ -96,6 +96,8 @@ public: const char *filename() const { return filename_; } LibertyCell *libertyCell() const { return liberty_cell_; } void setLibertyCell(LibertyCell *cell); + void *extCell() const { return ext_cell_; } + void setExtCell(void *ext_cell); int portBitCount() const { return port_bit_count_; } ConcretePort *findPort(const char *name) const; void findPortsMatching(const PatternMatch *pattern, @@ -147,6 +149,8 @@ protected: // Filename is optional. const char *filename_; LibertyCell *liberty_cell_; + // External application cell. + void *ext_cell_; // Non-bus and bus ports (but no expanded bus bit ports). ConcretePortSeq ports_; ConcretePortMap port_map_; @@ -172,6 +176,9 @@ public: PortDirection *direction() const { return direction_; } LibertyPort *libertyPort() const { return liberty_port_; } void setLibertyPort(LibertyPort *port); + // External application port. + void *extPort() const { return ext_port_; } + void setExtPort(void *port); void setDirection(PortDirection *dir); // Bundles are groups of related ports that do not use // bus notation. @@ -220,6 +227,8 @@ protected: ConcreteCell *cell_; PortDirection *direction_; LibertyPort *liberty_port_; + // External application port. + void *ext_port_; int pin_index_; bool is_bundle_; bool is_bus_;