Moved some passes to other source directories
authorClifford Wolf <clifford@clifford.at>
Sat, 8 Feb 2014 13:39:15 +0000 (14:39 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 8 Feb 2014 13:39:15 +0000 (14:39 +0100)
12 files changed:
passes/cmds/Makefile.inc
passes/cmds/scc.cc [new file with mode: 0644]
passes/extract/Makefile.inc [deleted file]
passes/extract/extract.cc [deleted file]
passes/hierarchy/Makefile.inc
passes/hierarchy/submod.cc [new file with mode: 0644]
passes/scc/Makefile.inc [deleted file]
passes/scc/scc.cc [deleted file]
passes/submod/Makefile.inc [deleted file]
passes/submod/submod.cc [deleted file]
passes/techmap/Makefile.inc
passes/techmap/extract.cc [new file with mode: 0644]

index 5ee82975772b7d60975c94d148696fdc96aef3ce..7638f6006ec46e858398ec78e051d2d42df96816 100644 (file)
@@ -13,4 +13,5 @@ OBJS += passes/cmds/stat.o
 OBJS += passes/cmds/setattr.o
 OBJS += passes/cmds/copy.o
 OBJS += passes/cmds/splice.o
+OBJS += passes/cmds/scc.o
 
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
new file mode 100644 (file)
index 0000000..f8c351a
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *  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.
+ *
+ */
+
+// [[CITE]] Tarjan's strongly connected components algorithm
+// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146–160, doi:10.1137/0201010
+// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <set>
+
+struct SccWorker
+{
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       SigMap sigmap;
+       CellTypes ct;
+
+       std::set<RTLIL::Cell*> workQueue;
+       std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
+       std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;
+
+       std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
+       std::map<RTLIL::Cell*, int> cellDepth;
+       std::set<RTLIL::Cell*> cellsOnStack;
+       std::vector<RTLIL::Cell*> cellStack;
+       int labelCounter;
+
+       std::map<RTLIL::Cell*, int> cell2scc;
+       std::vector<std::set<RTLIL::Cell*>> sccList;
+
+       void run(RTLIL::Cell *cell, int depth, int maxDepth)
+       {
+               assert(workQueue.count(cell) > 0);
+
+               workQueue.erase(cell);
+               cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
+               labelCounter++;
+
+               cellsOnStack.insert(cell);
+               cellStack.push_back(cell);
+
+               if (maxDepth >= 0)
+                       cellDepth[cell] = depth;
+
+               for (auto nextCell : cellToNextCell[cell])
+                       if (cellLabels.count(nextCell) == 0) {
+                               run(nextCell, depth+1, maxDepth);
+                               cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
+                       } else
+                       if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
+                                       cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
+                       }
+
+               if (cellLabels[cell].first == cellLabels[cell].second)
+               {
+                       if (cellStack.back() == cell)
+                       {
+                               cellStack.pop_back();
+                               cellsOnStack.erase(cell);
+                       }
+                       else
+                       {
+                               log("Found an SCC:");
+                               std::set<RTLIL::Cell*> scc;
+                               while (cellsOnStack.count(cell) > 0) {
+                                       RTLIL::Cell *c = cellStack.back();
+                                       cellStack.pop_back();
+                                       cellsOnStack.erase(c);
+                                       log(" %s", RTLIL::id2cstr(c->name));
+                                       cell2scc[c] = sccList.size();
+                                       scc.insert(c);
+                               }
+                               sccList.push_back(scc);
+                               log("\n");
+                       }
+               }
+       }
+
+       SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth) : design(design), module(module), sigmap(module)
+       {
+               if (module->processes.size() > 0) {
+                       log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
+                       return;
+               }
+
+               if (allCellTypes) {
+                       ct.setup(design);
+               } else {
+                       ct.setup_internals();
+                       ct.setup_stdcells();
+               }
+
+               SigPool selectedSignals;
+               SigSet<RTLIL::Cell*> sigToNextCells;
+
+               for (auto &it : module->wires)
+                       if (design->selected(module, it.second))
+                               selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));
+
+               for (auto &it : module->cells)
+               {
+                       RTLIL::Cell *cell = it.second;
+
+                       if (!design->selected(module, cell))
+                               continue;
+
+                       if (!allCellTypes && !ct.cell_known(cell->type))
+                               continue;
+
+                       workQueue.insert(cell);
+
+                       RTLIL::SigSpec inputSignals, outputSignals;
+
+                       for (auto &conn : cell->connections)
+                       {
+                               bool isInput = true, isOutput = true;
+
+                               if (ct.cell_known(cell->type)) {
+                                       isInput = ct.cell_input(cell->type, conn.first);
+                                       isOutput = ct.cell_output(cell->type, conn.first);
+                               }
+
+                               RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
+                               sig.sort_and_unify();
+
+                               if (isInput)
+                                       inputSignals.append(sig);
+                               if (isOutput)
+                                       outputSignals.append(sig);
+                       }
+
+                       inputSignals.sort_and_unify();
+                       outputSignals.sort_and_unify();
+
+                       cellToPrevSig[cell] = inputSignals;
+                       cellToNextSig[cell] = outputSignals;
+                       sigToNextCells.insert(inputSignals, cell);
+               }
+
+               for (auto cell : workQueue)
+                       cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
+
+               labelCounter = 0;
+               cellLabels.clear();
+
+               while (workQueue.size() > 0) {
+                       RTLIL::Cell *cell = *workQueue.begin();
+                       assert(cellStack.size() == 0);
+                       cellDepth.clear();
+                       run(cell, 0, maxDepth);
+               }
+
+               log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
+       }
+
+       void select(RTLIL::Selection &sel)
+       {
+               for (int i = 0; i < int(sccList.size()); i++)
+               {
+                       std::set<RTLIL::Cell*> &cells = sccList[i];
+                       RTLIL::SigSpec prevsig, nextsig, sig;
+
+                       for (auto cell : cells) {
+                               sel.selected_members[module->name].insert(cell->name);
+                               prevsig.append(cellToPrevSig[cell]);
+                               nextsig.append(cellToNextSig[cell]);
+                       }
+
+                       prevsig.sort_and_unify();
+                       nextsig.sort_and_unify();
+                       sig = prevsig.extract(nextsig);
+
+                       for (auto &chunk : sig.chunks)
+                               if (chunk.wire != NULL)
+                                       sel.selected_members[module->name].insert(chunk.wire->name);
+               }
+       }
+};
+
+struct SccPass : public Pass {
+       SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    scc [options] [selection]\n");
+               log("\n");
+               log("This command identifies strongly connected components (aka logic loops) in the\n");
+               log("design.\n");
+               log("\n");
+               log("    -max_depth <num>\n");
+               log("        limit to loops not longer than the specified number of cells. This can\n");
+               log("        e.g. be useful in identifying local loops in a module that turns out\n");
+               log("        to be one gigantic SCC.\n");
+               log("\n");
+               log("    -all_cell_types\n");
+               log("        Usually this command only considers internal non-memory cells. With\n");
+               log("        this option set, all cells are considered. For unkown cells all ports\n");
+               log("        are assumed to be bidirectional 'inout' ports.\n");
+               log("\n");
+               log("    -set_attr <name> <value>\n");
+               log("    -set_cell_attr <name> <value>\n");
+               log("    -set_wire_attr <name> <value>\n");
+               log("        set the specified attribute on all cells and/or wires that are part of\n");
+               log("        a logic loop. the special token {} in the value is replaced with a\n");
+               log("        unique identifier for the logic loop.\n");
+               log("\n");
+               log("    -select\n");
+               log("        replace the current selection with a selection of all cells and wires\n");
+               log("        that are part of a found logic loop\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               std::map<std::string, std::string> setCellAttr, setWireAttr;
+               bool allCellTypes = false;
+               bool selectMode = false;
+               int maxDepth = -1;
+
+               log_header("Executing SCC pass (detecting logic loops).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
+                               maxDepth = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-all_cell_types") {
+                               allCellTypes = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
+                               setCellAttr[args[argidx+1]] = args[argidx+2];
+                               setWireAttr[args[argidx+1]] = args[argidx+2];
+                               argidx += 2;
+                               continue;
+                       }
+                       if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
+                               setCellAttr[args[argidx+1]] = args[argidx+2];
+                               argidx += 2;
+                               continue;
+                       }
+                       if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
+                               setWireAttr[args[argidx+1]] = args[argidx+2];
+                               argidx += 2;
+                               continue;
+                       }
+                       if (args[argidx] == "-select") {
+                               selectMode = true;
+                               continue;
+                       }
+                       break;
+               }
+               int origSelectPos = design->selection_stack.size() - 1;
+               extra_args(args, argidx, design);
+
+               if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
+                       log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
+
+               RTLIL::Selection newSelection(false);
+
+               for (auto &mod_it : design->modules)
+                       if (design->selected(mod_it.second))
+                       {
+                               SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
+
+                               if (selectMode)
+                                       worker.select(newSelection);
+                       }
+
+               if (selectMode) {
+                       assert(origSelectPos >= 0);
+                       design->selection_stack[origSelectPos] = newSelection;
+                       design->selection_stack[origSelectPos].optimize(design);
+               }
+       }
+} SccPass;
diff --git a/passes/extract/Makefile.inc b/passes/extract/Makefile.inc
deleted file mode 100644 (file)
index 5ef88a3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-OBJS += passes/extract/extract.o
-
diff --git a/passes/extract/extract.cc b/passes/extract/extract.cc
deleted file mode 100644 (file)
index eff14ff..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- *  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/register.h"
-#include "kernel/sigtools.h"
-#include "kernel/log.h"
-#include "libs/subcircuit/subcircuit.h"
-#include <algorithm>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-using RTLIL::id2cstr;
-
-namespace
-{
-       class SubCircuitSolver : public SubCircuit::Solver
-       {
-       public:
-               std::set<RTLIL::IdString> cell_attr, wire_attr;
-
-               bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
-               {
-                       for (auto &it : attr) {
-                               size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
-                               if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
-                                       return false;
-                       }
-                       return true;
-               }
-
-               virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
-                               const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
-               {
-                       RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
-                       RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
-
-                       if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
-                               return false;
-
-                       if (wire_attr.size() > 0)
-                       {
-                               RTLIL::Wire *lastNeedleWire = NULL;
-                               RTLIL::Wire *lastHaystackWire = NULL;
-                               std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
-
-                               for (auto &conn : needleCell->connections)
-                               {
-                                       RTLIL::SigSpec needleSig = conn.second;
-                                       RTLIL::SigSpec haystackSig = haystackCell->connections.at(portMapping.at(conn.first));
-
-                                       needleSig.expand();
-                                       haystackSig.expand();
-
-                                       for (int i = 0; i < std::min(needleSig.width, haystackSig.width); i++) {
-                                               RTLIL::Wire *needleWire = needleSig.chunks.at(i).wire, *haystackWire = haystackSig.chunks.at(i).wire;
-                                               if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
-                                                       if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
-                                                               return false;
-                                               lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
-                                       }
-                               }
-                       }
-
-                       return true;
-               }
-       };
-
-       struct bit_ref_t {
-               std::string cell, port;
-               int bit;
-       };
-
-       bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
-                       int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
-       {
-               SigMap sigmap(mod);
-               std::map<RTLIL::SigChunk, bit_ref_t> sig_bit_ref;
-
-               if (sel && !sel->selected(mod)) {
-                       log("  Skipping module %s as it is not selected.\n", id2cstr(mod->name));
-                       return false;
-               }
-
-               if (mod->processes.size() > 0) {
-                       log("  Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
-                       return false;
-               }
-
-               if (constports) {
-                       graph.createNode("$const$0", "$const$0", NULL, true);
-                       graph.createNode("$const$1", "$const$1", NULL, true);
-                       graph.createNode("$const$x", "$const$x", NULL, true);
-                       graph.createNode("$const$z", "$const$z", NULL, true);
-                       graph.createPort("$const$0", "\\Y", 1);
-                       graph.createPort("$const$1", "\\Y", 1);
-                       graph.createPort("$const$x", "\\Y", 1);
-                       graph.createPort("$const$z", "\\Y", 1);
-                       graph.markExtern("$const$0", "\\Y", 0);
-                       graph.markExtern("$const$1", "\\Y", 0);
-                       graph.markExtern("$const$x", "\\Y", 0);
-                       graph.markExtern("$const$z", "\\Y", 0);
-               }
-
-               std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
-               if (max_fanout > 0)
-                       for (auto &cell_it : mod->cells)
-                       {
-                               RTLIL::Cell *cell = cell_it.second;
-                               if (!sel || sel->selected(mod, cell))
-                                       for (auto &conn : cell->connections) {
-                                               RTLIL::SigSpec conn_sig = conn.second;
-                                               sigmap.apply(conn_sig);
-                                               conn_sig.expand();
-                                               for (auto &chunk : conn_sig.chunks)
-                                                       if (chunk.wire != NULL)
-                                                               sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)]++;
-                                       }
-                       }
-
-               // create graph nodes from cells
-               for (auto &cell_it : mod->cells)
-               {
-                       RTLIL::Cell *cell = cell_it.second;
-                       if (sel && !sel->selected(mod, cell))
-                               continue;
-
-                       std::string type = cell->type;
-                       if (sel == NULL && type.substr(0, 2) == "\\$")
-                               type = type.substr(1);
-                       graph.createNode(cell->name, type, (void*)cell);
-
-                       for (auto &conn : cell->connections)
-                       {
-                               graph.createPort(cell->name, conn.first, conn.second.width);
-
-                               if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
-                                       continue;
-
-                               RTLIL::SigSpec conn_sig = conn.second;
-                               sigmap.apply(conn_sig);
-                               conn_sig.expand();
-
-                               for (size_t i = 0; i < conn_sig.chunks.size(); i++)
-                               {
-                                       auto &chunk = conn_sig.chunks[i];
-                                       assert(chunk.width == 1);
-
-                                       if (chunk.wire == NULL) {
-                                               if (constports) {
-                                                       std::string node = "$const$x";
-                                                       if (chunk.data.bits[0] == RTLIL::State::S0) node = "$const$0";
-                                                       if (chunk.data.bits[0] == RTLIL::State::S1) node = "$const$1";
-                                                       if (chunk.data.bits[0] == RTLIL::State::Sz) node = "$const$z";
-                                                       graph.createConnection(cell->name, conn.first, i, node, "\\Y", 0);
-                                               } else
-                                                       graph.createConstant(cell->name, conn.first, i, int(chunk.data.bits[0]));
-                                               continue;
-                                       }
-
-                                       if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout)
-                                               continue;
-
-                                       if (sel && !sel->selected(mod, chunk.wire))
-                                               continue;
-
-                                       if (sig_bit_ref.count(chunk) == 0) {
-                                               bit_ref_t &bit_ref = sig_bit_ref[chunk];
-                                               bit_ref.cell = cell->name;
-                                               bit_ref.port = conn.first;
-                                               bit_ref.bit = i;
-                                       }
-
-                                       bit_ref_t &bit_ref = sig_bit_ref[chunk];
-                                       graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name, conn.first, i);
-                               }
-                       }
-               }
-
-               // mark external signals (used in non-selected cells)
-               for (auto &cell_it : mod->cells)
-               {
-                       RTLIL::Cell *cell = cell_it.second;
-                       if (sel && !sel->selected(mod, cell))
-                               for (auto &conn : cell->connections)
-                               {
-                                       RTLIL::SigSpec conn_sig = conn.second;
-                                       sigmap.apply(conn_sig);
-                                       conn_sig.expand();
-
-                                       for (auto &chunk : conn_sig.chunks)
-                                               if (sig_bit_ref.count(chunk) != 0) {
-                                                       bit_ref_t &bit_ref = sig_bit_ref[chunk];
-                                                       graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
-                                               }
-                               }
-               }
-
-               // mark external signals (used in module ports)
-               for (auto &wire_it : mod->wires)
-               {
-                       RTLIL::Wire *wire = wire_it.second;
-                       if (wire->port_id > 0)
-                       {
-                               RTLIL::SigSpec conn_sig(wire);
-                               sigmap.apply(conn_sig);
-                               conn_sig.expand();
-
-                               for (auto &chunk : conn_sig.chunks)
-                                       if (sig_bit_ref.count(chunk) != 0) {
-                                               bit_ref_t &bit_ref = sig_bit_ref[chunk];
-                                               graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
-                                       }
-                       }
-               }
-
-               // graph.print();
-               return true;
-       }
-
-       RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
-       {
-               SigMap sigmap(needle);
-               SigSet<std::pair<std::string, int>> sig2port;
-
-               // create new cell
-               RTLIL::Cell *cell = new RTLIL::Cell;
-               cell->name = stringf("$extract$%s$%d", needle->name.c_str(), RTLIL::autoidx++);
-               cell->type = needle->name;
-               haystack->add(cell);
-
-               // create cell ports
-               for (auto &it : needle->wires) {
-                       RTLIL::Wire *wire = it.second;
-                       if (wire->port_id > 0) {
-                               for (int i = 0; i < wire->width; i++)
-                                       sig2port.insert(sigmap(RTLIL::SigSpec(wire, 1, i)), std::pair<std::string, int>(wire->name, i));
-                               cell->connections[wire->name] = RTLIL::SigSpec(RTLIL::State::Sz, wire->width);
-                       }
-               }
-
-               // delete replaced cells and connect new ports
-               for (auto &it : match.mappings)
-               {
-                       auto &mapping = it.second;
-                       RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
-                       RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
-
-                       if (needle_cell == NULL)
-                               continue;
-
-                       for (auto &conn : needle_cell->connections) {
-                               RTLIL::SigSpec sig = sigmap(conn.second);
-                               if (mapping.portMapping.count(conn.first) > 0 && sig2port.has(sigmap(sig))) {
-                                       sig.expand();
-                                       for (int i = 0; i < sig.width; i++)
-                                       for (auto &port : sig2port.find(sig.chunks[i])) {
-                                               RTLIL::SigSpec bitsig = haystack_cell->connections.at(mapping.portMapping[conn.first]).extract(i, 1);
-                                               cell->connections.at(port.first).replace(port.second, bitsig);
-                                       }
-                               }
-                       }
-
-                       haystack->cells.erase(haystack_cell->name);
-                       delete haystack_cell;
-               }
-
-               return cell;
-       }
-
-       bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
-       {
-               int left_idx = 0, right_idx = 0;
-               if (left->attributes.count("\\extract_order") > 0)
-                       left_idx = left->attributes.at("\\extract_order").as_int();
-               if (right->attributes.count("\\extract_order") > 0)
-                       right_idx = right->attributes.at("\\extract_order").as_int();
-               if (left_idx != right_idx)
-                       return left_idx < right_idx;
-               return left->name < right->name;
-       }
-}
-
-struct ExtractPass : public Pass {
-       ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
-       virtual void help()
-       {
-               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-               log("\n");
-               log("    extract -map <map_file> [options] [selection]\n");
-               log("    extract -mine <out_file> [options] [selection]\n");
-               log("\n");
-               log("This pass looks for subcircuits that are isomorphic to any of the modules\n");
-               log("in the given map file and replaces them with instances of this modules. The\n");
-               log("map file can be a verilog source file (*.v) or an ilang file (*.il).\n");
-               log("\n");
-               log("    -map <map_file>\n");
-               log("        use the modules in this file as reference. This option can be used\n");
-               log("        multiple times.\n");
-               log("\n");
-               log("    -verbose\n");
-               log("        print debug output while analyzing\n");
-               log("\n");
-               log("    -constports\n");
-               log("        also find instances with constant drivers. this may be much\n");
-               log("        slower than the normal operation.\n");
-               log("\n");
-               log("    -nodefaultswaps\n");
-               log("        normally builtin port swapping rules for internal cells are used per\n");
-               log("        default. This turns that off, so e.g. 'a^b' does not match 'b^a'\n");
-               log("        when this option is used.\n");
-               log("\n");
-               log("    -compat <needle_type> <haystack_type>\n");
-               log("        Per default, the cells in the map file (needle) must have the\n");
-               log("        type as the cells in the active design (haystack). This option\n");
-               log("        can be used to register additional pairs of types that should\n");
-               log("        match. This option can be used multiple times.\n");
-               log("\n");
-               log("    -swap <needle_type> <port1>,<port2>[,...]\n");
-               log("        Register a set of swapable ports for a needle cell type.\n");
-               log("        This option can be used multiple times.\n");
-               log("\n");
-               log("    -perm <needle_type> <port1>,<port2>[,...] <portA>,<portB>[,...]\n");
-               log("        Register a valid permutation of swapable ports for a needle\n");
-               log("        cell type. This option can be used multiple times.\n");
-               log("\n");
-               log("    -cell_attr <attribute_name>\n");
-               log("        Attributes on cells with the given name must match.\n");
-               log("\n");
-               log("    -wire_attr <attribute_name>\n");
-               log("        Attributes on wires with the given name must match.\n");
-               log("\n");
-               log("This pass does not operate on modules with uprocessed processes in it.\n");
-               log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
-               log("\n");
-               log("This pass can also be used for mining for frequent subcircuits. In this mode\n");
-               log("the following options are to be used instead of the -map option.\n");
-               log("\n");
-               log("    -mine <out_file>\n");
-               log("        mine for frequent subcircuits and write them to the given ilang file\n");
-               log("\n");
-               log("    -mine_cells_span <min> <max>\n");
-               log("        only mine for subcircuits with the specified number of cells\n");
-               log("        default value: 3 5\n");
-               log("\n");
-               log("    -mine_min_freq <num>\n");
-               log("        only mine for subcircuits with at least the specified number of matches\n");
-               log("        default value: 10\n");
-               log("\n");
-               log("    -mine_limit_matches_per_module <num>\n");
-               log("        when calculating the number of matches for a subcircuit, don't count\n");
-               log("        more than the specified number of matches per module\n");
-               log("\n");
-               log("    -mine_max_fanout <num>\n");
-               log("        don't consider internal signals with more than <num> connections\n");
-               log("\n");
-               log("The modules in the map file may have the attribute 'extract_order' set to an\n");
-               log("integer value. Then this value is used to determine the order in which the pass\n");
-               log("tries to map the modules to the design (ascending, default value is 0).\n");
-               log("\n");
-               log("See 'help techmap' for a pass that does the opposite thing.\n");
-               log("\n");
-       }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
-       {
-               log_header("Executing EXTRACT pass (map subcircuits to cells).\n");
-               log_push();
-
-               SubCircuitSolver solver;
-
-               std::vector<std::string> map_filenames;
-               std::string mine_outfile;
-               bool constports = false;
-               bool nodefaultswaps = false;
-
-               bool mine_mode = false;
-               int mine_cells_min = 3;
-               int mine_cells_max = 5;
-               int mine_min_freq = 10;
-               int mine_limit_mod = -1;
-               int mine_max_fanout = -1;
-               std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> mine_split;
-
-               size_t argidx;
-               for (argidx = 1; argidx < args.size(); argidx++) {
-                       if (args[argidx] == "-map" && argidx+1 < args.size()) {
-                               if (mine_mode)
-                                       log_cmd_error("You cannot mix -map and -mine.\n");
-                               map_filenames.push_back(args[++argidx]);
-                               continue;
-                       }
-                       if (args[argidx] == "-mine" && argidx+1 < args.size()) {
-                               if (!map_filenames.empty())
-                                       log_cmd_error("You cannot mix -map and -mine.\n");
-                               mine_outfile = args[++argidx];
-                               mine_mode = true;
-                               continue;
-                       }
-                       if (args[argidx] == "-mine_cells_span" && argidx+2 < args.size()) {
-                               mine_cells_min = atoi(args[++argidx].c_str());
-                               mine_cells_max = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (args[argidx] == "-mine_min_freq" && argidx+1 < args.size()) {
-                               mine_min_freq = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (args[argidx] == "-mine_limit_matches_per_module" && argidx+1 < args.size()) {
-                               mine_limit_mod = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (args[argidx] == "-mine_split" && argidx+2 < args.size()) {
-                               mine_split.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
-                               argidx += 2;
-                               continue;
-                       }
-                       if (args[argidx] == "-mine_max_fanout" && argidx+1 < args.size()) {
-                               mine_max_fanout = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (args[argidx] == "-verbose") {
-                               solver.setVerbose();
-                               continue;
-                       }
-                       if (args[argidx] == "-constports") {
-                               constports = true;
-                               continue;
-                       }
-                       if (args[argidx] == "-nodefaultswaps") {
-                               nodefaultswaps = true;
-                               continue;
-                       }
-                       if (args[argidx] == "-compat" && argidx+2 < args.size()) {
-                               std::string needle_type = RTLIL::escape_id(args[++argidx]);
-                               std::string haystack_type = RTLIL::escape_id(args[++argidx]);
-                               solver.addCompatibleTypes(needle_type, haystack_type);
-                               continue;
-                       }
-                       if (args[argidx] == "-swap" && argidx+2 < args.size()) {
-                               std::string type = RTLIL::escape_id(args[++argidx]);
-                               std::set<std::string> ports;
-                               char *ports_str = strdup(args[++argidx].c_str());
-                               for (char *sptr, *p = strtok_r(ports_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
-                                       ports.insert(RTLIL::escape_id(p));
-                               free(ports_str);
-                               solver.addSwappablePorts(type, ports);
-                               continue;
-                       }
-                       if (args[argidx] == "-perm" && argidx+3 < args.size()) {
-                               std::string type = RTLIL::escape_id(args[++argidx]);
-                               std::vector<std::string> map_left, map_right;
-                               char *left_str = strdup(args[++argidx].c_str());
-                               char *right_str = strdup(args[++argidx].c_str());
-                               for (char *sptr, *p = strtok_r(left_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
-                                       map_left.push_back(RTLIL::escape_id(p));
-                               for (char *sptr, *p = strtok_r(right_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
-                                       map_right.push_back(RTLIL::escape_id(p));
-                               free(left_str);
-                               free(right_str);
-                               if (map_left.size() != map_right.size())
-                                       log_cmd_error("Arguments to -perm are not a valid permutation!\n");
-                               std::map<std::string, std::string> map;
-                               for (size_t i = 0; i < map_left.size(); i++)
-                                       map[map_left[i]] = map_right[i];
-                               std::sort(map_left.begin(), map_left.end());
-                               std::sort(map_right.begin(), map_right.end());
-                               if (map_left != map_right)
-                                       log_cmd_error("Arguments to -perm are not a valid permutation!\n");
-                               solver.addSwappablePortsPermutation(type, map);
-                               continue;
-                       }
-                       if (args[argidx] == "-cell_attr" && argidx+1 < args.size()) {
-                               solver.cell_attr.insert(RTLIL::escape_id(args[++argidx]));
-                               continue;
-                       }
-                       if (args[argidx] == "-wire_attr" && argidx+1 < args.size()) {
-                               solver.wire_attr.insert(RTLIL::escape_id(args[++argidx]));
-                               continue;
-                       }
-                       break;
-               }
-               extra_args(args, argidx, design);
-
-               if (!nodefaultswaps) {
-                       solver.addSwappablePorts("$and",       "\\A", "\\B");
-                       solver.addSwappablePorts("$or",        "\\A", "\\B");
-                       solver.addSwappablePorts("$xor",       "\\A", "\\B");
-                       solver.addSwappablePorts("$xnor",      "\\A", "\\B");
-                       solver.addSwappablePorts("$eq",        "\\A", "\\B");
-                       solver.addSwappablePorts("$ne",        "\\A", "\\B");
-                       solver.addSwappablePorts("$eqx",       "\\A", "\\B");
-                       solver.addSwappablePorts("$nex",       "\\A", "\\B");
-                       solver.addSwappablePorts("$add",       "\\A", "\\B");
-                       solver.addSwappablePorts("$mul",       "\\A", "\\B");
-                       solver.addSwappablePorts("$logic_and", "\\A", "\\B");
-                       solver.addSwappablePorts("$logic_or",  "\\A", "\\B");
-                       solver.addSwappablePorts("$_AND_",     "\\A", "\\B");
-                       solver.addSwappablePorts("$_OR_",      "\\A", "\\B");
-                       solver.addSwappablePorts("$_XOR_",     "\\A", "\\B");
-               }
-
-               if (map_filenames.empty() && mine_outfile.empty())
-                       log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
-
-               RTLIL::Design *map = NULL;
-
-               if (!mine_mode)
-               {
-                       map = new RTLIL::Design;
-                       for (auto &filename : map_filenames) {
-                               FILE *f = fopen(filename.c_str(), "rt");
-                               if (f == NULL)
-                                       log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
-                               Frontend::frontend_call(map, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
-                               fclose(f);
-
-                               if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
-                                       Pass::call(map, "proc");
-                                       Pass::call(map, "opt_clean");
-                               }
-                       }
-               }
-
-               std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
-               std::vector<RTLIL::Module*> needle_list;
-
-               log_header("Creating graphs for SubCircuit library.\n");
-
-               if (!mine_mode)
-                       for (auto &mod_it : map->modules) {
-                               SubCircuit::Graph mod_graph;
-                               std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
-                               log("Creating needle graph %s.\n", graph_name.c_str());
-                               if (module2graph(mod_graph, mod_it.second, constports)) {
-                                       solver.addGraph(graph_name, mod_graph);
-                                       needle_map[graph_name] = mod_it.second;
-                                       needle_list.push_back(mod_it.second);
-                               }
-                       }
-
-               for (auto &mod_it : design->modules) {
-                       SubCircuit::Graph mod_graph;
-                       std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
-                       log("Creating haystack graph %s.\n", graph_name.c_str());
-                       if (module2graph(mod_graph, mod_it.second, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : NULL)) {
-                               solver.addGraph(graph_name, mod_graph);
-                               haystack_map[graph_name] = mod_it.second;
-                       }
-               }
-               
-               if (!mine_mode)
-               {
-                       std::vector<SubCircuit::Solver::Result> results;
-                       log_header("Running solver from SubCircuit library.\n");
-
-                       std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList);
-
-                       for (auto needle : needle_list)
-                       for (auto &haystack_it : haystack_map) {
-                               log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str());
-                               solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false);
-                       }
-                       log("Found %zd matches.\n", results.size());
-
-                       if (results.size() > 0)
-                       {
-                               log_header("Substitute SubCircuits with cells.\n");
-
-                               for (int i = 0; i < int(results.size()); i++) {
-                                       auto &result = results[i];
-                                       log("\nMatch #%d: (%s in %s)\n", i, result.needleGraphId.c_str(), result.haystackGraphId.c_str());
-                                       for (const auto &it : result.mappings) {
-                                               log("  %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str());
-                                               for (const auto & it2 : it.second.portMapping)
-                                                       log(" %s:%s", it2.first.c_str(), it2.second.c_str());
-                                               log("\n");
-                                       }
-                                       RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result);
-                                       design->select(haystack_map.at(result.haystackGraphId), new_cell);
-                                       log("  new cell: %s\n", id2cstr(new_cell->name));
-                               }
-                       }
-               }
-               else
-               {
-                       std::vector<SubCircuit::Solver::MineResult> results;
-
-                       log_header("Running miner from SubCircuit library.\n");
-                       solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod);
-
-                       map = new RTLIL::Design;
-
-                       int needleCounter = 0;
-                       for (auto &result: results)
-                       {
-                               log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
-                               log("  primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
-                               for (auto &node : result.nodes)
-                                       log(" %s", id2cstr(node.nodeId));
-                               log("\n");
-                               for (auto &it : result.matchesPerGraph)
-                                       log("  matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
-
-                               RTLIL::Module *mod = haystack_map.at(result.graphId);
-                               std::set<RTLIL::Cell*> cells;
-                               std::set<RTLIL::Wire*> wires;
-
-                               SigMap sigmap(mod);
-
-                               for (auto &node : result.nodes)
-                                       cells.insert((RTLIL::Cell*)node.userData);
-
-                               for (auto cell : cells)
-                               for (auto &conn : cell->connections) {
-                                       RTLIL::SigSpec sig = sigmap(conn.second);
-                                       for (auto &chunk : sig.chunks)
-                                               if (chunk.wire != NULL)
-                                                       wires.insert(chunk.wire);
-                               }
-
-                               RTLIL::Module *newMod = new RTLIL::Module;
-                               newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
-                               map->modules[newMod->name] = newMod;
-
-                               int portCounter = 1;
-                               for (auto wire : wires) {
-                                       RTLIL::Wire *newWire = new RTLIL::Wire;
-                                       newWire->name = wire->name;
-                                       newWire->width = wire->width;
-                                       newWire->port_id = portCounter++;
-                                       newWire->port_input = true;
-                                       newWire->port_output = true;
-                                       newMod->add(newWire);
-                               }
-
-                               for (auto cell : cells) {
-                                       RTLIL::Cell *newCell = new RTLIL::Cell;
-                                       newCell->name = cell->name;
-                                       newCell->type = cell->type;
-                                       newCell->parameters = cell->parameters;
-                                       for (auto &conn : cell->connections) {
-                                               RTLIL::SigSpec sig = sigmap(conn.second);
-                                               for (auto &chunk : sig.chunks)
-                                                       if (chunk.wire != NULL)
-                                                               chunk.wire = newMod->wires.at(chunk.wire->name);
-                                               newCell->connections[conn.first] = sig;
-                                       }
-                                       newMod->add(newCell);
-                               }
-                       }
-
-                       FILE *f = fopen(mine_outfile.c_str(), "wt");
-                       if (f == NULL)
-                               log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
-                       Backend::backend_call(map, f, mine_outfile, "ilang");
-                       fclose(f);
-               }
-
-               delete map;
-               log_pop();
-       }
-} ExtractPass;
index 37cc287ace97677f475ce0a2ededf91532b3b16f..99aa1e1164534767298f14b4afd94d499f9f7050 100644 (file)
@@ -1,3 +1,4 @@
 
 OBJS += passes/hierarchy/hierarchy.o
+OBJS += passes/hierarchy/submod.o
 
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
new file mode 100644 (file)
index 0000000..7d08112
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ *  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/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <set>
+
+struct SubmodWorker
+{
+       CellTypes ct;
+       RTLIL::Design *design;
+       RTLIL::Module *module;
+       std::string opt_name;
+
+       struct SubModule
+       {
+               std::string name, full_name;
+               std::set<RTLIL::Cell*> cells;
+       };
+
+       std::map<std::string, SubModule> submodules;
+
+       struct wire_flags_t {
+               RTLIL::Wire *new_wire;
+               bool is_int_driven, is_int_used, is_ext_driven, is_ext_used;
+               wire_flags_t() : new_wire(NULL), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
+       };
+       std::map<RTLIL::Wire*, wire_flags_t> wire_flags;
+       bool flag_found_something;
+
+       void flag_wire(RTLIL::Wire *wire, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+       {
+               if (wire_flags.count(wire) == 0) {
+                       if (!create)
+                               return;
+                       wire_flags[wire] = wire_flags_t();
+               }
+               if (set_int_driven)
+                       wire_flags[wire].is_int_driven = true;
+               if (set_int_used)
+                       wire_flags[wire].is_int_used = true;
+               if (set_ext_driven)
+                       wire_flags[wire].is_ext_driven = true;
+               if (set_ext_used)
+                       wire_flags[wire].is_ext_used = true;
+               flag_found_something = true;
+       }
+
+       void flag_signal(RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+       {
+               for (auto &c : sig.chunks)
+                       if (c.wire != NULL)
+                               flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
+       }
+
+       void handle_submodule(SubModule &submod)
+       {
+               log("Creating submodule %s (%s) of module %s.\n", submod.name.c_str(), submod.full_name.c_str(), module->name.c_str());
+
+               wire_flags.clear();
+               for (RTLIL::Cell *cell : submod.cells) {
+                       if (ct.cell_known(cell->type)) {
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
+                       } else {
+                               log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, true, true, true, false, false);
+                       }
+               }
+               for (auto &it : module->cells) {
+                       RTLIL::Cell *cell = it.second;
+                       if (submod.cells.count(cell) > 0)
+                               continue;
+                       if (ct.cell_known(cell->type)) {
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, false, false, false, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first));
+                       } else {
+                               flag_found_something = false;
+                               for (auto &conn : cell->connections)
+                                       flag_signal(conn.second, false, false, false, true, true);
+                               if (flag_found_something)
+                                       log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+                       }
+               }
+
+               RTLIL::Module *new_mod = new RTLIL::Module;
+               new_mod->name = submod.full_name;
+               design->modules[new_mod->name] = new_mod;
+               int port_counter = 1, auto_name_counter = 1;
+
+               std::set<std::string> all_wire_names;
+               for (auto &it : wire_flags) {
+                       all_wire_names.insert(it.first->name);
+               }
+
+               for (auto &it : wire_flags)
+               {
+                       RTLIL::Wire *wire = it.first;
+                       wire_flags_t &flags = it.second;
+
+                       if (wire->port_input)
+                               flags.is_ext_driven = true;
+                       if (wire->port_output)
+                               flags.is_ext_used = true;
+
+                       RTLIL::Wire *new_wire = new RTLIL::Wire;
+                       new_wire->name = wire->name;
+                       new_wire->width = wire->width;
+                       new_wire->start_offset = wire->start_offset;
+                       new_wire->attributes = wire->attributes;
+
+                       if (flags.is_int_driven && flags.is_ext_used)
+                               new_wire->port_output = true;
+                       if (flags.is_ext_driven && flags.is_int_used)
+                               new_wire->port_input = true;
+
+                       if (flags.is_int_driven && flags.is_ext_driven)
+                               new_wire->port_input = true, new_wire->port_output = true;
+
+                       if (new_wire->port_input || new_wire->port_output) {
+                               new_wire->port_id = port_counter++;
+                               while (new_wire->name[0] == '$') {
+                                       std::string new_wire_name = stringf("\\n%d", auto_name_counter++);
+                                       if (all_wire_names.count(new_wire_name) == 0) {
+                                               all_wire_names.insert(new_wire_name);
+                                               new_wire->name = new_wire_name;
+                                       }
+                               }
+                       }
+
+                       if (new_wire->port_input && new_wire->port_output)
+                               log("  signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else if (new_wire->port_input)
+                               log("  signal %s: input %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else if (new_wire->port_output)
+                               log("  signal %s: output %s\n", wire->name.c_str(), new_wire->name.c_str());
+                       else
+                               log("  signal %s: internal\n", wire->name.c_str());
+
+                       new_mod->wires[new_wire->name] = new_wire;
+                       flags.new_wire = new_wire;
+               }
+
+               for (RTLIL::Cell *cell : submod.cells) {
+                       RTLIL::Cell *new_cell = new RTLIL::Cell(*cell);
+                       for (auto &conn : new_cell->connections)
+                               for (auto &c : conn.second.chunks)
+                                       if (c.wire != NULL) {
+                                               assert(wire_flags.count(c.wire) > 0);
+                                               c.wire = wire_flags[c.wire].new_wire;
+                                       }
+                       log("  cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
+                       new_mod->cells[new_cell->name] = new_cell;
+                       module->cells.erase(cell->name);
+                       delete cell;
+               }
+               submod.cells.clear();
+
+               RTLIL::Cell *new_cell = new RTLIL::Cell;
+               new_cell->name = submod.full_name;
+               new_cell->type = submod.full_name;
+               for (auto &it : wire_flags)
+               {
+                       RTLIL::Wire *old_wire = it.first;
+                       RTLIL::Wire *new_wire = it.second.new_wire;
+                       if (new_wire->port_id > 0)
+                               new_cell->connections[new_wire->name] = RTLIL::SigSpec(old_wire);
+               }
+               module->cells[new_cell->name] = new_cell;
+       }
+
+       SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
+       {
+               if (!design->selected_whole_module(module->name) && opt_name.empty())
+                       return;
+
+               if (module->processes.size() > 0) {
+                       log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
+                       return;
+               }
+
+               if (module->memories.size() > 0) {
+                       log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module->name.c_str());
+                       return;
+               }
+
+               ct.setup_internals();
+               ct.setup_internals_mem();
+               ct.setup_stdcells();
+               ct.setup_stdcells_mem();
+               ct.setup_design(design);
+
+               if (opt_name.empty())
+               {
+                       for (auto &it : module->wires)
+                               it.second->attributes.erase("\\submod");
+
+                       for (auto &it : module->cells)
+                       {
+                               RTLIL::Cell *cell = it.second;
+                               if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].bits.size() == 0) {
+                                       cell->attributes.erase("\\submod");
+                                       continue;
+                               }
+
+                               std::string submod_str = cell->attributes["\\submod"].decode_string();
+                               cell->attributes.erase("\\submod");
+
+                               if (submodules.count(submod_str) == 0) {
+                                       submodules[submod_str].name = submod_str;
+                                       submodules[submod_str].full_name = module->name + "_" + submod_str;
+                                       while (design->modules.count(submodules[submod_str].full_name) != 0 ||
+                                                       module->count_id(submodules[submod_str].full_name) != 0)
+                                               submodules[submod_str].full_name += "_";
+                               }
+
+                               submodules[submod_str].cells.insert(cell);
+                       }
+               }
+               else
+               {
+                       for (auto &it : module->cells)
+                       {
+                               RTLIL::Cell *cell = it.second;
+                               if (!design->selected(module, cell))
+                                       continue;
+                               submodules[opt_name].name = opt_name;
+                               submodules[opt_name].full_name = RTLIL::escape_id(opt_name);
+                               submodules[opt_name].cells.insert(cell);
+                       }
+
+                       if (submodules.size() == 0)
+                               log("Nothing selected -> do nothing.\n");
+               }
+
+               for (auto &it : submodules)
+                       handle_submodule(it.second);
+       }
+};
+
+struct SubmodPass : public Pass {
+       SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    submod [selection]\n");
+               log("\n");
+               log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
+               log("a newly created module. The value of the attribute is used as name for the\n");
+               log("cell that replaces the group of cells with the same attribute value.\n");
+               log("\n");
+               log("This pass can be used to create a design hierarchy in flat design. This can\n");
+               log("be useful for analyzing or reverse-engineering a design.\n");
+               log("\n");
+               log("This pass only operates on completely selected modules with no processes\n");
+               log("or memories.\n");
+               log("\n");
+               log("\n");
+               log("    submod -name <name> [selection]\n");
+               log("\n");
+               log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
+               log("Only objects from one module might be selected. The value of the -name option\n");
+               log("is used as the value of the 'submod' attribute above.\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
+               log_push();
+
+               std::string opt_name;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-name" && argidx+1 < args.size()) {
+                               opt_name = args[++argidx];
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if (opt_name.empty())
+               {
+                       Pass::call(design, "opt_clean");
+                       log_header("Continuing SUBMOD pass.\n");
+
+                       std::set<std::string> handled_modules;
+
+                       bool did_something = true;
+                       while (did_something) {
+                               did_something = false;
+                               std::vector<std::string> queued_modules;
+                               for (auto &mod_it : design->modules)
+                                       if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
+                                               queued_modules.push_back(mod_it.first);
+                               for (auto &modname : queued_modules)
+                                       if (design->modules.count(modname) != 0) {
+                                               SubmodWorker worker(design, design->modules[modname]);
+                                               handled_modules.insert(modname);
+                                               did_something = true;
+                                       }
+                       }
+
+                       Pass::call(design, "opt_clean");
+               }
+               else
+               {
+                       RTLIL::Module *module = NULL;
+                       for (auto &mod_it : design->modules) {
+                               if (!design->selected_module(mod_it.first))
+                                       continue;
+                               if (module != NULL)
+                                       log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod_it.first.c_str());
+                               module = mod_it.second;
+                       }
+                       if (module == NULL)
+                               log("Nothing selected -> do nothing.\n");
+                       else {
+                               Pass::call_newsel(design, stringf("opt_clean %s", module->name.c_str()));
+                               log_header("Continuing SUBMOD pass.\n");
+                               SubmodWorker worker(design, module, opt_name);
+                       }
+               }
+
+               log_pop();
+       }
+} SubmodPass;
diff --git a/passes/scc/Makefile.inc b/passes/scc/Makefile.inc
deleted file mode 100644 (file)
index ca86e6e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-OBJS += passes/scc/scc.o
-
diff --git a/passes/scc/scc.cc b/passes/scc/scc.cc
deleted file mode 100644 (file)
index f8c351a..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- *  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.
- *
- */
-
-// [[CITE]] Tarjan's strongly connected components algorithm
-// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146–160, doi:10.1137/0201010
-// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
-
-#include "kernel/register.h"
-#include "kernel/celltypes.h"
-#include "kernel/sigtools.h"
-#include "kernel/log.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <set>
-
-struct SccWorker
-{
-       RTLIL::Design *design;
-       RTLIL::Module *module;
-       SigMap sigmap;
-       CellTypes ct;
-
-       std::set<RTLIL::Cell*> workQueue;
-       std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
-       std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;
-
-       std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
-       std::map<RTLIL::Cell*, int> cellDepth;
-       std::set<RTLIL::Cell*> cellsOnStack;
-       std::vector<RTLIL::Cell*> cellStack;
-       int labelCounter;
-
-       std::map<RTLIL::Cell*, int> cell2scc;
-       std::vector<std::set<RTLIL::Cell*>> sccList;
-
-       void run(RTLIL::Cell *cell, int depth, int maxDepth)
-       {
-               assert(workQueue.count(cell) > 0);
-
-               workQueue.erase(cell);
-               cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
-               labelCounter++;
-
-               cellsOnStack.insert(cell);
-               cellStack.push_back(cell);
-
-               if (maxDepth >= 0)
-                       cellDepth[cell] = depth;
-
-               for (auto nextCell : cellToNextCell[cell])
-                       if (cellLabels.count(nextCell) == 0) {
-                               run(nextCell, depth+1, maxDepth);
-                               cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
-                       } else
-                       if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
-                                       cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
-                       }
-
-               if (cellLabels[cell].first == cellLabels[cell].second)
-               {
-                       if (cellStack.back() == cell)
-                       {
-                               cellStack.pop_back();
-                               cellsOnStack.erase(cell);
-                       }
-                       else
-                       {
-                               log("Found an SCC:");
-                               std::set<RTLIL::Cell*> scc;
-                               while (cellsOnStack.count(cell) > 0) {
-                                       RTLIL::Cell *c = cellStack.back();
-                                       cellStack.pop_back();
-                                       cellsOnStack.erase(c);
-                                       log(" %s", RTLIL::id2cstr(c->name));
-                                       cell2scc[c] = sccList.size();
-                                       scc.insert(c);
-                               }
-                               sccList.push_back(scc);
-                               log("\n");
-                       }
-               }
-       }
-
-       SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth) : design(design), module(module), sigmap(module)
-       {
-               if (module->processes.size() > 0) {
-                       log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
-                       return;
-               }
-
-               if (allCellTypes) {
-                       ct.setup(design);
-               } else {
-                       ct.setup_internals();
-                       ct.setup_stdcells();
-               }
-
-               SigPool selectedSignals;
-               SigSet<RTLIL::Cell*> sigToNextCells;
-
-               for (auto &it : module->wires)
-                       if (design->selected(module, it.second))
-                               selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));
-
-               for (auto &it : module->cells)
-               {
-                       RTLIL::Cell *cell = it.second;
-
-                       if (!design->selected(module, cell))
-                               continue;
-
-                       if (!allCellTypes && !ct.cell_known(cell->type))
-                               continue;
-
-                       workQueue.insert(cell);
-
-                       RTLIL::SigSpec inputSignals, outputSignals;
-
-                       for (auto &conn : cell->connections)
-                       {
-                               bool isInput = true, isOutput = true;
-
-                               if (ct.cell_known(cell->type)) {
-                                       isInput = ct.cell_input(cell->type, conn.first);
-                                       isOutput = ct.cell_output(cell->type, conn.first);
-                               }
-
-                               RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
-                               sig.sort_and_unify();
-
-                               if (isInput)
-                                       inputSignals.append(sig);
-                               if (isOutput)
-                                       outputSignals.append(sig);
-                       }
-
-                       inputSignals.sort_and_unify();
-                       outputSignals.sort_and_unify();
-
-                       cellToPrevSig[cell] = inputSignals;
-                       cellToNextSig[cell] = outputSignals;
-                       sigToNextCells.insert(inputSignals, cell);
-               }
-
-               for (auto cell : workQueue)
-                       cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
-
-               labelCounter = 0;
-               cellLabels.clear();
-
-               while (workQueue.size() > 0) {
-                       RTLIL::Cell *cell = *workQueue.begin();
-                       assert(cellStack.size() == 0);
-                       cellDepth.clear();
-                       run(cell, 0, maxDepth);
-               }
-
-               log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
-       }
-
-       void select(RTLIL::Selection &sel)
-       {
-               for (int i = 0; i < int(sccList.size()); i++)
-               {
-                       std::set<RTLIL::Cell*> &cells = sccList[i];
-                       RTLIL::SigSpec prevsig, nextsig, sig;
-
-                       for (auto cell : cells) {
-                               sel.selected_members[module->name].insert(cell->name);
-                               prevsig.append(cellToPrevSig[cell]);
-                               nextsig.append(cellToNextSig[cell]);
-                       }
-
-                       prevsig.sort_and_unify();
-                       nextsig.sort_and_unify();
-                       sig = prevsig.extract(nextsig);
-
-                       for (auto &chunk : sig.chunks)
-                               if (chunk.wire != NULL)
-                                       sel.selected_members[module->name].insert(chunk.wire->name);
-               }
-       }
-};
-
-struct SccPass : public Pass {
-       SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
-       virtual void help()
-       {
-               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-               log("\n");
-               log("    scc [options] [selection]\n");
-               log("\n");
-               log("This command identifies strongly connected components (aka logic loops) in the\n");
-               log("design.\n");
-               log("\n");
-               log("    -max_depth <num>\n");
-               log("        limit to loops not longer than the specified number of cells. This can\n");
-               log("        e.g. be useful in identifying local loops in a module that turns out\n");
-               log("        to be one gigantic SCC.\n");
-               log("\n");
-               log("    -all_cell_types\n");
-               log("        Usually this command only considers internal non-memory cells. With\n");
-               log("        this option set, all cells are considered. For unkown cells all ports\n");
-               log("        are assumed to be bidirectional 'inout' ports.\n");
-               log("\n");
-               log("    -set_attr <name> <value>\n");
-               log("    -set_cell_attr <name> <value>\n");
-               log("    -set_wire_attr <name> <value>\n");
-               log("        set the specified attribute on all cells and/or wires that are part of\n");
-               log("        a logic loop. the special token {} in the value is replaced with a\n");
-               log("        unique identifier for the logic loop.\n");
-               log("\n");
-               log("    -select\n");
-               log("        replace the current selection with a selection of all cells and wires\n");
-               log("        that are part of a found logic loop\n");
-               log("\n");
-       }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
-       {
-               std::map<std::string, std::string> setCellAttr, setWireAttr;
-               bool allCellTypes = false;
-               bool selectMode = false;
-               int maxDepth = -1;
-
-               log_header("Executing SCC pass (detecting logic loops).\n");
-
-               size_t argidx;
-               for (argidx = 1; argidx < args.size(); argidx++) {
-                       if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
-                               maxDepth = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (args[argidx] == "-all_cell_types") {
-                               allCellTypes = true;
-                               continue;
-                       }
-                       if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
-                               setCellAttr[args[argidx+1]] = args[argidx+2];
-                               setWireAttr[args[argidx+1]] = args[argidx+2];
-                               argidx += 2;
-                               continue;
-                       }
-                       if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
-                               setCellAttr[args[argidx+1]] = args[argidx+2];
-                               argidx += 2;
-                               continue;
-                       }
-                       if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
-                               setWireAttr[args[argidx+1]] = args[argidx+2];
-                               argidx += 2;
-                               continue;
-                       }
-                       if (args[argidx] == "-select") {
-                               selectMode = true;
-                               continue;
-                       }
-                       break;
-               }
-               int origSelectPos = design->selection_stack.size() - 1;
-               extra_args(args, argidx, design);
-
-               if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
-                       log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
-
-               RTLIL::Selection newSelection(false);
-
-               for (auto &mod_it : design->modules)
-                       if (design->selected(mod_it.second))
-                       {
-                               SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
-
-                               if (selectMode)
-                                       worker.select(newSelection);
-                       }
-
-               if (selectMode) {
-                       assert(origSelectPos >= 0);
-                       design->selection_stack[origSelectPos] = newSelection;
-                       design->selection_stack[origSelectPos].optimize(design);
-               }
-       }
-} SccPass;
diff --git a/passes/submod/Makefile.inc b/passes/submod/Makefile.inc
deleted file mode 100644 (file)
index b0c00ea..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-OBJS += passes/submod/submod.o
-
diff --git a/passes/submod/submod.cc b/passes/submod/submod.cc
deleted file mode 100644 (file)
index 7d08112..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- *  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/register.h"
-#include "kernel/celltypes.h"
-#include "kernel/log.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <set>
-
-struct SubmodWorker
-{
-       CellTypes ct;
-       RTLIL::Design *design;
-       RTLIL::Module *module;
-       std::string opt_name;
-
-       struct SubModule
-       {
-               std::string name, full_name;
-               std::set<RTLIL::Cell*> cells;
-       };
-
-       std::map<std::string, SubModule> submodules;
-
-       struct wire_flags_t {
-               RTLIL::Wire *new_wire;
-               bool is_int_driven, is_int_used, is_ext_driven, is_ext_used;
-               wire_flags_t() : new_wire(NULL), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
-       };
-       std::map<RTLIL::Wire*, wire_flags_t> wire_flags;
-       bool flag_found_something;
-
-       void flag_wire(RTLIL::Wire *wire, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
-       {
-               if (wire_flags.count(wire) == 0) {
-                       if (!create)
-                               return;
-                       wire_flags[wire] = wire_flags_t();
-               }
-               if (set_int_driven)
-                       wire_flags[wire].is_int_driven = true;
-               if (set_int_used)
-                       wire_flags[wire].is_int_used = true;
-               if (set_ext_driven)
-                       wire_flags[wire].is_ext_driven = true;
-               if (set_ext_used)
-                       wire_flags[wire].is_ext_used = true;
-               flag_found_something = true;
-       }
-
-       void flag_signal(RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
-       {
-               for (auto &c : sig.chunks)
-                       if (c.wire != NULL)
-                               flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
-       }
-
-       void handle_submodule(SubModule &submod)
-       {
-               log("Creating submodule %s (%s) of module %s.\n", submod.name.c_str(), submod.full_name.c_str(), module->name.c_str());
-
-               wire_flags.clear();
-               for (RTLIL::Cell *cell : submod.cells) {
-                       if (ct.cell_known(cell->type)) {
-                               for (auto &conn : cell->connections)
-                                       flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
-                       } else {
-                               log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
-                               for (auto &conn : cell->connections)
-                                       flag_signal(conn.second, true, true, true, false, false);
-                       }
-               }
-               for (auto &it : module->cells) {
-                       RTLIL::Cell *cell = it.second;
-                       if (submod.cells.count(cell) > 0)
-                               continue;
-                       if (ct.cell_known(cell->type)) {
-                               for (auto &conn : cell->connections)
-                                       flag_signal(conn.second, false, false, false, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first));
-                       } else {
-                               flag_found_something = false;
-                               for (auto &conn : cell->connections)
-                                       flag_signal(conn.second, false, false, false, true, true);
-                               if (flag_found_something)
-                                       log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
-                       }
-               }
-
-               RTLIL::Module *new_mod = new RTLIL::Module;
-               new_mod->name = submod.full_name;
-               design->modules[new_mod->name] = new_mod;
-               int port_counter = 1, auto_name_counter = 1;
-
-               std::set<std::string> all_wire_names;
-               for (auto &it : wire_flags) {
-                       all_wire_names.insert(it.first->name);
-               }
-
-               for (auto &it : wire_flags)
-               {
-                       RTLIL::Wire *wire = it.first;
-                       wire_flags_t &flags = it.second;
-
-                       if (wire->port_input)
-                               flags.is_ext_driven = true;
-                       if (wire->port_output)
-                               flags.is_ext_used = true;
-
-                       RTLIL::Wire *new_wire = new RTLIL::Wire;
-                       new_wire->name = wire->name;
-                       new_wire->width = wire->width;
-                       new_wire->start_offset = wire->start_offset;
-                       new_wire->attributes = wire->attributes;
-
-                       if (flags.is_int_driven && flags.is_ext_used)
-                               new_wire->port_output = true;
-                       if (flags.is_ext_driven && flags.is_int_used)
-                               new_wire->port_input = true;
-
-                       if (flags.is_int_driven && flags.is_ext_driven)
-                               new_wire->port_input = true, new_wire->port_output = true;
-
-                       if (new_wire->port_input || new_wire->port_output) {
-                               new_wire->port_id = port_counter++;
-                               while (new_wire->name[0] == '$') {
-                                       std::string new_wire_name = stringf("\\n%d", auto_name_counter++);
-                                       if (all_wire_names.count(new_wire_name) == 0) {
-                                               all_wire_names.insert(new_wire_name);
-                                               new_wire->name = new_wire_name;
-                                       }
-                               }
-                       }
-
-                       if (new_wire->port_input && new_wire->port_output)
-                               log("  signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
-                       else if (new_wire->port_input)
-                               log("  signal %s: input %s\n", wire->name.c_str(), new_wire->name.c_str());
-                       else if (new_wire->port_output)
-                               log("  signal %s: output %s\n", wire->name.c_str(), new_wire->name.c_str());
-                       else
-                               log("  signal %s: internal\n", wire->name.c_str());
-
-                       new_mod->wires[new_wire->name] = new_wire;
-                       flags.new_wire = new_wire;
-               }
-
-               for (RTLIL::Cell *cell : submod.cells) {
-                       RTLIL::Cell *new_cell = new RTLIL::Cell(*cell);
-                       for (auto &conn : new_cell->connections)
-                               for (auto &c : conn.second.chunks)
-                                       if (c.wire != NULL) {
-                                               assert(wire_flags.count(c.wire) > 0);
-                                               c.wire = wire_flags[c.wire].new_wire;
-                                       }
-                       log("  cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
-                       new_mod->cells[new_cell->name] = new_cell;
-                       module->cells.erase(cell->name);
-                       delete cell;
-               }
-               submod.cells.clear();
-
-               RTLIL::Cell *new_cell = new RTLIL::Cell;
-               new_cell->name = submod.full_name;
-               new_cell->type = submod.full_name;
-               for (auto &it : wire_flags)
-               {
-                       RTLIL::Wire *old_wire = it.first;
-                       RTLIL::Wire *new_wire = it.second.new_wire;
-                       if (new_wire->port_id > 0)
-                               new_cell->connections[new_wire->name] = RTLIL::SigSpec(old_wire);
-               }
-               module->cells[new_cell->name] = new_cell;
-       }
-
-       SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
-       {
-               if (!design->selected_whole_module(module->name) && opt_name.empty())
-                       return;
-
-               if (module->processes.size() > 0) {
-                       log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
-                       return;
-               }
-
-               if (module->memories.size() > 0) {
-                       log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module->name.c_str());
-                       return;
-               }
-
-               ct.setup_internals();
-               ct.setup_internals_mem();
-               ct.setup_stdcells();
-               ct.setup_stdcells_mem();
-               ct.setup_design(design);
-
-               if (opt_name.empty())
-               {
-                       for (auto &it : module->wires)
-                               it.second->attributes.erase("\\submod");
-
-                       for (auto &it : module->cells)
-                       {
-                               RTLIL::Cell *cell = it.second;
-                               if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].bits.size() == 0) {
-                                       cell->attributes.erase("\\submod");
-                                       continue;
-                               }
-
-                               std::string submod_str = cell->attributes["\\submod"].decode_string();
-                               cell->attributes.erase("\\submod");
-
-                               if (submodules.count(submod_str) == 0) {
-                                       submodules[submod_str].name = submod_str;
-                                       submodules[submod_str].full_name = module->name + "_" + submod_str;
-                                       while (design->modules.count(submodules[submod_str].full_name) != 0 ||
-                                                       module->count_id(submodules[submod_str].full_name) != 0)
-                                               submodules[submod_str].full_name += "_";
-                               }
-
-                               submodules[submod_str].cells.insert(cell);
-                       }
-               }
-               else
-               {
-                       for (auto &it : module->cells)
-                       {
-                               RTLIL::Cell *cell = it.second;
-                               if (!design->selected(module, cell))
-                                       continue;
-                               submodules[opt_name].name = opt_name;
-                               submodules[opt_name].full_name = RTLIL::escape_id(opt_name);
-                               submodules[opt_name].cells.insert(cell);
-                       }
-
-                       if (submodules.size() == 0)
-                               log("Nothing selected -> do nothing.\n");
-               }
-
-               for (auto &it : submodules)
-                       handle_submodule(it.second);
-       }
-};
-
-struct SubmodPass : public Pass {
-       SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
-       virtual void help()
-       {
-               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-               log("\n");
-               log("    submod [selection]\n");
-               log("\n");
-               log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
-               log("a newly created module. The value of the attribute is used as name for the\n");
-               log("cell that replaces the group of cells with the same attribute value.\n");
-               log("\n");
-               log("This pass can be used to create a design hierarchy in flat design. This can\n");
-               log("be useful for analyzing or reverse-engineering a design.\n");
-               log("\n");
-               log("This pass only operates on completely selected modules with no processes\n");
-               log("or memories.\n");
-               log("\n");
-               log("\n");
-               log("    submod -name <name> [selection]\n");
-               log("\n");
-               log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
-               log("Only objects from one module might be selected. The value of the -name option\n");
-               log("is used as the value of the 'submod' attribute above.\n");
-               log("\n");
-       }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
-       {
-               log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
-               log_push();
-
-               std::string opt_name;
-
-               size_t argidx;
-               for (argidx = 1; argidx < args.size(); argidx++) {
-                       if (args[argidx] == "-name" && argidx+1 < args.size()) {
-                               opt_name = args[++argidx];
-                               continue;
-                       }
-                       break;
-               }
-               extra_args(args, argidx, design);
-
-               if (opt_name.empty())
-               {
-                       Pass::call(design, "opt_clean");
-                       log_header("Continuing SUBMOD pass.\n");
-
-                       std::set<std::string> handled_modules;
-
-                       bool did_something = true;
-                       while (did_something) {
-                               did_something = false;
-                               std::vector<std::string> queued_modules;
-                               for (auto &mod_it : design->modules)
-                                       if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
-                                               queued_modules.push_back(mod_it.first);
-                               for (auto &modname : queued_modules)
-                                       if (design->modules.count(modname) != 0) {
-                                               SubmodWorker worker(design, design->modules[modname]);
-                                               handled_modules.insert(modname);
-                                               did_something = true;
-                                       }
-                       }
-
-                       Pass::call(design, "opt_clean");
-               }
-               else
-               {
-                       RTLIL::Module *module = NULL;
-                       for (auto &mod_it : design->modules) {
-                               if (!design->selected_module(mod_it.first))
-                                       continue;
-                               if (module != NULL)
-                                       log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod_it.first.c_str());
-                               module = mod_it.second;
-                       }
-                       if (module == NULL)
-                               log("Nothing selected -> do nothing.\n");
-                       else {
-                               Pass::call_newsel(design, stringf("opt_clean %s", module->name.c_str()));
-                               log_header("Continuing SUBMOD pass.\n");
-                               SubmodWorker worker(design, module, opt_name);
-                       }
-               }
-
-               log_pop();
-       }
-} SubmodPass;
index 9751a47444a1b3e467b1df32cc1930b0e5bb11b8..ae1ebbb5691c535810245621580e86afcbe9234f 100644 (file)
@@ -5,6 +5,7 @@ OBJS += passes/techmap/dfflibmap.o
 OBJS += passes/techmap/iopadmap.o
 OBJS += passes/techmap/hilomap.o
 OBJS += passes/techmap/libparse.o
+OBJS += passes/techmap/extract.o
 
 GENFILES += passes/techmap/stdcells.inc
 
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
new file mode 100644 (file)
index 0000000..eff14ff
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ *  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/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "libs/subcircuit/subcircuit.h"
+#include <algorithm>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+using RTLIL::id2cstr;
+
+namespace
+{
+       class SubCircuitSolver : public SubCircuit::Solver
+       {
+       public:
+               std::set<RTLIL::IdString> cell_attr, wire_attr;
+
+               bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
+               {
+                       for (auto &it : attr) {
+                               size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
+                               if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
+                                       return false;
+                       }
+                       return true;
+               }
+
+               virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
+                               const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
+               {
+                       RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
+                       RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
+
+                       if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
+                               return false;
+
+                       if (wire_attr.size() > 0)
+                       {
+                               RTLIL::Wire *lastNeedleWire = NULL;
+                               RTLIL::Wire *lastHaystackWire = NULL;
+                               std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
+
+                               for (auto &conn : needleCell->connections)
+                               {
+                                       RTLIL::SigSpec needleSig = conn.second;
+                                       RTLIL::SigSpec haystackSig = haystackCell->connections.at(portMapping.at(conn.first));
+
+                                       needleSig.expand();
+                                       haystackSig.expand();
+
+                                       for (int i = 0; i < std::min(needleSig.width, haystackSig.width); i++) {
+                                               RTLIL::Wire *needleWire = needleSig.chunks.at(i).wire, *haystackWire = haystackSig.chunks.at(i).wire;
+                                               if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
+                                                       if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
+                                                               return false;
+                                               lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
+                                       }
+                               }
+                       }
+
+                       return true;
+               }
+       };
+
+       struct bit_ref_t {
+               std::string cell, port;
+               int bit;
+       };
+
+       bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
+                       int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
+       {
+               SigMap sigmap(mod);
+               std::map<RTLIL::SigChunk, bit_ref_t> sig_bit_ref;
+
+               if (sel && !sel->selected(mod)) {
+                       log("  Skipping module %s as it is not selected.\n", id2cstr(mod->name));
+                       return false;
+               }
+
+               if (mod->processes.size() > 0) {
+                       log("  Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
+                       return false;
+               }
+
+               if (constports) {
+                       graph.createNode("$const$0", "$const$0", NULL, true);
+                       graph.createNode("$const$1", "$const$1", NULL, true);
+                       graph.createNode("$const$x", "$const$x", NULL, true);
+                       graph.createNode("$const$z", "$const$z", NULL, true);
+                       graph.createPort("$const$0", "\\Y", 1);
+                       graph.createPort("$const$1", "\\Y", 1);
+                       graph.createPort("$const$x", "\\Y", 1);
+                       graph.createPort("$const$z", "\\Y", 1);
+                       graph.markExtern("$const$0", "\\Y", 0);
+                       graph.markExtern("$const$1", "\\Y", 0);
+                       graph.markExtern("$const$x", "\\Y", 0);
+                       graph.markExtern("$const$z", "\\Y", 0);
+               }
+
+               std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
+               if (max_fanout > 0)
+                       for (auto &cell_it : mod->cells)
+                       {
+                               RTLIL::Cell *cell = cell_it.second;
+                               if (!sel || sel->selected(mod, cell))
+                                       for (auto &conn : cell->connections) {
+                                               RTLIL::SigSpec conn_sig = conn.second;
+                                               sigmap.apply(conn_sig);
+                                               conn_sig.expand();
+                                               for (auto &chunk : conn_sig.chunks)
+                                                       if (chunk.wire != NULL)
+                                                               sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)]++;
+                                       }
+                       }
+
+               // create graph nodes from cells
+               for (auto &cell_it : mod->cells)
+               {
+                       RTLIL::Cell *cell = cell_it.second;
+                       if (sel && !sel->selected(mod, cell))
+                               continue;
+
+                       std::string type = cell->type;
+                       if (sel == NULL && type.substr(0, 2) == "\\$")
+                               type = type.substr(1);
+                       graph.createNode(cell->name, type, (void*)cell);
+
+                       for (auto &conn : cell->connections)
+                       {
+                               graph.createPort(cell->name, conn.first, conn.second.width);
+
+                               if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
+                                       continue;
+
+                               RTLIL::SigSpec conn_sig = conn.second;
+                               sigmap.apply(conn_sig);
+                               conn_sig.expand();
+
+                               for (size_t i = 0; i < conn_sig.chunks.size(); i++)
+                               {
+                                       auto &chunk = conn_sig.chunks[i];
+                                       assert(chunk.width == 1);
+
+                                       if (chunk.wire == NULL) {
+                                               if (constports) {
+                                                       std::string node = "$const$x";
+                                                       if (chunk.data.bits[0] == RTLIL::State::S0) node = "$const$0";
+                                                       if (chunk.data.bits[0] == RTLIL::State::S1) node = "$const$1";
+                                                       if (chunk.data.bits[0] == RTLIL::State::Sz) node = "$const$z";
+                                                       graph.createConnection(cell->name, conn.first, i, node, "\\Y", 0);
+                                               } else
+                                                       graph.createConstant(cell->name, conn.first, i, int(chunk.data.bits[0]));
+                                               continue;
+                                       }
+
+                                       if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout)
+                                               continue;
+
+                                       if (sel && !sel->selected(mod, chunk.wire))
+                                               continue;
+
+                                       if (sig_bit_ref.count(chunk) == 0) {
+                                               bit_ref_t &bit_ref = sig_bit_ref[chunk];
+                                               bit_ref.cell = cell->name;
+                                               bit_ref.port = conn.first;
+                                               bit_ref.bit = i;
+                                       }
+
+                                       bit_ref_t &bit_ref = sig_bit_ref[chunk];
+                                       graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name, conn.first, i);
+                               }
+                       }
+               }
+
+               // mark external signals (used in non-selected cells)
+               for (auto &cell_it : mod->cells)
+               {
+                       RTLIL::Cell *cell = cell_it.second;
+                       if (sel && !sel->selected(mod, cell))
+                               for (auto &conn : cell->connections)
+                               {
+                                       RTLIL::SigSpec conn_sig = conn.second;
+                                       sigmap.apply(conn_sig);
+                                       conn_sig.expand();
+
+                                       for (auto &chunk : conn_sig.chunks)
+                                               if (sig_bit_ref.count(chunk) != 0) {
+                                                       bit_ref_t &bit_ref = sig_bit_ref[chunk];
+                                                       graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
+                                               }
+                               }
+               }
+
+               // mark external signals (used in module ports)
+               for (auto &wire_it : mod->wires)
+               {
+                       RTLIL::Wire *wire = wire_it.second;
+                       if (wire->port_id > 0)
+                       {
+                               RTLIL::SigSpec conn_sig(wire);
+                               sigmap.apply(conn_sig);
+                               conn_sig.expand();
+
+                               for (auto &chunk : conn_sig.chunks)
+                                       if (sig_bit_ref.count(chunk) != 0) {
+                                               bit_ref_t &bit_ref = sig_bit_ref[chunk];
+                                               graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
+                                       }
+                       }
+               }
+
+               // graph.print();
+               return true;
+       }
+
+       RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
+       {
+               SigMap sigmap(needle);
+               SigSet<std::pair<std::string, int>> sig2port;
+
+               // create new cell
+               RTLIL::Cell *cell = new RTLIL::Cell;
+               cell->name = stringf("$extract$%s$%d", needle->name.c_str(), RTLIL::autoidx++);
+               cell->type = needle->name;
+               haystack->add(cell);
+
+               // create cell ports
+               for (auto &it : needle->wires) {
+                       RTLIL::Wire *wire = it.second;
+                       if (wire->port_id > 0) {
+                               for (int i = 0; i < wire->width; i++)
+                                       sig2port.insert(sigmap(RTLIL::SigSpec(wire, 1, i)), std::pair<std::string, int>(wire->name, i));
+                               cell->connections[wire->name] = RTLIL::SigSpec(RTLIL::State::Sz, wire->width);
+                       }
+               }
+
+               // delete replaced cells and connect new ports
+               for (auto &it : match.mappings)
+               {
+                       auto &mapping = it.second;
+                       RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
+                       RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
+
+                       if (needle_cell == NULL)
+                               continue;
+
+                       for (auto &conn : needle_cell->connections) {
+                               RTLIL::SigSpec sig = sigmap(conn.second);
+                               if (mapping.portMapping.count(conn.first) > 0 && sig2port.has(sigmap(sig))) {
+                                       sig.expand();
+                                       for (int i = 0; i < sig.width; i++)
+                                       for (auto &port : sig2port.find(sig.chunks[i])) {
+                                               RTLIL::SigSpec bitsig = haystack_cell->connections.at(mapping.portMapping[conn.first]).extract(i, 1);
+                                               cell->connections.at(port.first).replace(port.second, bitsig);
+                                       }
+                               }
+                       }
+
+                       haystack->cells.erase(haystack_cell->name);
+                       delete haystack_cell;
+               }
+
+               return cell;
+       }
+
+       bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
+       {
+               int left_idx = 0, right_idx = 0;
+               if (left->attributes.count("\\extract_order") > 0)
+                       left_idx = left->attributes.at("\\extract_order").as_int();
+               if (right->attributes.count("\\extract_order") > 0)
+                       right_idx = right->attributes.at("\\extract_order").as_int();
+               if (left_idx != right_idx)
+                       return left_idx < right_idx;
+               return left->name < right->name;
+       }
+}
+
+struct ExtractPass : public Pass {
+       ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    extract -map <map_file> [options] [selection]\n");
+               log("    extract -mine <out_file> [options] [selection]\n");
+               log("\n");
+               log("This pass looks for subcircuits that are isomorphic to any of the modules\n");
+               log("in the given map file and replaces them with instances of this modules. The\n");
+               log("map file can be a verilog source file (*.v) or an ilang file (*.il).\n");
+               log("\n");
+               log("    -map <map_file>\n");
+               log("        use the modules in this file as reference. This option can be used\n");
+               log("        multiple times.\n");
+               log("\n");
+               log("    -verbose\n");
+               log("        print debug output while analyzing\n");
+               log("\n");
+               log("    -constports\n");
+               log("        also find instances with constant drivers. this may be much\n");
+               log("        slower than the normal operation.\n");
+               log("\n");
+               log("    -nodefaultswaps\n");
+               log("        normally builtin port swapping rules for internal cells are used per\n");
+               log("        default. This turns that off, so e.g. 'a^b' does not match 'b^a'\n");
+               log("        when this option is used.\n");
+               log("\n");
+               log("    -compat <needle_type> <haystack_type>\n");
+               log("        Per default, the cells in the map file (needle) must have the\n");
+               log("        type as the cells in the active design (haystack). This option\n");
+               log("        can be used to register additional pairs of types that should\n");
+               log("        match. This option can be used multiple times.\n");
+               log("\n");
+               log("    -swap <needle_type> <port1>,<port2>[,...]\n");
+               log("        Register a set of swapable ports for a needle cell type.\n");
+               log("        This option can be used multiple times.\n");
+               log("\n");
+               log("    -perm <needle_type> <port1>,<port2>[,...] <portA>,<portB>[,...]\n");
+               log("        Register a valid permutation of swapable ports for a needle\n");
+               log("        cell type. This option can be used multiple times.\n");
+               log("\n");
+               log("    -cell_attr <attribute_name>\n");
+               log("        Attributes on cells with the given name must match.\n");
+               log("\n");
+               log("    -wire_attr <attribute_name>\n");
+               log("        Attributes on wires with the given name must match.\n");
+               log("\n");
+               log("This pass does not operate on modules with uprocessed processes in it.\n");
+               log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
+               log("\n");
+               log("This pass can also be used for mining for frequent subcircuits. In this mode\n");
+               log("the following options are to be used instead of the -map option.\n");
+               log("\n");
+               log("    -mine <out_file>\n");
+               log("        mine for frequent subcircuits and write them to the given ilang file\n");
+               log("\n");
+               log("    -mine_cells_span <min> <max>\n");
+               log("        only mine for subcircuits with the specified number of cells\n");
+               log("        default value: 3 5\n");
+               log("\n");
+               log("    -mine_min_freq <num>\n");
+               log("        only mine for subcircuits with at least the specified number of matches\n");
+               log("        default value: 10\n");
+               log("\n");
+               log("    -mine_limit_matches_per_module <num>\n");
+               log("        when calculating the number of matches for a subcircuit, don't count\n");
+               log("        more than the specified number of matches per module\n");
+               log("\n");
+               log("    -mine_max_fanout <num>\n");
+               log("        don't consider internal signals with more than <num> connections\n");
+               log("\n");
+               log("The modules in the map file may have the attribute 'extract_order' set to an\n");
+               log("integer value. Then this value is used to determine the order in which the pass\n");
+               log("tries to map the modules to the design (ascending, default value is 0).\n");
+               log("\n");
+               log("See 'help techmap' for a pass that does the opposite thing.\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing EXTRACT pass (map subcircuits to cells).\n");
+               log_push();
+
+               SubCircuitSolver solver;
+
+               std::vector<std::string> map_filenames;
+               std::string mine_outfile;
+               bool constports = false;
+               bool nodefaultswaps = false;
+
+               bool mine_mode = false;
+               int mine_cells_min = 3;
+               int mine_cells_max = 5;
+               int mine_min_freq = 10;
+               int mine_limit_mod = -1;
+               int mine_max_fanout = -1;
+               std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> mine_split;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-map" && argidx+1 < args.size()) {
+                               if (mine_mode)
+                                       log_cmd_error("You cannot mix -map and -mine.\n");
+                               map_filenames.push_back(args[++argidx]);
+                               continue;
+                       }
+                       if (args[argidx] == "-mine" && argidx+1 < args.size()) {
+                               if (!map_filenames.empty())
+                                       log_cmd_error("You cannot mix -map and -mine.\n");
+                               mine_outfile = args[++argidx];
+                               mine_mode = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-mine_cells_span" && argidx+2 < args.size()) {
+                               mine_cells_min = atoi(args[++argidx].c_str());
+                               mine_cells_max = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-mine_min_freq" && argidx+1 < args.size()) {
+                               mine_min_freq = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-mine_limit_matches_per_module" && argidx+1 < args.size()) {
+                               mine_limit_mod = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-mine_split" && argidx+2 < args.size()) {
+                               mine_split.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
+                               argidx += 2;
+                               continue;
+                       }
+                       if (args[argidx] == "-mine_max_fanout" && argidx+1 < args.size()) {
+                               mine_max_fanout = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-verbose") {
+                               solver.setVerbose();
+                               continue;
+                       }
+                       if (args[argidx] == "-constports") {
+                               constports = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-nodefaultswaps") {
+                               nodefaultswaps = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-compat" && argidx+2 < args.size()) {
+                               std::string needle_type = RTLIL::escape_id(args[++argidx]);
+                               std::string haystack_type = RTLIL::escape_id(args[++argidx]);
+                               solver.addCompatibleTypes(needle_type, haystack_type);
+                               continue;
+                       }
+                       if (args[argidx] == "-swap" && argidx+2 < args.size()) {
+                               std::string type = RTLIL::escape_id(args[++argidx]);
+                               std::set<std::string> ports;
+                               char *ports_str = strdup(args[++argidx].c_str());
+                               for (char *sptr, *p = strtok_r(ports_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+                                       ports.insert(RTLIL::escape_id(p));
+                               free(ports_str);
+                               solver.addSwappablePorts(type, ports);
+                               continue;
+                       }
+                       if (args[argidx] == "-perm" && argidx+3 < args.size()) {
+                               std::string type = RTLIL::escape_id(args[++argidx]);
+                               std::vector<std::string> map_left, map_right;
+                               char *left_str = strdup(args[++argidx].c_str());
+                               char *right_str = strdup(args[++argidx].c_str());
+                               for (char *sptr, *p = strtok_r(left_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+                                       map_left.push_back(RTLIL::escape_id(p));
+                               for (char *sptr, *p = strtok_r(right_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+                                       map_right.push_back(RTLIL::escape_id(p));
+                               free(left_str);
+                               free(right_str);
+                               if (map_left.size() != map_right.size())
+                                       log_cmd_error("Arguments to -perm are not a valid permutation!\n");
+                               std::map<std::string, std::string> map;
+                               for (size_t i = 0; i < map_left.size(); i++)
+                                       map[map_left[i]] = map_right[i];
+                               std::sort(map_left.begin(), map_left.end());
+                               std::sort(map_right.begin(), map_right.end());
+                               if (map_left != map_right)
+                                       log_cmd_error("Arguments to -perm are not a valid permutation!\n");
+                               solver.addSwappablePortsPermutation(type, map);
+                               continue;
+                       }
+                       if (args[argidx] == "-cell_attr" && argidx+1 < args.size()) {
+                               solver.cell_attr.insert(RTLIL::escape_id(args[++argidx]));
+                               continue;
+                       }
+                       if (args[argidx] == "-wire_attr" && argidx+1 < args.size()) {
+                               solver.wire_attr.insert(RTLIL::escape_id(args[++argidx]));
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if (!nodefaultswaps) {
+                       solver.addSwappablePorts("$and",       "\\A", "\\B");
+                       solver.addSwappablePorts("$or",        "\\A", "\\B");
+                       solver.addSwappablePorts("$xor",       "\\A", "\\B");
+                       solver.addSwappablePorts("$xnor",      "\\A", "\\B");
+                       solver.addSwappablePorts("$eq",        "\\A", "\\B");
+                       solver.addSwappablePorts("$ne",        "\\A", "\\B");
+                       solver.addSwappablePorts("$eqx",       "\\A", "\\B");
+                       solver.addSwappablePorts("$nex",       "\\A", "\\B");
+                       solver.addSwappablePorts("$add",       "\\A", "\\B");
+                       solver.addSwappablePorts("$mul",       "\\A", "\\B");
+                       solver.addSwappablePorts("$logic_and", "\\A", "\\B");
+                       solver.addSwappablePorts("$logic_or",  "\\A", "\\B");
+                       solver.addSwappablePorts("$_AND_",     "\\A", "\\B");
+                       solver.addSwappablePorts("$_OR_",      "\\A", "\\B");
+                       solver.addSwappablePorts("$_XOR_",     "\\A", "\\B");
+               }
+
+               if (map_filenames.empty() && mine_outfile.empty())
+                       log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
+
+               RTLIL::Design *map = NULL;
+
+               if (!mine_mode)
+               {
+                       map = new RTLIL::Design;
+                       for (auto &filename : map_filenames) {
+                               FILE *f = fopen(filename.c_str(), "rt");
+                               if (f == NULL)
+                                       log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
+                               Frontend::frontend_call(map, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+                               fclose(f);
+
+                               if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
+                                       Pass::call(map, "proc");
+                                       Pass::call(map, "opt_clean");
+                               }
+                       }
+               }
+
+               std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
+               std::vector<RTLIL::Module*> needle_list;
+
+               log_header("Creating graphs for SubCircuit library.\n");
+
+               if (!mine_mode)
+                       for (auto &mod_it : map->modules) {
+                               SubCircuit::Graph mod_graph;
+                               std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
+                               log("Creating needle graph %s.\n", graph_name.c_str());
+                               if (module2graph(mod_graph, mod_it.second, constports)) {
+                                       solver.addGraph(graph_name, mod_graph);
+                                       needle_map[graph_name] = mod_it.second;
+                                       needle_list.push_back(mod_it.second);
+                               }
+                       }
+
+               for (auto &mod_it : design->modules) {
+                       SubCircuit::Graph mod_graph;
+                       std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
+                       log("Creating haystack graph %s.\n", graph_name.c_str());
+                       if (module2graph(mod_graph, mod_it.second, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : NULL)) {
+                               solver.addGraph(graph_name, mod_graph);
+                               haystack_map[graph_name] = mod_it.second;
+                       }
+               }
+               
+               if (!mine_mode)
+               {
+                       std::vector<SubCircuit::Solver::Result> results;
+                       log_header("Running solver from SubCircuit library.\n");
+
+                       std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList);
+
+                       for (auto needle : needle_list)
+                       for (auto &haystack_it : haystack_map) {
+                               log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str());
+                               solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false);
+                       }
+                       log("Found %zd matches.\n", results.size());
+
+                       if (results.size() > 0)
+                       {
+                               log_header("Substitute SubCircuits with cells.\n");
+
+                               for (int i = 0; i < int(results.size()); i++) {
+                                       auto &result = results[i];
+                                       log("\nMatch #%d: (%s in %s)\n", i, result.needleGraphId.c_str(), result.haystackGraphId.c_str());
+                                       for (const auto &it : result.mappings) {
+                                               log("  %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str());
+                                               for (const auto & it2 : it.second.portMapping)
+                                                       log(" %s:%s", it2.first.c_str(), it2.second.c_str());
+                                               log("\n");
+                                       }
+                                       RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result);
+                                       design->select(haystack_map.at(result.haystackGraphId), new_cell);
+                                       log("  new cell: %s\n", id2cstr(new_cell->name));
+                               }
+                       }
+               }
+               else
+               {
+                       std::vector<SubCircuit::Solver::MineResult> results;
+
+                       log_header("Running miner from SubCircuit library.\n");
+                       solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod);
+
+                       map = new RTLIL::Design;
+
+                       int needleCounter = 0;
+                       for (auto &result: results)
+                       {
+                               log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
+                               log("  primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
+                               for (auto &node : result.nodes)
+                                       log(" %s", id2cstr(node.nodeId));
+                               log("\n");
+                               for (auto &it : result.matchesPerGraph)
+                                       log("  matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
+
+                               RTLIL::Module *mod = haystack_map.at(result.graphId);
+                               std::set<RTLIL::Cell*> cells;
+                               std::set<RTLIL::Wire*> wires;
+
+                               SigMap sigmap(mod);
+
+                               for (auto &node : result.nodes)
+                                       cells.insert((RTLIL::Cell*)node.userData);
+
+                               for (auto cell : cells)
+                               for (auto &conn : cell->connections) {
+                                       RTLIL::SigSpec sig = sigmap(conn.second);
+                                       for (auto &chunk : sig.chunks)
+                                               if (chunk.wire != NULL)
+                                                       wires.insert(chunk.wire);
+                               }
+
+                               RTLIL::Module *newMod = new RTLIL::Module;
+                               newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
+                               map->modules[newMod->name] = newMod;
+
+                               int portCounter = 1;
+                               for (auto wire : wires) {
+                                       RTLIL::Wire *newWire = new RTLIL::Wire;
+                                       newWire->name = wire->name;
+                                       newWire->width = wire->width;
+                                       newWire->port_id = portCounter++;
+                                       newWire->port_input = true;
+                                       newWire->port_output = true;
+                                       newMod->add(newWire);
+                               }
+
+                               for (auto cell : cells) {
+                                       RTLIL::Cell *newCell = new RTLIL::Cell;
+                                       newCell->name = cell->name;
+                                       newCell->type = cell->type;
+                                       newCell->parameters = cell->parameters;
+                                       for (auto &conn : cell->connections) {
+                                               RTLIL::SigSpec sig = sigmap(conn.second);
+                                               for (auto &chunk : sig.chunks)
+                                                       if (chunk.wire != NULL)
+                                                               chunk.wire = newMod->wires.at(chunk.wire->name);
+                                               newCell->connections[conn.first] = sig;
+                                       }
+                                       newMod->add(newCell);
+                               }
+                       }
+
+                       FILE *f = fopen(mine_outfile.c_str(), "wt");
+                       if (f == NULL)
+                               log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
+                       Backend::backend_call(map, f, mine_outfile, "ilang");
+                       fclose(f);
+               }
+
+               delete map;
+               log_pop();
+       }
+} ExtractPass;