Added "check" command
authorClifford Wolf <clifford@clifford.at>
Fri, 13 Feb 2015 13:34:51 +0000 (14:34 +0100)
committerClifford Wolf <clifford@clifford.at>
Fri, 13 Feb 2015 13:34:51 +0000 (14:34 +0100)
passes/cmds/Makefile.inc
passes/cmds/check.cc [new file with mode: 0644]
techlibs/common/synth.cc

index 0e62abbc4f6963e6c4850c5f214d518a81156c55..e4b40c41c687c6ab1f5e7b4b8a464affd956a32c 100644 (file)
@@ -21,4 +21,5 @@ OBJS += passes/cmds/connwrappers.o
 OBJS += passes/cmds/cover.o
 OBJS += passes/cmds/trace.o
 OBJS += passes/cmds/plugin.o
+OBJS += passes/cmds/check.o
 
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
new file mode 100644 (file)
index 0000000..39a732f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  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/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct CheckPass : public Pass {
+       CheckPass() : Pass("check", "check for obvious problems in the design") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    check [selection]\n");
+               log("\n");
+               log("This pass identifies the following problems in the current design:\n");
+               log("\n");
+               log(" - combinatorical loops\n");
+               log("\n");
+               log(" - two or more conflicting drivers for one wire\n");
+               log("\n");
+               log(" - used wires that do not have a driver\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               int counter = 0;
+
+               log_header("Executing CHECK pass (checking for obvious problems).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto module : design->selected_whole_modules_warn())
+               {
+                       if (module->has_processes_warn())
+                               continue;
+
+                       log("checking module %s..\n", log_id(module));
+
+                       SigMap sigmap(module);
+                       dict<SigBit, vector<string>> wire_drivers;
+                       pool<SigBit> used_wires;
+                       TopoSort<string> topo;
+
+                       for (auto cell : module->cells())
+                       for (auto &conn : cell->connections()) {
+                               SigSpec sig = sigmap(conn.second);
+                               bool logic_cell = yosys_celltypes.cell_evaluable(cell->type);
+                               if (cell->input(conn.first))
+                                       for (auto bit : sig)
+                                               if (bit.wire) {
+                                                       if (logic_cell)
+                                                               topo.edge(stringf("wire %s", log_signal(bit)),
+                                                                               stringf("cell %s (%s)", log_id(cell), log_id(cell->type)));
+                                                       used_wires.insert(bit);
+                                               }
+                               if (cell->output(conn.first))
+                                       for (int i = 0; i < GetSize(sig); i++) {
+                                               if (logic_cell)
+                                                       topo.edge(stringf("cell %s (%s)", log_id(cell), log_id(cell->type)),
+                                                                       stringf("wire %s", log_signal(sig[i])));
+                                               wire_drivers[sig[i]].push_back(stringf("port %s[%d] of cell %s (%s)",
+                                                               log_id(conn.first), i, log_id(cell), log_id(cell->type)));
+                                       }
+                       }
+
+                       for (auto wire : module->wires()) {
+                               if (wire->port_input) {
+                                       SigSpec sig = sigmap(wire);
+                                       for (int i = 0; i < GetSize(sig); i++)
+                                               wire_drivers[sig[i]].push_back(stringf("module input %s[%d]", log_id(wire), i));
+                               }
+                               if (wire->port_output)
+                                       for (auto bit : sigmap(wire)) used_wires.insert(bit);
+                       }
+
+                       for (auto it : wire_drivers)
+                               if (GetSize(it.second) > 1) {
+                                       string message = stringf("multiple conflicting drivers for %s.%s:\n", log_id(module), log_signal(it.first));
+                                       for (auto str : it.second)
+                                               message += stringf("    %s\n", str.c_str());
+                                       log_warning("%s", message.c_str());
+                                       counter++;
+                               }
+
+                       for (auto bit : used_wires)
+                               if (!wire_drivers.count(bit)) {
+                                       log_warning("Wire %s.%s is used but has no driver.\n", log_id(module), log_signal(bit));
+                                       counter++;
+                               }
+
+                       topo.sort();
+                       for (auto &loop : topo.loops) {
+                               string message = stringf("found logic loop in module %s:\n", log_id(module));
+                               for (auto &str : loop)
+                                       message += stringf("    %s\n", str.c_str());
+                               log_warning("%s", message.c_str());
+                               counter++;
+                       }
+               }
+
+               log("found and reported %d problems.\n", counter);
+       }
+} CheckPass;
+PRIVATE_NAMESPACE_END
index 69ef5bc5561f302a49363de396163e8ec43758d9..a50db53ee151f6642aaa6270e0dad18e4f5f5df3 100644 (file)
@@ -71,6 +71,8 @@ struct SynthPass : public Pass {
                log("\n");
                log("    coarse:\n");
                log("        proc\n");
+               log("        opt_clean\n");
+               log("        check\n");
                log("        opt\n");
                log("        wreduce\n");
                log("        alumacc\n");
@@ -150,6 +152,8 @@ struct SynthPass : public Pass {
                if (check_label(active, run_from, run_to, "coarse"))
                {
                        Pass::call(design, "proc");
+                       Pass::call(design, "opt_clean");
+                       Pass::call(design, "check");
                        Pass::call(design, "opt");
                        Pass::call(design, "wreduce");
                        Pass::call(design, "alumacc");