diff options
Diffstat (limited to 'kernel/driver.cc')
-rw-r--r-- | kernel/driver.cc | 180 |
1 files changed, 158 insertions, 22 deletions
diff --git a/kernel/driver.cc b/kernel/driver.cc index 1dddefdcb..3de16e724 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -20,13 +20,26 @@ #include <stdio.h> #include <readline/readline.h> #include <readline/history.h> +#include <string.h> +#include <unistd.h> +#include <dlfcn.h> #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/log.h" -#include <string.h> -#include <unistd.h> -#include <dlfcn.h> + +bool fgetline(FILE *f, std::string &buffer) +{ + buffer = ""; + char block[4096]; + while (1) { + if (fgets(block, 4096, f) == NULL) + return false; + buffer += block; + if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) + return true; + } +} static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command) { @@ -50,9 +63,13 @@ static void run_frontend(std::string filename, std::string command, RTLIL::Desig f = fopen(filename.c_str(), "r"); if (f == NULL) log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); - char buffer[4096]; - while (fgets(buffer, 4096, f) != NULL) { - Pass::call(design, buffer); + std::string command; + while (fgetline(f, command)) { + Pass::call(design, command); + design->check(); + } + if (!command.empty()) { + Pass::call(design, command); design->check(); } if (filename != "-") @@ -132,10 +149,13 @@ static char **readline_completion(const char *text, int start, int) return NULL; } -static const char *create_prompt(RTLIL::Design *design) +static const char *create_prompt(RTLIL::Design *design, int recursion_counter) { static char buffer[100]; - std::string str = "\nyosys"; + std::string str = "\n"; + if (recursion_counter > 1) + str += stringf("(%d) ", recursion_counter); + str += "yosys"; if (!design->selected_active_module.empty()) str += stringf(" [%s]", design->selected_active_module.c_str()); if (!design->selection_stack.back().full_selection) { @@ -151,26 +171,29 @@ static const char *create_prompt(RTLIL::Design *design) static void shell(RTLIL::Design *design) { - static bool recursion_detect = false; + static int recursion_counter = 0; - if (recursion_detect) { - log("Already in interactive shell.\n"); - return; - } - - recursion_detect = true; + recursion_counter++; log_cmd_error_throw = true; rl_readline_name = "yosys"; rl_attempted_completion_function = readline_completion; char *command = NULL; - while ((command = readline(create_prompt(design))) != NULL) + while ((command = readline(create_prompt(design, recursion_counter))) != NULL) { if (command[strspn(command, " \t\r\n")] == 0) continue; add_history(command); + char *p = command + strspn(command, " \t\r\n"); + if (!strncmp(p, "exit", 4)) { + p += 4; + p += strspn(p, " \t\r\n"); + if (*p == 0) + break; + } + try { assert(design->selection_stack.size() == 1); Pass::call(design, command); @@ -180,8 +203,10 @@ static void shell(RTLIL::Design *design) log_reset_stack(); } } + if (command == NULL) + printf("exit\n"); - recursion_detect = false; + recursion_counter--; log_cmd_error_throw = false; } @@ -216,7 +241,7 @@ struct ShellPass : public Pass { log("This command is the default action if nothing else has been specified\n"); log("on the command line.\n"); log("\n"); - log("Press Ctrl-D to leave the interactive shell.\n"); + log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { @@ -225,6 +250,82 @@ struct ShellPass : public Pass { } } ShellPass; +struct ScriptPass : public Pass { + ScriptPass() : Pass("script", "execute commands from script file") { } + virtual void help() { + log("\n"); + log(" script <filename>\n"); + log("\n"); + log("This command executes the yosys commands in the specified file.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + if (args.size() < 2) + log_cmd_error("Missing script file.\n"); + if (args.size() > 2) + extra_args(args, 1, design, false); + run_frontend(args[1], "script", design, NULL); + } +} ScriptPass; + +#ifdef YOSYS_ENABLE_TCL +struct TclPass : public Pass { + TclPass() : Pass("tcl", "execute a TCL script file") { } + virtual void help() { + log("\n"); + log(" tcl <filename>\n"); + log("\n"); + log("This command executes the tcl commands in the specified file.\n"); + log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); + log("\n"); + log("The tcl command 'yosys -import' can be used to import all yosys\n"); + log("commands directly as tcl commands to the tcl shell. The yosys\n"); + log("command 'proc' is wrapped using the tcl command 'procs' in order\n"); + log("to avoid a name collision with the tcl builting command 'proc'.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + if (args.size() < 2) + log_cmd_error("Missing script file.\n"); + if (args.size() > 2) + extra_args(args, 1, design, false); + if (Tcl_EvalFile(yosys_tcl, args[1].c_str()) != TCL_OK) + log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_tcl)); + } +} TclPass; + +static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + std::vector<std::string> args; + for (int i = 1; i < argc; i++) + args.push_back(argv[i]); + + if (args.size() >= 1 && args[0] == "-import") { + for (auto &it : REGISTER_INTERN::pass_register) { + std::string tcl_command_name = it.first; + if (tcl_command_name == "proc") + tcl_command_name = "procs"; + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) { + log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str()); + } else { + std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str()); + Tcl_Eval(interp, tcl_script.c_str()); + } + } + return TCL_OK; + } + + if (args.size() == 1) { + Pass::call(yosys_tcl_design, args[0]); + return TCL_OK; + } + + Pass::call(yosys_tcl_design, args); + return TCL_OK; +} +#endif + int main(int argc, char **argv) { std::string frontend_command = "auto"; @@ -233,10 +334,16 @@ int main(int argc, char **argv) std::vector<void*> loaded_modules; std::string output_filename = ""; std::string scriptfile = ""; + bool scriptfile_tcl = false; bool got_output_filename = false; +#ifdef YOSYS_ENABLE_TCL + yosys_tcl = Tcl_CreateInterp(); + Tcl_CreateCommand(yosys_tcl, "yosys", tcl_yosys_cmd, NULL, NULL); +#endif + int opt; - while ((opt = getopt(argc, argv, "Sm:f:b:o:p:l:qts:")) != -1) + while ((opt = getopt(argc, argv, "Sm:f:b:o:p:l:qts:c:")) != -1) { switch (opt) { @@ -284,10 +391,15 @@ int main(int argc, char **argv) break; case 's': scriptfile = optarg; + scriptfile_tcl = false; + break; + case 'c': + scriptfile = optarg; + scriptfile_tcl = true; break; default: fprintf(stderr, "\n"); - fprintf(stderr, "Usage: %s [-S] [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [-s <scriptfile>]\n", argv[0]); + fprintf(stderr, "Usage: %s [-S] [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [{-s|-c} <scriptfile>]\n", argv[0]); fprintf(stderr, " %*s[-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), ""); fprintf(stderr, "\n"); fprintf(stderr, " -q\n"); @@ -311,6 +423,9 @@ int main(int argc, char **argv) fprintf(stderr, " -s scriptfile\n"); fprintf(stderr, " execute the commands in the script file\n"); fprintf(stderr, "\n"); + fprintf(stderr, " -c tcl_scriptfile\n"); + fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n"); + fprintf(stderr, "\n"); fprintf(stderr, " -p command\n"); fprintf(stderr, " execute the commands\n"); fprintf(stderr, "\n"); @@ -366,6 +481,10 @@ int main(int argc, char **argv) design->selection_stack.push_back(RTLIL::Selection()); log_push(); +#ifdef YOSYS_ENABLE_TCL + yosys_tcl_design = design; +#endif + if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) { if (!got_output_filename) backend_command = ""; @@ -375,8 +494,17 @@ int main(int argc, char **argv) while (optind < argc) run_frontend(argv[optind++], frontend_command, design, output_filename == "-" ? &backend_command : NULL); - if (!scriptfile.empty()) - run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL); + if (!scriptfile.empty()) { + if (scriptfile_tcl) { +#ifdef YOSYS_ENABLE_TCL + if (Tcl_EvalFile(yosys_tcl, scriptfile.c_str()) != TCL_OK) + log_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_tcl)); +#else + log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n"); +#endif + } else + run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL); + } for (auto it = passes_commands.begin(); it != passes_commands.end(); it++) run_pass(*it, design); @@ -386,6 +514,10 @@ int main(int argc, char **argv) delete design; +#ifdef YOSYS_ENABLE_TCL + yosys_tcl_design = NULL; +#endif + log("\nREADY.\n"); log_pop(); @@ -400,6 +532,10 @@ int main(int argc, char **argv) for (auto mod : loaded_modules) dlclose(mod); +#ifdef YOSYS_ENABLE_TCL + Tcl_DeleteInterp(yosys_tcl); +#endif + return 0; } |