Python passes are now looked for in share/plugins and can be added by specifying...
[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 #include "kernel/celltypes.h"
22
23 #ifdef YOSYS_ENABLE_READLINE
24 # include <readline/readline.h>
25 # include <readline/history.h>
26 #endif
27
28 #ifdef YOSYS_ENABLE_EDITLINE
29 # include <editline/readline.h>
30 #endif
31
32 #ifdef YOSYS_ENABLE_PLUGINS
33 # include <dlfcn.h>
34 #endif
35
36 #ifdef _WIN32
37 # include <windows.h>
38 # include <io.h>
39 #elif defined(__APPLE__)
40 # include <mach-o/dyld.h>
41 # include <unistd.h>
42 # include <dirent.h>
43 # include <sys/stat.h>
44 # include <glob.h>
45 #else
46 # include <unistd.h>
47 # include <dirent.h>
48 # include <sys/types.h>
49 # include <sys/wait.h>
50 # include <sys/stat.h>
51 # include <glob.h>
52 #endif
53
54 #ifdef __FreeBSD__
55 # include <sys/sysctl.h>
56 #endif
57
58 #ifdef WITH_PYTHON
59 #if PY_MAJOR_VERSION >= 3
60 # define INIT_MODULE PyInit_libyosys
61 extern "C" PyObject* INIT_MODULE();
62 #else
63 # define INIT_MODULE initlibyosys
64 extern "C" void INIT_MODULE();
65 #endif
66 #endif
67
68 #include <limits.h>
69 #include <errno.h>
70
71 YOSYS_NAMESPACE_BEGIN
72
73 int autoidx = 1;
74 int yosys_xtrace = 0;
75 RTLIL::Design *yosys_design = NULL;
76 CellTypes yosys_celltypes;
77
78 #ifdef YOSYS_ENABLE_TCL
79 Tcl_Interp *yosys_tcl_interp = NULL;
80 #endif
81
82 std::set<std::string> yosys_input_files, yosys_output_files;
83
84 bool memhasher_active = false;
85 uint32_t memhasher_rng = 123456;
86 std::vector<void*> memhasher_store;
87
88 void memhasher_on()
89 {
90 #if defined(__linux__) || defined(__FreeBSD__)
91 memhasher_rng += time(NULL) << 16 ^ getpid();
92 #endif
93 memhasher_store.resize(0x10000);
94 memhasher_active = true;
95 }
96
97 void memhasher_off()
98 {
99 for (auto p : memhasher_store)
100 if (p) free(p);
101 memhasher_store.clear();
102 memhasher_active = false;
103 }
104
105 void memhasher_do()
106 {
107 memhasher_rng ^= memhasher_rng << 13;
108 memhasher_rng ^= memhasher_rng >> 17;
109 memhasher_rng ^= memhasher_rng << 5;
110
111 int size, index = (memhasher_rng >> 4) & 0xffff;
112 switch (memhasher_rng & 7) {
113 case 0: size = 16; break;
114 case 1: size = 256; break;
115 case 2: size = 1024; break;
116 case 3: size = 4096; break;
117 default: size = 0;
118 }
119 if (index < 16) size *= 16;
120 memhasher_store[index] = realloc(memhasher_store[index], size);
121 }
122
123 void yosys_banner()
124 {
125 log("\n");
126 log(" /----------------------------------------------------------------------------\\\n");
127 log(" | |\n");
128 log(" | yosys -- Yosys Open SYnthesis Suite |\n");
129 log(" | |\n");
130 log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n");
131 log(" | |\n");
132 log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
133 log(" | purpose with or without fee is hereby granted, provided that the above |\n");
134 log(" | copyright notice and this permission notice appear in all copies. |\n");
135 log(" | |\n");
136 log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
137 log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
138 log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
139 log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
140 log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
141 log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
142 log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
143 log(" | |\n");
144 log(" \\----------------------------------------------------------------------------/\n");
145 log("\n");
146 log(" %s\n", yosys_version_str);
147 log("\n");
148 }
149
150 int ceil_log2(int x)
151 {
152 if (x <= 0)
153 return 0;
154
155 for (int i = 0; i < 32; i++)
156 if (((x-1) >> i) == 0)
157 return i;
158
159 log_abort();
160 }
161
162 std::string stringf(const char *fmt, ...)
163 {
164 std::string string;
165 va_list ap;
166
167 va_start(ap, fmt);
168 string = vstringf(fmt, ap);
169 va_end(ap);
170
171 return string;
172 }
173
174 std::string vstringf(const char *fmt, va_list ap)
175 {
176 std::string string;
177 char *str = NULL;
178
179 #ifdef _WIN32
180 int sz = 64, rc;
181 while (1) {
182 va_list apc;
183 va_copy(apc, ap);
184 str = (char*)realloc(str, sz);
185 rc = vsnprintf(str, sz, fmt, apc);
186 va_end(apc);
187 if (rc >= 0 && rc < sz)
188 break;
189 sz *= 2;
190 }
191 #else
192 if (vasprintf(&str, fmt, ap) < 0)
193 str = NULL;
194 #endif
195
196 if (str != NULL) {
197 string = str;
198 free(str);
199 }
200
201 return string;
202 }
203
204 int readsome(std::istream &f, char *s, int n)
205 {
206 int rc = int(f.readsome(s, n));
207
208 // f.readsome() sometimes returns 0 on a non-empty stream..
209 if (rc == 0) {
210 int c = f.get();
211 if (c != EOF) {
212 *s = c;
213 rc = 1;
214 }
215 }
216
217 return rc;
218 }
219
220 std::string next_token(std::string &text, const char *sep, bool long_strings)
221 {
222 size_t pos_begin = text.find_first_not_of(sep);
223
224 if (pos_begin == std::string::npos)
225 pos_begin = text.size();
226
227 if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
228 string sep_string = sep;
229 for (size_t i = pos_begin+1; i < text.size(); i++)
230 if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
231 std::string token = text.substr(pos_begin, i-pos_begin+1);
232 text = text.substr(i+1);
233 return token;
234 }
235 }
236
237 size_t pos_end = text.find_first_of(sep, pos_begin);
238
239 if (pos_end == std::string::npos)
240 pos_end = text.size();
241
242 std::string token = text.substr(pos_begin, pos_end-pos_begin);
243 text = text.substr(pos_end);
244 return token;
245 }
246
247 std::vector<std::string> split_tokens(const std::string &text, const char *sep)
248 {
249 std::vector<std::string> tokens;
250 std::string current_token;
251 for (char c : text) {
252 if (strchr(sep, c)) {
253 if (!current_token.empty()) {
254 tokens.push_back(current_token);
255 current_token.clear();
256 }
257 } else
258 current_token += c;
259 }
260 if (!current_token.empty()) {
261 tokens.push_back(current_token);
262 current_token.clear();
263 }
264 return tokens;
265 }
266
267 // this is very similar to fnmatch(). the exact rules used by this
268 // function are:
269 //
270 // ? matches any character except
271 // * matches any sequence of characters
272 // [...] matches any of the characters in the list
273 // [!..] matches any of the characters not in the list
274 //
275 // a backslash may be used to escape the next characters in the
276 // pattern. each special character can also simply match itself.
277 //
278 bool patmatch(const char *pattern, const char *string)
279 {
280 if (*pattern == 0)
281 return *string == 0;
282
283 if (*pattern == '\\') {
284 if (pattern[1] == string[0] && patmatch(pattern+2, string+1))
285 return true;
286 }
287
288 if (*pattern == '?') {
289 if (*string == 0)
290 return false;
291 return patmatch(pattern+1, string+1);
292 }
293
294 if (*pattern == '*') {
295 while (*string) {
296 if (patmatch(pattern+1, string++))
297 return true;
298 }
299 return pattern[1] == 0;
300 }
301
302 if (*pattern == '[') {
303 bool found_match = false;
304 bool inverted_list = pattern[1] == '!';
305 const char *p = pattern + (inverted_list ? 1 : 0);
306
307 while (*++p) {
308 if (*p == ']') {
309 if (found_match != inverted_list && patmatch(p+1, string+1))
310 return true;
311 break;
312 }
313
314 if (*p == '\\') {
315 if (*++p == *string)
316 found_match = true;
317 } else
318 if (*p == *string)
319 found_match = true;
320 }
321 }
322
323 if (*pattern == *string)
324 return patmatch(pattern+1, string+1);
325
326 return false;
327 }
328
329 int run_command(const std::string &command, std::function<void(const std::string&)> process_line)
330 {
331 if (!process_line)
332 return system(command.c_str());
333
334 FILE *f = popen(command.c_str(), "r");
335 if (f == nullptr)
336 return -1;
337
338 std::string line;
339 char logbuf[128];
340 while (fgets(logbuf, 128, f) != NULL) {
341 line += logbuf;
342 if (!line.empty() && line.back() == '\n')
343 process_line(line), line.clear();
344 }
345 if (!line.empty())
346 process_line(line);
347
348 int ret = pclose(f);
349 if (ret < 0)
350 return -1;
351 #ifdef _WIN32
352 return ret;
353 #else
354 return WEXITSTATUS(ret);
355 #endif
356 }
357
358 std::string make_temp_file(std::string template_str)
359 {
360 #ifdef _WIN32
361 if (template_str.rfind("/tmp/", 0) == 0) {
362 # ifdef __MINGW32__
363 char longpath[MAX_PATH + 1];
364 char shortpath[MAX_PATH + 1];
365 # else
366 WCHAR longpath[MAX_PATH + 1];
367 TCHAR shortpath[MAX_PATH + 1];
368 # endif
369 if (!GetTempPath(MAX_PATH+1, longpath))
370 log_error("GetTempPath() failed.\n");
371 if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
372 log_error("GetShortPathName() failed.\n");
373 std::string path;
374 for (int i = 0; shortpath[i]; i++)
375 path += char(shortpath[i]);
376 template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
377 }
378
379 size_t pos = template_str.rfind("XXXXXX");
380 log_assert(pos != std::string::npos);
381
382 while (1) {
383 for (int i = 0; i < 6; i++) {
384 static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
385 static uint32_t x = 314159265 ^ uint32_t(time(NULL));
386 x ^= x << 13, x ^= x >> 17, x ^= x << 5;
387 template_str[pos+i] = y[x % y.size()];
388 }
389 if (_access(template_str.c_str(), 0) != 0)
390 break;
391 }
392 #else
393 size_t pos = template_str.rfind("XXXXXX");
394 log_assert(pos != std::string::npos);
395
396 int suffixlen = GetSize(template_str) - pos - 6;
397
398 char *p = strdup(template_str.c_str());
399 close(mkstemps(p, suffixlen));
400 template_str = p;
401 free(p);
402 #endif
403
404 return template_str;
405 }
406
407 std::string make_temp_dir(std::string template_str)
408 {
409 #ifdef _WIN32
410 template_str = make_temp_file(template_str);
411 mkdir(template_str.c_str());
412 return template_str;
413 #else
414 # ifndef NDEBUG
415 size_t pos = template_str.rfind("XXXXXX");
416 log_assert(pos != std::string::npos);
417
418 int suffixlen = GetSize(template_str) - pos - 6;
419 log_assert(suffixlen == 0);
420 # endif
421
422 char *p = strdup(template_str.c_str());
423 p = mkdtemp(p);
424 log_assert(p != NULL);
425 template_str = p;
426 free(p);
427
428 return template_str;
429 #endif
430 }
431
432 #ifdef _WIN32
433 bool check_file_exists(std::string filename, bool)
434 {
435 return _access(filename.c_str(), 0) == 0;
436 }
437 #else
438 bool check_file_exists(std::string filename, bool is_exec)
439 {
440 return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
441 }
442 #endif
443
444 bool is_absolute_path(std::string filename)
445 {
446 #ifdef _WIN32
447 return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':');
448 #else
449 return filename[0] == '/';
450 #endif
451 }
452
453 void remove_directory(std::string dirname)
454 {
455 #ifdef _WIN32
456 run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
457 #else
458 struct stat stbuf;
459 struct dirent **namelist;
460 int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
461 log_assert(n >= 0);
462 for (int i = 0; i < n; i++) {
463 if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
464 std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
465 if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
466 remove(buffer.c_str());
467 } else
468 remove_directory(buffer);
469 }
470 free(namelist[i]);
471 }
472 free(namelist);
473 rmdir(dirname.c_str());
474 #endif
475 }
476
477 int GetSize(RTLIL::Wire *wire)
478 {
479 return wire->width;
480 }
481
482 bool already_setup = false;
483
484 void yosys_setup()
485 {
486 if(already_setup)
487 return;
488 already_setup = true;
489 // if there are already IdString objects then we have a global initialization order bug
490 IdString empty_id;
491 log_assert(empty_id.index_ == 0);
492 IdString::get_reference(empty_id.index_);
493
494 #ifdef WITH_PYTHON
495 PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
496 Py_Initialize();
497 PyRun_SimpleString("import sys");
498 PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
499 #endif
500
501 Pass::init_register();
502 yosys_design = new RTLIL::Design;
503 yosys_celltypes.setup();
504 log_push();
505 }
506
507 bool yosys_already_setup()
508 {
509 return already_setup;
510 }
511
512 bool already_shutdown = false;
513
514 void yosys_shutdown()
515 {
516 if(already_shutdown)
517 return;
518 already_shutdown = true;
519 log_pop();
520
521 delete yosys_design;
522 yosys_design = NULL;
523
524 for (auto f : log_files)
525 if (f != stderr)
526 fclose(f);
527 log_errfile = NULL;
528 log_files.clear();
529
530 Pass::done_register();
531 yosys_celltypes.clear();
532
533 #ifdef YOSYS_ENABLE_TCL
534 if (yosys_tcl_interp != NULL) {
535 Tcl_DeleteInterp(yosys_tcl_interp);
536 Tcl_Finalize();
537 yosys_tcl_interp = NULL;
538 }
539 #endif
540
541 #ifdef YOSYS_ENABLE_PLUGINS
542 for (auto &it : loaded_plugins)
543 dlclose(it.second);
544
545 loaded_plugins.clear();
546 #ifdef WITH_PYTHON
547 loaded_python_plugins.clear();
548 #endif
549 loaded_plugin_aliases.clear();
550 #endif
551
552 #ifdef WITH_PYTHON
553 Py_Finalize();
554 #endif
555
556 IdString empty_id;
557 IdString::put_reference(empty_id.index_);
558 }
559
560 RTLIL::IdString new_id(std::string file, int line, std::string func)
561 {
562 #ifdef _WIN32
563 size_t pos = file.find_last_of("/\\");
564 #else
565 size_t pos = file.find_last_of('/');
566 #endif
567 if (pos != std::string::npos)
568 file = file.substr(pos+1);
569
570 pos = func.find_last_of(':');
571 if (pos != std::string::npos)
572 func = func.substr(pos+1);
573
574 return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
575 }
576
577 RTLIL::Design *yosys_get_design()
578 {
579 return yosys_design;
580 }
581
582 const char *create_prompt(RTLIL::Design *design, int recursion_counter)
583 {
584 static char buffer[100];
585 std::string str = "\n";
586 if (recursion_counter > 1)
587 str += stringf("(%d) ", recursion_counter);
588 str += "yosys";
589 if (!design->selected_active_module.empty())
590 str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
591 if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
592 if (design->selected_active_module.empty())
593 str += "*";
594 else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
595 design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
596 str += "*";
597 }
598 snprintf(buffer, 100, "%s> ", str.c_str());
599 return buffer;
600 }
601
602 std::vector<std::string> glob_filename(const std::string &filename_pattern)
603 {
604 std::vector<std::string> results;
605
606 #ifdef _WIN32
607 results.push_back(filename_pattern);
608 #else
609 glob_t globbuf;
610
611 int err = glob(filename_pattern.c_str(), 0, NULL, &globbuf);
612
613 if(err == 0) {
614 for (size_t i = 0; i < globbuf.gl_pathc; i++)
615 results.push_back(globbuf.gl_pathv[i]);
616 globfree(&globbuf);
617 } else {
618 results.push_back(filename_pattern);
619 }
620 #endif
621
622 return results;
623 }
624
625 void rewrite_filename(std::string &filename)
626 {
627 if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"")
628 filename = filename.substr(1, GetSize(filename)-2);
629 if (filename.substr(0, 2) == "+/")
630 filename = proc_share_dirname() + filename.substr(2);
631 }
632
633 #ifdef YOSYS_ENABLE_TCL
634 static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
635 {
636 std::vector<std::string> args;
637 for (int i = 1; i < argc; i++)
638 args.push_back(argv[i]);
639
640 if (args.size() >= 1 && args[0] == "-import") {
641 for (auto &it : pass_register) {
642 std::string tcl_command_name = it.first;
643 if (tcl_command_name == "proc")
644 tcl_command_name = "procs";
645 else if (tcl_command_name == "rename")
646 tcl_command_name = "renames";
647 Tcl_CmdInfo info;
648 if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
649 log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
650 } else {
651 std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
652 Tcl_Eval(interp, tcl_script.c_str());
653 }
654 }
655 return TCL_OK;
656 }
657
658 if (args.size() == 1) {
659 Pass::call(yosys_get_design(), args[0]);
660 return TCL_OK;
661 }
662
663 Pass::call(yosys_get_design(), args);
664 return TCL_OK;
665 }
666
667 extern Tcl_Interp *yosys_get_tcl_interp()
668 {
669 if (yosys_tcl_interp == NULL) {
670 yosys_tcl_interp = Tcl_CreateInterp();
671 Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
672 }
673 return yosys_tcl_interp;
674 }
675
676 struct TclPass : public Pass {
677 TclPass() : Pass("tcl", "execute a TCL script file") { }
678 virtual void help() {
679 log("\n");
680 log(" tcl <filename>\n");
681 log("\n");
682 log("This command executes the tcl commands in the specified file.\n");
683 log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
684 log("\n");
685 log("The tcl command 'yosys -import' can be used to import all yosys\n");
686 log("commands directly as tcl commands to the tcl shell. Yosys commands\n");
687 log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
688 log("in order to avoid a name collision with the built in commands.\n");
689 log("\n");
690 }
691 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
692 if (args.size() < 2)
693 log_cmd_error("Missing script file.\n");
694 if (args.size() > 2)
695 extra_args(args, 1, design, false);
696 if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
697 log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
698 }
699 } TclPass;
700 #endif
701
702 #if defined(__linux__) || defined(__CYGWIN__)
703 std::string proc_self_dirname()
704 {
705 char path[PATH_MAX];
706 ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
707 if (buflen < 0) {
708 log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
709 }
710 while (buflen > 0 && path[buflen-1] != '/')
711 buflen--;
712 return std::string(path, buflen);
713 }
714 #elif defined(__FreeBSD__)
715 std::string proc_self_dirname()
716 {
717 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
718 size_t buflen;
719 char *buffer;
720 std::string path;
721 if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0)
722 log_error("sysctl failed: %s\n", strerror(errno));
723 buffer = (char*)malloc(buflen);
724 if (buffer == NULL)
725 log_error("malloc failed: %s\n", strerror(errno));
726 if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0)
727 log_error("sysctl failed: %s\n", strerror(errno));
728 while (buflen > 0 && buffer[buflen-1] != '/')
729 buflen--;
730 path.assign(buffer, buflen);
731 free(buffer);
732 return path;
733 }
734 #elif defined(__APPLE__)
735 std::string proc_self_dirname()
736 {
737 char *path = NULL;
738 uint32_t buflen = 0;
739 while (_NSGetExecutablePath(path, &buflen) != 0)
740 path = (char *) realloc((void *) path, buflen);
741 while (buflen > 0 && path[buflen-1] != '/')
742 buflen--;
743 return std::string(path, buflen);
744 }
745 #elif defined(_WIN32)
746 std::string proc_self_dirname()
747 {
748 int i = 0;
749 # ifdef __MINGW32__
750 char longpath[MAX_PATH + 1];
751 char shortpath[MAX_PATH + 1];
752 # else
753 WCHAR longpath[MAX_PATH + 1];
754 TCHAR shortpath[MAX_PATH + 1];
755 # endif
756 if (!GetModuleFileName(0, longpath, MAX_PATH+1))
757 log_error("GetModuleFileName() failed.\n");
758 if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
759 log_error("GetShortPathName() failed.\n");
760 while (shortpath[i] != 0)
761 i++;
762 while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\')
763 shortpath[--i] = 0;
764 std::string path;
765 for (i = 0; shortpath[i]; i++)
766 path += char(shortpath[i]);
767 return path;
768 }
769 #elif defined(EMSCRIPTEN)
770 std::string proc_self_dirname()
771 {
772 return "/";
773 }
774 #else
775 #error Dont know how to determine process executable base path!
776 #endif
777
778 #ifdef EMSCRIPTEN
779 std::string proc_share_dirname()
780 {
781 return "/share/";
782 }
783 #else
784 std::string proc_share_dirname()
785 {
786 std::string proc_self_path = proc_self_dirname();
787 # if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
788 std::string proc_share_path = proc_self_path + "share\\";
789 if (check_file_exists(proc_share_path, true))
790 return proc_share_path;
791 proc_share_path = proc_self_path + "..\\share\\";
792 if (check_file_exists(proc_share_path, true))
793 return proc_share_path;
794 # else
795 std::string proc_share_path = proc_self_path + "share/";
796 if (check_file_exists(proc_share_path, true))
797 return proc_share_path;
798 proc_share_path = proc_self_path + "../share/yosys/";
799 if (check_file_exists(proc_share_path, true))
800 return proc_share_path;
801 # ifdef YOSYS_DATDIR
802 proc_share_path = YOSYS_DATDIR "/";
803 if (check_file_exists(proc_share_path, true))
804 return proc_share_path;
805 # endif
806 # endif
807 log_error("proc_share_dirname: unable to determine share/ directory!\n");
808 }
809 #endif
810
811 bool fgetline(FILE *f, std::string &buffer)
812 {
813 buffer = "";
814 char block[4096];
815 while (1) {
816 if (fgets(block, 4096, f) == NULL)
817 return false;
818 buffer += block;
819 if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
820 while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
821 buffer.resize(buffer.size()-1);
822 return true;
823 }
824 }
825 }
826
827 static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
828 {
829 int pos = 0;
830 std::string label;
831
832 while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
833 pos++;
834
835 if (pos < GetSize(command) && command[pos] == '#')
836 return;
837
838 while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
839 label += command[pos++];
840
841 if (label.back() == ':' && GetSize(label) > 1)
842 {
843 label = label.substr(0, GetSize(label)-1);
844 command = command.substr(pos);
845
846 if (label == run_from)
847 from_to_active = true;
848 else if (label == run_to || (run_from == run_to && !run_from.empty()))
849 from_to_active = false;
850 }
851 }
852
853 void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
854 {
855 if (design == nullptr)
856 design = yosys_design;
857
858 if (command == "auto") {
859 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
860 command = "verilog";
861 else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
862 command = "verilog -sv";
863 else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd")
864 command = "vhdl";
865 else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
866 command = "blif";
867 else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
868 command = "json";
869 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
870 command = "ilang";
871 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
872 command = "script";
873 else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl")
874 command = "tcl";
875 else if (filename == "-")
876 command = "script";
877 else
878 log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
879 }
880
881 if (command == "script")
882 {
883 std::string run_from, run_to;
884 bool from_to_active = true;
885
886 if (from_to_label != NULL) {
887 size_t pos = from_to_label->find(':');
888 if (pos == std::string::npos) {
889 run_from = *from_to_label;
890 run_to = *from_to_label;
891 } else {
892 run_from = from_to_label->substr(0, pos);
893 run_to = from_to_label->substr(pos+1);
894 }
895 from_to_active = run_from.empty();
896 }
897
898 log("\n-- Executing script file `%s' --\n", filename.c_str());
899
900 FILE *f = stdin;
901
902 if (filename != "-") {
903 f = fopen(filename.c_str(), "r");
904 yosys_input_files.insert(filename);
905 }
906
907 if (f == NULL)
908 log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
909
910 FILE *backup_script_file = Frontend::current_script_file;
911 Frontend::current_script_file = f;
912
913 try {
914 std::string command;
915 while (fgetline(f, command)) {
916 while (!command.empty() && command[command.size()-1] == '\\') {
917 std::string next_line;
918 if (!fgetline(f, next_line))
919 break;
920 command.resize(command.size()-1);
921 command += next_line;
922 }
923 handle_label(command, from_to_active, run_from, run_to);
924 if (from_to_active)
925 Pass::call(design, command);
926 }
927
928 if (!command.empty()) {
929 handle_label(command, from_to_active, run_from, run_to);
930 if (from_to_active)
931 Pass::call(design, command);
932 }
933 }
934 catch (...) {
935 Frontend::current_script_file = backup_script_file;
936 throw;
937 }
938
939 Frontend::current_script_file = backup_script_file;
940
941 if (filename != "-")
942 fclose(f);
943
944 if (backend_command != NULL && *backend_command == "auto")
945 *backend_command = "";
946
947 return;
948 }
949
950 if (filename == "-") {
951 log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
952 } else {
953 log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
954 }
955
956 if (command == "tcl")
957 Pass::call(design, vector<string>({command, filename}));
958 else
959 Frontend::frontend_call(design, NULL, filename, command);
960 }
961
962 void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
963 {
964 run_frontend(filename, command, nullptr, nullptr, design);
965 }
966
967 void run_pass(std::string command, RTLIL::Design *design)
968 {
969 if (design == nullptr)
970 design = yosys_design;
971
972 log("\n-- Running command `%s' --\n", command.c_str());
973
974 Pass::call(design, command);
975 }
976
977 void run_backend(std::string filename, std::string command, RTLIL::Design *design)
978 {
979 if (design == nullptr)
980 design = yosys_design;
981
982 if (command == "auto") {
983 if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
984 command = "verilog";
985 else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
986 command = "ilang";
987 else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig")
988 command = "aiger";
989 else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
990 command = "blif";
991 else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif")
992 command = "edif";
993 else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".json")
994 command = "json";
995 else if (filename == "-")
996 command = "ilang";
997 else if (filename.empty())
998 return;
999 else
1000 log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
1001 }
1002
1003 if (filename.empty())
1004 filename = "-";
1005
1006 if (filename == "-") {
1007 log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
1008 } else {
1009 log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
1010 }
1011
1012 Backend::backend_call(design, NULL, filename, command);
1013 }
1014
1015 #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
1016 static char *readline_cmd_generator(const char *text, int state)
1017 {
1018 static std::map<std::string, Pass*>::iterator it;
1019 static int len;
1020
1021 if (!state) {
1022 it = pass_register.begin();
1023 len = strlen(text);
1024 }
1025
1026 for (; it != pass_register.end(); it++) {
1027 if (it->first.substr(0, len) == text)
1028 return strdup((it++)->first.c_str());
1029 }
1030 return NULL;
1031 }
1032
1033 static char *readline_obj_generator(const char *text, int state)
1034 {
1035 static std::vector<char*> obj_names;
1036 static size_t idx;
1037
1038 if (!state)
1039 {
1040 idx = 0;
1041 obj_names.clear();
1042
1043 RTLIL::Design *design = yosys_get_design();
1044 int len = strlen(text);
1045
1046 if (design->selected_active_module.empty())
1047 {
1048 for (auto &it : design->modules_)
1049 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
1050 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
1051 }
1052 else
1053 if (design->modules_.count(design->selected_active_module) > 0)
1054 {
1055 RTLIL::Module *module = design->modules_.at(design->selected_active_module);
1056
1057 for (auto &it : module->wires_)
1058 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
1059 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
1060
1061 for (auto &it : module->memories)
1062 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
1063 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
1064
1065 for (auto &it : module->cells_)
1066 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
1067 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
1068
1069 for (auto &it : module->processes)
1070 if (RTLIL::unescape_id(it.first).substr(0, len) == text)
1071 obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
1072 }
1073
1074 std::sort(obj_names.begin(), obj_names.end());
1075 }
1076
1077 if (idx < obj_names.size())
1078 return strdup(obj_names[idx++]);
1079
1080 idx = 0;
1081 obj_names.clear();
1082 return NULL;
1083 }
1084
1085 static char **readline_completion(const char *text, int start, int)
1086 {
1087 if (start == 0)
1088 return rl_completion_matches(text, readline_cmd_generator);
1089 if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
1090 return rl_completion_matches(text, readline_obj_generator);
1091 return NULL;
1092 }
1093 #endif
1094
1095 void shell(RTLIL::Design *design)
1096 {
1097 static int recursion_counter = 0;
1098
1099 recursion_counter++;
1100 log_cmd_error_throw = true;
1101
1102 #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
1103 rl_readline_name = (char*)"yosys";
1104 rl_attempted_completion_function = readline_completion;
1105 rl_basic_word_break_characters = (char*)" \t\n";
1106 #endif
1107
1108 char *command = NULL;
1109 #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
1110 while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
1111 {
1112 #else
1113 char command_buffer[4096];
1114 while (1)
1115 {
1116 fputs(create_prompt(design, recursion_counter), stdout);
1117 fflush(stdout);
1118 if ((command = fgets(command_buffer, 4096, stdin)) == NULL)
1119 break;
1120 #endif
1121 if (command[strspn(command, " \t\r\n")] == 0)
1122 continue;
1123 #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
1124 add_history(command);
1125 #endif
1126
1127 char *p = command + strspn(command, " \t\r\n");
1128 if (!strncmp(p, "exit", 4)) {
1129 p += 4;
1130 p += strspn(p, " \t\r\n");
1131 if (*p == 0)
1132 break;
1133 }
1134
1135 try {
1136 log_assert(design->selection_stack.size() == 1);
1137 Pass::call(design, command);
1138 } catch (log_cmd_error_exception) {
1139 while (design->selection_stack.size() > 1)
1140 design->selection_stack.pop_back();
1141 log_reset_stack();
1142 }
1143 }
1144 if (command == NULL)
1145 printf("exit\n");
1146
1147 recursion_counter--;
1148 log_cmd_error_throw = false;
1149 }
1150
1151 struct ShellPass : public Pass {
1152 ShellPass() : Pass("shell", "enter interactive command mode") { }
1153 virtual void help() {
1154 log("\n");
1155 log(" shell\n");
1156 log("\n");
1157 log("This command enters the interactive command mode. This can be useful\n");
1158 log("in a script to interrupt the script at a certain point and allow for\n");
1159 log("interactive inspection or manual synthesis of the design at this point.\n");
1160 log("\n");
1161 log("The command prompt of the interactive shell indicates the current\n");
1162 log("selection (see 'help select'):\n");
1163 log("\n");
1164 log(" yosys>\n");
1165 log(" the entire design is selected\n");
1166 log("\n");
1167 log(" yosys*>\n");
1168 log(" only part of the design is selected\n");
1169 log("\n");
1170 log(" yosys [modname]>\n");
1171 log(" the entire module 'modname' is selected using 'select -module modname'\n");
1172 log("\n");
1173 log(" yosys [modname]*>\n");
1174 log(" only part of current module 'modname' is selected\n");
1175 log("\n");
1176 log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
1177 log("do not terminate yosys but return to the command prompt.\n");
1178 log("\n");
1179 log("This command is the default action if nothing else has been specified\n");
1180 log("on the command line.\n");
1181 log("\n");
1182 log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
1183 log("\n");
1184 }
1185 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
1186 extra_args(args, 1, design, false);
1187 shell(design);
1188 }
1189 } ShellPass;
1190
1191 #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
1192 struct HistoryPass : public Pass {
1193 HistoryPass() : Pass("history", "show last interactive commands") { }
1194 virtual void help() {
1195 log("\n");
1196 log(" history\n");
1197 log("\n");
1198 log("This command prints all commands in the shell history buffer. This are\n");
1199 log("all commands executed in an interactive session, but not the commands\n");
1200 log("from executed scripts.\n");
1201 log("\n");
1202 }
1203 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
1204 extra_args(args, 1, design, false);
1205 #ifdef YOSYS_ENABLE_READLINE
1206 for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
1207 log("%s\n", (*list)->line);
1208 #else
1209 for (int i = where_history(); history_get(i); i++)
1210 log("%s\n", history_get(i)->line);
1211 #endif
1212 }
1213 } HistoryPass;
1214 #endif
1215
1216 struct ScriptCmdPass : public Pass {
1217 ScriptCmdPass() : Pass("script", "execute commands from script file") { }
1218 virtual void help() {
1219 log("\n");
1220 log(" script <filename> [<from_label>:<to_label>]\n");
1221 log("\n");
1222 log("This command executes the yosys commands in the specified file.\n");
1223 log("\n");
1224 log("The 2nd argument can be used to only execute the section of the\n");
1225 log("file between the specified labels. An empty from label is synonymous\n");
1226 log("for the beginning of the file and an empty to label is synonymous\n");
1227 log("for the end of the file.\n");
1228 log("\n");
1229 log("If only one label is specified (without ':') then only the block\n");
1230 log("marked with that label (until the next label) is executed.\n");
1231 log("\n");
1232 }
1233 virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
1234 if (args.size() < 2)
1235 log_cmd_error("Missing script file.\n");
1236 else if (args.size() == 2)
1237 run_frontend(args[1], "script", design);
1238 else if (args.size() == 3)
1239 run_frontend(args[1], "script", NULL, &args[2], design);
1240 else
1241 extra_args(args, 2, design, false);
1242 }
1243 } ScriptCmdPass;
1244
1245 YOSYS_NAMESPACE_END