diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/celledges.cc | 209 | ||||
-rw-r--r-- | kernel/celledges.h | 63 | ||||
-rw-r--r-- | kernel/celltypes.h | 42 | ||||
-rw-r--r-- | kernel/driver.cc | 38 | ||||
-rw-r--r-- | kernel/hashlib.h | 7 | ||||
-rw-r--r-- | kernel/log.cc | 51 | ||||
-rw-r--r-- | kernel/log.h | 48 | ||||
-rw-r--r-- | kernel/register.cc | 77 | ||||
-rw-r--r-- | kernel/register.h | 17 | ||||
-rw-r--r-- | kernel/rtlil.cc | 51 | ||||
-rw-r--r-- | kernel/rtlil.h | 5 | ||||
-rw-r--r-- | kernel/satgen.h | 131 | ||||
-rw-r--r-- | kernel/yosys.cc | 45 | ||||
-rw-r--r-- | kernel/yosys.h | 4 |
14 files changed, 748 insertions, 40 deletions
diff --git a/kernel/celledges.cc b/kernel/celledges.cc new file mode 100644 index 00000000..556e8b82 --- /dev/null +++ b/kernel/celledges.cc @@ -0,0 +1,209 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/celledges.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int y_width = GetSize(cell->getPort(Y)); + + for (int i = 0; i < y_width; i++) + { + if (i < a_width) + db->add_edge(cell, A, i, Y, i, -1); + else if (is_signed && a_width > 0) + db->add_edge(cell, A, a_width-1, Y, i, -1); + } +} + +void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int y_width = GetSize(cell->getPort(Y)); + + if (cell->type == "$and" && !is_signed) { + if (a_width > b_width) + a_width = b_width; + else + b_width = a_width; + } + + for (int i = 0; i < y_width; i++) + { + if (i < a_width) + db->add_edge(cell, A, i, Y, i, -1); + else if (is_signed && a_width > 0) + db->add_edge(cell, A, a_width-1, Y, i, -1); + + if (i < b_width) + db->add_edge(cell, B, i, Y, i, -1); + else if (is_signed && b_width > 0) + db->add_edge(cell, B, b_width-1, Y, i, -1); + } +} + +void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int y_width = GetSize(cell->getPort(Y)); + + if (is_signed && a_width == 1) + y_width = std::min(y_width, 1); + + for (int i = 0; i < y_width; i++) + for (int k = 0; k <= i && k < a_width; k++) + db->add_edge(cell, A, k, Y, i, -1); +} + +void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int y_width = GetSize(cell->getPort(Y)); + + if (!is_signed && cell->type != "$sub") { + int ab_width = std::max(a_width, b_width); + y_width = std::min(y_width, ab_width+1); + } + + for (int i = 0; i < y_width; i++) + { + for (int k = 0; k <= i; k++) + { + if (k < a_width) + db->add_edge(cell, A, k, Y, i, -1); + + if (k < b_width) + db->add_edge(cell, B, k, Y, i, -1); + } + } +} + +void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, A, i, Y, 0, -1); +} + +void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, A, i, Y, 0, -1); + + for (int i = 0; i < b_width; i++) + db->add_edge(cell, B, i, Y, 0, -1); +} + +void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; + + int a_width = GetSize(cell->getPort(A)); + int b_width = GetSize(cell->getPort(B)); + int s_width = GetSize(cell->getPort(S)); + + for (int i = 0; i < a_width; i++) + { + db->add_edge(cell, A, i, Y, i, -1); + + for (int k = i; k < b_width; k += a_width) + db->add_edge(cell, B, k, Y, i, -1); + + for (int k = 0; k < s_width; k++) + db->add_edge(cell, S, k, Y, i, -1); + } +} + +PRIVATE_NAMESPACE_END + +bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) +{ + if (cell->type.in("$not", "$pos")) { + bitwise_unary_op(this, cell); + return true; + } + + if (cell->type.in("$and", "$or", "$xor", "$xnor")) { + bitwise_binary_op(this, cell); + return true; + } + + if (cell->type == "$neg") { + arith_neg_op(this, cell); + return true; + } + + if (cell->type.in("$add", "$sub")) { + arith_binary_op(this, cell); + return true; + } + + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) { + reduce_op(this, cell); + return true; + } + + // FIXME: + // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { + // shift_op(this, cell); + // return true; + // } + + if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { + compare_op(this, cell); + return true; + } + + if (cell->type.in("$mux", "$pmux")) { + mux_op(this, cell); + return true; + } + + // FIXME: $mul $div $mod $slice $concat + // FIXME: $lut $sop $alu $lcu $macc $fa + + return false; +} + diff --git a/kernel/celledges.h b/kernel/celledges.h new file mode 100644 index 00000000..6aab9ed4 --- /dev/null +++ b/kernel/celledges.h @@ -0,0 +1,63 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef CELLEDGES_H +#define CELLEDGES_H + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +YOSYS_NAMESPACE_BEGIN + +struct AbstractCellEdgesDatabase +{ + virtual ~AbstractCellEdgesDatabase() { } + virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int delay) = 0; + bool add_edges_from_cell(RTLIL::Cell *cell); +}; + +struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase +{ + SigMap &sigmap; + dict<SigBit, pool<SigBit>> db; + FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } + + virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override { + SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); + SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); + db[from_sigbit].insert(to_sigbit); + } +}; + +struct RevCellEdgesDatabase : AbstractCellEdgesDatabase +{ + SigMap &sigmap; + dict<SigBit, pool<SigBit>> db; + RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } + + virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override { + SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); + SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); + db[to_sigbit].insert(from_sigbit); + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 40fdca36..900c12d0 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -85,7 +85,7 @@ struct CellTypes std::vector<RTLIL::IdString> unary_ops = { "$not", "$pos", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$logic_not", "$slice", "$lut" + "$logic_not", "$slice", "$lut", "$sop" }; std::vector<RTLIL::IdString> binary_ops = { @@ -116,6 +116,8 @@ struct CellTypes setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true); setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true); + setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true); + setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true); setup_type("$equiv", {A, B}, {Y}, true); } @@ -357,6 +359,44 @@ struct CellTypes return t; } + if (cell->type == "$sop") + { + int width = cell->parameters.at("\\WIDTH").as_int(); + int depth = cell->parameters.at("\\DEPTH").as_int(); + std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits; + + while (GetSize(t) < width*depth*2) + t.push_back(RTLIL::S0); + + RTLIL::State default_ret = State::S0; + + for (int i = 0; i < depth; i++) + { + bool match = true; + bool match_x = true; + + for (int j = 0; j < width; j++) { + RTLIL::State a = arg1.bits.at(j); + if (t.at(2*width*i + 2*j + 0) == State::S1) { + if (a == State::S1) match_x = false; + if (a != State::S0) match = false; + } + if (t.at(2*width*i + 2*j + 1) == State::S1) { + if (a == State::S0) match_x = false; + if (a != State::S1) match = false; + } + } + + if (match) + return State::S1; + + if (match_x) + default_ret = State::Sx; + } + + return default_ret; + } + bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1; diff --git a/kernel/driver.cc b/kernel/driver.cc index 02e332f9..5cfc4171 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -183,8 +183,8 @@ int main(int argc, char **argv) printf(" -b backend\n"); printf(" use this backend for the output file specified on the command line\n"); printf("\n"); - printf(" -f backend\n"); - printf(" use the specified front for the input files on the command line\n"); + printf(" -f frontend\n"); + printf(" use the specified frontend for the input files on the command line\n"); printf("\n"); printf(" -H\n"); printf(" print the command list\n"); @@ -213,6 +213,11 @@ int main(int argc, char **argv) printf(" -A\n"); printf(" will call abort() at the end of the script. for debugging\n"); printf("\n"); + printf(" -D <header_id>[:<filename>]\n"); + printf(" dump the design when printing the specified log header to a file.\n"); + printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n"); + printf(" Use 'ALL' as <header_id> to dump at every header.\n"); + printf("\n"); printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); @@ -233,7 +238,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1) { switch (opt) { @@ -315,6 +320,28 @@ int main(int argc, char **argv) scriptfile = optarg; scriptfile_tcl = true; break; + case 'D': + { + auto args = split_tokens(optarg, ":"); + if (!args.empty() && args[0] == "ALL") { + if (GetSize(args) != 1) { + fprintf(stderr, "Invalid number of tokens in -D ALL.\n"); + exit(1); + } + log_hdump_all = true; + } else { + if (!args.empty() && !args[0].empty() && args[0].back() == '.') + args[0].pop_back(); + if (GetSize(args) == 1) + args.push_back("yosys_dump_" + args[0] + ".il"); + if (GetSize(args) != 2) { + fprintf(stderr, "Invalid number of tokens in -D.\n"); + exit(1); + } + log_hdump[args[0]].insert(args[1]); + } + } + break; default: fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); @@ -482,6 +509,11 @@ int main(int argc, char **argv) free(hist_list); #endif + log_flush(); +#ifdef _WIN32 + _Exit(0); +#endif + yosys_shutdown(); return 0; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 280b1693..3c824b8c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -10,6 +10,7 @@ // ------------------------------------------------------- #ifndef HASHLIB_H +#define HASHLIB_H #include <stdexcept> #include <algorithm> @@ -136,8 +137,8 @@ struct hash_cstr_ops { static inline unsigned int hash(const char *a) { unsigned int hash = mkhash_init; while (*a) - hash = mkhash(hash, *(a++)); - return hash; + hash = mkhash(hash, *(a++)); + return hash; } }; @@ -156,7 +157,7 @@ struct hash_obj_ops { } template<typename T> static inline unsigned int hash(const T *a) { - return a->hash(); + return a ? a->hash() : 0; } }; diff --git a/kernel/log.cc b/kernel/log.cc index 4f395c75..3f1d8881 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -40,6 +40,8 @@ YOSYS_NAMESPACE_BEGIN std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; +std::map<std::string, std::set<std::string>> log_hdump; +bool log_hdump_all = false; FILE *log_errfile = NULL; SHA1 *log_hasher = NULL; @@ -136,7 +138,7 @@ void logv(const char *format, va_list ap) *f << str; } -void logv_header(const char *format, va_list ap) +void logv_header(RTLIL::Design *design, const char *format, va_list ap) { bool pop_errfile = false; @@ -149,12 +151,24 @@ void logv_header(const char *format, va_list ap) pop_errfile = true; } + std::string header_id; + for (int c : header_count) - log("%d.", c); - log(" "); + header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); + + log("%s. ", header_id.c_str()); logv(format, ap); log_flush(); + if (log_hdump_all) + log_hdump[header_id].insert("yosys_dump_" + header_id + ".il"); + + if (log_hdump.count(header_id) && design != nullptr) + for (auto &filename : log_hdump.at(header_id)) { + log("Dumping current design to '%s'.\n", filename.c_str()); + Pass::call(design, {"dump", "-o", filename}); + } + if (pop_errfile) log_files.pop_back(); } @@ -194,7 +208,7 @@ void logv_error(const char *format, va_list ap) log_files = backup_log_files; throw 0; #else - exit(1); + _Exit(1); #endif } @@ -206,11 +220,11 @@ void log(const char *format, ...) va_end(ap); } -void log_header(const char *format, ...) +void log_header(RTLIL::Design *design, const char *format, ...) { va_list ap; va_start(ap, format); - logv_header(format, ap); + logv_header(design, format, ap); va_end(ap); } @@ -400,6 +414,24 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) } } +const char *log_const(const RTLIL::Const &value, bool autoint) +{ + if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0) + return log_signal(value, autoint); + + std::string str = "\"" + value.decode_string() + "\""; + + if (string_buf.size() < 100) { + string_buf.push_back(str); + return string_buf.back().c_str(); + } else { + if (++string_buf_index == 100) + string_buf_index = 0; + string_buf[string_buf_index] = str; + return string_buf[string_buf_index].c_str(); + } +} + const char *log_id(RTLIL::IdString str) { log_id_cache.insert(str); @@ -413,6 +445,13 @@ const char *log_id(RTLIL::IdString str) return p+1; } +void log_module(RTLIL::Module *module, std::string indent) +{ + std::stringstream buf; + ILANG_BACKEND::dump_module(buf, indent, module, module->design, false); + log("%s", buf.str().c_str()); +} + void log_cell(RTLIL::Cell *cell, std::string indent) { std::stringstream buf; diff --git a/kernel/log.h b/kernel/log.h index 28baf988..53480db3 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -47,6 +47,8 @@ struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; extern std::vector<std::ostream*> log_streams; +extern std::map<std::string, std::set<std::string>> log_hdump; +extern bool log_hdump_all; extern FILE *log_errfile; extern SHA1 *log_hasher; @@ -58,12 +60,12 @@ extern int log_verbose_level; extern string log_last_error; void logv(const char *format, va_list ap); -void logv_header(const char *format, va_list ap); +void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_warning(const char *format, va_list ap); YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); +void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); @@ -77,12 +79,14 @@ void log_reset_stack(); void log_flush(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); +const char *log_const(const RTLIL::Const &value, bool autoint = true); const char *log_id(RTLIL::IdString id); template<typename T> static inline const char *log_id(T *obj) { return log_id(obj->name); } +void log_module(RTLIL::Module *module, std::string indent = ""); void log_cell(RTLIL::Cell *cell, std::string indent = ""); #ifndef NDEBUG @@ -161,11 +165,13 @@ struct PerformanceTimer } static int64_t query() { -#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) +# if _WIN32 + return 0; +# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec; -#elif defined(RUSAGE_SELF) +# elif defined(RUSAGE_SELF) struct rusage rusage; int64_t t; if (getrusage(RUSAGE_SELF, &rusage) == -1) { @@ -175,11 +181,9 @@ struct PerformanceTimer t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; -#elif _WIN32 - return 0; -#else - #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). -#endif +# else +# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +# endif } void reset() { @@ -230,6 +234,32 @@ static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { lo void log_dump_val_worker(RTLIL::IdString v); void log_dump_val_worker(RTLIL::SigSpec v); +template<typename K, typename T, typename OPS> +static inline void log_dump_val_worker(dict<K, T, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it.first); + log(": "); + log_dump_val_worker(it.second); + first = false; + } + log(" }"); +} + +template<typename K, typename OPS> +static inline void log_dump_val_worker(pool<K, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it); + first = false; + } + log(" }"); +} + template<typename T> static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } diff --git a/kernel/register.cc b/kernel/register.cc index 49a67324..7a1d0b44 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -80,6 +80,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute() state.begin_ns = PerformanceTimer::query(); state.parent_pass = current_pass; current_pass = this; + clear_flags(); return state; } @@ -99,6 +100,10 @@ void Pass::help() log("\n"); } +void Pass::clear_flags() +{ +} + void Pass::cmd_log_args(const std::vector<std::string> &args) { if (args.size() <= 1) @@ -160,7 +165,7 @@ void Pass::call(RTLIL::Design *design, std::string command) while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) cmd_buf.resize(cmd_buf.size()-1); - log_header("Shell command: %s\n", cmd_buf.c_str()); + log_header(design, "Shell command: %s\n", cmd_buf.c_str()); int retCode = run_command(cmd_buf); if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); @@ -282,6 +287,60 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec design->selected_active_module = backup_selected_active_module; } +bool ScriptPass::check_label(std::string label, std::string info) +{ + if (active_design == nullptr) { + log("\n"); + if (info.empty()) + log(" %s:\n", label.c_str()); + else + log(" %s: %s\n", label.c_str(), info.c_str()); + return true; + } else { + if (!active_run_from.empty() && active_run_from == active_run_to) { + block_active = (label == active_run_from); + } else { + if (label == active_run_from) + block_active = true; + if (label == active_run_to) + block_active = false; + } + return block_active; + } +} + +void ScriptPass::run(std::string command, std::string info) +{ + if (active_design == nullptr) { + if (info.empty()) + log(" %s\n", command.c_str()); + else + log(" %s %s\n", command.c_str(), info.c_str()); + } else + Pass::call(active_design, command); +} + +void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) +{ + help_mode = false; + active_design = design; + block_active = run_from.empty(); + active_run_from = run_from; + active_run_to = run_to; + script(); +} + +void ScriptPass::help_script() +{ + clear_flags(); + help_mode = true; + active_design = nullptr; + block_active = true; + active_run_from.clear(); + active_run_to.clear(); + script(); +} + Frontend::Frontend(std::string name, std::string short_help) : Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) @@ -323,7 +382,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s bool called_with_fp = f != NULL; next_args.clear(); - for (; argidx < args.size(); argidx++) + + if (argidx < args.size()) { std::string arg = args[argidx]; @@ -360,6 +420,12 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s f = new std::istringstream(last_here_document); } else { rewrite_filename(filename); + vector<string> filenames = glob_filename(filename); + filename = filenames.front(); + if (GetSize(filenames) > 1) { + next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); + next_args.insert(next_args.end(), filenames.begin()+1, filenames.end()); + } std::ifstream *ff = new std::ifstream; ff->open(filename.c_str()); if (ff->fail()) @@ -375,12 +441,13 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s cmd_error(args, i, "Found option, expected arguments."); if (argidx+1 < args.size()) { - next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx); - next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end()); + if (next_args.empty()) + next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); + next_args.insert(next_args.end(), args.begin()+argidx+1, args.end()); args.erase(args.begin()+argidx+1, args.end()); } - break; } + if (f == NULL) cmd_error(args, argidx, "No filename given."); diff --git a/kernel/register.h b/kernel/register.h index 0ef07b76..8024c56a 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -31,6 +31,7 @@ struct Pass virtual ~Pass(); virtual void help(); + virtual void clear_flags(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0; int call_counter; @@ -63,6 +64,22 @@ struct Pass static void done_register(); }; +struct ScriptPass : Pass +{ + bool block_active, help_mode; + RTLIL::Design *active_design; + std::string active_run_from, active_run_to; + + ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { } + + virtual void script() = 0; + + bool check_label(std::string label, std::string info = std::string()); + void run(std::string command, std::string info = std::string()); + void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string()); + void help_script(); +}; + struct Frontend : Pass { // for reading of here documents diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a706491e..32efe4f0 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -304,6 +304,8 @@ RTLIL::Design::~Design() { for (auto it = modules_.begin(); it != modules_.end(); ++it) delete it->second; + for (auto n : verilog_packages) + delete n; } RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() @@ -845,6 +847,15 @@ namespace { return; } + if (cell->type == "$sop") { + param("\\DEPTH"); + param("\\TABLE"); + port("\\A", param("\\WIDTH")); + port("\\Y", 1); + check_expected(); + return; + } + if (cell->type == "$sr") { param_bool("\\SET_POLARITY"); param_bool("\\CLR_POLARITY"); @@ -1006,16 +1017,21 @@ namespace { return; } - if (cell->type == "$assert") { + if (cell->type.in("$assert", "$assume")) { port("\\A", 1); port("\\EN", 1); check_expected(); return; } - if (cell->type == "$assume") { - port("\\A", 1); - port("\\EN", 1); + if (cell->type == "$initstate") { + port("\\Y", 1); + check_expected(); + return; + } + + if (cell->type == "$anyconst") { + port("\\Y", param("\\WIDTH")); check_expected(); return; } @@ -1466,6 +1482,7 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn) log_backtrace("-X- ", yosys_xtrace-1); } + log_assert(GetSize(conn.first) == GetSize(conn.second)); connections_.push_back(conn); } @@ -1784,6 +1801,14 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a return cell; } +RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en) +{ + RTLIL::Cell *cell = addCell(name, "$assume"); + cell->setPort("\\A", sig_a); + cell->setPort("\\EN", sig_en); + return cell; +} + RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y) { RTLIL::Cell *cell = addCell(name, "$equiv"); @@ -1950,6 +1975,22 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec return cell; } +RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, width); + Cell *cell = addCell(name, "$anyconst"); + cell->setParam("\\WIDTH", width); + cell->setPort("\\Y", sig); + return sig; +} + +RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name) +{ + RTLIL::SigSpec sig = addWire(NEW_ID); + Cell *cell = addCell(name, "$initstate"); + cell->setPort("\\Y", sig); + return sig; +} RTLIL::Wire::Wire() { @@ -2133,7 +2174,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; } - if (type == "$lut") { + if (type == "$lut" || type == "$sop") { parameters["\\WIDTH"] = GetSize(connections_["\\A"]); return; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 940e36ab..a426e0bd 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -792,6 +792,7 @@ struct RTLIL::Design int refcount_modules_; dict<RTLIL::IdString, RTLIL::Module*> modules_; + std::vector<AST::AstNode*> verilog_packages; std::vector<RTLIL::Selection> selection_stack; dict<RTLIL::IdString, RTLIL::Selection> selection_vars; @@ -1003,6 +1004,7 @@ public: RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut); RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y); RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); + RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y); RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true); @@ -1101,6 +1103,9 @@ public: RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c); RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); + + RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1); + RTLIL::SigSpec Initstate (RTLIL::IdString name); }; struct RTLIL::Wire : public RTLIL::AttrObject diff --git a/kernel/satgen.h b/kernel/satgen.h index d44d61f1..0a65b490 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -70,6 +70,7 @@ struct SatGen std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en; std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en; std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals; + std::map<std::pair<std::string, int>, bool> initstates; bool ignore_div_by_zero; bool model_undef; @@ -266,6 +267,13 @@ struct SatGen ez->assume(ez->OR(undef, ez->IFF(y, yy))); } + void setInitState(int timestep) + { + auto key = make_pair(prefix, timestep); + log_assert(initstates.count(key) == 0 || initstates.at(key) == true); + initstates[key] = true; + } + bool importCell(RTLIL::Cell *cell, int timestep = -1) { bool arith_undef_handled = false; @@ -1048,6 +1056,88 @@ struct SatGen return true; } + if (cell->type == "$sop") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + int width = cell->getParam("\\WIDTH").as_int(); + int depth = cell->getParam("\\DEPTH").as_int(); + + vector<State> table_raw = cell->getParam("\\TABLE").bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector<vector<int>> table(depth); + + for (int i = 0; i < depth; i++) + for (int j = 0; j < width; j++) + { + bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); + bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); + + if (pat0 && !pat1) + table.at(i).push_back(0); + else if (!pat0 && pat1) + table.at(i).push_back(1); + else + table.at(i).push_back(-1); + } + + if (model_undef) + { + std::vector<int> products, undef_products; + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_ua, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_ua.push_back(undef_a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + std::vector<int> masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector<int> masked_b = ez->vec_or(cmp_b, cmp_ua); + + int masked_eq = ez->vec_eq(masked_a, masked_b); + int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); + + undef_products.push_back(ez->AND(any_undef, masked_eq)); + products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); + } + + int yy = ez->expression(ezSAT::OpOr, products); + ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); + undefGating(y, yy, undef_y); + } + else + { + std::vector<int> products; + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + products.push_back(ez->vec_eq(cmp_a, cmp_b)); + } + + ez->SET(y, ez->expression(ezSAT::OpOr, products)); + } + + return true; + } + if (cell->type == "$fa") { std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); @@ -1229,6 +1319,28 @@ struct SatGen return true; } + if (cell->type == "$anyconst") + { + if (timestep < 2) + return true; + + std::vector<int> d = importDefSigSpec(cell->getPort("\\Y"), timestep-1); + std::vector<int> q = importDefSigSpec(cell->getPort("\\Y"), timestep); + + std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); + std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + return true; + } + if (cell->type == "$_BUF_" || cell->type == "$equiv") { std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); @@ -1248,6 +1360,25 @@ struct SatGen return true; } + if (cell->type == "$initstate") + { + auto key = make_pair(prefix, timestep); + if (initstates.count(key) == 0) + initstates[key] = false; + + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + log_assert(GetSize(y) == 1); + ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); + + if (model_undef) { + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + log_assert(GetSize(undef_y) == 1); + ez->SET(undef_y[0], ez->CONST_FALSE); + } + + return true; + } + if (cell->type == "$assert") { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index eba1aef1..08fee974 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -37,11 +37,13 @@ # include <unistd.h> # include <dirent.h> # include <sys/stat.h> +# include <glob.h> #else # include <unistd.h> # include <dirent.h> # include <sys/types.h> # include <sys/stat.h> +# include <glob.h> #endif #include <limits.h> @@ -104,7 +106,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | Copyright (C) 2012 - 2016 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"); @@ -547,6 +549,29 @@ const char *create_prompt(RTLIL::Design *design, int recursion_counter) return buffer; } +std::vector<std::string> glob_filename(const std::string &filename_pattern) +{ + std::vector<std::string> results; + +#ifdef _WIN32 + results.push_back(filename_pattern); +#else + glob_t globbuf; + + int err = glob(filename_pattern.c_str(), 0, NULL, &globbuf); + + if(err == 0) { + for (size_t i = 0; i < globbuf.gl_pathc; i++) + results.push_back(globbuf.gl_pathv[i]); + globfree(&globbuf); + } else { + results.push_back(filename_pattern); + } +#endif + + return results; +} + void rewrite_filename(std::string &filename) { if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"") @@ -622,7 +647,7 @@ struct TclPass : public Pass { } TclPass; #endif -#if defined(__linux__) +#if defined(__linux__) || defined(__CYGWIN__) std::string proc_self_dirname() { char path[PATH_MAX]; @@ -687,7 +712,7 @@ std::string proc_share_dirname() std::string proc_share_dirname() { std::string proc_self_path = proc_self_dirname(); -# ifdef _WIN32 +# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR) std::string proc_share_path = proc_self_path + "share\\"; if (check_file_exists(proc_share_path, true)) return proc_share_path; @@ -701,6 +726,11 @@ std::string proc_share_dirname() proc_share_path = proc_self_path + "../share/yosys/"; if (check_file_exists(proc_share_path, true)) return proc_share_path; +# ifdef YOSYS_DATDIR + proc_share_path = YOSYS_DATDIR "/"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; +# endif # endif log_error("proc_share_dirname: unable to determine share/ directory!\n"); } @@ -758,6 +788,8 @@ void run_frontend(std::string filename, std::string command, std::string *backen command = "verilog"; else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") command = "verilog -sv"; + else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd") + command = "vhdl"; else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") command = "blif"; else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") @@ -1093,8 +1125,8 @@ struct HistoryPass : public Pass { } HistoryPass; #endif -struct ScriptPass : public Pass { - ScriptPass() : Pass("script", "execute commands from script file") { } +struct ScriptCmdPass : public Pass { + ScriptCmdPass() : Pass("script", "execute commands from script file") { } virtual void help() { log("\n"); log(" script <filename> [<from_label>:<to_label>]\n"); @@ -1120,7 +1152,6 @@ struct ScriptPass : public Pass { else extra_args(args, 2, design, false); } -} ScriptPass; +} ScriptCmdPass; YOSYS_NAMESPACE_END - diff --git a/kernel/yosys.h b/kernel/yosys.h index c8bc46b6..aab6b584 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -51,6 +51,7 @@ #include <initializer_list> #include <stdexcept> #include <memory> +#include <cmath> #include <sstream> #include <fstream> @@ -91,9 +92,9 @@ # define mkdir _mkdir # define popen _popen # define pclose _pclose -# define PATH_MAX MAX_PATH # ifndef __MINGW32__ +# define PATH_MAX MAX_PATH # define isatty _isatty # define fileno _fileno # endif @@ -279,6 +280,7 @@ RTLIL::Design *yosys_get_design(); std::string proc_self_dirname(); std::string proc_share_dirname(); const char *create_prompt(RTLIL::Design *design, int recursion_counter); +std::vector<std::string> glob_filename(const std::string &filename_pattern); void rewrite_filename(std::string &filename); void run_pass(std::string command, RTLIL::Design *design = nullptr); |