yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
scc.cc
Go to the documentation of this file.
1 /*
2  * yosys -- Yosys Open SYnthesis Suite
3  *
4  * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  */
19 
20 // [[CITE]] Tarjan's strongly connected components algorithm
21 // Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146–160, doi:10.1137/0201010
22 // http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
23 
24 #include "kernel/register.h"
25 #include "kernel/celltypes.h"
26 #include "kernel/sigtools.h"
27 #include "kernel/log.h"
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <set>
31 
34 
35 struct SccWorker
36 {
41 
42  std::set<RTLIL::Cell*> workQueue;
43  std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
44  std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;
45 
46  std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
47  std::map<RTLIL::Cell*, int> cellDepth;
48  std::set<RTLIL::Cell*> cellsOnStack;
49  std::vector<RTLIL::Cell*> cellStack;
51 
52  std::map<RTLIL::Cell*, int> cell2scc;
53  std::vector<std::set<RTLIL::Cell*>> sccList;
54 
55  void run(RTLIL::Cell *cell, int depth, int maxDepth)
56  {
57  log_assert(workQueue.count(cell) > 0);
58 
59  workQueue.erase(cell);
60  cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
61  labelCounter++;
62 
63  cellsOnStack.insert(cell);
64  cellStack.push_back(cell);
65 
66  if (maxDepth >= 0)
67  cellDepth[cell] = depth;
68 
69  for (auto nextCell : cellToNextCell[cell])
70  if (cellLabels.count(nextCell) == 0) {
71  run(nextCell, depth+1, maxDepth);
72  cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
73  } else
74  if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
75  cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
76  }
77 
78  if (cellLabels[cell].first == cellLabels[cell].second)
79  {
80  if (cellStack.back() == cell)
81  {
82  cellStack.pop_back();
83  cellsOnStack.erase(cell);
84  }
85  else
86  {
87  log("Found an SCC:");
88  std::set<RTLIL::Cell*> scc;
89  while (cellsOnStack.count(cell) > 0) {
90  RTLIL::Cell *c = cellStack.back();
91  cellStack.pop_back();
92  cellsOnStack.erase(c);
93  log(" %s", RTLIL::id2cstr(c->name));
94  cell2scc[c] = sccList.size();
95  scc.insert(c);
96  }
97  sccList.push_back(scc);
98  log("\n");
99  }
100  }
101  }
102 
103  SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth) : design(design), module(module), sigmap(module)
104  {
105  if (module->processes.size() > 0) {
106  log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
107  return;
108  }
109 
110  if (allCellTypes) {
111  ct.setup(design);
112  } else {
114  ct.setup_stdcells();
115  }
116 
117  SigPool selectedSignals;
118  SigSet<RTLIL::Cell*> sigToNextCells;
119 
120  for (auto &it : module->wires_)
121  if (design->selected(module, it.second))
122  selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));
123 
124  for (auto &it : module->cells_)
125  {
126  RTLIL::Cell *cell = it.second;
127 
128  if (!design->selected(module, cell))
129  continue;
130 
131  if (!allCellTypes && !ct.cell_known(cell->type))
132  continue;
133 
134  workQueue.insert(cell);
135 
136  RTLIL::SigSpec inputSignals, outputSignals;
137 
138  for (auto &conn : cell->connections())
139  {
140  bool isInput = true, isOutput = true;
141 
142  if (ct.cell_known(cell->type)) {
143  isInput = ct.cell_input(cell->type, conn.first);
144  isOutput = ct.cell_output(cell->type, conn.first);
145  }
146 
147  RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
148  sig.sort_and_unify();
149 
150  if (isInput)
151  inputSignals.append(sig);
152  if (isOutput)
153  outputSignals.append(sig);
154  }
155 
156  inputSignals.sort_and_unify();
157  outputSignals.sort_and_unify();
158 
159  cellToPrevSig[cell] = inputSignals;
160  cellToNextSig[cell] = outputSignals;
161  sigToNextCells.insert(inputSignals, cell);
162  }
163 
164  for (auto cell : workQueue)
165  cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
166 
167  labelCounter = 0;
168  cellLabels.clear();
169 
170  while (workQueue.size() > 0) {
171  RTLIL::Cell *cell = *workQueue.begin();
172  log_assert(cellStack.size() == 0);
173  cellDepth.clear();
174  run(cell, 0, maxDepth);
175  }
176 
177  log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
178  }
179 
181  {
182  for (int i = 0; i < int(sccList.size()); i++)
183  {
184  std::set<RTLIL::Cell*> &cells = sccList[i];
185  RTLIL::SigSpec prevsig, nextsig, sig;
186 
187  for (auto cell : cells) {
188  sel.selected_members[module->name].insert(cell->name);
189  prevsig.append(cellToPrevSig[cell]);
190  nextsig.append(cellToNextSig[cell]);
191  }
192 
193  prevsig.sort_and_unify();
194  nextsig.sort_and_unify();
195  sig = prevsig.extract(nextsig);
196 
197  for (auto &chunk : sig.chunks())
198  if (chunk.wire != NULL)
199  sel.selected_members[module->name].insert(chunk.wire->name);
200  }
201  }
202 };
203 
204 struct SccPass : public Pass {
205  SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
206  virtual void help()
207  {
208  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
209  log("\n");
210  log(" scc [options] [selection]\n");
211  log("\n");
212  log("This command identifies strongly connected components (aka logic loops) in the\n");
213  log("design.\n");
214  log("\n");
215  log(" -max_depth <num>\n");
216  log(" limit to loops not longer than the specified number of cells. This can\n");
217  log(" e.g. be useful in identifying local loops in a module that turns out\n");
218  log(" to be one gigantic SCC.\n");
219  log("\n");
220  log(" -all_cell_types\n");
221  log(" Usually this command only considers internal non-memory cells. With\n");
222  log(" this option set, all cells are considered. For unknown cells all ports\n");
223  log(" are assumed to be bidirectional 'inout' ports.\n");
224  log("\n");
225  log(" -set_attr <name> <value>\n");
226  log(" -set_cell_attr <name> <value>\n");
227  log(" -set_wire_attr <name> <value>\n");
228  log(" set the specified attribute on all cells and/or wires that are part of\n");
229  log(" a logic loop. the special token {} in the value is replaced with a\n");
230  log(" unique identifier for the logic loop.\n");
231  log("\n");
232  log(" -select\n");
233  log(" replace the current selection with a selection of all cells and wires\n");
234  log(" that are part of a found logic loop\n");
235  log("\n");
236  }
237  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
238  {
239  std::map<std::string, std::string> setCellAttr, setWireAttr;
240  bool allCellTypes = false;
241  bool selectMode = false;
242  int maxDepth = -1;
243 
244  log_header("Executing SCC pass (detecting logic loops).\n");
245 
246  size_t argidx;
247  for (argidx = 1; argidx < args.size(); argidx++) {
248  if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
249  maxDepth = atoi(args[++argidx].c_str());
250  continue;
251  }
252  if (args[argidx] == "-all_cell_types") {
253  allCellTypes = true;
254  continue;
255  }
256  if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
257  setCellAttr[args[argidx+1]] = args[argidx+2];
258  setWireAttr[args[argidx+1]] = args[argidx+2];
259  argidx += 2;
260  continue;
261  }
262  if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
263  setCellAttr[args[argidx+1]] = args[argidx+2];
264  argidx += 2;
265  continue;
266  }
267  if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
268  setWireAttr[args[argidx+1]] = args[argidx+2];
269  argidx += 2;
270  continue;
271  }
272  if (args[argidx] == "-select") {
273  selectMode = true;
274  continue;
275  }
276  break;
277  }
278  int origSelectPos = design->selection_stack.size() - 1;
279  extra_args(args, argidx, design);
280 
281  if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
282  log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
283 
284  RTLIL::Selection newSelection(false);
285 
286  for (auto &mod_it : design->modules_)
287  if (design->selected(mod_it.second))
288  {
289  SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
290 
291  if (selectMode)
292  worker.select(newSelection);
293  }
294 
295  if (selectMode) {
296  log_assert(origSelectPos >= 0);
297  design->selection_stack[origSelectPos] = newSelection;
298  design->selection_stack[origSelectPos].optimize(design);
299  }
300  }
301 } SccPass;
302 
const char * c_str() const
Definition: rtlil.h:178
bool selected(T1 *module) const
Definition: rtlil.h:551
RTLIL::SigSpec extract(RTLIL::SigSpec sig)
Definition: sigtools.h:77
std::vector< RTLIL::Selection > selection_stack
Definition: rtlil.h:509
void setup_stdcells()
Definition: celltypes.h:132
void run(RTLIL::Cell *cell, int depth, int maxDepth)
Definition: scc.cc:55
void log_header(const char *format,...)
Definition: log.cc:188
void setup(RTLIL::Design *design=NULL)
Definition: celltypes.h:47
std::map< RTLIL::Cell *, int > cell2scc
Definition: scc.cc:52
int labelCounter
Definition: scc.cc:50
std::map< RTLIL::IdString, std::set< RTLIL::IdString > > selected_members
Definition: rtlil.h:464
CellTypes ct
Definition: scc.cc:40
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
Definition: rtlil.h:595
RTLIL::IdString name
Definition: rtlil.h:853
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: scc.cc:237
RTLIL::IdString type
Definition: rtlil.h:854
std::map< RTLIL::Cell *, int > cellDepth
Definition: scc.cc:47
std::map< RTLIL::Cell *, std::pair< int, int > > cellLabels
Definition: scc.cc:46
Definition: scc.cc:204
bool cell_known(RTLIL::IdString type)
Definition: celltypes.h:188
RTLIL::Module * module
Definition: scc.cc:38
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:193
#define log_assert(_assert_expr_)
Definition: log.h:85
RTLIL::IdString name
Definition: rtlil.h:599
std::map< RTLIL::Cell *, std::set< RTLIL::Cell * > > cellToNextCell
Definition: scc.cc:43
RTLIL::Design * design
Definition: scc.cc:37
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
static const char * id2cstr(const RTLIL::IdString &str)
Definition: rtlil.h:267
void log_cmd_error(const char *format,...)
Definition: log.cc:211
SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth)
Definition: scc.cc:103
std::map< RTLIL::IdString, RTLIL::Process * > processes
Definition: rtlil.h:602
void add(RTLIL::SigSpec sig)
Definition: sigtools.h:41
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
std::map< RTLIL::IdString, RTLIL::Module * > modules_
Definition: rtlil.h:507
void sort_and_unify()
Definition: rtlil.cc:2291
std::vector< std::set< RTLIL::Cell * > > sccList
Definition: scc.cc:53
#define NULL
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
Definition: rtlil.h:596
void log(const char *format,...)
Definition: log.cc:180
void setup_internals()
Definition: celltypes.h:83
SigMap sigmap
Definition: scc.cc:39
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
std::vector< RTLIL::Cell * > cellStack
Definition: scc.cc:49
virtual void help()
Definition: scc.cc:206
void append(const RTLIL::SigSpec &signal)
Definition: rtlil.cc:2523
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:199
Definition: scc.cc:35
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
std::map< RTLIL::Cell *, RTLIL::SigSpec > cellToNextSig
Definition: scc.cc:44
std::set< RTLIL::Cell * > workQueue
Definition: scc.cc:42
SccPass SccPass
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
Definition: rtlil.cc:1814
void find(RTLIL::SigSpec sig, std::set< T > &result)
Definition: sigtools.h:187
void insert(RTLIL::SigSpec sig, T data)
Definition: sigtools.h:152
SccPass()
Definition: scc.cc:205
std::map< RTLIL::Cell *, RTLIL::SigSpec > cellToPrevSig
Definition: scc.cc:44
const std::vector< RTLIL::SigChunk > & chunks() const
Definition: rtlil.h:1016
std::set< RTLIL::Cell * > cellsOnStack
Definition: scc.cc:48
void select(RTLIL::Selection &sel)
Definition: scc.cc:180