summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/celledges.cc209
-rw-r--r--kernel/celledges.h63
-rw-r--r--kernel/celltypes.h42
-rw-r--r--kernel/driver.cc38
-rw-r--r--kernel/hashlib.h7
-rw-r--r--kernel/log.cc51
-rw-r--r--kernel/log.h48
-rw-r--r--kernel/register.cc77
-rw-r--r--kernel/register.h17
-rw-r--r--kernel/rtlil.cc51
-rw-r--r--kernel/rtlil.h5
-rw-r--r--kernel/satgen.h131
-rw-r--r--kernel/yosys.cc45
-rw-r--r--kernel/yosys.h4
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);