mirror of
https://github.com/YosysHQ/yosys
synced 2025-05-10 09:15:49 +00:00
check: promote some problems to errors by default, add -permissive
This commit is contained in:
parent
ecf9c9f0cf
commit
c7cd70b103
3 changed files with 58 additions and 20 deletions
|
@ -400,6 +400,16 @@ void log_file_error(const string &filename, int lineno,
|
||||||
logv_file_error(filename, lineno, format, ap);
|
logv_file_error(filename, lineno, format, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string fmt(const char *format, ...)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
s = vstringf(format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void log(const char *format, ...)
|
void log(const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
|
@ -126,6 +126,7 @@ void logv_warning_noprefix(const char *format, va_list ap);
|
||||||
[[noreturn]] void logv_error(const char *format, va_list ap);
|
[[noreturn]] void logv_error(const char *format, va_list ap);
|
||||||
[[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap);
|
[[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap);
|
||||||
|
|
||||||
|
std::string fmt(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||||
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
void log(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_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));
|
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||||
|
|
|
@ -27,6 +27,11 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct CheckPass : public Pass {
|
struct CheckPass : public Pass {
|
||||||
|
enum Mode {
|
||||||
|
Permissive,
|
||||||
|
Smart,
|
||||||
|
Assert,
|
||||||
|
};
|
||||||
CheckPass() : Pass("check", "check for obvious problems in the design") { }
|
CheckPass() : Pass("check", "check for obvious problems in the design") { }
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
|
@ -59,6 +64,10 @@ struct CheckPass : public Pass {
|
||||||
log(" -assert\n");
|
log(" -assert\n");
|
||||||
log(" produce a runtime error if any problems are found in the current design\n");
|
log(" produce a runtime error if any problems are found in the current design\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -permissive\n");
|
||||||
|
log(" treat even severe problems as just warnings.\n");
|
||||||
|
log(" Used to be the default behavior\n");
|
||||||
|
log("\n");
|
||||||
log(" -force-detailed-loop-check\n");
|
log(" -force-detailed-loop-check\n");
|
||||||
log(" for the detection of combinatorial loops, use a detailed connectivity\n");
|
log(" for the detection of combinatorial loops, use a detailed connectivity\n");
|
||||||
log(" model for all internal cells for which it is available. This disables\n");
|
log(" model for all internal cells for which it is available. This disables\n");
|
||||||
|
@ -68,14 +77,25 @@ struct CheckPass : public Pass {
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
{
|
{
|
||||||
|
// Number of all problems (warnings and errors)
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool noinit = false;
|
bool noinit = false;
|
||||||
bool initdrv = false;
|
bool initdrv = false;
|
||||||
bool mapped = false;
|
bool mapped = false;
|
||||||
bool allow_tbuf = false;
|
bool allow_tbuf = false;
|
||||||
bool assert_mode = false;
|
|
||||||
bool force_detailed_loop_check = false;
|
bool force_detailed_loop_check = false;
|
||||||
bool suggest_detail = false;
|
bool suggest_detail = false;
|
||||||
|
Mode mode = Mode::Smart;
|
||||||
|
// log_error always terminates and it's a huge hassle to refactor
|
||||||
|
std::vector<std::string> errors;
|
||||||
|
std::function<void(std::string)> bad = [&errors, &counter](std::string message) {
|
||||||
|
counter++;
|
||||||
|
errors.push_back(message);
|
||||||
|
};
|
||||||
|
std::function<void(std::string)> warn = [&counter](std::string message) {
|
||||||
|
counter++;
|
||||||
|
log_warning("%s", message.c_str());
|
||||||
|
};
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
@ -95,8 +115,12 @@ struct CheckPass : public Pass {
|
||||||
allow_tbuf = true;
|
allow_tbuf = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-permissive") {
|
||||||
|
mode = Mode::Permissive;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-assert") {
|
if (args[argidx] == "-assert") {
|
||||||
assert_mode = true;
|
mode = Mode::Assert;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-force-detailed-loop-check") {
|
if (args[argidx] == "-force-detailed-loop-check") {
|
||||||
|
@ -109,6 +133,11 @@ struct CheckPass : public Pass {
|
||||||
|
|
||||||
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
|
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
|
||||||
|
|
||||||
|
if (mode == Mode::Permissive)
|
||||||
|
bad = warn;
|
||||||
|
if (mode == Mode::Assert)
|
||||||
|
warn = bad;
|
||||||
|
|
||||||
for (auto module : design->selected_whole_modules_warn())
|
for (auto module : design->selected_whole_modules_warn())
|
||||||
{
|
{
|
||||||
log("Checking module %s...\n", log_id(module));
|
log("Checking module %s...\n", log_id(module));
|
||||||
|
@ -246,8 +275,7 @@ struct CheckPass : public Pass {
|
||||||
{
|
{
|
||||||
if (mapped && cell->type.begins_with("$") && design->module(cell->type) == nullptr) {
|
if (mapped && cell->type.begins_with("$") && design->module(cell->type) == nullptr) {
|
||||||
if (allow_tbuf && cell->type == ID($_TBUF_)) goto cell_allowed;
|
if (allow_tbuf && cell->type == ID($_TBUF_)) goto cell_allowed;
|
||||||
log_warning("Cell %s.%s is an unmapped internal cell of type %s.\n", log_id(module), log_id(cell), log_id(cell->type));
|
warn(fmt("Cell %s.%s is an unmapped internal cell of type %s.\n", log_id(module), log_id(cell), log_id(cell->type)));
|
||||||
counter++;
|
|
||||||
cell_allowed:;
|
cell_allowed:;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,8 +327,7 @@ struct CheckPass : public Pass {
|
||||||
if (initval[i] == State::S0 || initval[i] == State::S1)
|
if (initval[i] == State::S0 || initval[i] == State::S1)
|
||||||
init_bits.insert(sigmap(SigBit(wire, i)));
|
init_bits.insert(sigmap(SigBit(wire, i)));
|
||||||
if (noinit) {
|
if (noinit) {
|
||||||
log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
|
warn(fmt("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire)));
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,8 +337,7 @@ struct CheckPass : public Pass {
|
||||||
string message = stringf("Drivers conflicting with a constant %s driver:\n", log_signal(state));
|
string message = stringf("Drivers conflicting with a constant %s driver:\n", log_signal(state));
|
||||||
for (auto str : wire_drivers[state])
|
for (auto str : wire_drivers[state])
|
||||||
message += stringf(" %s\n", str.c_str());
|
message += stringf(" %s\n", str.c_str());
|
||||||
log_warning("%s", message.c_str());
|
bad(message);
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it : wire_drivers)
|
for (auto it : wire_drivers)
|
||||||
|
@ -319,14 +345,12 @@ struct CheckPass : public Pass {
|
||||||
string message = stringf("multiple conflicting drivers for %s.%s:\n", log_id(module), log_signal(it.first));
|
string message = stringf("multiple conflicting drivers for %s.%s:\n", log_id(module), log_signal(it.first));
|
||||||
for (auto str : it.second)
|
for (auto str : it.second)
|
||||||
message += stringf(" %s\n", str.c_str());
|
message += stringf(" %s\n", str.c_str());
|
||||||
log_warning("%s", message.c_str());
|
bad(message);
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto bit : used_wires)
|
for (auto bit : used_wires)
|
||||||
if (!wire_drivers.count(bit)) {
|
if (!wire_drivers.count(bit)) {
|
||||||
log_warning("Wire %s.%s is used but has no driver.\n", log_id(module), log_signal(bit));
|
warn(fmt("Wire %s.%s is used but has no driver.\n", log_id(module), log_signal(bit)));
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
topo.sort();
|
topo.sort();
|
||||||
|
@ -405,8 +429,7 @@ struct CheckPass : public Pass {
|
||||||
|
|
||||||
prev = bit;
|
prev = bit;
|
||||||
}
|
}
|
||||||
log_warning("%s", message.c_str());
|
bad(message.c_str());
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initdrv)
|
if (initdrv)
|
||||||
|
@ -424,8 +447,7 @@ struct CheckPass : public Pass {
|
||||||
init_sig.sort_and_unify();
|
init_sig.sort_and_unify();
|
||||||
|
|
||||||
for (auto chunk : init_sig.chunks()) {
|
for (auto chunk : init_sig.chunks()) {
|
||||||
log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module), log_signal(chunk));
|
warn(fmt("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module), log_signal(chunk)));
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,8 +457,13 @@ struct CheckPass : public Pass {
|
||||||
if (suggest_detail)
|
if (suggest_detail)
|
||||||
log("Consider re-running with '-force-detailed-loop-check' to rule out false positives.\n");
|
log("Consider re-running with '-force-detailed-loop-check' to rule out false positives.\n");
|
||||||
|
|
||||||
if (assert_mode && counter > 0)
|
if (errors.size()) {
|
||||||
log_error("Found %d problems in 'check -assert'.\n", counter);
|
std::string err_message;
|
||||||
|
for (auto error : errors)
|
||||||
|
err_message += error + "\n";
|
||||||
|
err_message += fmt("Found %zu severe problems in 'check'.\n", errors.size());
|
||||||
|
log_error("%s", err_message.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} CheckPass;
|
} CheckPass;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue