aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/driver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/driver.cc')
-rw-r--r--kernel/driver.cc180
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;
}