yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
extract.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 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
24 #include <algorithm>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 
31 
32 using RTLIL::id2cstr;
33 
35 {
36 public:
38  std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
39  std::set<RTLIL::IdString> cell_attr, wire_attr;
40 
42  {
43  }
44 
45  bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
46  {
47  for (auto &it : attr) {
48  size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
49  if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
50  return false;
51  }
52  return true;
53  }
54 
56  {
57  if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
58  return value;
59 
60  #define param_bool(_n) if (param == _n) return value.as_bool();
61  param_bool("\\ARST_POLARITY");
62  param_bool("\\A_SIGNED");
63  param_bool("\\B_SIGNED");
64  param_bool("\\CLK_ENABLE");
65  param_bool("\\CLK_POLARITY");
66  param_bool("\\CLR_POLARITY");
67  param_bool("\\EN_POLARITY");
68  param_bool("\\SET_POLARITY");
69  param_bool("\\TRANSPARENT");
70  #undef param_bool
71 
72  #define param_int(_n) if (param == _n) return value.as_int();
73  param_int("\\ABITS")
74  param_int("\\A_WIDTH")
75  param_int("\\B_WIDTH")
76  param_int("\\CTRL_IN_WIDTH")
77  param_int("\\CTRL_OUT_WIDTH")
78  param_int("\\OFFSET")
79  param_int("\\PRIORITY")
80  param_int("\\RD_PORTS")
81  param_int("\\SIZE")
82  param_int("\\STATE_BITS")
83  param_int("\\STATE_NUM")
84  param_int("\\STATE_NUM_LOG2")
85  param_int("\\STATE_RST")
86  param_int("\\S_WIDTH")
87  param_int("\\TRANS_NUM")
88  param_int("\\WIDTH")
89  param_int("\\WR_PORTS")
90  param_int("\\Y_WIDTH")
91  #undef param_int
92 
93  return value;
94  }
95 
96  virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
97  const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
98  {
99  RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
100  RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
101 
102  if (!needleCell || !haystackCell) {
103  log_assert(!needleCell && !haystackCell);
104  return true;
105  }
106 
107  if (!ignore_parameters) {
108  std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
109  for (auto &it : needleCell->parameters)
110  if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
111  needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
112  for (auto &it : haystackCell->parameters)
113  if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
114  haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
115  if (needle_param != haystack_param)
116  return false;
117  }
118 
119  if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
120  return false;
121 
122  if (wire_attr.size() > 0)
123  {
124  RTLIL::Wire *lastNeedleWire = NULL;
125  RTLIL::Wire *lastHaystackWire = NULL;
126  std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
127 
128  for (auto &conn : needleCell->connections())
129  {
130  RTLIL::SigSpec needleSig = conn.second;
131  RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
132 
133  for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
134  RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
135  if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
136  if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
137  return false;
138  lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
139  }
140  }
141  }
142 
143  return true;
144  }
145 };
146 
147 struct bit_ref_t {
148  std::string cell, port;
149  int bit;
150 };
151 
152 bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
153  int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
154 {
155  SigMap sigmap(mod);
156  std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
157 
158  if (sel && !sel->selected(mod)) {
159  log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
160  return false;
161  }
162 
163  if (mod->processes.size() > 0) {
164  log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
165  return false;
166  }
167 
168  if (constports) {
169  graph.createNode("$const$0", "$const$0", NULL, true);
170  graph.createNode("$const$1", "$const$1", NULL, true);
171  graph.createNode("$const$x", "$const$x", NULL, true);
172  graph.createNode("$const$z", "$const$z", NULL, true);
173  graph.createPort("$const$0", "\\Y", 1);
174  graph.createPort("$const$1", "\\Y", 1);
175  graph.createPort("$const$x", "\\Y", 1);
176  graph.createPort("$const$z", "\\Y", 1);
177  graph.markExtern("$const$0", "\\Y", 0);
178  graph.markExtern("$const$1", "\\Y", 0);
179  graph.markExtern("$const$x", "\\Y", 0);
180  graph.markExtern("$const$z", "\\Y", 0);
181  }
182 
183  std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
184  if (max_fanout > 0)
185  for (auto &cell_it : mod->cells_)
186  {
187  RTLIL::Cell *cell = cell_it.second;
188  if (!sel || sel->selected(mod, cell))
189  for (auto &conn : cell->connections()) {
190  RTLIL::SigSpec conn_sig = conn.second;
191  sigmap.apply(conn_sig);
192  for (auto &bit : conn_sig)
193  if (bit.wire != NULL)
194  sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
195  }
196  }
197 
198  // create graph nodes from cells
199  for (auto &cell_it : mod->cells_)
200  {
201  RTLIL::Cell *cell = cell_it.second;
202  if (sel && !sel->selected(mod, cell))
203  continue;
204 
205  std::string type = cell->type.str();
206  if (sel == NULL && type.substr(0, 2) == "\\$")
207  type = type.substr(1);
208  graph.createNode(cell->name.str(), type, (void*)cell);
209 
210  for (auto &conn : cell->connections())
211  {
212  graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
213 
214  if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
215  continue;
216 
217  RTLIL::SigSpec conn_sig = conn.second;
218  sigmap.apply(conn_sig);
219 
220  for (int i = 0; i < conn_sig.size(); i++)
221  {
222  auto &bit = conn_sig[i];
223 
224  if (bit.wire == NULL) {
225  if (constports) {
226  std::string node = "$const$x";
227  if (bit == RTLIL::State::S0) node = "$const$0";
228  if (bit == RTLIL::State::S1) node = "$const$1";
229  if (bit == RTLIL::State::Sz) node = "$const$z";
230  graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
231  } else
232  graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
233  continue;
234  }
235 
236  if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
237  continue;
238 
239  if (sel && !sel->selected(mod, bit.wire))
240  continue;
241 
242  if (sig_bit_ref.count(bit) == 0) {
243  bit_ref_t &bit_ref = sig_bit_ref[bit];
244  bit_ref.cell = cell->name.str();
245  bit_ref.port = conn.first.str();
246  bit_ref.bit = i;
247  }
248 
249  bit_ref_t &bit_ref = sig_bit_ref[bit];
250  graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
251  }
252  }
253  }
254 
255  // mark external signals (used in non-selected cells)
256  for (auto &cell_it : mod->cells_)
257  {
258  RTLIL::Cell *cell = cell_it.second;
259  if (sel && !sel->selected(mod, cell))
260  for (auto &conn : cell->connections())
261  {
262  RTLIL::SigSpec conn_sig = conn.second;
263  sigmap.apply(conn_sig);
264 
265  for (auto &bit : conn_sig)
266  if (sig_bit_ref.count(bit) != 0) {
267  bit_ref_t &bit_ref = sig_bit_ref[bit];
268  graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
269  }
270  }
271  }
272 
273  // mark external signals (used in module ports)
274  for (auto &wire_it : mod->wires_)
275  {
276  RTLIL::Wire *wire = wire_it.second;
277  if (wire->port_id > 0)
278  {
279  RTLIL::SigSpec conn_sig(wire);
280  sigmap.apply(conn_sig);
281 
282  for (auto &bit : conn_sig)
283  if (sig_bit_ref.count(bit) != 0) {
284  bit_ref_t &bit_ref = sig_bit_ref[bit];
285  graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
286  }
287  }
288  }
289 
290  // graph.print();
291  return true;
292 }
293 
295 {
296  SigMap sigmap(needle);
298 
299  // create new cell
300  RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
301 
302  // create cell ports
303  for (auto &it : needle->wires_) {
304  RTLIL::Wire *wire = it.second;
305  if (wire->port_id > 0) {
306  for (int i = 0; i < wire->width; i++)
307  sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
308  cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
309  }
310  }
311 
312  // delete replaced cells and connect new ports
313  for (auto &it : match.mappings)
314  {
315  auto &mapping = it.second;
316  RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
317  RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
318 
319  if (needle_cell == NULL)
320  continue;
321 
322  for (auto &conn : needle_cell->connections()) {
323  RTLIL::SigSpec sig = sigmap(conn.second);
324  if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
325  for (int i = 0; i < sig.size(); i++)
326  for (auto &port : sig2port.find(sig[i])) {
327  RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
328  RTLIL::SigSpec new_sig = cell->getPort(port.first);
329  new_sig.replace(port.second, bitsig);
330  cell->setPort(port.first, new_sig);
331  }
332  }
333  }
334 
335  haystack->remove(haystack_cell);
336  }
337 
338  return cell;
339 }
340 
342 {
343  int left_idx = 0, right_idx = 0;
344  if (left->attributes.count("\\extract_order") > 0)
345  left_idx = left->attributes.at("\\extract_order").as_int();
346  if (right->attributes.count("\\extract_order") > 0)
347  right_idx = right->attributes.at("\\extract_order").as_int();
348  if (left_idx != right_idx)
349  return left_idx < right_idx;
350  return left->name < right->name;
351 }
352 
353 struct ExtractPass : public Pass {
354  ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
355  virtual void help()
356  {
357  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
358  log("\n");
359  log(" extract -map <map_file> [options] [selection]\n");
360  log(" extract -mine <out_file> [options] [selection]\n");
361  log("\n");
362  log("This pass looks for subcircuits that are isomorphic to any of the modules\n");
363  log("in the given map file and replaces them with instances of this modules. The\n");
364  log("map file can be a verilog source file (*.v) or an ilang file (*.il).\n");
365  log("\n");
366  log(" -map <map_file>\n");
367  log(" use the modules in this file as reference. This option can be used\n");
368  log(" multiple times.\n");
369  log("\n");
370  log(" -map %%<design-name>\n");
371  log(" use the modules in this in-memory design as reference. This option can\n");
372  log(" be used multiple times.\n");
373  log("\n");
374  log(" -verbose\n");
375  log(" print debug output while analyzing\n");
376  log("\n");
377  log(" -constports\n");
378  log(" also find instances with constant drivers. this may be much\n");
379  log(" slower than the normal operation.\n");
380  log("\n");
381  log(" -nodefaultswaps\n");
382  log(" normally builtin port swapping rules for internal cells are used per\n");
383  log(" default. This turns that off, so e.g. 'a^b' does not match 'b^a'\n");
384  log(" when this option is used.\n");
385  log("\n");
386  log(" -compat <needle_type> <haystack_type>\n");
387  log(" Per default, the cells in the map file (needle) must have the\n");
388  log(" type as the cells in the active design (haystack). This option\n");
389  log(" can be used to register additional pairs of types that should\n");
390  log(" match. This option can be used multiple times.\n");
391  log("\n");
392  log(" -swap <needle_type> <port1>,<port2>[,...]\n");
393  log(" Register a set of swapable ports for a needle cell type.\n");
394  log(" This option can be used multiple times.\n");
395  log("\n");
396  log(" -perm <needle_type> <port1>,<port2>[,...] <portA>,<portB>[,...]\n");
397  log(" Register a valid permutation of swapable ports for a needle\n");
398  log(" cell type. This option can be used multiple times.\n");
399  log("\n");
400  log(" -cell_attr <attribute_name>\n");
401  log(" Attributes on cells with the given name must match.\n");
402  log("\n");
403  log(" -wire_attr <attribute_name>\n");
404  log(" Attributes on wires with the given name must match.\n");
405  log("\n");
406  log(" -ignore_parameters\n");
407  log(" Do not use parameters when matching cells.\n");
408  log("\n");
409  log(" -ignore_param <cell_type> <parameter_name>\n");
410  log(" Do not use this parameter when matching cells.\n");
411  log("\n");
412  log("This pass does not operate on modules with uprocessed processes in it.\n");
413  log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
414  log("\n");
415  log("This pass can also be used for mining for frequent subcircuits. In this mode\n");
416  log("the following options are to be used instead of the -map option.\n");
417  log("\n");
418  log(" -mine <out_file>\n");
419  log(" mine for frequent subcircuits and write them to the given ilang file\n");
420  log("\n");
421  log(" -mine_cells_span <min> <max>\n");
422  log(" only mine for subcircuits with the specified number of cells\n");
423  log(" default value: 3 5\n");
424  log("\n");
425  log(" -mine_min_freq <num>\n");
426  log(" only mine for subcircuits with at least the specified number of matches\n");
427  log(" default value: 10\n");
428  log("\n");
429  log(" -mine_limit_matches_per_module <num>\n");
430  log(" when calculating the number of matches for a subcircuit, don't count\n");
431  log(" more than the specified number of matches per module\n");
432  log("\n");
433  log(" -mine_max_fanout <num>\n");
434  log(" don't consider internal signals with more than <num> connections\n");
435  log("\n");
436  log("The modules in the map file may have the attribute 'extract_order' set to an\n");
437  log("integer value. Then this value is used to determine the order in which the pass\n");
438  log("tries to map the modules to the design (ascending, default value is 0).\n");
439  log("\n");
440  log("See 'help techmap' for a pass that does the opposite thing.\n");
441  log("\n");
442  }
443  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
444  {
445  log_header("Executing EXTRACT pass (map subcircuits to cells).\n");
446  log_push();
447 
448  SubCircuitSolver solver;
449 
450  std::vector<std::string> map_filenames;
451  std::string mine_outfile;
452  bool constports = false;
453  bool nodefaultswaps = false;
454 
455  bool mine_mode = false;
456  int mine_cells_min = 3;
457  int mine_cells_max = 5;
458  int mine_min_freq = 10;
459  int mine_limit_mod = -1;
460  int mine_max_fanout = -1;
461  std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> mine_split;
462 
463  size_t argidx;
464  for (argidx = 1; argidx < args.size(); argidx++) {
465  if (args[argidx] == "-map" && argidx+1 < args.size()) {
466  if (mine_mode)
467  log_cmd_error("You cannot mix -map and -mine.\n");
468  map_filenames.push_back(args[++argidx]);
469  continue;
470  }
471  if (args[argidx] == "-mine" && argidx+1 < args.size()) {
472  if (!map_filenames.empty())
473  log_cmd_error("You cannot mix -map and -mine.\n");
474  mine_outfile = args[++argidx];
475  mine_mode = true;
476  continue;
477  }
478  if (args[argidx] == "-mine_cells_span" && argidx+2 < args.size()) {
479  mine_cells_min = atoi(args[++argidx].c_str());
480  mine_cells_max = atoi(args[++argidx].c_str());
481  continue;
482  }
483  if (args[argidx] == "-mine_min_freq" && argidx+1 < args.size()) {
484  mine_min_freq = atoi(args[++argidx].c_str());
485  continue;
486  }
487  if (args[argidx] == "-mine_limit_matches_per_module" && argidx+1 < args.size()) {
488  mine_limit_mod = atoi(args[++argidx].c_str());
489  continue;
490  }
491  if (args[argidx] == "-mine_split" && argidx+2 < args.size()) {
492  mine_split.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
493  argidx += 2;
494  continue;
495  }
496  if (args[argidx] == "-mine_max_fanout" && argidx+1 < args.size()) {
497  mine_max_fanout = atoi(args[++argidx].c_str());
498  continue;
499  }
500  if (args[argidx] == "-verbose") {
501  solver.setVerbose();
502  continue;
503  }
504  if (args[argidx] == "-constports") {
505  constports = true;
506  continue;
507  }
508  if (args[argidx] == "-nodefaultswaps") {
509  nodefaultswaps = true;
510  continue;
511  }
512  if (args[argidx] == "-compat" && argidx+2 < args.size()) {
513  std::string needle_type = RTLIL::escape_id(args[++argidx]);
514  std::string haystack_type = RTLIL::escape_id(args[++argidx]);
515  solver.addCompatibleTypes(needle_type, haystack_type);
516  continue;
517  }
518  if (args[argidx] == "-swap" && argidx+2 < args.size()) {
519  std::string type = RTLIL::escape_id(args[++argidx]);
520  std::set<std::string> ports;
521  std::string ports_str = args[++argidx], p;
522  while (!(p = next_token(ports_str, ",\t\r\n ")).empty())
523  ports.insert(RTLIL::escape_id(p));
524  solver.addSwappablePorts(type, ports);
525  continue;
526  }
527  if (args[argidx] == "-perm" && argidx+3 < args.size()) {
528  std::string type = RTLIL::escape_id(args[++argidx]);
529  std::vector<std::string> map_left, map_right;
530  std::string left_str = args[++argidx];
531  std::string right_str = args[++argidx], p;
532  while (!(p = next_token(left_str, ",\t\r\n ")).empty())
533  map_left.push_back(RTLIL::escape_id(p));
534  while (!(p = next_token(right_str, ",\t\r\n ")).empty())
535  map_right.push_back(RTLIL::escape_id(p));
536  if (map_left.size() != map_right.size())
537  log_cmd_error("Arguments to -perm are not a valid permutation!\n");
538  std::map<std::string, std::string> map;
539  for (size_t i = 0; i < map_left.size(); i++)
540  map[map_left[i]] = map_right[i];
541  std::sort(map_left.begin(), map_left.end());
542  std::sort(map_right.begin(), map_right.end());
543  if (map_left != map_right)
544  log_cmd_error("Arguments to -perm are not a valid permutation!\n");
545  solver.addSwappablePortsPermutation(type, map);
546  continue;
547  }
548  if (args[argidx] == "-cell_attr" && argidx+1 < args.size()) {
549  solver.cell_attr.insert(RTLIL::escape_id(args[++argidx]));
550  continue;
551  }
552  if (args[argidx] == "-wire_attr" && argidx+1 < args.size()) {
553  solver.wire_attr.insert(RTLIL::escape_id(args[++argidx]));
554  continue;
555  }
556  if (args[argidx] == "-ignore_parameters") {
557  solver.ignore_parameters = true;
558  continue;
559  }
560  if (args[argidx] == "-ignore_param" && argidx+2 < args.size()) {
561  solver.ignored_parameters.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
562  argidx += 2;
563  continue;
564  }
565  break;
566  }
567  extra_args(args, argidx, design);
568 
569  if (!nodefaultswaps) {
570  solver.addSwappablePorts("$and", "\\A", "\\B");
571  solver.addSwappablePorts("$or", "\\A", "\\B");
572  solver.addSwappablePorts("$xor", "\\A", "\\B");
573  solver.addSwappablePorts("$xnor", "\\A", "\\B");
574  solver.addSwappablePorts("$eq", "\\A", "\\B");
575  solver.addSwappablePorts("$ne", "\\A", "\\B");
576  solver.addSwappablePorts("$eqx", "\\A", "\\B");
577  solver.addSwappablePorts("$nex", "\\A", "\\B");
578  solver.addSwappablePorts("$add", "\\A", "\\B");
579  solver.addSwappablePorts("$mul", "\\A", "\\B");
580  solver.addSwappablePorts("$logic_and", "\\A", "\\B");
581  solver.addSwappablePorts("$logic_or", "\\A", "\\B");
582  solver.addSwappablePorts("$_AND_", "\\A", "\\B");
583  solver.addSwappablePorts("$_OR_", "\\A", "\\B");
584  solver.addSwappablePorts("$_XOR_", "\\A", "\\B");
585  }
586 
587  if (map_filenames.empty() && mine_outfile.empty())
588  log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
589 
590  RTLIL::Design *map = NULL;
591 
592  if (!mine_mode)
593  {
594  map = new RTLIL::Design;
595  for (auto &filename : map_filenames)
596  {
597  if (filename.substr(0, 1) == "%")
598  {
599  if (!saved_designs.count(filename.substr(1))) {
600  delete map;
601  log_cmd_error("Can't saved design `%s'.\n", filename.c_str()+1);
602  }
603  for (auto mod : saved_designs.at(filename.substr(1))->modules())
604  if (!map->has(mod->name))
605  map->add(mod->clone());
606  }
607  else
608  {
609  std::ifstream f;
610  f.open(filename.c_str());
611  if (f.fail()) {
612  delete map;
613  log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
614  }
615  Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
616  f.close();
617 
618  if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
619  Pass::call(map, "proc");
620  Pass::call(map, "opt_clean");
621  }
622  }
623  }
624  }
625 
626  std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
627  std::vector<RTLIL::Module*> needle_list;
628 
629  log_header("Creating graphs for SubCircuit library.\n");
630 
631  if (!mine_mode)
632  for (auto &mod_it : map->modules_) {
633  SubCircuit::Graph mod_graph;
634  std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
635  log("Creating needle graph %s.\n", graph_name.c_str());
636  if (module2graph(mod_graph, mod_it.second, constports)) {
637  solver.addGraph(graph_name, mod_graph);
638  needle_map[graph_name] = mod_it.second;
639  needle_list.push_back(mod_it.second);
640  }
641  }
642 
643  for (auto &mod_it : design->modules_) {
644  SubCircuit::Graph mod_graph;
645  std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
646  log("Creating haystack graph %s.\n", graph_name.c_str());
647  if (module2graph(mod_graph, mod_it.second, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : NULL)) {
648  solver.addGraph(graph_name, mod_graph);
649  haystack_map[graph_name] = mod_it.second;
650  }
651  }
652 
653  if (!mine_mode)
654  {
655  std::vector<SubCircuit::Solver::Result> results;
656  log_header("Running solver from SubCircuit library.\n");
657 
658  std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList);
659 
660  for (auto needle : needle_list)
661  for (auto &haystack_it : haystack_map) {
662  log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str());
663  solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false);
664  }
665  log("Found %d matches.\n", GetSize(results));
666 
667  if (results.size() > 0)
668  {
669  log_header("Substitute SubCircuits with cells.\n");
670 
671  for (int i = 0; i < int(results.size()); i++) {
672  auto &result = results[i];
673  log("\nMatch #%d: (%s in %s)\n", i, result.needleGraphId.c_str(), result.haystackGraphId.c_str());
674  for (const auto &it : result.mappings) {
675  log(" %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str());
676  for (const auto & it2 : it.second.portMapping)
677  log(" %s:%s", it2.first.c_str(), it2.second.c_str());
678  log("\n");
679  }
680  RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result);
681  design->select(haystack_map.at(result.haystackGraphId), new_cell);
682  log(" new cell: %s\n", id2cstr(new_cell->name));
683  }
684  }
685  }
686  else
687  {
688  std::vector<SubCircuit::Solver::MineResult> results;
689 
690  log_header("Running miner from SubCircuit library.\n");
691  solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod);
692 
693  map = new RTLIL::Design;
694 
695  int needleCounter = 0;
696  for (auto &result: results)
697  {
698  log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
699  log(" primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
700  for (auto &node : result.nodes)
701  log(" %s", RTLIL::unescape_id(node.nodeId).c_str());
702  log("\n");
703  for (auto &it : result.matchesPerGraph)
704  log(" matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
705 
706  RTLIL::Module *mod = haystack_map.at(result.graphId);
707  std::set<RTLIL::Cell*> cells;
708  std::set<RTLIL::Wire*> wires;
709 
710  SigMap sigmap(mod);
711 
712  for (auto &node : result.nodes)
713  cells.insert((RTLIL::Cell*)node.userData);
714 
715  for (auto cell : cells)
716  for (auto &conn : cell->connections()) {
717  RTLIL::SigSpec sig = sigmap(conn.second);
718  for (auto &chunk : sig.chunks())
719  if (chunk.wire != NULL)
720  wires.insert(chunk.wire);
721  }
722 
723  RTLIL::Module *newMod = new RTLIL::Module;
724  newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
725  map->add(newMod);
726 
727  for (auto wire : wires) {
728  RTLIL::Wire *newWire = newMod->addWire(wire->name, wire->width);
729  newWire->port_input = true;
730  newWire->port_output = true;
731  }
732 
733  newMod->fixup_ports();
734 
735  for (auto cell : cells) {
736  RTLIL::Cell *newCell = newMod->addCell(cell->name, cell->type);
737  newCell->parameters = cell->parameters;
738  for (auto &conn : cell->connections()) {
739  std::vector<RTLIL::SigChunk> chunks = sigmap(conn.second);
740  for (auto &chunk : chunks)
741  if (chunk.wire != NULL)
742  chunk.wire = newMod->wires_.at(chunk.wire->name);
743  newCell->setPort(conn.first, chunks);
744  }
745  }
746  }
747 
748  std::ofstream f;
749  f.open(mine_outfile.c_str(), std::ofstream::trunc);
750  if (f.fail())
751  log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
752  Backend::backend_call(map, &f, mine_outfile, "ilang");
753  f.close();
754  }
755 
756  delete map;
757  log_pop();
758  }
759 } ExtractPass;
760 
const char * c_str() const
Definition: rtlil.h:178
static std::string next_token(bool pass_newline=false)
Definition: preproc.cc:96
std::string str() const
Definition: rtlil.h:182
std::set< RTLIL::IdString > wire_attr
Definition: extract.cc:39
RTLIL::Wire * wire(RTLIL::IdString id)
Definition: rtlil.h:637
std::string stringf(const char *fmt,...)
Definition: yosys.cc:58
bool has(RTLIL::SigSpec sig)
Definition: sigtools.h:203
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:57
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
Definition: rtlil.cc:1353
void add(RTLIL::Module *module)
Definition: rtlil.cc:259
std::set< RTLIL::IdString > cell_attr
Definition: extract.cc:39
void log_header(const char *format,...)
Definition: log.cc:188
ExtractPass ExtractPass
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
Definition: rtlil.h:595
static std::string unescape_id(std::string str)
Definition: rtlil.h:257
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
Definition: register.cc:375
RTLIL::IdString name
Definition: rtlil.h:853
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
Definition: rtlil.cc:1789
bool port_input
Definition: rtlil.h:827
void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3=std::string(), std::string portId4=std::string())
Definition: subcircuit.cc:1647
int width
Definition: rtlil.h:826
void log_error(const char *format,...)
Definition: log.cc:204
int port_id
Definition: rtlil.h:826
RTLIL::IdString type
Definition: rtlil.h:854
std::map< RTLIL::IdString, RTLIL::Const > parameters
Definition: rtlil.h:856
void log_pop()
Definition: log.cc:237
int size() const
Definition: rtlil.h:1019
void select(T1 *module, T2 *member)
Definition: rtlil.h:559
virtual void help()
Definition: extract.cc:355
bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
Definition: extract.cc:341
#define param_int(_n)
void apply(RTLIL::SigBit &bit) const
Definition: sigtools.h:383
static std::string escape_id(std::string str)
Definition: rtlil.h:251
bool port_output
Definition: rtlil.h:827
void createNode(std::string nodeId, std::string typeId, void *userData=NULL, bool shared=false)
Definition: subcircuit.cc:107
void solve(std::vector< Result > &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap=true, int maxSolutions=-1)
Definition: subcircuit.cc:1668
std::map< std::string, RTLIL::Design * > saved_designs
Definition: design.cc:27
std::string cell
Definition: extract.cc:148
std::string port
Definition: extract.cc:148
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
Definition: register.cc:479
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue)
Definition: subcircuit.cc:209
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1809
void addGraph(std::string graphId, const Graph &graph)
Definition: subcircuit.cc:1632
int GetSize(RTLIL::Wire *wire)
Definition: yosys.cc:334
RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
Definition: extract.cc:55
void fixup_ports()
Definition: rtlil.cc:1312
#define log_assert(_assert_expr_)
Definition: log.h:85
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)
Definition: extract.cc:96
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
Definition: rtlil.cc:1331
RTLIL::IdString name
Definition: rtlil.h:599
void addSwappablePortsPermutation(std::string needleTypeId, std::map< std::string, std::string > portMapping)
Definition: subcircuit.cc:1663
static bool match(B &in, const char *str)
Definition: ParseUtils.h:96
void markExtern(std::string nodeId, std::string portId, int bit=-1)
Definition: subcircuit.cc:244
void mine(std::vector< MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph=-1)
Definition: subcircuit.cc:1680
#define param_bool(_n)
bool compareAttributes(const std::set< RTLIL::IdString > &attr, const std::map< RTLIL::IdString, RTLIL::Const > &needleAttr, const std::map< RTLIL::IdString, RTLIL::Const > &haystackAttr)
Definition: extract.cc:45
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
RTLIL::IdString name
Definition: rtlil.h:825
static const char * id2cstr(const RTLIL::IdString &str)
Definition: rtlil.h:267
void log_cmd_error(const char *format,...)
Definition: log.cc:211
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)
Definition: extract.cc:152
std::set< std::pair< RTLIL::IdString, RTLIL::IdString > > ignored_parameters
Definition: extract.cc:38
void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width=1)
Definition: subcircuit.cc:144
std::map< RTLIL::IdString, RTLIL::Process * > processes
Definition: rtlil.h:602
std::string substr(size_t pos=0, size_t len=std::string::npos) const
Definition: rtlil.h:208
bool has(RTLIL::IdString id) const
Definition: rtlil.h:519
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
int bit
Definition: extract.cc:149
std::map< RTLIL::IdString, RTLIL::Module * > modules_
Definition: rtlil.h:507
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
Definition: rtlil.cc:2297
#define NULL
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
Definition: rtlil.h:596
void remove(const std::set< RTLIL::Wire * > &wires)
Definition: rtlil.cc:1158
void log(const char *format,...)
Definition: log.cc:180
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: extract.cc:443
RTLIL::Cell * replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
Definition: extract.cc:294
void log_push()
Definition: log.cc:232
void createPort(std::string nodeId, std::string portId, int width=1, int minWidth=-1)
Definition: subcircuit.cc:120
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
static void call(RTLIL::Design *design, std::string command)
Definition: register.cc:146
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
Definition: rtlil.cc:1814
std::map< std::string, ResultNodeMapping > mappings
Definition: subcircuit.h:102
void find(RTLIL::SigSpec sig, std::set< T > &result)
Definition: sigtools.h:187
void insert(RTLIL::SigSpec sig, T data)
Definition: sigtools.h:152
YOSYS_NAMESPACE_BEGIN int autoidx
Definition: yosys.cc:51
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
Definition: subcircuit.cc:1637
const std::vector< RTLIL::SigChunk > & chunks() const
Definition: rtlil.h:1016
bool ignore_parameters
Definition: extract.cc:37