diff --git a/kernel/driver.cc b/kernel/driver.cc index b7f0268db..3c3c399b2 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -180,7 +180,7 @@ extern char yosys_path[PATH_MAX]; #endif #ifdef YOSYS_ENABLE_TCL namespace Yosys { - extern int yosys_tcl_iterp_init(Tcl_Interp *interp); + extern int yosys_tcl_interp_init(Tcl_Interp *interp); extern void yosys_tcl_activate_repl(); }; #endif @@ -602,7 +602,7 @@ int main(int argc, char **argv) if (run_tcl_shell) { #ifdef YOSYS_ENABLE_TCL yosys_tcl_activate_repl(); - Tcl_Main(argc, argv, yosys_tcl_iterp_init); + Tcl_Main(argc, argv, yosys_tcl_interp_init); #else log_error("Can't exectue TCL shell: this version of yosys is not built with TCL support enabled.\n"); #endif diff --git a/kernel/tclapi.cc b/kernel/tclapi.cc index e970779d7..8541b8d20 100644 --- a/kernel/tclapi.cc +++ b/kernel/tclapi.cc @@ -532,7 +532,65 @@ static int tcl_set_param(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *cons return TCL_OK; } -int yosys_tcl_iterp_init(Tcl_Interp *interp) +static int sdc_get_pins_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) +{ + (void)interp; + bool hierarchical_flag = false; + bool regexp_flag = false; + bool nocase_flag = false; + std::string separator = "/"; + Tcl_Obj* of_objects; + std::vector patterns; + int i = 1; + for (; i < objc; i++) { + FLAG2(hierarchical) + FLAG2(regexp) + FLAG2(nocase) + if (!strcmp(Tcl_GetString(objv[i]), "-hsc")) { + i++; + separator = Tcl_GetString(objv[i]); + continue; + } + if (!strcmp(Tcl_GetString(objv[i]), "-of_objects")) { + i++; + of_objects = objv[i]; + continue; + } + // Onto the next loop + break; + } + for (; i < objc; i++) { + patterns.push_back(Tcl_GetString(objv[i])); + } + log("get_pins patterns:\n"); + for (auto pat : patterns) { + log("\t%s\n", pat.c_str()); + } + (void)hierarchical_flag; + (void)regexp_flag; + (void)nocase_flag; + (void)separator; + (void)of_objects; + return TCL_OK; +} +static int sdc_dummy_cmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) +{ + (void)interp; + (void)objc; + log("Ignoring known SDC command %s\n", Tcl_GetString(objv[0])); + return TCL_OK; +} + +int yosys_sdc_interp_init(Tcl_Interp *interp) +{ + if (Tcl_Init(interp)!=TCL_OK) + log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); + Tcl_CreateObjCommand(interp, "set_false_path", sdc_dummy_cmd, NULL, NULL); + Tcl_CreateObjCommand(interp, "get_pins", sdc_get_pins_cmd, NULL, NULL); + return TCL_OK; +} + +int yosys_tcl_interp_init(Tcl_Interp *interp) { if (Tcl_Init(interp)!=TCL_OK) log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 9b0bc92ce..0de242805 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -86,6 +86,7 @@ CellTypes yosys_celltypes; #ifdef YOSYS_ENABLE_TCL Tcl_Interp *yosys_tcl_interp = NULL; +Tcl_Interp *yosys_sdc_interp = NULL; #endif std::set yosys_input_files, yosys_output_files; @@ -361,16 +362,25 @@ void rewrite_filename(std::string &filename) #ifdef YOSYS_ENABLE_TCL // defined in tclapi.cc -extern int yosys_tcl_iterp_init(Tcl_Interp *interp); +extern int yosys_tcl_interp_init(Tcl_Interp *interp); +extern int yosys_sdc_interp_init(Tcl_Interp *interp); extern Tcl_Interp *yosys_get_tcl_interp() { if (yosys_tcl_interp == NULL) { yosys_tcl_interp = Tcl_CreateInterp(); - yosys_tcl_iterp_init(yosys_tcl_interp); + yosys_tcl_interp_init(yosys_tcl_interp); } return yosys_tcl_interp; } +extern Tcl_Interp *yosys_get_sdc_interp() +{ + if (yosys_sdc_interp == NULL) { + yosys_sdc_interp = Tcl_CreateInterp(); + yosys_sdc_interp_init(yosys_sdc_interp); + } + return yosys_sdc_interp; +} struct TclPass : public Pass { TclPass() : Pass("tcl", "execute a TCL script file") { } @@ -414,6 +424,26 @@ struct TclPass : public Pass { Tcl_Release(interp); } } TclPass; +struct SdcPass : public Pass { + SdcPass() : Pass("sdc", "sniff at some SDC") { } + void execute(std::vector args, RTLIL::Design *) override { + if (args.size() < 2) + log_cmd_error("Missing script file.\n"); + + std::vector script_args; + for (auto it = args.begin() + 2; it != args.end(); ++it) + script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size())); + + Tcl_Interp *interp = yosys_get_sdc_interp(); + Tcl_Preserve(interp); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0); + if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) + log_cmd_error("SDC interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); + Tcl_Release(interp); + } +} SdcPass; #endif #if defined(__linux__) || defined(__CYGWIN__)