22 #ifdef YOSYS_ENABLE_READLINE
23 # include <readline/readline.h>
24 # include <readline/history.h>
27 #ifdef YOSYS_ENABLE_PLUGINS
34 #elif defined(__APPLE__)
35 # include <mach-o/dyld.h>
38 # include <sys/stat.h>
42 # include <sys/types.h>
43 # include <sys/stat.h>
54 #ifdef YOSYS_ENABLE_TCL
55 Tcl_Interp *yosys_tcl_interp =
NULL;
70 std::string
vstringf(
const char *fmt, va_list ap)
80 str = (
char*)realloc(str, sz);
81 rc = vsnprintf(str, sz, fmt, apc);
83 if (rc >= 0 && rc < sz)
88 if (vasprintf(&str, fmt, ap) < 0)
102 int rc = f.readsome(s, n);
118 size_t pos_begin = text.find_first_not_of(sep);
120 if (pos_begin == std::string::npos)
121 pos_begin = text.size();
123 size_t pos_end = text.find_first_of(sep, pos_begin);
125 if (pos_end == std::string::npos)
126 pos_end = text.size();
128 std::string token = text.substr(pos_begin, pos_end-pos_begin);
129 text = text.substr(pos_end);
144 bool patmatch(
const char *pattern,
const char *
string)
149 if (*pattern ==
'\\') {
150 if (pattern[1] ==
string[0] &&
patmatch(pattern+2,
string+1))
154 if (*pattern ==
'?') {
157 return patmatch(pattern+1,
string+1);
160 if (*pattern ==
'*') {
165 return pattern[1] == 0;
168 if (*pattern ==
'[') {
169 bool found_match =
false;
170 bool inverted_list = pattern[1] ==
'!';
171 const char *p = pattern + (inverted_list ? 1 : 0);
175 if (found_match != inverted_list &&
patmatch(p+1,
string+1))
189 if (*pattern == *
string)
190 return patmatch(pattern+1,
string+1);
195 int run_command(
const std::string &command, std::function<
void(
const std::string&)> process_line)
198 return system(command.c_str());
200 FILE *f = popen(command.c_str(),
"r");
206 while (fgets(logbuf, 128, f) !=
NULL) {
208 if (!line.empty() && line.back() ==
'\n')
209 process_line(line), line.clear();
220 return WEXITSTATUS(ret);
227 if (template_str.rfind(
"/tmp/", 0) == 0) {
229 char longpath[MAX_PATH + 1];
230 char shortpath[MAX_PATH + 1];
232 WCHAR longpath[MAX_PATH + 1];
233 TCHAR shortpath[MAX_PATH + 1];
235 if (!GetTempPath(MAX_PATH+1, longpath))
237 if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
238 log_error(
"GetShortPathName() failed.\n");
240 for (
int i = 0; shortpath[i]; i++)
241 path +=
char(shortpath[i]);
242 template_str =
stringf(
"%s\\%s", path.c_str(), template_str.c_str() + 5);
245 size_t pos = template_str.rfind(
"XXXXXX");
249 for (
int i = 0; i < 6; i++) {
250 static std::string y =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
251 static uint32_t x = 314159265 ^ uint32_t(
time(
NULL));
252 x ^= x << 13, x ^= x >> 17, x ^= x << 5;
253 template_str[pos+i] = y[x % y.size()];
255 if (_access(template_str.c_str(), 0) != 0)
259 size_t pos = template_str.rfind(
"XXXXXX");
262 int suffixlen =
GetSize(template_str) - pos - 6;
264 char *p = strdup(template_str.c_str());
265 close(mkstemps(p, suffixlen));
277 mkdir(template_str.c_str());
280 size_t pos = template_str.rfind(
"XXXXXX");
283 int suffixlen =
GetSize(template_str) - pos - 6;
286 char *p = strdup(template_str.c_str());
299 return _access(filename.c_str(), 0) == 0;
304 return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
314 struct dirent **namelist;
315 int n = scandir(dirname.c_str(), &namelist,
nullptr, alphasort);
317 for (
int i = 0; i <
n; i++) {
318 if (strcmp(namelist[i]->d_name,
".") && strcmp(namelist[i]->d_name,
"..")) {
319 std::string buffer =
stringf(
"%s/%s", dirname.c_str(), namelist[i]->d_name);
320 if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
321 log(
"Removing `%s'.\n", buffer.c_str());
322 remove(buffer.c_str());
329 log(
"Removing `%s'.\n", dirname.c_str());
330 rmdir(dirname.c_str());
361 #ifdef YOSYS_ENABLE_TCL
362 if (yosys_tcl_interp !=
NULL) {
363 Tcl_DeleteInterp(yosys_tcl_interp);
365 yosys_tcl_interp =
NULL;
369 #ifdef YOSYS_ENABLE_PLUGINS
373 loaded_plugins.clear();
381 size_t pos = file.find_last_of(
"/\\");
383 size_t pos = file.find_last_of(
'/');
385 if (pos != std::string::npos)
386 file = file.
substr(pos+1);
388 pos = func.find_last_of(
':');
389 if (pos != std::string::npos)
390 func = func.substr(pos+1);
402 static char buffer[100];
403 std::string str =
"\n";
404 if (recursion_counter > 1)
405 str +=
stringf(
"(%d) ", recursion_counter);
416 snprintf(buffer, 100,
"%s> ", str.c_str());
420 #ifdef YOSYS_ENABLE_TCL
421 static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp,
int argc,
const char *argv[])
423 std::vector<std::string>
args;
424 for (
int i = 1; i < argc; i++)
425 args.push_back(argv[i]);
427 if (args.size() >= 1 && args[0] ==
"-import") {
429 std::string tcl_command_name = it.first;
430 if (tcl_command_name ==
"proc")
431 tcl_command_name =
"procs";
433 if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
434 log(
"[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
436 std::string tcl_script =
stringf(
"proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
437 Tcl_Eval(interp, tcl_script.c_str());
443 if (args.size() == 1) {
452 extern Tcl_Interp *yosys_get_tcl_interp()
454 if (yosys_tcl_interp ==
NULL) {
455 yosys_tcl_interp = Tcl_CreateInterp();
456 Tcl_CreateCommand(yosys_tcl_interp,
"yosys", tcl_yosys_cmd,
NULL,
NULL);
458 return yosys_tcl_interp;
461 struct TclPass :
public Pass {
462 TclPass() :
Pass(
"tcl",
"execute a TCL script file") { }
463 virtual void help() {
465 log(
" tcl <filename>\n");
467 log(
"This command executes the tcl commands in the specified file.\n");
468 log(
"Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
470 log(
"The tcl command 'yosys -import' can be used to import all yosys\n");
471 log(
"commands directly as tcl commands to the tcl shell. The yosys\n");
472 log(
"command 'proc' is wrapped using the tcl command 'procs' in order\n");
473 log(
"to avoid a name collision with the tcl builting command 'proc'.\n");
481 if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
482 log_cmd_error(
"TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
487 #if defined(__linux__)
491 ssize_t buflen = readlink(
"/proc/self/exe", path,
sizeof(path));
493 log_error(
"readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
495 while (buflen > 0 && path[buflen-1] !=
'/')
497 return std::string(path, buflen);
499 #elif defined(__APPLE__)
504 while (_NSGetExecutablePath(path, &buflen) != 0)
505 path = (
char *) realloc((
void *) path, buflen);
506 while (buflen > 0 && path[buflen-1] !=
'/')
508 return std::string(path, buflen);
510 #elif defined(_WIN32)
515 char longpath[MAX_PATH + 1];
516 char shortpath[MAX_PATH + 1];
518 WCHAR longpath[MAX_PATH + 1];
519 TCHAR shortpath[MAX_PATH + 1];
521 if (!GetModuleFileName(0, longpath, MAX_PATH+1))
522 log_error(
"GetModuleFileName() failed.\n");
523 if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
524 log_error(
"GetShortPathName() failed.\n");
525 while (shortpath[i] != 0)
527 while (i > 0 && shortpath[i-1] !=
'/' && shortpath[i-1] !=
'\\')
530 for (i = 0; shortpath[i]; i++)
531 path +=
char(shortpath[i]);
534 #elif defined(EMSCRIPTEN)
540 #error Dont know how to determine process executable base path!
547 std::string proc_share_path = proc_self_path +
"share\\";
549 return proc_share_path;
550 proc_share_path = proc_self_path +
"..\\share\\";
552 return proc_share_path;
554 std::string proc_share_path = proc_self_path +
"share/";
556 return proc_share_path;
557 proc_share_path = proc_self_path +
"../share/yosys/";
559 return proc_share_path;
561 log_error(
"proc_share_dirname: unable to determine share/ directory!\n");
569 if (fgets(block, 4096, f) ==
NULL)
572 if (buffer.size() > 0 && (buffer[buffer.size()-1] ==
'\n' || buffer[buffer.size()-1] ==
'\r')) {
573 while (buffer.size() > 0 && (buffer[buffer.size()-1] ==
'\n' || buffer[buffer.size()-1] ==
'\r'))
574 buffer.resize(buffer.size()-1);
580 static void handle_label(std::string &command,
bool &from_to_active,
const std::string &run_from,
const std::string &run_to)
585 while (pos <
GetSize(command) && (command[pos] ==
' ' || command[pos] ==
'\t'))
588 while (pos <
GetSize(command) && command[pos] !=
' ' && command[pos] !=
'\t' && command[pos] !=
'\r' && command[pos] !=
'\n')
589 label += command[pos++];
591 if (label.back() ==
':' &&
GetSize(label) > 1)
593 label = label.substr(0,
GetSize(label)-1);
594 command = command.substr(pos);
596 if (label == run_from)
597 from_to_active =
true;
598 else if (label == run_to || (run_from == run_to && !run_from.empty()))
599 from_to_active =
false;
603 void run_frontend(std::string filename, std::string command,
RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
605 if (command ==
"auto") {
606 if (filename.size() > 2 && filename.substr(filename.size()-2) ==
".v")
608 else if (filename.size() > 2 && filename.substr(filename.size()-3) ==
".sv")
609 command =
"verilog -sv";
610 else if (filename.size() > 3 && filename.substr(filename.size()-3) ==
".il")
612 else if (filename.size() > 3 && filename.substr(filename.size()-3) ==
".ys")
614 else if (filename ==
"-")
617 log_error(
"Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
620 if (command ==
"script")
622 std::string run_from, run_to;
623 bool from_to_active =
true;
625 if (from_to_label !=
NULL) {
626 size_t pos = from_to_label->find(
':');
627 if (pos == std::string::npos) {
628 run_from = *from_to_label;
629 run_to = *from_to_label;
631 run_from = from_to_label->substr(0, pos);
632 run_to = from_to_label->substr(pos+1);
634 from_to_active = run_from.empty();
637 log(
"\n-- Executing script file `%s' --\n", filename.c_str());
642 f = fopen(filename.c_str(),
"r");
645 log_error(
"Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
653 while (!command.empty() && command[command.size()-1] ==
'\\') {
654 std::string next_line;
657 command.resize(command.size()-1);
658 command += next_line;
660 handle_label(command, from_to_active, run_from, run_to);
665 if (!command.empty()) {
666 handle_label(command, from_to_active, run_from, run_to);
681 if (backend_command !=
NULL && *backend_command ==
"auto")
682 *backend_command =
"";
687 if (filename ==
"-") {
688 log(
"\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
690 log(
"\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
698 log(
"\n-- Running pass `%s' --\n", command.c_str());
705 if (command ==
"auto") {
706 if (filename.size() > 2 && filename.substr(filename.size()-2) ==
".v")
708 else if (filename.size() > 3 && filename.substr(filename.size()-3) ==
".il")
710 else if (filename.size() > 5 && filename.substr(filename.size()-5) ==
".blif")
712 else if (filename ==
"-")
714 else if (filename.empty())
717 log_error(
"Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
720 if (filename.empty())
723 if (filename ==
"-") {
724 log(
"\n-- Writing to stdout using backend `%s' --\n", command.c_str());
726 log(
"\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
732 #ifdef YOSYS_ENABLE_READLINE
733 static char *readline_cmd_generator(
const char *text,
int state)
735 static std::map<std::string, Pass*>::iterator it;
739 it = pass_register.begin();
743 for (; it != pass_register.end(); it++) {
744 if (it->first.substr(0, len) == text)
745 return strdup((it++)->first.c_str());
750 static char *readline_obj_generator(
const char *text,
int state)
752 static std::vector<char*> obj_names;
761 int len = strlen(text);
774 for (
auto &it : module->
wires_)
782 for (
auto &it : module->
cells_)
791 std::sort(obj_names.begin(), obj_names.end());
794 if (idx < obj_names.size())
795 return strdup(obj_names[idx++]);
802 static char **readline_completion(
const char *text,
int start,
int)
805 return rl_completion_matches(text, readline_cmd_generator);
806 if (strncmp(rl_line_buffer,
"read_", 5) && strncmp(rl_line_buffer,
"write_", 6))
807 return rl_completion_matches(text, readline_obj_generator);
814 static int recursion_counter = 0;
819 #ifdef YOSYS_ENABLE_READLINE
820 rl_readline_name =
"yosys";
821 rl_attempted_completion_function = readline_completion;
822 rl_basic_word_break_characters =
" \t\n";
825 char *command =
NULL;
826 #ifdef YOSYS_ENABLE_READLINE
830 char command_buffer[4096];
835 if ((command = fgets(command_buffer, 4096, stdin)) ==
NULL)
838 if (command[strspn(command,
" \t\r\n")] == 0)
840 #ifdef YOSYS_ENABLE_READLINE
841 add_history(command);
844 char *p = command + strspn(command,
" \t\r\n");
845 if (!strncmp(p,
"exit", 4)) {
847 p += strspn(p,
" \t\r\n");
874 log(
"This command enters the interactive command mode. This can be useful\n");
875 log(
"in a script to interrupt the script at a certain point and allow for\n");
876 log(
"interactive inspection or manual synthesis of the design at this point.\n");
878 log(
"The command prompt of the interactive shell indicates the current\n");
879 log(
"selection (see 'help select'):\n");
882 log(
" the entire design is selected\n");
885 log(
" only part of the design is selected\n");
887 log(
" yosys [modname]>\n");
888 log(
" the entire module 'modname' is selected using 'select -module modname'\n");
890 log(
" yosys [modname]*>\n");
891 log(
" only part of current module 'modname' is selected\n");
893 log(
"When in interactive shell, some errors (e.g. invalid command arguments)\n");
894 log(
"do not terminate yosys but return to the command prompt.\n");
896 log(
"This command is the default action if nothing else has been specified\n");
897 log(
"on the command line.\n");
899 log(
"Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
908 #ifdef YOSYS_ENABLE_READLINE
909 struct HistoryPass :
public Pass {
910 HistoryPass() :
Pass(
"history",
"show last interactive commands") { }
911 virtual void help() {
915 log(
"This command prints all commands in the shell history buffer. This are\n");
916 log(
"all commands executed in an interactive session, but not the commands\n");
917 log(
"from executed scripts.\n");
922 for(HIST_ENTRY **list = history_list(); *list !=
NULL; list++)
923 log(
"%s\n", (*list)->line);
932 log(
" script <filename> [<from_label>:<to_label>]\n");
934 log(
"This command executes the yosys commands in the specified file.\n");
936 log(
"The 2nd argument can be used to only execute the section of the\n");
937 log(
"file between the specified labels. An empty from label is synonymous\n");
938 log(
"for the beginning of the file and an empty to label is synonymous\n");
939 log(
"for the end of the file.\n");
941 log(
"If only one label is specified (without ':') then only the block\n");
942 log(
"marked with that label (until the next label) is executed.\n");
948 else if (args.size() == 2)
950 else if (args.size() == 3)
static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
std::string next_token(std::string &text, const char *sep)
std::vector< RTLIL::Selection > selection_stack
std::string stringf(const char *fmt,...)
const char * create_prompt(RTLIL::Design *design, int recursion_counter)
void remove_directory(std::string dirname)
void sort(T *array, int size, LessThan lt)
RTLIL::Design * yosys_design
#define YOSYS_NAMESPACE_END
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
static std::string unescape_id(std::string str)
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
static std::string idx(std::string str)
std::map< RTLIL::IdString, RTLIL::Memory * > memories
void log_error(const char *format,...)
RTLIL::IdString new_id(std::string file, int line, std::string func)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)=0
std::string make_temp_file(std::string template_str)
static FILE * current_script_file
int run_command(const std::string &command, std::function< void(const std::string &)> process_line)
YOSYS_NAMESPACE_BEGIN std::vector< FILE * > log_files
std::string vstringf(const char *fmt, va_list ap)
bool patmatch(const char *pattern, const char *string)
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
std::string proc_self_dirname()
int GetSize(RTLIL::Wire *wire)
#define log_assert(_assert_expr_)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
static void done_register()
std::string make_temp_dir(std::string template_str)
static const char * id2cstr(const RTLIL::IdString &str)
void log_cmd_error(const char *format,...)
int readsome(std::istream &f, char *s, int n)
bool check_file_exists(std::string filename, bool is_exec)
std::map< RTLIL::IdString, RTLIL::Process * > processes
std::string substr(size_t pos=0, size_t len=std::string::npos) const
RTLIL::Design * yosys_get_design()
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
std::map< RTLIL::IdString, RTLIL::Module * > modules_
std::map< std::string, std::string > loaded_plugin_aliases
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
#define YOSYS_NAMESPACE_BEGIN
void shell(RTLIL::Design *design)
void log(const char *format,...)
void run_backend(std::string filename, std::string command, RTLIL::Design *design)
std::map< std::string, Pass * > pass_register
std::string proc_share_dirname()
std::string selected_active_module
static void init_register()
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
static void call(RTLIL::Design *design, std::string command)
void run_pass(std::string command, RTLIL::Design *design)
YOSYS_NAMESPACE_BEGIN int autoidx
bool fgetline(FILE *f, std::string &buffer)
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
std::map< std::string, void * > loaded_plugins