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