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