diff options
Diffstat (limited to 'kernel/yosys.cc')
-rw-r--r-- | kernel/yosys.cc | 479 |
1 files changed, 450 insertions, 29 deletions
diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 0ecb4cdaf..884b2c59b 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -18,26 +18,112 @@ */ #include "kernel/yosys.h" +#include "kernel/celltypes.h" #ifdef YOSYS_ENABLE_READLINE # include <readline/readline.h> # include <readline/history.h> #endif -#include <dlfcn.h> -#include <unistd.h> +#ifdef YOSYS_ENABLE_PLUGINS +# include <dlfcn.h> +#endif + +#ifdef _WIN32 +# include <windows.h> +# include <io.h> +#elif defined(__APPLE__) +# include <mach-o/dyld.h> +# include <unistd.h> +# include <dirent.h> +# include <sys/stat.h> +#else +# include <unistd.h> +# include <dirent.h> +# include <sys/types.h> +# include <sys/stat.h> +#endif + #include <limits.h> #include <errno.h> YOSYS_NAMESPACE_BEGIN int autoidx = 1; +int yosys_xtrace = 0; RTLIL::Design *yosys_design = NULL; +CellTypes yosys_celltypes; #ifdef YOSYS_ENABLE_TCL Tcl_Interp *yosys_tcl_interp = NULL; #endif +bool memhasher_active = false; +uint32_t memhasher_rng = 123456; +std::vector<void*> memhasher_store; + +void memhasher_on() +{ +#ifdef __linux__ + memhasher_rng += time(NULL) << 16 ^ getpid(); +#endif + memhasher_store.resize(0x10000); + memhasher_active = true; +} + +void memhasher_off() +{ + for (auto p : memhasher_store) + if (p) free(p); + memhasher_store.clear(); + memhasher_active = false; +} + +void memhasher_do() +{ + memhasher_rng ^= memhasher_rng << 13; + memhasher_rng ^= memhasher_rng >> 17; + memhasher_rng ^= memhasher_rng << 5; + + int size, index = (memhasher_rng >> 4) & 0xffff; + switch (memhasher_rng & 7) { + case 0: size = 16; break; + case 1: size = 256; break; + case 2: size = 1024; break; + case 3: size = 4096; break; + default: size = 0; + } + if (index < 16) size *= 16; + memhasher_store[index] = realloc(memhasher_store[index], size); +} + +void yosys_banner() +{ + log("\n"); + log(" /----------------------------------------------------------------------------\\\n"); + log(" | |\n"); + log(" | yosys -- Yosys Open SYnthesis Suite |\n"); + log(" | |\n"); + log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | |\n"); + log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); + log(" | purpose with or without fee is hereby granted, provided that the above |\n"); + log(" | copyright notice and this permission notice appear in all copies. |\n"); + log(" | |\n"); + log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n"); + log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n"); + log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n"); + log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n"); + log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n"); + log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n"); + log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n"); + log(" | |\n"); + log(" \\----------------------------------------------------------------------------/\n"); + log("\n"); + log(" %s\n", yosys_version_str); + log("\n"); +} + std::string stringf(const char *fmt, ...) { std::string string; @@ -55,8 +141,22 @@ std::string vstringf(const char *fmt, va_list ap) std::string string; char *str = NULL; +#ifdef _WIN32 + int sz = 64, rc; + while (1) { + va_list apc; + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } +#else if (vasprintf(&str, fmt, ap) < 0) str = NULL; +#endif if (str != NULL) { string = str; @@ -66,15 +166,264 @@ std::string vstringf(const char *fmt, va_list ap) return string; } -int SIZE(RTLIL::Wire *wire) +int readsome(std::istream &f, char *s, int n) +{ + int rc = f.readsome(s, n); + + // f.readsome() sometimes returns 0 on a non-empty stream.. + if (rc == 0) { + int c = f.get(); + if (c != EOF) { + *s = c; + rc = 1; + } + } + + return rc; +} + +std::string next_token(std::string &text, const char *sep) +{ + size_t pos_begin = text.find_first_not_of(sep); + + if (pos_begin == std::string::npos) + pos_begin = text.size(); + + size_t pos_end = text.find_first_of(sep, pos_begin); + + if (pos_end == std::string::npos) + pos_end = text.size(); + + std::string token = text.substr(pos_begin, pos_end-pos_begin); + text = text.substr(pos_end); + return token; +} + +// this is very similar to fnmatch(). the exact rules used by this +// function are: +// +// ? matches any character except +// * matches any sequence of characters +// [...] matches any of the characters in the list +// [!..] matches any of the characters not in the list +// +// a backslash may be used to escape the next characters in the +// pattern. each special character can also simply match itself. +// +bool patmatch(const char *pattern, const char *string) +{ + if (*pattern == 0) + return *string == 0; + + if (*pattern == '\\') { + if (pattern[1] == string[0] && patmatch(pattern+2, string+1)) + return true; + } + + if (*pattern == '?') { + if (*string == 0) + return false; + return patmatch(pattern+1, string+1); + } + + if (*pattern == '*') { + while (*string) { + if (patmatch(pattern+1, string++)) + return true; + } + return pattern[1] == 0; + } + + if (*pattern == '[') { + bool found_match = false; + bool inverted_list = pattern[1] == '!'; + const char *p = pattern + (inverted_list ? 1 : 0); + + while (*++p) { + if (*p == ']') { + if (found_match != inverted_list && patmatch(p+1, string+1)) + return true; + break; + } + + if (*p == '\\') { + if (*++p == *string) + found_match = true; + } else + if (*p == *string) + found_match = true; + } + } + + if (*pattern == *string) + return patmatch(pattern+1, string+1); + + return false; +} + +int run_command(const std::string &command, std::function<void(const std::string&)> process_line) +{ + if (!process_line) + return system(command.c_str()); + + FILE *f = popen(command.c_str(), "r"); + if (f == nullptr) + return -1; + + std::string line; + char logbuf[128]; + while (fgets(logbuf, 128, f) != NULL) { + line += logbuf; + if (!line.empty() && line.back() == '\n') + process_line(line), line.clear(); + } + if (!line.empty()) + process_line(line); + + int ret = pclose(f); + if (ret < 0) + return -1; +#ifdef _WIN32 + return ret; +#else + return WEXITSTATUS(ret); +#endif +} + +std::string make_temp_file(std::string template_str) +{ +#ifdef _WIN32 + if (template_str.rfind("/tmp/", 0) == 0) { +# ifdef __MINGW32__ + char longpath[MAX_PATH + 1]; + char shortpath[MAX_PATH + 1]; +# else + WCHAR longpath[MAX_PATH + 1]; + TCHAR shortpath[MAX_PATH + 1]; +# endif + if (!GetTempPath(MAX_PATH+1, longpath)) + log_error("GetTempPath() failed.\n"); + if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1)) + log_error("GetShortPathName() failed.\n"); + std::string path; + for (int i = 0; shortpath[i]; i++) + path += char(shortpath[i]); + template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5); + } + + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + while (1) { + for (int i = 0; i < 6; i++) { + static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static uint32_t x = 314159265 ^ uint32_t(time(NULL)); + x ^= x << 13, x ^= x >> 17, x ^= x << 5; + template_str[pos+i] = y[x % y.size()]; + } + if (_access(template_str.c_str(), 0) != 0) + break; + } +#else + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + int suffixlen = GetSize(template_str) - pos - 6; + + char *p = strdup(template_str.c_str()); + close(mkstemps(p, suffixlen)); + template_str = p; + free(p); +#endif + + return template_str; +} + +std::string make_temp_dir(std::string template_str) +{ +#ifdef _WIN32 + template_str = make_temp_file(template_str); + mkdir(template_str.c_str()); + return template_str; +#else +# ifndef NDEBUG + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + int suffixlen = GetSize(template_str) - pos - 6; + log_assert(suffixlen == 0); +# endif + + char *p = strdup(template_str.c_str()); + p = mkdtemp(p); + log_assert(p != NULL); + template_str = p; + free(p); + + return template_str; +#endif +} + +#ifdef _WIN32 +bool check_file_exists(std::string filename, bool) +{ + return _access(filename.c_str(), 0) == 0; +} +#else +bool check_file_exists(std::string filename, bool is_exec) +{ + return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0; +} +#endif + +bool is_absolute_path(std::string filename) +{ +#ifdef _WIN32 + return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':'); +#else + return filename[0] == '/'; +#endif +} + +void remove_directory(std::string dirname) +{ +#ifdef _WIN32 + run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str())); +#else + struct stat stbuf; + struct dirent **namelist; + int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort); + log_assert(n >= 0); + for (int i = 0; i < n; i++) { + if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) { + std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name); + if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) { + remove(buffer.c_str()); + } else + remove_directory(buffer); + } + free(namelist[i]); + } + free(namelist); + rmdir(dirname.c_str()); +#endif +} + +int GetSize(RTLIL::Wire *wire) { return wire->width; } void yosys_setup() { + // if there are already IdString objects then we have a global initialization order bug + IdString empty_id; + log_assert(empty_id.index_ == 0); + IdString::get_reference(empty_id.index_); + Pass::init_register(); yosys_design = new RTLIL::Design; + yosys_celltypes.setup(); log_push(); } @@ -92,6 +441,7 @@ void yosys_shutdown() log_files.clear(); Pass::done_register(); + yosys_celltypes.clear(); #ifdef YOSYS_ENABLE_TCL if (yosys_tcl_interp != NULL) { @@ -101,20 +451,33 @@ void yosys_shutdown() } #endif +#ifdef YOSYS_ENABLE_PLUGINS for (auto &it : loaded_plugins) dlclose(it.second); loaded_plugins.clear(); loaded_plugin_aliases.clear(); +#endif + + IdString empty_id; + IdString::put_reference(empty_id.index_); } RTLIL::IdString new_id(std::string file, int line, std::string func) { - std::string str = "$auto$"; +#ifdef _WIN32 + size_t pos = file.find_last_of("/\\"); +#else size_t pos = file.find_last_of('/'); - str += pos != std::string::npos ? file.substr(pos+1) : file; - str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++); - return str; +#endif + if (pos != std::string::npos) + file = file.substr(pos+1); + + pos = func.find_last_of(':'); + if (pos != std::string::npos) + func = func.substr(pos+1); + + return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++); } RTLIL::Design *yosys_get_design() @@ -210,9 +573,9 @@ struct TclPass : public Pass { #endif #if defined(__linux__) -std::string proc_self_dirname () +std::string proc_self_dirname() { - char path [PATH_MAX]; + char path[PATH_MAX]; ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); if (buflen < 0) { log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno)); @@ -222,10 +585,9 @@ std::string proc_self_dirname () return std::string(path, buflen); } #elif defined(__APPLE__) -#include <mach-o/dyld.h> -std::string proc_self_dirname () +std::string proc_self_dirname() { - char * path = NULL; + char *path = NULL; uint32_t buflen = 0; while (_NSGetExecutablePath(path, &buflen) != 0) path = (char *) realloc((void *) path, buflen); @@ -233,8 +595,32 @@ std::string proc_self_dirname () buflen--; return std::string(path, buflen); } +#elif defined(_WIN32) +std::string proc_self_dirname() +{ + int i = 0; +# ifdef __MINGW32__ + char longpath[MAX_PATH + 1]; + char shortpath[MAX_PATH + 1]; +# else + WCHAR longpath[MAX_PATH + 1]; + TCHAR shortpath[MAX_PATH + 1]; +# endif + if (!GetModuleFileName(0, longpath, MAX_PATH+1)) + log_error("GetModuleFileName() failed.\n"); + if (!GetShortPathName(longpath, shortpath, MAX_PATH+1)) + log_error("GetShortPathName() failed.\n"); + while (shortpath[i] != 0) + i++; + while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') + shortpath[--i] = 0; + std::string path; + for (i = 0; shortpath[i]; i++) + path += char(shortpath[i]); + return path; +} #elif defined(EMSCRIPTEN) -std::string proc_self_dirname () +std::string proc_self_dirname() { return "/"; } @@ -242,17 +628,33 @@ std::string proc_self_dirname () #error Dont know how to determine process executable base path! #endif -std::string proc_share_dirname () +#ifdef EMSCRIPTEN +std::string proc_share_dirname() +{ + return "/share"; +} +#else +std::string proc_share_dirname() { std::string proc_self_path = proc_self_dirname(); +# ifdef _WIN32 + std::string proc_share_path = proc_self_path + "share\\"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; + proc_share_path = proc_self_path + "..\\share\\"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; +# else std::string proc_share_path = proc_self_path + "share/"; - if (access(proc_share_path.c_str(), X_OK) == 0) + if (check_file_exists(proc_share_path, true)) return proc_share_path; proc_share_path = proc_self_path + "../share/yosys/"; - if (access(proc_share_path.c_str(), X_OK) == 0) + if (check_file_exists(proc_share_path, true)) return proc_share_path; +# endif log_error("proc_share_dirname: unable to determine share/ directory!\n"); } +#endif bool fgetline(FILE *f, std::string &buffer) { @@ -275,15 +677,15 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: int pos = 0; std::string label; - while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t')) + while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t')) pos++; - while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') + while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') label += command[pos++]; - if (label.back() == ':' && SIZE(label) > 1) + if (label.back() == ':' && GetSize(label) > 1) { - label = label.substr(0, SIZE(label)-1); + label = label.substr(0, GetSize(label)-1); command = command.substr(pos); if (label == run_from) @@ -293,8 +695,11 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: } } -void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label) +void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design) { + if (design == nullptr) + design = yosys_design; + if (command == "auto") { if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") command = "verilog"; @@ -361,9 +766,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi Pass::call(design, command); } } - catch (log_cmd_error_expection) { + catch (...) { Frontend::current_script_file = backup_script_file; - throw log_cmd_error_expection(); + throw; } Frontend::current_script_file = backup_script_file; @@ -386,15 +791,26 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi Frontend::frontend_call(design, NULL, filename, command); } +void run_frontend(std::string filename, std::string command, RTLIL::Design *design) +{ + run_frontend(filename, command, nullptr, nullptr, design); +} + void run_pass(std::string command, RTLIL::Design *design) { - log("\n-- Running pass `%s' --\n", command.c_str()); + if (design == nullptr) + design = yosys_design; + + log("\n-- Running command `%s' --\n", command.c_str()); Pass::call(design, command); } void run_backend(std::string filename, std::string command, RTLIL::Design *design) { + if (design == nullptr) + design = yosys_design; + if (command == "auto") { if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") command = "verilog"; @@ -518,11 +934,16 @@ void shell(RTLIL::Design *design) char *command = NULL; #ifdef YOSYS_ENABLE_READLINE while ((command = readline(create_prompt(design, recursion_counter))) != NULL) + { #else char command_buffer[4096]; - while ((command = fgets(command_buffer, 4096, stdin)) != NULL) -#endif + while (1) { + fputs(create_prompt(design, recursion_counter), stdout); + fflush(stdout); + if ((command = fgets(command_buffer, 4096, stdin)) == NULL) + break; +#endif if (command[strspn(command, " \t\r\n")] == 0) continue; #ifdef YOSYS_ENABLE_READLINE @@ -540,7 +961,7 @@ void shell(RTLIL::Design *design) try { log_assert(design->selection_stack.size() == 1); Pass::call(design, command); - } catch (log_cmd_error_expection) { + } catch (log_cmd_error_exception) { while (design->selection_stack.size() > 1) design->selection_stack.pop_back(); log_reset_stack(); @@ -634,9 +1055,9 @@ struct ScriptPass : public Pass { if (args.size() < 2) log_cmd_error("Missing script file.\n"); else if (args.size() == 2) - run_frontend(args[1], "script", design, NULL, NULL); + run_frontend(args[1], "script", design); else if (args.size() == 3) - run_frontend(args[1], "script", design, NULL, &args[2]); + run_frontend(args[1], "script", NULL, &args[2], design); else extra_args(args, 2, design, false); } |