Added equiv_struct command
authorClifford Wolf <clifford@clifford.at>
Wed, 21 Oct 2015 15:12:35 +0000 (17:12 +0200)
committerClifford Wolf <clifford@clifford.at>
Wed, 21 Oct 2015 15:12:35 +0000 (17:12 +0200)
passes/equiv/Makefile.inc
passes/equiv/equiv_struct.cc [new file with mode: 0644]

index 548eaca3b5d0a9c9c37981ad8b126f4a4f5a56c9..d5bb9495a9e4c7275b4a21fc2be02b72e7b668b3 100644 (file)
@@ -6,4 +6,5 @@ OBJS += passes/equiv/equiv_status.o
 OBJS += passes/equiv/equiv_add.o
 OBJS += passes/equiv/equiv_remove.o
 OBJS += passes/equiv/equiv_induct.o
+OBJS += passes/equiv/equiv_struct.o
 
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
new file mode 100644 (file)
index 0000000..00e112b
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *  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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivStructWorker
+{
+       Module *module;
+       SigMap sigmap;
+       SigMap equiv_bits;
+       bool mode_nortl;
+       int merge_count;
+
+       dict<IdString, pool<IdString>> cells_by_type;
+
+       void handle_cell_pair(Cell *cell_a, Cell *cell_b)
+       {
+               if (cell_a->parameters != cell_b->parameters)
+                       return;
+
+               bool merge_this_cells = false;
+               vector<SigSpec> inputs_a, inputs_b;
+
+               for (auto &port_a : cell_a->connections())
+               {
+                       SigSpec bits_a = equiv_bits(port_a.second);
+                       SigSpec bits_b = equiv_bits(cell_b->getPort(port_a.first));
+
+                       if (GetSize(bits_a) != GetSize(bits_b))
+                               return;
+
+                       if (cell_a->output(port_a.first)) {
+                               for (int i = 0; i < GetSize(bits_a); i++)
+                                       if (bits_a[i] == bits_b[i])
+                                               merge_this_cells = true;
+                       } else {
+                               SigSpec diff_bits_a, diff_bits_b;
+                               for (int i = 0; i < GetSize(bits_a); i++)
+                                       if (bits_a[i] != bits_b[i]) {
+                                               diff_bits_a.append(bits_a[i]);
+                                               diff_bits_b.append(bits_b[i]);
+                                       }
+                               if (!diff_bits_a.empty()) {
+                                       inputs_a.push_back(diff_bits_a);
+                                       inputs_b.push_back(diff_bits_b);
+                               }
+                       }
+               }
+
+               if (merge_this_cells)
+               {
+                       SigMap merged_map;
+
+                       log("      Merging cells %s and %s.\n", log_id(cell_a),  log_id(cell_b));
+                       merge_count++;
+
+                       for (int i = 0; i < GetSize(inputs_a); i++) {
+                               SigSpec &sig_a = inputs_a[i], &sig_b = inputs_b[i];
+                               SigSpec sig_y = module->addWire(NEW_ID, GetSize(sig_a));
+                               log("        A: %s, B: %s, Y: %s\n", log_signal(sig_a),  log_signal(sig_b), log_signal(sig_y));
+                               module->addEquiv(NEW_ID, sig_a, sig_b, sig_y);
+                               merged_map.add(sig_a, sig_y);
+                               merged_map.add(sig_b, sig_y);
+                       }
+
+                       std::vector<IdString> outport_names, inport_names;
+
+                       for (auto &port_a : cell_a->connections())
+                               if (cell_a->output(port_a.first))
+                                       outport_names.push_back(port_a.first);
+                               else
+                                       inport_names.push_back(port_a.first);
+
+                       for (auto &pn : inport_names)
+                               cell_a->setPort(pn, merged_map(equiv_bits(cell_a->getPort(pn))));
+
+                       for (auto &pn : outport_names) {
+                               SigSpec sig_a = cell_a->getPort(pn);
+                               SigSpec sig_b = cell_b->getPort(pn);
+                               module->connect(sig_b, sig_a);
+                               sigmap.add(sig_b, sig_a);
+                               equiv_bits.add(sig_b, sig_a);
+                       }
+
+                       module->remove(cell_b);
+               }
+       }
+
+       EquivStructWorker(Module *module, bool mode_nortl) :
+                       module(module), sigmap(module), equiv_bits(module), mode_nortl(mode_nortl), merge_count(0)
+       {
+               log("  Starting new iteration.\n");
+
+               for (auto cell : module->selected_cells())
+                       if (cell->type == "$equiv") {
+                               equiv_bits.add(sigmap(cell->getPort("\\A")), sigmap(cell->getPort("\\B")));
+                       } else
+                       if (module->design->selected(module, cell)) {
+                               if (!mode_nortl || module->design->module(cell->type))
+                                       cells_by_type[cell->type].insert(cell->name);
+                       }
+
+               for (auto &it : cells_by_type)
+               {
+                       if (it.second.size() <= 1)
+                               continue;
+
+                       log("    Merging %s cells..\n", log_id(it.first));
+
+                       // FIXME: O(n^2)
+                       for (auto cell_name_a : it.second)
+                       for (auto cell_name_b : it.second)
+                               if (cell_name_a < cell_name_b) {
+                                       Cell *cell_a = module->cell(cell_name_a);
+                                       Cell *cell_b = module->cell(cell_name_b);
+                                       if (cell_a && cell_b)
+                                               handle_cell_pair(cell_a, cell_b);
+                               }
+               }
+       }
+};
+
+struct EquivStructPass : public Pass {
+       EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    equiv_struct [options] [selection]\n");
+               log("\n");
+               log("This command adds additional $equiv cells based on the assumption that the\n");
+               log("gold and gate circuit are structurally equivalent. Note that this can introduce\n");
+               log("bad $equiv cells in cases where the netlists are not structurally equivalent,\n");
+               log("for example when analyzing circuits with cells with commutative inputs.\n");
+               log("\n");
+               log("    -nortl\n");
+               log("        only operate on 'blackbox' cells and hierarchical module instantiations\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, Design *design)
+       {
+               bool mode_nortl = false;
+
+               log_header("Executing EQUIV_STRUCT pass.\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-bb") {
+                               mode_nortl = true;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules()) {
+                       log("Running equiv_struct on module %s:", log_id(module));
+                       while (1) {
+                               EquivStructWorker worker(module, mode_nortl);
+                               if (worker.merge_count == 0)
+                                       break;
+                       }
+               }
+       }
+} EquivStructPass;
+
+PRIVATE_NAMESPACE_END