Header changes so it will compile on VS
[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 #elif defined(__APPLE__)
34 # include <mach-o/dyld.h>
35 #else
36 # include <unistd.h>
37 # include <dirent.h>
38 # include <sys/types.h>
39 # include <sys/stat.h>
40 #endif
41
42 #include <limits.h>
43 #include <errno.h>
44
45 YOSYS_NAMESPACE_BEGIN
46
47 #ifdef _WIN32
48 const char *yosys_version_str = "Windows";
49 #endif
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 char path[MAX_PATH+1];
213 GetTempPath(MAX_PATH+1, path);
214 template_str = stringf("%s\\%s", path, template_str.c_str() + 5);
215 }
216
217 size_t pos = template_str.rfind("XXXXXX");
218 log_assert(pos != std::string::npos);
219
220 while (1) {
221 for (int i = 0; i < 6; i++) {
222 static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
223 static uint32_t x = 314159265 ^ time(NULL);
224 x ^= x << 13, x ^= x >> 17, x ^= x << 5;
225 template_str[pos+i] = y[x % y.size()];
226 }
227 if (access(template_str.c_str(), F_OK) != 0)
228 break;
229 }
230 #else
231 size_t pos = template_str.rfind("XXXXXX");
232 log_assert(pos != std::string::npos);
233
234 int suffixlen = GetSize(template_str) - pos - 6;
235
236 char *p = strdup(template_str.c_str());
237 close(mkstemps(p, suffixlen));
238 template_str = p;
239 free(p);
240 #endif
241
242 return template_str;
243 }
244
245 std::string make_temp_dir(std::string template_str)
246 {
247 #ifdef _WIN32
248 template_str = make_temp_file(template_str);
249 mkdir(template_str.c_str());
250 return template_str;
251 #else
252 size_t pos = template_str.rfind("XXXXXX");
253 log_assert(pos != std::string::npos);
254
255 int suffixlen = GetSize(template_str) - pos - 6;
256 log_assert(suffixlen == 0);
257
258 char *p = strdup(template_str.c_str());
259 p = mkdtemp(p);
260 log_assert(p != NULL);
261 template_str = p;
262 free(p);
263
264 return template_str;
265 #endif
266 }
267
268 void remove_directory(std::string dirname)
269 {
270 #ifdef _WIN32
271 run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
272 #else
273 struct stat stbuf;
274 struct dirent **namelist;
275 int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
276 log_assert(n >= 0);
277 for (int i = 0; i < n; i++) {
278 if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
279 std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
280 if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
281 log("Removing `%s'.\n", buffer.c_str());
282 remove(buffer.c_str());
283 } else
284 remove_directory(buffer);
285 }
286 free(namelist[i]);
287 }
288 free(namelist);
289 log("Removing `%s'.\n", dirname.c_str());
290 rmdir(dirname.c_str());
291 #endif
292 }
293
294 int GetSize(RTLIL::Wire *wire)
295 {
296 return wire->width;
297 }
298
299 void yosys_setup()
300 {
301 Pass::init_register();
302 yosys_design = new RTLIL::Design;
303 log_push();
304 }
305
306 void yosys_shutdown()
307 {
308 log_pop();
309
310 delete yosys_design;
311 yosys_design = NULL;
312
313 for (auto f : log_files)
314 if (f != stderr)
315 fclose(f);
316 log_errfile = NULL;
317 log_files.clear();
318
319 Pass::done_register();
320
321 #ifdef YOSYS_ENABLE_TCL
322 if (yosys_tcl_interp != NULL) {
323 Tcl_DeleteInterp(yosys_tcl_interp);
324 Tcl_Finalize();
325 yosys_tcl_interp = NULL;
326 }
327 #endif
328
329 #ifdef YOSYS_ENABLE_PLUGINS
330 for (auto &it : loaded_plugins)
331 dlclose(it.second);
332
333 loaded_plugins.clear();
334 loaded_plugin_aliases.clear();
335 #endif
336 }
337
338 RTLIL::IdString new_id(std::string file, int line, std::string func)
339 {
340 std::string str = "$auto$";
341 size_t pos = file.find_last_of('/');
342 str += pos != std::string::npos ? file.substr(pos+1) : file;
343 str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
344 return str;
345 }
346
347 RTLIL::Design *yosys_get_design()
348 {
349 return yosys_design;
350 }
351
352 const char *create_prompt(RTLIL::Design *design, int recursion_counter)
353 {
354 static char buffer[100];
355 std::string str = "\n";
356 if (recursion_counter > 1)
357 str += stringf("(%d) ", recursion_counter);
358 str += "yosys";
359 if (!design->selected_active_module.empty())
360 str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
361 if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
362 if (design->selected_active_module.empty())
363 str += "*";
364 else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
365 design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
366 str += "*";
367 }
368 snprintf(buffer, 100, "%s> ", str.c_str());
369 return buffer;
370 }
371
372 #ifdef YOSYS_ENABLE_TCL
373 static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
374 {
375 std::vector<std::string> args;
376 for (int i = 1; i < argc; i++)
377 args.push_back(argv[i]);
378
379 if (args.size() >= 1 && args[0] == "-import") {
380 for (auto &it : pass_register) {
381 std::string tcl_command_name = it.first;
382 if (tcl_command_name == "proc")
383 tcl_command_name = "procs";
384 Tcl_CmdInfo info;
385 if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
386 log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
387 } else {
388 std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
389 Tcl_Eval(interp, tcl_script.c_str());
390 }
391 }
392 return TCL_OK;
393 }
394
395 if (args.size() == 1) {
396 Pass::call(yosys_get_design(), args[0]);
397 return TCL_OK;
398 }
399
400 Pass::call(yosys_get_design(), args);
401 return TCL_OK;
402 }
403
404 extern Tcl_Interp *yosys_get_tcl_interp()
405 {
406 if (yosys_tcl_interp == NULL) {
407 yosys_tcl_interp = Tcl_CreateInterp();
408 Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
409 }
410 return yosys_tcl_interp;
411 }
412
413 struct TclPass : public Pass {
414 TclPass() : Pass("tcl", "execute a TCL script file") { }
415 virtual void help() {
416 log("\n");
417 log(" tcl <filename>\n");
418 log("\n");
419 log("This command executes the tcl commands in the specified file.\n");
420 log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
421 log("\n");
422 log("The tcl command 'yosys -import' can be used to import all yosys\n");
423 log("commands directly as tcl commands to the tcl shell. The yosys\n");
424 log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
425 log("to avoid a name collision with the tcl builting command 'proc'.\n");
426 log("\n");
427 }
428 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
429 if (args.size() < 2)
430 log_cmd_error("Missing script file.\n");
431 if (args.size() > 2)
432 extra_args(args, 1, design, false);
433 if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
434 log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
435 }
436 } TclPass;
437 #endif
438
439 #if defined(__linux__)
440 std::string proc_self_dirname()
441 {
442 char path[PATH_MAX];
443 ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
444 if (buflen < 0) {
445 log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
446 }
447 while (buflen > 0 && path[buflen-1] != '/')
448 buflen--;
449 return std::string(path, buflen);
450 }
451 #elif defined(__APPLE__)
452 std::string proc_self_dirname()
453 {
454 char *path = NULL;
455 uint32_t buflen = 0;
456 while (_NSGetExecutablePath(path, &buflen) != 0)
457 path = (char *) realloc((void *) path, buflen);
458 while (buflen > 0 && path[buflen-1] != '/')
459 buflen--;
460 return std::string(path, buflen);
461 }
462 #elif defined(_WIN32)
463 std::string proc_self_dirname()
464 {
465 char longpath[MAX_PATH+1], shortpath[MAX_PATH+1];
466 if (!GetModuleFileName(0, longpath, MAX_PATH+1))
467 log_error("GetModuleFileName() failed.\n");
468 if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
469 log_error("GetShortPathName() failed.\n");
470 for (int i = strlen(shortpath)-1; i >= 0 && shortpath[i] != '/' && shortpath[i] != '\\' ; i--)
471 shortpath[i] = 0;
472 return std::string(shortpath);
473 }
474 #elif defined(EMSCRIPTEN)
475 std::string proc_self_dirname()
476 {
477 return "/";
478 }
479 #else
480 #error Dont know how to determine process executable base path!
481 #endif
482
483 std::string proc_share_dirname()
484 {
485 std::string proc_self_path = proc_self_dirname();
486 std::string proc_share_path = proc_self_path + "share/";
487 if (access(proc_share_path.c_str(), X_OK) == 0)
488 return proc_share_path;
489 proc_share_path = proc_self_path + "../share/yosys/";
490 if (access(proc_share_path.c_str(), X_OK) == 0)
491 return proc_share_path;
492 log_error("proc_share_dirname: unable to determine share/ directory!\n");
493 }
494
495 bool fgetline(FILE *f, std::string &buffer)
496 {
497 buffer = "";
498 char block[4096];
499 while (1) {
500 if (fgets(block, 4096, f) == NULL)
501 return false;
502 buffer += block;
503 if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
504 while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
505 buffer.resize(buffer.size()-1);
506 return true;
507 }
508 }
509 }
510
511 static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
512 {
513 int pos = 0;
514 std::string label;
515
516 while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
517 pos++;
518
519 while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
520 label += command[pos++];
521
522 if (label.back() == ':' && GetSize(label) > 1)
523 {
524 label = label.substr(0, GetSize(label)-1);
525 command = command.substr(pos);
526
527 if (label == run_from)
528 from_to_active = true;
529 else if (label == run_to || (run_from == run_to && !run_from.empty()))
530 from_to_active = false;
531 }
532 }
533
534 void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
535 {
536 if (command == "auto") {
537 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
538 command = "verilog";
539 else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
540 command = "verilog -sv";
541 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
542 command = "ilang";
543 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
544 command = "script";
545 else if (filename == "-")
546 command = "script";
547 else
548 log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
549 }
550
551 if (command == "script")
552 {
553 std::string run_from, run_to;
554 bool from_to_active = true;
555
556 if (from_to_label != NULL) {
557 size_t pos = from_to_label->find(':');
558 if (pos == std::string::npos) {
559 run_from = *from_to_label;
560 run_to = *from_to_label;
561 } else {
562 run_from = from_to_label->substr(0, pos);
563 run_to = from_to_label->substr(pos+1);
564 }
565 from_to_active = run_from.empty();
566 }
567
568 log("\n-- Executing script file `%s' --\n", filename.c_str());
569
570 FILE *f = stdin;
571
572 if (filename != "-")
573 f = fopen(filename.c_str(), "r");
574
575 if (f == NULL)
576 log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
577
578 FILE *backup_script_file = Frontend::current_script_file;
579 Frontend::current_script_file = f;
580
581 try {
582 std::string command;
583 while (fgetline(f, command)) {
584 while (!command.empty() && command[command.size()-1] == '\\') {
585 std::string next_line;
586 if (!fgetline(f, next_line))
587 break;
588 command.resize(command.size()-1);
589 command += next_line;
590 }
591 handle_label(command, from_to_active, run_from, run_to);
592 if (from_to_active)
593 Pass::call(design, command);
594 }
595
596 if (!command.empty()) {
597 handle_label(command, from_to_active, run_from, run_to);
598 if (from_to_active)
599 Pass::call(design, command);
600 }
601 }
602 catch (log_cmd_error_expection) {
603 Frontend::current_script_file = backup_script_file;
604 throw log_cmd_error_expection();
605 }
606
607 Frontend::current_script_file = backup_script_file;
608
609 if (filename != "-")
610 fclose(f);
611
612 if (backend_command != NULL && *backend_command == "auto")
613 *backend_command = "";
614
615 return;
616 }
617
618 if (filename == "-") {
619 log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
620 } else {
621 log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
622 }
623
624 Frontend::frontend_call(design, NULL, filename, command);
625 }
626
627 void run_pass(std::string command, RTLIL::Design *design)
628 {
629 log("\n-- Running pass `%s' --\n", command.c_str());
630
631 Pass::call(design, command);
632 }
633
634 void run_backend(std::string filename, std::string command, RTLIL::Design *design)
635 {
636 if (command == "auto") {
637 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
638 command = "verilog";
639 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
640 command = "ilang";
641 else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
642 command = "blif";
643 else if (filename == "-")
644 command = "ilang";
645 else if (filename.empty())
646 return;
647 else
648 log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
649 }
650
651 if (filename.empty())
652 filename = "-";
653
654 if (filename == "-") {
655 log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
656 } else {
657 log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
658 }
659
660 Backend::backend_call(design, NULL, filename, command);
661 }
662
663 #ifdef YOSYS_ENABLE_READLINE
664 static char *readline_cmd_generator(const char *text, int state)
665 {
666 static std::map<std::string, Pass*>::iterator it;
667 static int len;
668
669 if (!state) {
670 it = pass_register.begin();
671 len = strlen(text);
672 }
673
674 for (; it != pass_register.end(); it++) {
675 if (it->first.substr(0, len) == text)
676 return strdup((it++)->first.c_str());
677 }
678 return NULL;
679 }
680
681 static char *readline_obj_generator(const char *text, int state)
682 {
683 static std::vector<char*> obj_names;
684 static size_t idx;
685
686 if (!state)
687 {
688 idx = 0;
689 obj_names.clear();
690
691 RTLIL::Design *design = yosys_get_design();
692 int len = strlen(text);
693
694 if (design->selected_active_module.empty())
695 {
696 for (auto &it : design->modules_)
697 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
698 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
699 }
700 else
701 if (design->modules_.count(design->selected_active_module) > 0)
702 {
703 RTLIL::Module *module = design->modules_.at(design->selected_active_module);
704
705 for (auto &it : module->wires_)
706 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
707 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
708
709 for (auto &it : module->memories)
710 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
711 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
712
713 for (auto &it : module->cells_)
714 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
715 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
716
717 for (auto &it : module->processes)
718 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
719 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
720 }
721
722 std::sort(obj_names.begin(), obj_names.end());
723 }
724
725 if (idx < obj_names.size())
726 return strdup(obj_names[idx++]);
727
728 idx = 0;
729 obj_names.clear();
730 return NULL;
731 }
732
733 static char **readline_completion(const char *text, int start, int)
734 {
735 if (start == 0)
736 return rl_completion_matches(text, readline_cmd_generator);
737 if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
738 return rl_completion_matches(text, readline_obj_generator);
739 return NULL;
740 }
741 #endif
742
743 void shell(RTLIL::Design *design)
744 {
745 static int recursion_counter = 0;
746
747 recursion_counter++;
748 log_cmd_error_throw = true;
749
750 #ifdef YOSYS_ENABLE_READLINE
751 rl_readline_name = "yosys";
752 rl_attempted_completion_function = readline_completion;
753 rl_basic_word_break_characters = " \t\n";
754 #endif
755
756 char *command = NULL;
757 #ifdef YOSYS_ENABLE_READLINE
758 while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
759 #else
760 char command_buffer[4096];
761 while ((command = fgets(command_buffer, 4096, stdin)) != NULL)
762 #endif
763 {
764 if (command[strspn(command, " \t\r\n")] == 0)
765 continue;
766 #ifdef YOSYS_ENABLE_READLINE
767 add_history(command);
768 #endif
769
770 char *p = command + strspn(command, " \t\r\n");
771 if (!strncmp(p, "exit", 4)) {
772 p += 4;
773 p += strspn(p, " \t\r\n");
774 if (*p == 0)
775 break;
776 }
777
778 try {
779 log_assert(design->selection_stack.size() == 1);
780 Pass::call(design, command);
781 } catch (log_cmd_error_expection) {
782 while (design->selection_stack.size() > 1)
783 design->selection_stack.pop_back();
784 log_reset_stack();
785 }
786 }
787 if (command == NULL)
788 printf("exit\n");
789
790 recursion_counter--;
791 log_cmd_error_throw = false;
792 }
793
794 struct ShellPass : public Pass {
795 ShellPass() : Pass("shell", "enter interactive command mode") { }
796 virtual void help() {
797 log("\n");
798 log(" shell\n");
799 log("\n");
800 log("This command enters the interactive command mode. This can be useful\n");
801 log("in a script to interrupt the script at a certain point and allow for\n");
802 log("interactive inspection or manual synthesis of the design at this point.\n");
803 log("\n");
804 log("The command prompt of the interactive shell indicates the current\n");
805 log("selection (see 'help select'):\n");
806 log("\n");
807 log(" yosys>\n");
808 log(" the entire design is selected\n");
809 log("\n");
810 log(" yosys*>\n");
811 log(" only part of the design is selected\n");
812 log("\n");
813 log(" yosys [modname]>\n");
814 log(" the entire module 'modname' is selected using 'select -module modname'\n");
815 log("\n");
816 log(" yosys [modname]*>\n");
817 log(" only part of current module 'modname' is selected\n");
818 log("\n");
819 log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
820 log("do not terminate yosys but return to the command prompt.\n");
821 log("\n");
822 log("This command is the default action if nothing else has been specified\n");
823 log("on the command line.\n");
824 log("\n");
825 log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
826 log("\n");
827 }
828 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
829 extra_args(args, 1, design, false);
830 shell(design);
831 }
832 } ShellPass;
833
834 #ifdef YOSYS_ENABLE_READLINE
835 struct HistoryPass : public Pass {
836 HistoryPass() : Pass("history", "show last interactive commands") { }
837 virtual void help() {
838 log("\n");
839 log(" history\n");
840 log("\n");
841 log("This command prints all commands in the shell history buffer. This are\n");
842 log("all commands executed in an interactive session, but not the commands\n");
843 log("from executed scripts.\n");
844 log("\n");
845 }
846 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
847 extra_args(args, 1, design, false);
848 for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
849 log("%s\n", (*list)->line);
850 }
851 } HistoryPass;
852 #endif
853
854 struct ScriptPass : public Pass {
855 ScriptPass() : Pass("script", "execute commands from script file") { }
856 virtual void help() {
857 log("\n");
858 log(" script <filename> [<from_label>:<to_label>]\n");
859 log("\n");
860 log("This command executes the yosys commands in the specified file.\n");
861 log("\n");
862 log("The 2nd argument can be used to only execute the section of the\n");
863 log("file between the specified labels. An empty from label is synonymous\n");
864 log("for the beginning of the file and an empty to label is synonymous\n");
865 log("for the end of the file.\n");
866 log("\n");
867 log("If only one label is specified (without ':') then only the block\n");
868 log("marked with that label (until the next label) is executed.\n");
869 log("\n");
870 }
871 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
872 if (args.size() < 2)
873 log_cmd_error("Missing script file.\n");
874 else if (args.size() == 2)
875 run_frontend(args[1], "script", design, NULL, NULL);
876 else if (args.size() == 3)
877 run_frontend(args[1], "script", design, NULL, &args[2]);
878 else
879 extra_args(args, 2, design, false);
880 }
881 } ScriptPass;
882
883 YOSYS_NAMESPACE_END
884