aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/driver.cc6
-rw-r--r--kernel/log.cc76
-rw-r--r--kernel/log.h19
-rw-r--r--kernel/register.cc12
-rw-r--r--kernel/register.h1
-rw-r--r--kernel/rtlil.cc10
-rw-r--r--kernel/timinginfo.h179
-rw-r--r--kernel/yosys.cc4
8 files changed, 301 insertions, 6 deletions
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 9040408bc..398c89e03 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -558,6 +558,10 @@ int main(int argc, char **argv)
fprintf(f, "\n");
}
+ if (log_expect_no_warnings && log_warnings_count_noexpect)
+ log_error("Unexpected warnings found: %d unique messages, %d total, %d expected\n", GetSize(log_warnings),
+ log_warnings_count, log_warnings_count - log_warnings_count_noexpect);
+
if (print_stats)
{
std::string hash = log_hasher->final().substr(0, 10);
@@ -664,6 +668,8 @@ int main(int argc, char **argv)
}
#endif
+ log_check_expected();
+
yosys_atexit();
memhasher_off();
diff --git a/kernel/log.cc b/kernel/log.cc
index f5d6c488e..2f8ce9e8c 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -42,8 +42,11 @@ std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
std::map<std::string, std::set<std::string>> log_hdump;
std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
+std::vector<std::pair<std::regex,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;
+bool log_expect_no_warnings = false;
bool log_hdump_all = false;
FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
@@ -68,6 +71,8 @@ int string_buf_index = -1;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
+static bool check_expected_logs = true;
+static bool display_error_log_msg = true;
static void log_id_cache_clear()
{
@@ -162,7 +167,7 @@ void logv(const char *format, va_list ap)
{
log_warn_regex_recusion_guard = true;
- if (log_warn_regexes.empty())
+ if (log_warn_regexes.empty() && log_expect_log.empty())
{
linebuffer.clear();
}
@@ -174,6 +179,11 @@ void logv(const char *format, va_list ap)
for (auto &re : log_warn_regexes)
if (std::regex_search(linebuffer, re))
log_warning("Found log message matching -W regex:\n%s", str.c_str());
+
+ for (auto &item : log_expect_log)
+ if (std::regex_search(linebuffer, item.first))
+ item.second.current_count++;
+
linebuffer.clear();
}
}
@@ -244,6 +254,13 @@ static void logv_warning_with_prefix(const char *prefix,
if (std::regex_search(message, re))
log_error("%s", message.c_str());
+ bool warning_match = false;
+ for (auto &item : log_expect_warning)
+ if (std::regex_search(message, item.first)) {
+ item.second.current_count++;
+ warning_match = true;
+ }
+
if (log_warnings.count(message))
{
log("%s%s", prefix, message.c_str());
@@ -263,6 +280,8 @@ static void logv_warning_with_prefix(const char *prefix,
log_warnings.insert(message);
}
+ if (!warning_match)
+ log_warnings_count_noexpect++;
log_warnings_count++;
log_make_debug = bak_log_make_debug;
}
@@ -320,7 +339,8 @@ static void logv_error_with_prefix(const char *prefix,
f = stderr;
log_last_error = vstringf(format, ap);
- log("%s%s", prefix, log_last_error.c_str());
+ if (display_error_log_msg)
+ log("%s%s", prefix, log_last_error.c_str());
log_flush();
log_make_debug = bak_log_make_debug;
@@ -328,6 +348,12 @@ static void logv_error_with_prefix(const char *prefix,
if (log_error_atexit)
log_error_atexit();
+ for (auto &item : log_expect_error)
+ if (std::regex_search(log_last_error, item.first))
+ item.second.current_count++;
+
+ if (check_expected_logs)
+ log_check_expected();
#ifdef EMSCRIPTEN
log_files = backup_log_files;
throw 0;
@@ -636,6 +662,52 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
log("%s", buf.str().c_str());
}
+void log_check_expected()
+{
+ check_expected_logs = false;
+
+ 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());
+ }
+ 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);
+ }
+ }
+
+ 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());
+ }
+ 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);
+ }
+ }
+
+ 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());
+ #ifdef EMSCRIPTEN
+ throw 0;
+ #elif defined(_MSC_VER)
+ _exit(0);
+ #else
+ _Exit(0);
+ #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());
+ }
+}
+
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
diff --git a/kernel/log.h b/kernel/log.h
index 9db8efaa5..603938f4c 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -52,6 +52,8 @@ extern std::map<std::string, std::set<std::string>> log_hdump;
extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
extern int log_warnings_count;
+extern int log_warnings_count_noexpect;
+extern bool log_expect_no_warnings;
extern bool log_hdump_all;
extern FILE *log_errfile;
extern SHA1 *log_hasher;
@@ -135,6 +137,23 @@ void log_backtrace(const char *prefix, int levels);
void log_reset_stack();
void log_flush();
+struct LogExpectedItem
+{
+ LogExpectedItem(std::string pattern, int expected) :
+ expected_count(expected),
+ current_count(0),
+ pattern(pattern)
+ {
+ }
+
+ int expected_count;
+ int current_count;
+ std::string pattern;
+};
+
+extern std::vector<std::pair<std::regex,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);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
const char *log_id(RTLIL::IdString id);
diff --git a/kernel/register.cc b/kernel/register.cc
index e59d59654..af8c1b8e8 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -400,6 +400,18 @@ void ScriptPass::run(std::string command, std::string info)
}
}
+void ScriptPass::run_nocheck(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;
diff --git a/kernel/register.h b/kernel/register.h
index 4622845b6..3d89386b7 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -84,6 +84,7 @@ struct ScriptPass : Pass
bool check_label(std::string label, std::string info = std::string());
void run(std::string command, std::string info = std::string());
+ void run_nocheck(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();
};
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index f286d139f..06181b763 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1258,8 +1258,12 @@ namespace {
param_bool(ID(SRC_POL));
param_bool(ID(DST_PEN));
param_bool(ID(DST_POL));
- param(ID(T_LIMIT));
- param(ID(T_LIMIT2));
+ param(ID(T_LIMIT_MIN));
+ param(ID(T_LIMIT_TYP));
+ param(ID(T_LIMIT_MAX));
+ param(ID(T_LIMIT2_MIN));
+ param(ID(T_LIMIT2_TYP));
+ param(ID(T_LIMIT2_MAX));
port(ID(SRC_EN), 1);
port(ID(DST_EN), 1);
port(ID(SRC), param(ID(SRC_WIDTH)));
@@ -3920,8 +3924,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
cover("kernel.rtlil.sigspec.parse");
AST::current_filename = "input";
- AST::use_internal_line_num();
- AST::set_line_num(0);
std::vector<std::string> tokens;
sigspec_parse_split(tokens, str, ',');
diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h
new file mode 100644
index 000000000..4b77c02e8
--- /dev/null
+++ b/kernel/timinginfo.h
@@ -0,0 +1,179 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * (C) 2020 Eddie Hung <eddie@fpgeh.com>
+ *
+ * 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 TIMINGINFO_H
+#define TIMINGINFO_H
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct TimingInfo
+{
+ struct NameBit
+ {
+ RTLIL::IdString name;
+ int offset;
+ NameBit() : offset(0) {}
+ NameBit(const RTLIL::IdString name, int offset) : name(name), offset(offset) {}
+ explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}
+ bool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; }
+ bool operator!=(const NameBit& nb) const { return !operator==(nb); }
+ unsigned int hash() const { return mkhash_add(name.hash(), offset); }
+ };
+ struct BitBit
+ {
+ NameBit first, second;
+ BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
+ BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {}
+ bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; }
+ unsigned int hash() const { return mkhash_add(first.hash(), second.hash()); }
+ };
+
+ struct ModuleTiming
+ {
+ RTLIL::IdString type;
+ dict<BitBit, int> comb;
+ dict<NameBit, int> arrival, required;
+ };
+
+ dict<RTLIL::IdString, ModuleTiming> data;
+
+ TimingInfo()
+ {
+ }
+
+ TimingInfo(RTLIL::Design *design)
+ {
+ setup(design);
+ }
+
+ void setup(RTLIL::Design *design)
+ {
+ for (auto module : design->modules()) {
+ if (!module->get_blackbox_attribute())
+ continue;
+ setup_module(module);
+ }
+ }
+
+ const ModuleTiming& setup_module(RTLIL::Module *module)
+ {
+ auto r = data.insert(module->name);
+ log_assert(r.second);
+ auto &t = r.first->second;
+
+ for (auto cell : module->cells()) {
+ if (cell->type == ID($specify2)) {
+ auto src = cell->getPort(ID(SRC));
+ auto dst = cell->getPort(ID(DST));
+ for (const auto &c : src.chunks())
+ if (!c.wire->port_input)
+ log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+ for (const auto &c : dst.chunks())
+ if (!c.wire->port_output)
+ log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
+ 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_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell));
+ if (cell->getParam(ID(FULL)).as_bool()) {
+ for (const auto &s : src)
+ for (const auto &d : dst) {
+ auto r = t.comb.insert(BitBit(s,d));
+ if (!r.second)
+ log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
+ r.first->second = max;
+ }
+ }
+ else {
+ log_assert(GetSize(src) == GetSize(dst));
+ for (auto i = 0; i < GetSize(src); i++) {
+ const auto &s = src[i];
+ const auto &d = dst[i];
+ auto r = t.comb.insert(BitBit(s,d));
+ if (!r.second)
+ log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
+ r.first->second = max;
+ }
+ }
+ }
+ else if (cell->type == ID($specify3)) {
+ auto src = cell->getPort(ID(SRC));
+ auto dst = cell->getPort(ID(DST));
+ for (const auto &c : src.chunks())
+ if (!c.wire->port_input)
+ log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+ for (const auto &c : dst.chunks())
+ if (!c.wire->port_output)
+ log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
+ 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;
+ }
+ for (const auto &d : dst) {
+ auto &v = t.arrival[NameBit(d)];
+ v = std::max(v, max);
+ }
+ }
+ else if (cell->type == ID($specrule)) {
+ auto type = cell->getParam(ID(TYPE)).decode_string();
+ if (type != "$setup" && type != "$setuphold")
+ continue;
+ auto src = cell->getPort(ID(SRC));
+ auto dst = cell->getPort(ID(DST));
+ for (const auto &c : src.chunks())
+ if (!c.wire->port_input)
+ log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+ for (const auto &c : dst.chunks())
+ 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;
+ }
+ for (const auto &s : src) {
+ auto &v = t.required[NameBit(s)];
+ v = std::max(v, max);
+ }
+ }
+ }
+
+ return t;
+ }
+
+ decltype(data)::const_iterator find(RTLIL::IdString module_name) const { return data.find(module_name); }
+ decltype(data)::const_iterator end() const { return data.end(); }
+ int count(RTLIL::IdString module_name) const { return data.count(module_name); }
+ const ModuleTiming& at(RTLIL::IdString module_name) const { return data.at(module_name); }
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 8190d8902..7694fc9b6 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -341,7 +341,11 @@ int run_command(const std::string &command, std::function<void(const std::string
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;