Improved new_id() for win32
[yosys.git] / kernel / yosys.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21
22 #ifdef YOSYS_ENABLE_READLINE
23 # include <readline/readline.h>
24 # include <readline/history.h>
25 #endif
26
27 #ifdef YOSYS_ENABLE_PLUGINS
28 # include <dlfcn.h>
29 #endif
30
31 #ifdef _WIN32
32 # include <windows.h>
33 # include <io.h>
34 #elif defined(__APPLE__)
35 # include <mach-o/dyld.h>
36 #else
37 # include <unistd.h>
38 # include <dirent.h>
39 # include <sys/types.h>
40 # include <sys/stat.h>
41 #endif
42
43 #include <limits.h>
44 #include <errno.h>
45
46 YOSYS_NAMESPACE_BEGIN
47
48 int autoidx = 1;
49 RTLIL::Design *yosys_design = NULL;
50
51 #ifdef YOSYS_ENABLE_TCL
52 Tcl_Interp *yosys_tcl_interp = NULL;
53 #endif
54
55 std::string stringf(const char *fmt, ...)
56 {
57 std::string string;
58 va_list ap;
59
60 va_start(ap, fmt);
61 string = vstringf(fmt, ap);
62 va_end(ap);
63
64 return string;
65 }
66
67 std::string vstringf(const char *fmt, va_list ap)
68 {
69 std::string string;
70 char *str = NULL;
71
72 #ifdef _WIN32
73 int sz = 64, rc;
74 while (1) {
75 va_list apc;
76 va_copy(apc, ap);
77 str = (char*)realloc(str, sz);
78 rc = vsnprintf(str, sz, fmt, apc);
79 va_end(apc);
80 if (rc >= 0 && rc < sz)
81 break;
82 sz *= 2;
83 }
84 #else
85 if (vasprintf(&str, fmt, ap) < 0)
86 str = NULL;
87 #endif
88
89 if (str != NULL) {
90 string = str;
91 free(str);
92 }
93
94 return string;
95 }
96
97 std::string next_token(std::string &text, const char *sep)
98 {
99 size_t pos_begin = text.find_first_not_of(sep);
100
101 if (pos_begin == std::string::npos)
102 pos_begin = text.size();
103
104 size_t pos_end = text.find_first_of(sep, pos_begin);
105
106 if (pos_end == std::string::npos)
107 pos_end = text.size();
108
109 std::string token = text.substr(pos_begin, pos_end-pos_begin);
110 text = text.substr(pos_end);
111 return token;
112 }
113
114 // this is very similar to fnmatch(). the exact rules used by this
115 // function are:
116 //
117 // ? matches any character except
118 // * matches any sequence of characters
119 // [...] matches any of the characters in the list
120 // [!..] matches any of the characters not in the list
121 //
122 // a backslash may be used to escape the next characters in the
123 // pattern. each special character can also simply match itself.
124 //
125 bool patmatch(const char *pattern, const char *string)
126 {
127 if (*pattern == 0)
128 return *string == 0;
129
130 if (*pattern == '\\') {
131 if (pattern[1] == string[0] && patmatch(pattern+2, string+1))
132 return true;
133 }
134
135 if (*pattern == '?') {
136 if (*string == 0)
137 return false;
138 return patmatch(pattern+1, string+1);
139 }
140
141 if (*pattern == '*') {
142 while (*string) {
143 if (patmatch(pattern+1, string++))
144 return true;
145 }
146 return pattern[1] == 0;
147 }
148
149 if (*pattern == '[') {
150 bool found_match = false;
151 bool inverted_list = pattern[1] == '!';
152 const char *p = pattern + (inverted_list ? 1 : 0);
153
154 while (*++p) {
155 if (*p == ']') {
156 if (found_match != inverted_list && patmatch(p+1, string+1))
157 return true;
158 break;
159 }
160
161 if (*p == '\\') {
162 if (*++p == *string)
163 found_match = true;
164 } else
165 if (*p == *string)
166 found_match = true;
167 }
168 }
169
170 if (*pattern == *string)
171 return patmatch(pattern+1, string+1);
172
173 return false;
174 }
175
176 int run_command(const std::string &command, std::function<void(const std::string&)> process_line)
177 {
178 if (!process_line)
179 return system(command.c_str());
180
181 FILE *f = popen(command.c_str(), "r");
182 if (f == nullptr)
183 return -1;
184
185 std::string line;
186 char logbuf[128];
187 while (fgets(logbuf, 128, f) != NULL) {
188 line += logbuf;
189 if (!line.empty() && line.back() == '\n')
190 process_line(line), line.clear();
191 }
192 if (!line.empty())
193 process_line(line);
194
195 int ret = pclose(f);
196 if (ret < 0)
197 return -1;
198 #ifdef _WIN32
199 return ret;
200 #else
201 return WEXITSTATUS(ret);
202 #endif
203 }
204
205 std::string make_temp_file(std::string template_str)
206 {
207 #ifdef _WIN32
208 if (template_str.rfind("/tmp/", 0) == 0) {
209 # ifdef __MINGW32__
210 char longpath[MAX_PATH + 1];
211 char shortpath[MAX_PATH + 1];
212 # else
213 WCHAR longpath[MAX_PATH + 1];
214 TCHAR shortpath[MAX_PATH + 1];
215 # endif
216 if (!GetTempPath(MAX_PATH+1, longpath))
217 log_error("GetTempPath() failed.\n");
218 if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
219 log_error("GetShortPathName() failed.\n");
220 std::string path;
221 for (int i = 0; shortpath[i]; i++)
222 path += char(shortpath[i]);
223 template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
224 }
225
226 size_t pos = template_str.rfind("XXXXXX");
227 log_assert(pos != std::string::npos);
228
229 while (1) {
230 for (int i = 0; i < 6; i++) {
231 static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
232 static uint32_t x = 314159265 ^ uint32_t(time(NULL));
233 x ^= x << 13, x ^= x >> 17, x ^= x << 5;
234 template_str[pos+i] = y[x % y.size()];
235 }
236 if (_access(template_str.c_str(), 0) != 0)
237 break;
238 }
239 #else
240 size_t pos = template_str.rfind("XXXXXX");
241 log_assert(pos != std::string::npos);
242
243 int suffixlen = GetSize(template_str) - pos - 6;
244
245 char *p = strdup(template_str.c_str());
246 close(mkstemps(p, suffixlen));
247 template_str = p;
248 free(p);
249 #endif
250
251 return template_str;
252 }
253
254 std::string make_temp_dir(std::string template_str)
255 {
256 #ifdef _WIN32
257 template_str = make_temp_file(template_str);
258 mkdir(template_str.c_str());
259 return template_str;
260 #else
261 size_t pos = template_str.rfind("XXXXXX");
262 log_assert(pos != std::string::npos);
263
264 int suffixlen = GetSize(template_str) - pos - 6;
265 log_assert(suffixlen == 0);
266
267 char *p = strdup(template_str.c_str());
268 p = mkdtemp(p);
269 log_assert(p != NULL);
270 template_str = p;
271 free(p);
272
273 return template_str;
274 #endif
275 }
276
277 #ifdef _WIN32
278 bool check_file_exists(std::string filename, bool)
279 {
280 return _access(filename.c_str(), 0) == 0;
281 }
282 #else
283 bool check_file_exists(std::string filename, bool is_exec)
284 {
285 return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
286 }
287 #endif
288
289 void remove_directory(std::string dirname)
290 {
291 #ifdef _WIN32
292 run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
293 #else
294 struct stat stbuf;
295 struct dirent **namelist;
296 int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
297 log_assert(n >= 0);
298 for (int i = 0; i < n; i++) {
299 if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
300 std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
301 if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
302 log("Removing `%s'.\n", buffer.c_str());
303 remove(buffer.c_str());
304 } else
305 remove_directory(buffer);
306 }
307 free(namelist[i]);
308 }
309 free(namelist);
310 log("Removing `%s'.\n", dirname.c_str());
311 rmdir(dirname.c_str());
312 #endif
313 }
314
315 int GetSize(RTLIL::Wire *wire)
316 {
317 return wire->width;
318 }
319
320 void yosys_setup()
321 {
322 Pass::init_register();
323 yosys_design = new RTLIL::Design;
324 log_push();
325 }
326
327 void yosys_shutdown()
328 {
329 log_pop();
330
331 delete yosys_design;
332 yosys_design = NULL;
333
334 for (auto f : log_files)
335 if (f != stderr)
336 fclose(f);
337 log_errfile = NULL;
338 log_files.clear();
339
340 Pass::done_register();
341
342 #ifdef YOSYS_ENABLE_TCL
343 if (yosys_tcl_interp != NULL) {
344 Tcl_DeleteInterp(yosys_tcl_interp);
345 Tcl_Finalize();
346 yosys_tcl_interp = NULL;
347 }
348 #endif
349
350 #ifdef YOSYS_ENABLE_PLUGINS
351 for (auto &it : loaded_plugins)
352 dlclose(it.second);
353
354 loaded_plugins.clear();
355 loaded_plugin_aliases.clear();
356 #endif
357 }
358
359 RTLIL::IdString new_id(std::string file, int line, std::string func)
360 {
361 #ifdef _WIN32
362 size_t pos = file.find_last_of("/\\");
363 #else
364 size_t pos = file.find_last_of('/');
365 #endif
366 if (pos != std::string::npos)
367 file = file.substr(pos+1);
368
369 pos = func.find_last_of(':');
370 if (pos != std::string::npos)
371 func = func.substr(pos+1);
372
373 return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
374 }
375
376 RTLIL::Design *yosys_get_design()
377 {
378 return yosys_design;
379 }
380
381 const char *create_prompt(RTLIL::Design *design, int recursion_counter)
382 {
383 static char buffer[100];
384 std::string str = "\n";
385 if (recursion_counter > 1)
386 str += stringf("(%d) ", recursion_counter);
387 str += "yosys";
388 if (!design->selected_active_module.empty())
389 str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
390 if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
391 if (design->selected_active_module.empty())
392 str += "*";
393 else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
394 design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
395 str += "*";
396 }
397 snprintf(buffer, 100, "%s> ", str.c_str());
398 return buffer;
399 }
400
401 #ifdef YOSYS_ENABLE_TCL
402 static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
403 {
404 std::vector<std::string> args;
405 for (int i = 1; i < argc; i++)
406 args.push_back(argv[i]);
407
408 if (args.size() >= 1 && args[0] == "-import") {
409 for (auto &it : pass_register) {
410 std::string tcl_command_name = it.first;
411 if (tcl_command_name == "proc")
412 tcl_command_name = "procs";
413 Tcl_CmdInfo info;
414 if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
415 log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
416 } else {
417 std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
418 Tcl_Eval(interp, tcl_script.c_str());
419 }
420 }
421 return TCL_OK;
422 }
423
424 if (args.size() == 1) {
425 Pass::call(yosys_get_design(), args[0]);
426 return TCL_OK;
427 }
428
429 Pass::call(yosys_get_design(), args);
430 return TCL_OK;
431 }
432
433 extern Tcl_Interp *yosys_get_tcl_interp()
434 {
435 if (yosys_tcl_interp == NULL) {
436 yosys_tcl_interp = Tcl_CreateInterp();
437 Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
438 }
439 return yosys_tcl_interp;
440 }
441
442 struct TclPass : public Pass {
443 TclPass() : Pass("tcl", "execute a TCL script file") { }
444 virtual void help() {
445 log("\n");
446 log(" tcl <filename>\n");
447 log("\n");
448 log("This command executes the tcl commands in the specified file.\n");
449 log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
450 log("\n");
451 log("The tcl command 'yosys -import' can be used to import all yosys\n");
452 log("commands directly as tcl commands to the tcl shell. The yosys\n");
453 log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
454 log("to avoid a name collision with the tcl builting command 'proc'.\n");
455 log("\n");
456 }
457 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
458 if (args.size() < 2)
459 log_cmd_error("Missing script file.\n");
460 if (args.size() > 2)
461 extra_args(args, 1, design, false);
462 if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
463 log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
464 }
465 } TclPass;
466 #endif
467
468 #if defined(__linux__)
469 std::string proc_self_dirname()
470 {
471 char path[PATH_MAX];
472 ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
473 if (buflen < 0) {
474 log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
475 }
476 while (buflen > 0 && path[buflen-1] != '/')
477 buflen--;
478 return std::string(path, buflen);
479 }
480 #elif defined(__APPLE__)
481 std::string proc_self_dirname()
482 {
483 char *path = NULL;
484 uint32_t buflen = 0;
485 while (_NSGetExecutablePath(path, &buflen) != 0)
486 path = (char *) realloc((void *) path, buflen);
487 while (buflen > 0 && path[buflen-1] != '/')
488 buflen--;
489 return std::string(path, buflen);
490 }
491 #elif defined(_WIN32)
492 std::string proc_self_dirname()
493 {
494 int i = 0;
495 # ifdef __MINGW32__
496 char longpath[MAX_PATH + 1];
497 char shortpath[MAX_PATH + 1];
498 # else
499 WCHAR longpath[MAX_PATH + 1];
500 TCHAR shortpath[MAX_PATH + 1];
501 # endif
502 if (!GetModuleFileName(0, longpath, MAX_PATH+1))
503 log_error("GetModuleFileName() failed.\n");
504 if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
505 log_error("GetShortPathName() failed.\n");
506 while (shortpath[i] != 0)
507 i++;
508 while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\')
509 shortpath[--i] = 0;
510 std::string path;
511 for (i = 0; shortpath[i]; i++)
512 path += char(shortpath[i]);
513 return path;
514 }
515 #elif defined(EMSCRIPTEN)
516 std::string proc_self_dirname()
517 {
518 return "/";
519 }
520 #else
521 #error Dont know how to determine process executable base path!
522 #endif
523
524 std::string proc_share_dirname()
525 {
526 std::string proc_self_path = proc_self_dirname();
527 #ifdef _WIN32
528 std::string proc_share_path = proc_self_path + "share\\";
529 if (check_file_exists(proc_share_path, true))
530 return proc_share_path;
531 proc_share_path = proc_self_path + "..\\share\\";
532 if (check_file_exists(proc_share_path, true))
533 return proc_share_path;
534 #else
535 std::string proc_share_path = proc_self_path + "share/";
536 if (check_file_exists(proc_share_path, true))
537 return proc_share_path;
538 proc_share_path = proc_self_path + "../share/yosys/";
539 if (check_file_exists(proc_share_path, true))
540 return proc_share_path;
541 #endif
542 log_error("proc_share_dirname: unable to determine share/ directory!\n");
543 }
544
545 bool fgetline(FILE *f, std::string &buffer)
546 {
547 buffer = "";
548 char block[4096];
549 while (1) {
550 if (fgets(block, 4096, f) == NULL)
551 return false;
552 buffer += block;
553 if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
554 while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
555 buffer.resize(buffer.size()-1);
556 return true;
557 }
558 }
559 }
560
561 static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
562 {
563 int pos = 0;
564 std::string label;
565
566 while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
567 pos++;
568
569 while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
570 label += command[pos++];
571
572 if (label.back() == ':' && GetSize(label) > 1)
573 {
574 label = label.substr(0, GetSize(label)-1);
575 command = command.substr(pos);
576
577 if (label == run_from)
578 from_to_active = true;
579 else if (label == run_to || (run_from == run_to && !run_from.empty()))
580 from_to_active = false;
581 }
582 }
583
584 void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
585 {
586 if (command == "auto") {
587 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
588 command = "verilog";
589 else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
590 command = "verilog -sv";
591 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
592 command = "ilang";
593 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
594 command = "script";
595 else if (filename == "-")
596 command = "script";
597 else
598 log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
599 }
600
601 if (command == "script")
602 {
603 std::string run_from, run_to;
604 bool from_to_active = true;
605
606 if (from_to_label != NULL) {
607 size_t pos = from_to_label->find(':');
608 if (pos == std::string::npos) {
609 run_from = *from_to_label;
610 run_to = *from_to_label;
611 } else {
612 run_from = from_to_label->substr(0, pos);
613 run_to = from_to_label->substr(pos+1);
614 }
615 from_to_active = run_from.empty();
616 }
617
618 log("\n-- Executing script file `%s' --\n", filename.c_str());
619
620 FILE *f = stdin;
621
622 if (filename != "-")
623 f = fopen(filename.c_str(), "r");
624
625 if (f == NULL)
626 log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
627
628 FILE *backup_script_file = Frontend::current_script_file;
629 Frontend::current_script_file = f;
630
631 try {
632 std::string command;
633 while (fgetline(f, command)) {
634 while (!command.empty() && command[command.size()-1] == '\\') {
635 std::string next_line;
636 if (!fgetline(f, next_line))
637 break;
638 command.resize(command.size()-1);
639 command += next_line;
640 }
641 handle_label(command, from_to_active, run_from, run_to);
642 if (from_to_active)
643 Pass::call(design, command);
644 }
645
646 if (!command.empty()) {
647 handle_label(command, from_to_active, run_from, run_to);
648 if (from_to_active)
649 Pass::call(design, command);
650 }
651 }
652 catch (log_cmd_error_expection) {
653 Frontend::current_script_file = backup_script_file;
654 throw log_cmd_error_expection();
655 }
656
657 Frontend::current_script_file = backup_script_file;
658
659 if (filename != "-")
660 fclose(f);
661
662 if (backend_command != NULL && *backend_command == "auto")
663 *backend_command = "";
664
665 return;
666 }
667
668 if (filename == "-") {
669 log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
670 } else {
671 log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
672 }
673
674 Frontend::frontend_call(design, NULL, filename, command);
675 }
676
677 void run_pass(std::string command, RTLIL::Design *design)
678 {
679 log("\n-- Running pass `%s' --\n", command.c_str());
680
681 Pass::call(design, command);
682 }
683
684 void run_backend(std::string filename, std::string command, RTLIL::Design *design)
685 {
686 if (command == "auto") {
687 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
688 command = "verilog";
689 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
690 command = "ilang";
691 else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
692 command = "blif";
693 else if (filename == "-")
694 command = "ilang";
695 else if (filename.empty())
696 return;
697 else
698 log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
699 }
700
701 if (filename.empty())
702 filename = "-";
703
704 if (filename == "-") {
705 log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
706 } else {
707 log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
708 }
709
710 Backend::backend_call(design, NULL, filename, command);
711 }
712
713 #ifdef YOSYS_ENABLE_READLINE
714 static char *readline_cmd_generator(const char *text, int state)
715 {
716 static std::map<std::string, Pass*>::iterator it;
717 static int len;
718
719 if (!state) {
720 it = pass_register.begin();
721 len = strlen(text);
722 }
723
724 for (; it != pass_register.end(); it++) {
725 if (it->first.substr(0, len) == text)
726 return strdup((it++)->first.c_str());
727 }
728 return NULL;
729 }
730
731 static char *readline_obj_generator(const char *text, int state)
732 {
733 static std::vector<char*> obj_names;
734 static size_t idx;
735
736 if (!state)
737 {
738 idx = 0;
739 obj_names.clear();
740
741 RTLIL::Design *design = yosys_get_design();
742 int len = strlen(text);
743
744 if (design->selected_active_module.empty())
745 {
746 for (auto &it : design->modules_)
747 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
748 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
749 }
750 else
751 if (design->modules_.count(design->selected_active_module) > 0)
752 {
753 RTLIL::Module *module = design->modules_.at(design->selected_active_module);
754
755 for (auto &it : module->wires_)
756 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
757 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
758
759 for (auto &it : module->memories)
760 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
761 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
762
763 for (auto &it : module->cells_)
764 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
765 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
766
767 for (auto &it : module->processes)
768 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
769 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
770 }
771
772 std::sort(obj_names.begin(), obj_names.end());
773 }
774
775 if (idx < obj_names.size())
776 return strdup(obj_names[idx++]);
777
778 idx = 0;
779 obj_names.clear();
780 return NULL;
781 }
782
783 static char **readline_completion(const char *text, int start, int)
784 {
785 if (start == 0)
786 return rl_completion_matches(text, readline_cmd_generator);
787 if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
788 return rl_completion_matches(text, readline_obj_generator);
789 return NULL;
790 }
791 #endif
792
793 void shell(RTLIL::Design *design)
794 {
795 static int recursion_counter = 0;
796
797 recursion_counter++;
798 log_cmd_error_throw = true;
799
800 #ifdef YOSYS_ENABLE_READLINE
801 rl_readline_name = "yosys";
802 rl_attempted_completion_function = readline_completion;
803 rl_basic_word_break_characters = " \t\n";
804 #endif
805
806 char *command = NULL;
807 #ifdef YOSYS_ENABLE_READLINE
808 while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
809 {
810 #else
811 char command_buffer[4096];
812 while (1)
813 {
814 fputs(create_prompt(design, recursion_counter), stdout);
815 fflush(stdout);
816 if ((command = fgets(command_buffer, 4096, stdin)) == NULL)
817 break;
818 #endif
819 if (command[strspn(command, " \t\r\n")] == 0)
820 continue;
821 #ifdef YOSYS_ENABLE_READLINE
822 add_history(command);
823 #endif
824
825 char *p = command + strspn(command, " \t\r\n");
826 if (!strncmp(p, "exit", 4)) {
827 p += 4;
828 p += strspn(p, " \t\r\n");
829 if (*p == 0)
830 break;
831 }
832
833 try {
834 log_assert(design->selection_stack.size() == 1);
835 Pass::call(design, command);
836 } catch (log_cmd_error_expection) {
837 while (design->selection_stack.size() > 1)
838 design->selection_stack.pop_back();
839 log_reset_stack();
840 }
841 }
842 if (command == NULL)
843 printf("exit\n");
844
845 recursion_counter--;
846 log_cmd_error_throw = false;
847 }
848
849 struct ShellPass : public Pass {
850 ShellPass() : Pass("shell", "enter interactive command mode") { }
851 virtual void help() {
852 log("\n");
853 log(" shell\n");
854 log("\n");
855 log("This command enters the interactive command mode. This can be useful\n");
856 log("in a script to interrupt the script at a certain point and allow for\n");
857 log("interactive inspection or manual synthesis of the design at this point.\n");
858 log("\n");
859 log("The command prompt of the interactive shell indicates the current\n");
860 log("selection (see 'help select'):\n");
861 log("\n");
862 log(" yosys>\n");
863 log(" the entire design is selected\n");
864 log("\n");
865 log(" yosys*>\n");
866 log(" only part of the design is selected\n");
867 log("\n");
868 log(" yosys [modname]>\n");
869 log(" the entire module 'modname' is selected using 'select -module modname'\n");
870 log("\n");
871 log(" yosys [modname]*>\n");
872 log(" only part of current module 'modname' is selected\n");
873 log("\n");
874 log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
875 log("do not terminate yosys but return to the command prompt.\n");
876 log("\n");
877 log("This command is the default action if nothing else has been specified\n");
878 log("on the command line.\n");
879 log("\n");
880 log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
881 log("\n");
882 }
883 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
884 extra_args(args, 1, design, false);
885 shell(design);
886 }
887 } ShellPass;
888
889 #ifdef YOSYS_ENABLE_READLINE
890 struct HistoryPass : public Pass {
891 HistoryPass() : Pass("history", "show last interactive commands") { }
892 virtual void help() {
893 log("\n");
894 log(" history\n");
895 log("\n");
896 log("This command prints all commands in the shell history buffer. This are\n");
897 log("all commands executed in an interactive session, but not the commands\n");
898 log("from executed scripts.\n");
899 log("\n");
900 }
901 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
902 extra_args(args, 1, design, false);
903 for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
904 log("%s\n", (*list)->line);
905 }
906 } HistoryPass;
907 #endif
908
909 struct ScriptPass : public Pass {
910 ScriptPass() : Pass("script", "execute commands from script file") { }
911 virtual void help() {
912 log("\n");
913 log(" script <filename> [<from_label>:<to_label>]\n");
914 log("\n");
915 log("This command executes the yosys commands in the specified file.\n");
916 log("\n");
917 log("The 2nd argument can be used to only execute the section of the\n");
918 log("file between the specified labels. An empty from label is synonymous\n");
919 log("for the beginning of the file and an empty to label is synonymous\n");
920 log("for the end of the file.\n");
921 log("\n");
922 log("If only one label is specified (without ':') then only the block\n");
923 log("marked with that label (until the next label) is executed.\n");
924 log("\n");
925 }
926 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
927 if (args.size() < 2)
928 log_cmd_error("Missing script file.\n");
929 else if (args.size() == 2)
930 run_frontend(args[1], "script", design, NULL, NULL);
931 else if (args.size() == 3)
932 run_frontend(args[1], "script", design, NULL, &args[2]);
933 else
934 extra_args(args, 2, design, false);
935 }
936 } ScriptPass;
937
938 YOSYS_NAMESPACE_END
939