diff --git a/Makefile b/Makefile index 1ef5bd160..ee969b09e 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXSTD ?= c++17 -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include +CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -Werror=implicit-function-declaration -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm PLUGIN_LINKFLAGS := PLUGIN_LIBS := @@ -611,6 +611,7 @@ ifeq ($(ENABLE_ZLIB),1) $(eval $(call add_include_file,kernel/fstdata.h)) endif $(eval $(call add_include_file,kernel/hashlib.h)) +$(eval $(call add_include_file,kernel/io.h)) $(eval $(call add_include_file,kernel/json.h)) $(eval $(call add_include_file,kernel/log.h)) $(eval $(call add_include_file,kernel/macc.h)) @@ -641,7 +642,7 @@ $(eval $(call add_include_file,frontends/ast/ast_binding.h)) $(eval $(call add_include_file,frontends/blif/blifparse.h)) $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) -OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o +OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o OBJS += kernel/binding.o kernel/tclapi.o OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o OBJS += kernel/drivertools.o kernel/functional.o diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 43d189679..fa3cc728e 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -30,6 +30,7 @@ #include "kernel/mem.h" #include "kernel/json.h" #include "kernel/yw.h" +#include "kernel/utils.h" #include USING_YOSYS_NAMESPACE diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index a6e1965ba..02784b975 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -24,6 +24,7 @@ #include "kernel/log.h" #include "kernel/mem.h" #include "libs/json11/json11.hpp" +#include "kernel/utils.h" #include USING_YOSYS_NAMESPACE diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index b00cde28e..475f27cdf 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2777,13 +2777,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin mux_input = new AstNode(AST_BIT_NOT, mux_input); } AstNode *node = new AstNode(AST_TERNARY, children_list.at(2)); - if (str == "bufif0") { - node->children.push_back(AstNode::mkconst_bits(z_const, false)); - node->children.push_back(mux_input); - } else { - node->children.push_back(mux_input); - node->children.push_back(AstNode::mkconst_bits(z_const, false)); - } + // if (str == "bufif0") { + // node->children.push_back(AstNode::mkconst_bits(z_const, false)); + // node->children.push_back(mux_input); + // } else { + // node->children.push_back(mux_input); + // node->children.push_back(AstNode::mkconst_bits(z_const, false)); + // } str.clear(); type = AST_ASSIGN; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 08b8c505d..b6525a63b 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -21,6 +21,7 @@ #include "kernel/sigtools.h" #include "kernel/celltypes.h" #include "kernel/log.h" +#include "kernel/utils.h" #include "libs/sha1/sha1.h" #include #include diff --git a/kernel/io.cc b/kernel/io.cc new file mode 100644 index 000000000..a91827c69 --- /dev/null +++ b/kernel/io.cc @@ -0,0 +1,457 @@ +#include "kernel/yosys_common.h" +#include "kernel/log.h" +#include +#include +#include +#include +#include + +YOSYS_NAMESPACE_BEGIN + +// Set of utilities for handling files + +int readsome(std::istream &f, char *s, int n) +{ + int rc = int(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, bool long_strings) +{ + size_t pos_begin = text.find_first_not_of(sep); + + if (pos_begin == std::string::npos) + pos_begin = text.size(); + + if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { + std::string sep_string = sep; + for (size_t i = pos_begin+1; i < text.size(); i++) { + if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { + std::string token = text.substr(pos_begin, i-pos_begin+1); + text = text.substr(i+1); + return token; + } + if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) { + std::string token = text.substr(pos_begin, i-pos_begin+1); + text = text.substr(i+2); + return token + ";"; + } + } + } + + 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; +} + +std::vector split_tokens(const std::string &text, const char *sep) +{ + std::vector tokens; + std::string current_token; + for (char c : text) { + if (strchr(sep, c)) { + if (!current_token.empty()) { + tokens.push_back(current_token); + current_token.clear(); + } + } else + current_token += c; + } + if (!current_token.empty()) { + tokens.push_back(current_token); + current_token.clear(); + } + return tokens; +} + +// 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; +} + +std::string get_base_tmpdir() +{ + static std::string tmpdir; + + if (!tmpdir.empty()) { + return tmpdir; + } + +#if defined(_WIN32) +# 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"); + for (int i = 0; shortpath[i]; i++) + tmpdir += char(shortpath[i]); +#else + char * var = std::getenv("TMPDIR"); + if (var && strlen(var)!=0) { + tmpdir.assign(var); + // We return the directory name without the trailing '/' + while (!tmpdir.empty() && (tmpdir.back() == '/')) { + tmpdir.pop_back(); + } + } else { + tmpdir.assign("/tmp"); + } +#endif + return tmpdir; +} + +std::string make_temp_file(std::string template_str) +{ + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); +#if defined(__wasm) + static size_t index = 0; + template_str.replace(pos, 6, stringf("%06zu", index++)); +#elif defined(_WIN32) +#ifndef YOSYS_WIN32_UNIX_DIR + std::replace(template_str.begin(), template_str.end(), '/', '\\'); +#endif + 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 + int suffixlen = template_str.size() - 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) +{ +#if defined(_WIN32) + template_str = make_temp_file(template_str); + mkdir(template_str.c_str()); + return template_str; +#elif defined(__wasm) + template_str = make_temp_file(template_str); + mkdir(template_str.c_str(), 0777); + return template_str; +#else +# ifndef NDEBUG + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + int suffixlen = template_str.size() - pos - 6; + log_assert(suffixlen == 0); +# endif + + char *p = strdup(template_str.c_str()); + char *res = mkdtemp(p); + log_assert(res != NULL); + template_str = p; + free(p); + + return template_str; +#endif +} + +bool check_directory_exists(const std::string& dirname) +{ +#if defined(_WIN32) + struct _stat info; + if (_stat(dirname.c_str(), &info) != 0) + { + return false; + } + return (info.st_mode & _S_IFDIR) != 0; +#else + struct stat info; + if (stat(dirname.c_str(), &info) != 0) + { + return false; + } + return (info.st_mode & S_IFDIR) != 0; +#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 +} + +bool create_directory(const std::string& dirname) +{ +#if defined(_WIN32) + int ret = _mkdir(dirname.c_str()); +#else + mode_t mode = 0755; + int ret = mkdir(dirname.c_str(), mode); +#endif + if (ret == 0) + return true; + + switch (errno) + { + case ENOENT: + // parent didn't exist, try to create it + { + std::string::size_type pos = dirname.find_last_of('/'); + if (pos == std::string::npos) +#if defined(_WIN32) + pos = dirname.find_last_of('\\'); + if (pos == std::string::npos) +#endif + return false; + if (!create_directory( dirname.substr(0, pos) )) + return false; + } + // now, try to create again +#if defined(_WIN32) + return 0 == _mkdir(dirname.c_str()); +#else + return 0 == mkdir(dirname.c_str(), mode); +#endif + + case EEXIST: + // done! + return check_directory_exists(dirname); + + default: + return false; + } +} + +std::string escape_filename_spaces(const std::string& filename) +{ + std::string out; + out.reserve(filename.size()); + for (auto c : filename) + { + if (c == ' ') + out += "\\ "; + else + out.push_back(c); + } + return out; +} + +#ifdef YOSYS_ENABLE_ZLIB + +PRIVATE_NAMESPACE_BEGIN + +static const size_t GZ_BUFFER_SIZE = 8192; +static void decompress_gzip(const std::string &filename, std::stringstream &out) +{ + char buffer[GZ_BUFFER_SIZE]; + int bytes_read; + gzFile gzf = gzopen(filename.c_str(), "rb"); + while(!gzeof(gzf)) { + bytes_read = gzread(gzf, reinterpret_cast(buffer), GZ_BUFFER_SIZE); + out.write(buffer, bytes_read); + } + gzclose(gzf); +} + +PRIVATE_NAMESPACE_END + +gzip_ostream::gzip_ostream() : std::ostream(nullptr) { + rdbuf(&outbuf); +} + +bool gzip_ostream::open(const std::string &filename) { + return outbuf.open(filename); +} + +gzip_ostream::gzip_streambuf::gzip_streambuf() { + setp(buffer, buffer + buffer_size - 1); +} + +bool gzip_ostream::gzip_streambuf::open(const std::string &filename) { + gzf = gzopen(filename.c_str(), "wb"); + return gzf != nullptr; +} + +int gzip_ostream::gzip_streambuf::sync() { + int num = pptr() - pbase(); + if (num > 0) { + if (gzwrite(gzf, reinterpret_cast(pbase()), num) != num) { + return -1; + } + pbump(-num); + } + return 0; +} + +gzip_ostream::gzip_streambuf::~gzip_streambuf() { + if (gzf) { + sync(); + gzclose(gzf); + } +} + +#endif // YOSYS_ENABLE_ZLIB + + +// Takes a successfully opened ifstream. If it's gzipped, returns an istream +// over a buffer of the file fully decompressed in memory. Otherwise, +// returns the original ifstream, rewound to the start. +std::istream* uncompressed(std::ifstream* f, const std::string filename) { + if (!f) + return nullptr; + // Check for gzip magic + unsigned char magic[3]; + int n = 0; + while (n < 3) + { + int c = f->get(); + if (c != EOF) { + magic[n] = (unsigned char) c; + } + n++; + } + if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { +#ifdef YOSYS_ENABLE_ZLIB + log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); + if (magic[2] != 8) + log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", + filename.c_str(), unsigned(magic[2])); + delete f; + std::stringstream *df = new std::stringstream(); + decompress_gzip(filename, *df); + return df; +#else + log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); +#endif // YOSYS_ENABLE_ZLIB + } else { + f->clear(); + f->seekg(0, std::ios::beg); + return f; + } +} + +YOSYS_NAMESPACE_END diff --git a/kernel/io.h b/kernel/io.h new file mode 100644 index 000000000..99b2dc62a --- /dev/null +++ b/kernel/io.h @@ -0,0 +1,100 @@ +#include "kernel/yosys_common.h" +#include + +#ifndef YOSYS_IO_H +#define YOSYS_IO_H + +#ifdef YOSYS_ENABLE_ZLIB +#include +#endif + +YOSYS_NAMESPACE_BEGIN + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32) || defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + 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; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + +inline std::string stringf(const char *fmt, ...) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + +#ifdef YOSYS_ENABLE_ZLIB +/* +An output stream that uses a stringbuf to buffer data internally, +using zlib to write gzip-compressed data every time the stream is flushed. +*/ +class gzip_ostream : public std::ostream { +public: + gzip_ostream(); + bool open(const std::string &filename); +private: + class gzip_streambuf : public std::stringbuf { + public: + gzip_streambuf(); + bool open(const std::string &filename); + virtual int sync() override; + virtual ~gzip_streambuf(); + private: + static const int buffer_size = 4096; // Size of the internal buffer + char buffer[buffer_size]; // Internal buffer for compressed data + gzFile gzf = nullptr; // Handle to the gzip file + }; + + gzip_streambuf outbuf; // The stream buffer instance +}; +#endif // YOSYS_ENABLE_ZLIB + +std::istream* uncompressed(std::ifstream* f, const std::string filename); + +YOSYS_NAMESPACE_END + +#endif // YOSYS_IO_H diff --git a/kernel/register.cc b/kernel/register.cc index d6e765ce4..00e0c29fd 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -26,65 +26,6 @@ #include #include -#ifdef YOSYS_ENABLE_ZLIB -#include - -PRIVATE_NAMESPACE_BEGIN -#define GZ_BUFFER_SIZE 8192 -void decompress_gzip(const std::string &filename, std::stringstream &out) -{ - char buffer[GZ_BUFFER_SIZE]; - int bytes_read; - gzFile gzf = gzopen(filename.c_str(), "rb"); - while(!gzeof(gzf)) { - bytes_read = gzread(gzf, reinterpret_cast(buffer), GZ_BUFFER_SIZE); - out.write(buffer, bytes_read); - } - gzclose(gzf); -} - -/* -An output stream that uses a stringbuf to buffer data internally, -using zlib to write gzip-compressed data every time the stream is flushed. -*/ -class gzip_ostream : public std::ostream { -public: - gzip_ostream() : std::ostream(nullptr) - { - rdbuf(&outbuf); - } - bool open(const std::string &filename) - { - return outbuf.open(filename); - } -private: - class gzip_streambuf : public std::stringbuf { - public: - gzip_streambuf() { }; - bool open(const std::string &filename) - { - gzf = gzopen(filename.c_str(), "wb"); - return gzf != nullptr; - } - virtual int sync() override - { - gzwrite(gzf, reinterpret_cast(str().c_str()), unsigned(str().size())); - str(""); - return 0; - } - virtual ~gzip_streambuf() - { - sync(); - gzclose(gzf); - } - private: - gzFile gzf = nullptr; - } outbuf; -}; -PRIVATE_NAMESPACE_END - -#endif - YOSYS_NAMESPACE_BEGIN #define MAX_REG_COUNT 1000 @@ -534,37 +475,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vectorget(); - if (c != EOF) { - magic[n] = (unsigned char) c; - } - n++; - } - if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { - #ifdef YOSYS_ENABLE_ZLIB - log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); - if (magic[2] != 8) - log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", - filename.c_str(), unsigned(magic[2])); - delete ff; - std::stringstream *df = new std::stringstream(); - decompress_gzip(filename, *df); - f = df; - #else - log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); - #endif - } else { - ff->clear(); - ff->seekg(0, std::ios::beg); - } - } + f = uncompressed(ff, filename); } if (f == NULL) log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); diff --git a/kernel/utils.h b/kernel/utils.h index 99f327db4..ca51e149e 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -262,6 +262,20 @@ struct arrow_proxy { T* operator->() { return &v; } }; +inline int ceil_log2(int x) +{ +#if defined(__GNUC__) + return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0; +#else + if (x <= 0) + return 0; + for (int i = 0; i < 32; i++) + if (((x-1) >> i) == 0) + return i; + log_abort(); +#endif +} + YOSYS_NAMESPACE_END #endif diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bdd7303aa..3073c6d84 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -146,151 +146,6 @@ void yosys_banner() log(" %s\n", yosys_version_str); } -int ceil_log2(int x) -{ -#if defined(__GNUC__) - return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0; -#else - if (x <= 0) - return 0; - for (int i = 0; i < 32; i++) - if (((x-1) >> i) == 0) - return i; - log_abort(); -#endif -} - -int readsome(std::istream &f, char *s, int n) -{ - int rc = int(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, bool long_strings) -{ - size_t pos_begin = text.find_first_not_of(sep); - - if (pos_begin == std::string::npos) - pos_begin = text.size(); - - if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { - string sep_string = sep; - for (size_t i = pos_begin+1; i < text.size(); i++) { - if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { - std::string token = text.substr(pos_begin, i-pos_begin+1); - text = text.substr(i+1); - return token; - } - if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) { - std::string token = text.substr(pos_begin, i-pos_begin+1); - text = text.substr(i+2); - return token + ";"; - } - } - } - - 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; -} - -std::vector split_tokens(const std::string &text, const char *sep) -{ - std::vector tokens; - std::string current_token; - for (char c : text) { - if (strchr(sep, c)) { - if (!current_token.empty()) { - tokens.push_back(current_token); - current_token.clear(); - } - } else - current_token += c; - } - if (!current_token.empty()) { - tokens.push_back(current_token); - current_token.clear(); - } - return tokens; -} - -// 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; -} - #if !defined(YOSYS_DISABLE_SPAWN) int run_command(const std::string &command, std::function process_line) { @@ -322,225 +177,6 @@ int run_command(const std::string &command, std::function> 17, x ^= x << 5; - template_str[pos+i] = y[x % y.size()]; - } - if (_access(template_str.c_str(), 0) != 0) - break; - } -#else - 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) -{ -#if defined(_WIN32) - template_str = make_temp_file(template_str); - mkdir(template_str.c_str()); - return template_str; -#elif defined(__wasm) - template_str = make_temp_file(template_str); - mkdir(template_str.c_str(), 0777); - 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()); - char *res = mkdtemp(p); - log_assert(res != NULL); - template_str = p; - free(p); - - return template_str; -#endif -} - -bool check_directory_exists(const std::string& dirname) -{ -#if defined(_WIN32) - struct _stat info; - if (_stat(dirname.c_str(), &info) != 0) - { - return false; - } - return (info.st_mode & _S_IFDIR) != 0; -#else - struct stat info; - if (stat(dirname.c_str(), &info) != 0) - { - return false; - } - return (info.st_mode & S_IFDIR) != 0; -#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 -} - -bool create_directory(const std::string& dirname) -{ -#if defined(_WIN32) - int ret = _mkdir(dirname.c_str()); -#else - mode_t mode = 0755; - int ret = mkdir(dirname.c_str(), mode); -#endif - if (ret == 0) - return true; - - switch (errno) - { - case ENOENT: - // parent didn't exist, try to create it - { - std::string::size_type pos = dirname.find_last_of('/'); - if (pos == std::string::npos) -#if defined(_WIN32) - pos = dirname.find_last_of('\\'); - if (pos == std::string::npos) -#endif - return false; - if (!create_directory( dirname.substr(0, pos) )) - return false; - } - // now, try to create again -#if defined(_WIN32) - return 0 == _mkdir(dirname.c_str()); -#else - return 0 == mkdir(dirname.c_str(), mode); -#endif - - case EEXIST: - // done! - return check_directory_exists(dirname); - - default: - return false; - } -} - -std::string escape_filename_spaces(const std::string& filename) -{ - std::string out; - out.reserve(filename.size()); - for (auto c : filename) - { - if (c == ' ') - out += "\\ "; - else - out.push_back(c); - } - return out; -} - bool already_setup = false; void yosys_setup() diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 29dcd58c5..c8c6c7c41 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -128,6 +128,7 @@ # error "C++17 or later compatible compiler is required" #endif +#include "kernel/io.h" YOSYS_NAMESPACE_BEGIN @@ -247,63 +248,6 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); -inline std::string vstringf(const char *fmt, va_list ap) -{ - // For the common case of strings shorter than 128, save a heap - // allocation by using a stack allocated buffer. - const int kBufSize = 128; - char buf[kBufSize]; - buf[0] = '\0'; - va_list apc; - va_copy(apc, ap); - int n = vsnprintf(buf, kBufSize, fmt, apc); - va_end(apc); - if (n < kBufSize) - return std::string(buf); - - std::string string; - char *str = NULL; -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 2 * kBufSize, rc; - while (1) { - 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; - } - if (str != NULL) { - string = str; - free(str); - } - return string; -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; - if (str != NULL) { - string = str; - free(str); - } - return string; -#endif -} - -std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - -inline std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc index cf6622d55..bcdea9d87 100644 --- a/passes/fsm/fsm_recode.cc +++ b/passes/fsm/fsm_recode.cc @@ -22,6 +22,7 @@ #include "kernel/sigtools.h" #include "kernel/consteval.h" #include "kernel/celltypes.h" +#include "kernel/utils.h" #include "fsmdata.h" #include #include diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 9873f12a5..e512a5be1 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" #include "kernel/ffinit.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 02678d676..a13d039a4 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -21,6 +21,7 @@ #include "kernel/sigtools.h" #include "kernel/modtools.h" #include "kernel/ffinit.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 5b678ee55..664563e24 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 6e2fabeeb..97c6f5600 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -354,6 +354,7 @@ with open(outfile, "w") as f: if genhdr: print("#include \"kernel/yosys.h\"", file=f) print("#include \"kernel/sigtools.h\"", file=f) + print("#include \"kernel/utils.h\"", file=f) print("", file=f) print("YOSYS_NAMESPACE_BEGIN", file=f) print("", file=f) diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc index abdcb2240..991977ab9 100644 --- a/passes/sat/assertpmux.cc +++ b/passes/sat/assertpmux.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN