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