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