diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/calc.cc | 47 | ||||
-rw-r--r-- | kernel/celledges.cc | 2 | ||||
-rw-r--r-- | kernel/celltypes.h | 4 | ||||
-rw-r--r-- | kernel/constids.inc | 13 | ||||
-rw-r--r-- | kernel/driver.cc | 17 | ||||
-rw-r--r-- | kernel/hashlib.h | 10 | ||||
-rw-r--r-- | kernel/log.cc | 27 | ||||
-rw-r--r-- | kernel/log.h | 53 | ||||
-rw-r--r-- | kernel/register.cc | 4 | ||||
-rw-r--r-- | kernel/rtlil.cc | 4 | ||||
-rw-r--r-- | kernel/rtlil.h | 44 | ||||
-rw-r--r-- | kernel/satgen.h | 42 | ||||
-rw-r--r-- | kernel/timinginfo.h | 19 | ||||
-rw-r--r-- | kernel/yosys.cc | 27 | ||||
-rw-r--r-- | kernel/yosys.h | 12 |
15 files changed, 255 insertions, 70 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc index 4a4840771..ae18809d3 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -489,6 +489,7 @@ RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +// truncating division RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; @@ -502,6 +503,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +// truncating modulo RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; @@ -515,6 +517,51 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + int undef_bit_pos = -1; + BigInteger a = const2big(arg1, signed1, undef_bit_pos); + BigInteger b = const2big(arg2, signed2, undef_bit_pos); + if (b.isZero()) + return RTLIL::Const(RTLIL::State::Sx, result_len); + + bool result_pos = (a.getSign() == BigInteger::negative) == (b.getSign() == BigInteger::negative); + a = a.getSign() == BigInteger::negative ? -a : a; + b = b.getSign() == BigInteger::negative ? -b : b; + BigInteger result; + + if (result_pos || a == 0) { + result = a / b; + } else { + // bigint division with negative numbers is wonky, make sure we only negate at the very end + result = -((a + b - 1) / b); + } + return big2const(result, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); +} + +RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + int undef_bit_pos = -1; + BigInteger a = const2big(arg1, signed1, undef_bit_pos); + BigInteger b = const2big(arg2, signed2, undef_bit_pos); + if (b.isZero()) + return RTLIL::Const(RTLIL::State::Sx, result_len); + + BigInteger::Sign a_sign = a.getSign(); + BigInteger::Sign b_sign = b.getSign(); + a = a_sign == BigInteger::negative ? -a : a; + b = b_sign == BigInteger::negative ? -b : b; + BigInteger truncated = a_sign == BigInteger::negative ? -(a % b) : (a % b); + BigInteger modulo; + + if (truncated == 0 || (a_sign == b_sign)) { + modulo = truncated; + } else { + modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b; + } + return big2const(modulo, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); +} + RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 54e0168e2..314e7c77e 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -187,7 +187,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } - // FIXME: $mul $div $mod $slice $concat + // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat // FIXME: $lut $sop $alu $lcu $macc $fa return false; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 450865ce9..db54436cb 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -114,7 +114,7 @@ struct CellTypes ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($logic_and), ID($logic_or), ID($concat), ID($macc) }; @@ -304,6 +304,8 @@ struct CellTypes HANDLE_CELL_TYPE(mul) HANDLE_CELL_TYPE(div) HANDLE_CELL_TYPE(mod) + HANDLE_CELL_TYPE(divfloor) + HANDLE_CELL_TYPE(modfloor) HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pos) HANDLE_CELL_TYPE(neg) diff --git a/kernel/constids.inc b/kernel/constids.inc index c5f672d09..383d7c615 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -2,13 +2,12 @@ X(A) X(abc9_box) X(abc9_box_id) X(abc9_box_seq) +X(abc9_bypass) X(abc9_carry) X(abc9_flop) -X(abc9_holes) -X(abc9_init) +X(abc9_keep) X(abc9_lut) X(abc9_mergeability) -X(abc9_scc) X(abc9_scc_id) X(abcgroup) X(ABITS) @@ -29,6 +28,7 @@ X(B) X(BI) X(blackbox) X(B_SIGNED) +X(bugpoint_keep) X(B_WIDTH) X(C) X(cells_not_processed) @@ -73,10 +73,14 @@ X(EN) X(EN_DST) X(EN_POLARITY) X(EN_SRC) +X(enum_base_type) +X(enum_type) X(equiv_merged) X(equiv_region) X(extract_order) X(F) +X(force_downto) +X(force_upto) X(fsm_encoding) X(fsm_export) X(FULL) @@ -122,6 +126,7 @@ X(nomem2init) X(nomem2reg) X(nomeminit) X(nosync) +X(nowrshmsk) X(O) X(OFFSET) X(onehot) @@ -166,6 +171,7 @@ X(techmap_autopurge) X(_TECHMAP_BITS_CONNMAP_) X(_TECHMAP_CELLTYPE_) X(techmap_celltype) +X(_TECHMAP_FAIL_) X(techmap_maccmap) X(_TECHMAP_REPLACE_) X(techmap_simplemap) @@ -195,6 +201,7 @@ X(U) X(unique) X(unused_bits) X(V) +X(via_celltype) X(wand) X(whitebox) X(WIDTH) diff --git a/kernel/driver.cc b/kernel/driver.cc index 5f0959776..57ed7b8b4 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -155,6 +155,19 @@ int yosys_history_offset = 0; std::string yosys_history_file; #endif +#if defined(__wasm) +extern "C" { + // FIXME: WASI does not currently support exceptions. + void* __cxa_allocate_exception(size_t thrown_size) throw() { + return malloc(thrown_size); + } + bool __cxa_uncaught_exception() throw(); + void __cxa_throw(void* thrown_exception, struct std::type_info * tinfo, void (*dest)(void*)) { + std::terminate(); + } +} +#endif + void yosys_atexit() { #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) @@ -587,9 +600,11 @@ int main(int argc, char **argv) ru_buffer.ru_utime.tv_usec += ru_buffer_children.ru_utime.tv_usec; ru_buffer.ru_stime.tv_sec += ru_buffer_children.ru_stime.tv_sec; ru_buffer.ru_stime.tv_usec += ru_buffer_children.ru_stime.tv_usec; +#if defined(__linux__) || defined(__FreeBSD__) ru_buffer.ru_maxrss = std::max(ru_buffer.ru_maxrss, ru_buffer_children.ru_maxrss); +#endif } -# if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) meminfo = stringf(", MEM: %.2f MB peak", ru_buffer.ru_maxrss / 1024.0); #endif diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 592d6e577..5c87b55f5 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -207,6 +207,7 @@ class dict entry_t() { } entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { } entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { } + bool operator<(const entry_t &other) const { return udata.first < other.udata.first; } }; std::vector<int> hashtable; @@ -615,6 +616,15 @@ public: return !operator==(other); } + unsigned int hash() const { + unsigned int h = mkhash_init; + for (auto &entry : entries) { + h ^= hash_ops<K>::hash(entry.udata.first); + h ^= hash_ops<T>::hash(entry.udata.second); + } + return h; + } + void reserve(size_t n) { entries.reserve(n); } size_t size() const { return entries.size(); } bool empty() const { return entries.empty(); } diff --git a/kernel/log.cc b/kernel/log.cc index d84a4381e..104bee078 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -42,7 +42,7 @@ std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; std::map<std::string, std::set<std::string>> log_hdump; std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error; std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; int log_warnings_count_noexpect = 0; @@ -181,7 +181,7 @@ void logv(const char *format, va_list ap) log_warning("Found log message matching -W regex:\n%s", str.c_str()); for (auto &item : log_expect_log) - if (YS_REGEX_NS::regex_search(linebuffer, item.first)) + if (YS_REGEX_NS::regex_search(linebuffer, item.second.pattern)) item.second.current_count++; linebuffer.clear(); @@ -256,7 +256,7 @@ static void logv_warning_with_prefix(const char *prefix, bool warning_match = false; for (auto &item : log_expect_warning) - if (YS_REGEX_NS::regex_search(message, item.first)) { + if (YS_REGEX_NS::regex_search(message, item.second.pattern)) { item.second.current_count++; warning_match = true; } @@ -349,11 +349,14 @@ static void logv_error_with_prefix(const char *prefix, log_error_atexit(); for (auto &item : log_expect_error) - if (YS_REGEX_NS::regex_search(log_last_error, item.first)) + if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern)) item.second.current_count++; if (check_expected_logs) log_check_expected(); + + YS_DEBUGTRAP_IF_DEBUGGING; + #ifdef EMSCRIPTEN log_files = backup_log_files; throw 0; @@ -669,42 +672,42 @@ void log_check_expected() for (auto &item : log_expect_warning) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected warning pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_log) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected log pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected log pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_error) if (item.second.current_count == item.second.expected_count) { log_warn_regexes.clear(); - log("Expected error pattern '%s' found !!!\n", item.second.pattern.c_str()); + log("Expected error pattern '%s' found !!!\n", item.first.c_str()); #ifdef EMSCRIPTEN throw 0; #elif defined(_MSC_VER) _exit(0); #else _Exit(0); - #endif + #endif } else { display_error_log_msg = false; log_warn_regexes.clear(); - log_error("Expected error pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected error pattern '%s' not found !\n", item.first.c_str()); } } diff --git a/kernel/log.h b/kernel/log.h index 5478482ac..516744b50 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -50,9 +50,12 @@ std::regex_constants::egrep) #endif -#ifndef _WIN32 +#if defined(_WIN32) +# include <intrin.h> +#else # include <sys/time.h> # include <sys/resource.h> +# include <signal.h> #endif #if defined(_MSC_VER) @@ -69,6 +72,41 @@ YOSYS_NAMESPACE_BEGIN #define S__LINE__sub1(x) S__LINE__sub2(x) #define S__LINE__ S__LINE__sub1(__LINE__) +// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint +// if the platform provides such functionality, and does nothing otherwise. +// If no debugger is attached, it starts a just-in-time debugger if available, +// and crashes the process otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP __debugbreak() +#else +# ifndef __has_builtin +// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang) +// that does not have it, using __has_builtin(...) is a syntax error. +# define __has_builtin(x) 0 +# endif +# if __has_builtin(__builtin_debugtrap) +# define YS_DEBUGTRAP __builtin_debugtrap() +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# define YS_DEBUGTRAP raise(SIGTRAP) +# else +# define YS_DEBUGTRAP do {} while(0) +# endif +#endif + +// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint +// if a debugger is attached, and does nothing otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, +// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. +# define YS_DEBUGTRAP_IF_DEBUGGING do { \ + auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ + } while(0) +#else +# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) +#endif + struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; @@ -164,19 +202,16 @@ void log_flush(); struct LogExpectedItem { - LogExpectedItem(std::string pattern, int expected) : - expected_count(expected), - current_count(0), - pattern(pattern) - { - } + LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) : + pattern(pat), expected_count(expected), current_count(0) {} + LogExpectedItem() : expected_count(0), current_count(0) {} + YS_REGEX_TYPE pattern; int expected_count; int current_count; - std::string pattern; }; -extern std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); diff --git a/kernel/register.cc b/kernel/register.cc index 925d0d776..02974e534 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -238,6 +238,7 @@ void Pass::call(RTLIL::Design *design, std::string command) return; if (tok[0] == '!') { +#if !defined(YOSYS_DISABLE_SPAWN) cmd_buf = command.substr(command.find('!') + 1); while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) @@ -247,6 +248,9 @@ void Pass::call(RTLIL::Design *design, std::string command) if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); return; +#else + log_cmd_error("Shell is not available.\n"); +#endif } while (!tok.empty()) { diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 98d6ed41f..397edc4e7 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -948,7 +948,7 @@ namespace { return; } - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) { + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { param_bool(ID::A_SIGNED); param_bool(ID::B_SIGNED); port(ID::A, param(ID::A_WIDTH)); @@ -1950,6 +1950,8 @@ DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub)) DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) +DEF_METHOD(DivFloor, max(sig_a.size(), sig_b.size()), ID($divfloor)) +DEF_METHOD(ModFloor, max(sig_a.size(), sig_b.size()), ID($modfloor)) DEF_METHOD(LogicAnd, 1, ID($logic_and)) DEF_METHOD(LogicOr, 1, ID($logic_or)) #undef DEF_METHOD diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 04d4325d1..51e573e76 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -150,9 +150,6 @@ namespace RTLIL if (!p[0]) return 0; - log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { #ifndef YOSYS_NO_IDS_REFCNT @@ -165,6 +162,11 @@ namespace RTLIL return it->second; } + log_assert(p[0] == '$' || p[0] == '\\'); + log_assert(p[1] != 0); + for (const char *c = p; *c; c++) + log_assert((unsigned)*c > (unsigned)' '); + #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { if (global_id_storage_.empty()) { @@ -296,8 +298,8 @@ namespace RTLIL // The methods below are just convenience functions for better compatibility with std::string. - bool operator==(const std::string &rhs) const { return str() == rhs; } - bool operator!=(const std::string &rhs) const { return str() != rhs; } + bool operator==(const std::string &rhs) const { return c_str() == rhs; } + bool operator!=(const std::string &rhs) const { return c_str() != rhs; } bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } @@ -466,6 +468,8 @@ namespace RTLIL RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); @@ -721,7 +725,7 @@ struct RTLIL::SigBit SigBit(const RTLIL::SigChunk &chunk); SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigSpec &sig); - SigBit(const RTLIL::SigBit &sigbit); + SigBit(const RTLIL::SigBit &sigbit) = default; RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; bool operator <(const RTLIL::SigBit &other) const; @@ -1134,8 +1138,14 @@ public: return design->selected_member(name, member->name); } - RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; } - RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; } + RTLIL::Wire* wire(RTLIL::IdString id) { + auto it = wires_.find(id); + return it == wires_.end() ? nullptr : it->second; + } + RTLIL::Cell* cell(RTLIL::IdString id) { + auto it = cells_.find(id); + return it == cells_.end() ? nullptr : it->second; + } RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); } RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); } @@ -1196,8 +1206,12 @@ public: RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + // truncating division RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + // truncating modulo RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); @@ -1222,13 +1236,10 @@ public: RTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); RTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = ""); RTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); + RTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); RTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); RTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); RTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); @@ -1295,8 +1306,12 @@ public: RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + // truncating division RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + // truncating modulo RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); @@ -1494,7 +1509,6 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } -inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){ if (wire) offset = sigbit.offset; } inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { if (wire == other.wire) diff --git a/kernel/satgen.h b/kernel/satgen.h index 88b84b7e6..3929a8708 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -279,7 +279,7 @@ struct SatGen bool arith_undef_handled = false; bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare)) + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) { std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); @@ -293,7 +293,7 @@ struct SatGen int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - if (cell->type.in(ID($div), ID($mod))) { + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); } @@ -935,7 +935,7 @@ struct SatGen return true; } - if (cell->type.in(ID($div), ID($mod))) + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); @@ -970,23 +970,48 @@ struct SatGen } std::vector<int> y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); + + // modulo calculation + std::vector<int> modulo_trunc; + int floored_eq_trunc; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); + // floor == trunc when sgn(a) == sgn(b) or trunc == 0 + floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); + } else { + modulo_trunc = chain_buf; + floored_eq_trunc = ez->CONST_TRUE; + } + if (cell->type == ID($div)) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); else ez->assume(ez->vec_eq(y_tmp, y_u)); - } else { + } else if (cell->type == ID($mod)) { + ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); + } else if (cell->type == ID($divfloor)) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf))); + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( + ez->XOR(a.back(), b.back()), + ez->vec_neg(ez->vec_ite( + ez->vec_reduce_or(modulo_trunc), + ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), + y_u + )), + y_u + ))); else - ez->assume(ez->vec_eq(y_tmp, chain_buf)); + ez->assume(ez->vec_eq(y_tmp, y_u)); + } else if (cell->type == ID($modfloor)) { + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); } if (ignore_div_by_zero) { ez->assume(ez->expression(ezSAT::OpOr, b)); } else { std::vector<int> div_zero_result; - if (cell->type == ID($div)) { + if (cell->type.in(ID($div), ID($divfloor))) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { std::vector<int> all_ones(y.size(), ez->CONST_TRUE); std::vector<int> only_first_one(y.size(), ez->CONST_FALSE); @@ -996,7 +1021,8 @@ struct SatGen div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } - } else { + } else if (cell->type.in(ID($mod), ID($modfloor))) { + // a mod 0 = a int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index fb4e0930d..d818e580b 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -82,6 +82,9 @@ struct TimingInfo for (auto cell : module->cells()) { if (cell->type == ID($specify2)) { + auto en = cell->getPort(ID::EN); + if (en.is_fully_const() && !en.as_bool()) + continue; auto src = cell->getPort(ID::SRC); auto dst = cell->getPort(ID::DST); for (const auto &c : src.chunks()) @@ -128,11 +131,9 @@ struct TimingInfo int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); int max = std::max(rise_max,fall_max); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &d : dst) { auto &v = t.arrival[NameBit(d)]; @@ -152,11 +153,9 @@ struct TimingInfo if (!c.wire->port_input) log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst)); int max = cell->getParam(ID::T_LIMIT_MAX).as_int(); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &s : src) { auto &v = t.required[NameBit(s)]; diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 01131601f..2ec3dca0c 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -45,8 +45,10 @@ # include <unistd.h> # include <dirent.h> # include <sys/types.h> -# include <sys/wait.h> # include <sys/stat.h> +# if !defined(YOSYS_DISABLE_SPAWN) +# include <sys/wait.h> +# endif #endif #if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) @@ -336,16 +338,13 @@ bool patmatch(const char *pattern, const char *string) return false; } +#if !defined(YOSYS_DISABLE_SPAWN) int run_command(const std::string &command, std::function<void(const std::string&)> process_line) { if (!process_line) return system(command.c_str()); -#ifdef EMSCRIPTEN - FILE *f = nullptr; -#else FILE *f = popen(command.c_str(), "r"); -#endif if (f == nullptr) return -1; @@ -368,10 +367,16 @@ int run_command(const std::string &command, std::function<void(const std::string return WEXITSTATUS(ret); #endif } +#endif std::string make_temp_file(std::string template_str) { -#ifdef _WIN32 +#if defined(__wasm) + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + static size_t index = 0; + template_str.replace(pos, 6, stringf("%06zu", index++)); +#elif defined(_WIN32) if (template_str.rfind("/tmp/", 0) == 0) { # ifdef __MINGW32__ char longpath[MAX_PATH + 1]; @@ -420,10 +425,14 @@ std::string make_temp_file(std::string template_str) std::string make_temp_dir(std::string template_str) { -#ifdef _WIN32 +#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"); @@ -806,7 +815,7 @@ std::string proc_self_dirname() path += char(shortpath[i]); return path; } -#elif defined(EMSCRIPTEN) +#elif defined(EMSCRIPTEN) || defined(__wasm) std::string proc_self_dirname() { return "/"; @@ -815,7 +824,7 @@ std::string proc_self_dirname() #error "Don't know how to determine process executable base path!" #endif -#ifdef EMSCRIPTEN +#if defined(EMSCRIPTEN) || defined(__wasm) std::string proc_share_dirname() { return "/share/"; diff --git a/kernel/yosys.h b/kernel/yosys.h index ed48eec09..c922faf26 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -155,6 +155,16 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p # define YS_NORETURN #endif +#if __cplusplus >= 201703L +# define YS_FALLTHROUGH [[fallthrough]]; +#elif defined(__clang__) +# define YS_FALLTHROUGH [[clang::fallthrough]]; +#elif defined(__GNUC__) +# define YS_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define YS_FALLTHROUGH +#endif + YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included @@ -264,7 +274,9 @@ 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<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n"); bool patmatch(const char *pattern, const char *string); +#if !defined(YOSYS_DISABLE_SPAWN) int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>()); +#endif std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); |