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)
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)))
57 if (cell_type.
substr(0, 1) !=
"$" || cell_type.
substr(0, 2) ==
"$_")
60 #define param_bool(_n) if (param == _n) return value.as_bool();
72 #define param_int(_n) if (param == _n) return value.as_int();
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)
102 if (!needleCell || !haystackCell) {
108 std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
114 haystack_param[it.first] =
unified_param(haystackCell->
type, it.first, it.second);
115 if (needle_param != haystack_param)
126 std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
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))
138 lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
153 int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split =
NULL)
156 std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
158 if (sel && !sel->selected(mod)) {
159 log(
" Skipping module %s as it is not selected.\n",
id2cstr(mod->
name));
164 log(
" Skipping module %s as it contains unprocessed processes.\n",
id2cstr(mod->
name));
183 std::map<std::pair<RTLIL::Wire*, int>,
int> sig_use_count;
185 for (
auto &cell_it : mod->
cells_)
188 if (!sel || sel->selected(mod, cell))
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)]++;
199 for (
auto &cell_it : mod->
cells_)
202 if (sel && !sel->selected(mod, cell))
205 std::string type = cell->
type.
str();
206 if (sel ==
NULL && type.substr(0, 2) ==
"\\$")
207 type = type.substr(1);
210 for (
auto &conn : cell->connections())
212 graph.
createPort(cell->name.str(), conn.first.str(), conn.second.size());
214 if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
218 sigmap.
apply(conn_sig);
220 for (
int i = 0; i < conn_sig.
size(); i++)
222 auto &bit = conn_sig[i];
224 if (bit.wire ==
NULL) {
226 std::string node =
"$const$x";
230 graph.
createConnection(cell->name.str(), conn.first.str(), i, node,
"\\Y", 0);
232 graph.
createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
236 if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
239 if (sel && !sel->selected(mod, bit.
wire))
242 if (sig_bit_ref.count(bit) == 0) {
244 bit_ref.
cell = cell->name.str();
245 bit_ref.
port = conn.first.str();
256 for (
auto &cell_it : mod->
cells_)
259 if (sel && !sel->selected(mod, cell))
263 sigmap.
apply(conn_sig);
265 for (
auto &bit : conn_sig)
266 if (sig_bit_ref.count(bit) != 0) {
274 for (
auto &wire_it : mod->
wires_)
280 sigmap.
apply(conn_sig);
282 for (
auto &bit : conn_sig)
283 if (sig_bit_ref.count(bit) != 0) {
303 for (
auto &it : needle->
wires_) {
306 for (
int i = 0; i < wire->
width; i++)
315 auto &mapping = it.second;
319 if (needle_cell ==
NULL)
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);
329 new_sig.
replace(port.second, bitsig);
330 cell->
setPort(port.first, new_sig);
335 haystack->
remove(haystack_cell);
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;
359 log(
" extract -map <map_file> [options] [selection]\n");
360 log(
" extract -mine <out_file> [options] [selection]\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");
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");
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");
375 log(
" print debug output while analyzing\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");
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");
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");
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");
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");
400 log(
" -cell_attr <attribute_name>\n");
401 log(
" Attributes on cells with the given name must match.\n");
403 log(
" -wire_attr <attribute_name>\n");
404 log(
" Attributes on wires with the given name must match.\n");
406 log(
" -ignore_parameters\n");
407 log(
" Do not use parameters when matching cells.\n");
409 log(
" -ignore_param <cell_type> <parameter_name>\n");
410 log(
" Do not use this parameter when matching cells.\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");
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");
418 log(
" -mine <out_file>\n");
419 log(
" mine for frequent subcircuits and write them to the given ilang file\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");
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");
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");
433 log(
" -mine_max_fanout <num>\n");
434 log(
" don't consider internal signals with more than <num> connections\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");
440 log(
"See 'help techmap' for a pass that does the opposite thing.\n");
445 log_header(
"Executing EXTRACT pass (map subcircuits to cells).\n");
450 std::vector<std::string> map_filenames;
451 std::string mine_outfile;
452 bool constports =
false;
453 bool nodefaultswaps =
false;
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;
464 for (argidx = 1; argidx < args.size(); argidx++) {
465 if (args[argidx] ==
"-map" && argidx+1 < args.size()) {
468 map_filenames.push_back(args[++argidx]);
471 if (args[argidx] ==
"-mine" && argidx+1 < args.size()) {
472 if (!map_filenames.empty())
474 mine_outfile = args[++argidx];
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());
483 if (args[argidx] ==
"-mine_min_freq" && argidx+1 < args.size()) {
484 mine_min_freq = atoi(args[++argidx].c_str());
487 if (args[argidx] ==
"-mine_limit_matches_per_module" && argidx+1 < args.size()) {
488 mine_limit_mod = atoi(args[++argidx].c_str());
491 if (args[argidx] ==
"-mine_split" && argidx+2 < args.size()) {
496 if (args[argidx] ==
"-mine_max_fanout" && argidx+1 < args.size()) {
497 mine_max_fanout = atoi(args[++argidx].c_str());
500 if (args[argidx] ==
"-verbose") {
504 if (args[argidx] ==
"-constports") {
508 if (args[argidx] ==
"-nodefaultswaps") {
509 nodefaultswaps =
true;
512 if (args[argidx] ==
"-compat" && argidx+2 < args.size()) {
518 if (args[argidx] ==
"-swap" && argidx+2 < args.size()) {
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())
527 if (args[argidx] ==
"-perm" && argidx+3 < args.size()) {
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())
534 while (!(p =
next_token(right_str,
",\t\r\n ")).empty())
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");
548 if (args[argidx] ==
"-cell_attr" && argidx+1 < args.size()) {
552 if (args[argidx] ==
"-wire_attr" && argidx+1 < args.size()) {
556 if (args[argidx] ==
"-ignore_parameters") {
560 if (args[argidx] ==
"-ignore_param" && argidx+2 < args.size()) {
569 if (!nodefaultswaps) {
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");
595 for (
auto &filename : map_filenames)
597 if (filename.substr(0, 1) ==
"%")
601 log_cmd_error(
"Can't saved design `%s'.\n", filename.c_str()+1);
603 for (
auto mod :
saved_designs.at(filename.substr(1))->modules())
604 if (!map->
has(mod->name))
605 map->
add(mod->clone());
610 f.open(filename.c_str());
613 log_cmd_error(
"Can't open map file `%s'.\n", filename.c_str());
615 Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) ==
".il") ?
"ilang" :
"verilog");
618 if (filename.size() <= 3 || filename.substr(filename.size()-3) !=
".il") {
626 std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
627 std::vector<RTLIL::Module*> needle_list;
629 log_header(
"Creating graphs for SubCircuit library.\n");
632 for (
auto &mod_it : map->
modules_) {
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);
643 for (
auto &mod_it : design->
modules_) {
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;
655 std::vector<SubCircuit::Solver::Result> results;
656 log_header(
"Running solver from SubCircuit library.\n");
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());
667 if (results.size() > 0)
669 log_header(
"Substitute SubCircuits with cells.\n");
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());
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);
688 std::vector<SubCircuit::Solver::MineResult> results;
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);
695 int needleCounter = 0;
696 for (
auto &result: results)
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)
703 for (
auto &it : result.matchesPerGraph)
704 log(
" matches in %s: %d\n",
id2cstr(haystack_map.at(it.first)->name), it.second);
707 std::set<RTLIL::Cell*> cells;
708 std::set<RTLIL::Wire*> wires;
712 for (
auto &node : result.nodes)
715 for (
auto cell : cells)
716 for (
auto &conn : cell->connections()) {
718 for (
auto &chunk : sig.
chunks())
719 if (chunk.wire !=
NULL)
720 wires.insert(chunk.wire);
724 newMod->
name =
stringf(
"\\needle%05d_%s_%dx", needleCounter++,
id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
727 for (
auto wire : wires) {
735 for (
auto cell : cells) {
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);
749 f.open(mine_outfile.c_str(), std::ofstream::trunc);
751 log_error(
"Can't open output file `%s'.\n", mine_outfile.c_str());
const char * c_str() const
static std::string next_token(bool pass_newline=false)
std::set< RTLIL::IdString > wire_attr
RTLIL::Wire * wire(RTLIL::IdString id)
std::string stringf(const char *fmt,...)
bool has(RTLIL::SigSpec sig)
void sort(T *array, int size, LessThan lt)
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
void add(RTLIL::Module *module)
std::set< RTLIL::IdString > cell_attr
void log_header(const char *format,...)
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
static std::string unescape_id(std::string str)
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3=std::string(), std::string portId4=std::string())
void log_error(const char *format,...)
std::map< RTLIL::IdString, RTLIL::Const > parameters
void select(T1 *module, T2 *member)
void apply(RTLIL::SigBit &bit) const
static std::string escape_id(std::string str)
void createNode(std::string nodeId, std::string typeId, void *userData=NULL, bool shared=false)
void solve(std::vector< Result > &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap=true, int maxSolutions=-1)
std::map< std::string, RTLIL::Design * > saved_designs
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
#define PRIVATE_NAMESPACE_BEGIN
void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue)
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
void addGraph(std::string graphId, const Graph &graph)
int GetSize(RTLIL::Wire *wire)
RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
#define log_assert(_assert_expr_)
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::Wire * addWire(RTLIL::IdString name, int width=1)
void addSwappablePortsPermutation(std::string needleTypeId, std::map< std::string, std::string > portMapping)
static bool match(B &in, const char *str)
void markExtern(std::string nodeId, std::string portId, int bit=-1)
void mine(std::vector< MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph=-1)
bool compareAttributes(const std::set< RTLIL::IdString > &attr, const std::map< RTLIL::IdString, RTLIL::Const > &needleAttr, const std::map< RTLIL::IdString, RTLIL::Const > &haystackAttr)
#define PRIVATE_NAMESPACE_END
static const char * id2cstr(const RTLIL::IdString &str)
void log_cmd_error(const char *format,...)
std::set< std::pair< RTLIL::IdString, RTLIL::IdString > > ignored_parameters
void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width=1)
std::map< RTLIL::IdString, RTLIL::Process * > processes
std::string substr(size_t pos=0, size_t len=std::string::npos) const
bool has(RTLIL::IdString id) const
#define USING_YOSYS_NAMESPACE
std::map< RTLIL::IdString, RTLIL::Module * > modules_
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
void remove(const std::set< RTLIL::Wire * > &wires)
void log(const char *format,...)
void createPort(std::string nodeId, std::string portId, int width=1, int minWidth=-1)
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
static void call(RTLIL::Design *design, std::string command)
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
std::map< std::string, ResultNodeMapping > mappings
void find(RTLIL::SigSpec sig, std::set< T > &result)
void insert(RTLIL::SigSpec sig, T data)
YOSYS_NAMESPACE_BEGIN int autoidx
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
const std::vector< RTLIL::SigChunk > & chunks() const