| /* | |
| * yosys -- Yosys Open SYnthesis Suite | |
| * | |
| * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> | |
| * | |
| * Permission to use, copy, modify, and/or distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| * | |
| */ | |
| #include "kernel/yosys.h" | |
| #include "kernel/cellaigs.h" | |
| USING_YOSYS_NAMESPACE | |
| PRIVATE_NAMESPACE_BEGIN | |
| struct AigmapPass : public Pass { | |
| AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { } | |
| void help() YS_OVERRIDE | |
| { | |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | |
| log("\n"); | |
| log(" aigmap [options] [selection]\n"); | |
| log("\n"); | |
| log("Replace all logic cells with circuits made of only $_AND_ and\n"); | |
| log("$_NOT_ cells.\n"); | |
| log("\n"); | |
| log(" -nand\n"); | |
| log(" Enable creation of $_NAND_ cells\n"); | |
| log("\n"); | |
| log(" -select\n"); | |
| log(" Overwrite replaced cells in the current selection with new $_AND_,\n"); | |
| log(" $_NOT_, and $_NAND_, cells\n"); | |
| log("\n"); | |
| } | |
| void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | |
| { | |
| bool nand_mode = false, select_mode = false; | |
| log_header(design, "Executing AIGMAP pass (map logic to AIG).\n"); | |
| size_t argidx; | |
| for (argidx = 1; argidx < args.size(); argidx++) | |
| { | |
| if (args[argidx] == "-nand") { | |
| nand_mode = true; | |
| continue; | |
| } | |
| if (args[argidx] == "-select") { | |
| select_mode = true; | |
| continue; | |
| } | |
| break; | |
| } | |
| extra_args(args, argidx, design); | |
| for (auto module : design->selected_modules()) | |
| { | |
| vector<Cell*> replaced_cells; | |
| int not_replaced_count = 0; | |
| dict<IdString, int> stat_replaced; | |
| dict<IdString, int> stat_not_replaced; | |
| int orig_num_cells = GetSize(module->cells()); | |
| pool<IdString> new_sel; | |
| for (auto cell : module->selected_cells()) | |
| { | |
| Aig aig(cell); | |
| if (cell->type.in(ID($_AND_), ID($_NOT_))) | |
| aig.name.clear(); | |
| if (nand_mode && cell->type == ID($_NAND_)) | |
| aig.name.clear(); | |
| if (aig.name.empty()) { | |
| not_replaced_count++; | |
| stat_not_replaced[cell->type]++; | |
| if (select_mode) | |
| new_sel.insert(cell->name); | |
| continue; | |
| } | |
| vector<SigBit> sigs; | |
| dict<pair<int, int>, SigBit> and_cache; | |
| for (int node_idx = 0; node_idx < GetSize(aig.nodes); node_idx++) | |
| { | |
| SigBit bit; | |
| auto &node = aig.nodes[node_idx]; | |
| if (node.portbit >= 0) { | |
| bit = cell->getPort(node.portname)[node.portbit]; | |
| } else if (node.left_parent < 0 && node.right_parent < 0) { | |
| bit = node.inverter ? State::S1 : State::S0; | |
| goto skip_inverter; | |
| } else { | |
| SigBit A = sigs.at(node.left_parent); | |
| SigBit B = sigs.at(node.right_parent); | |
| if (nand_mode && node.inverter) { | |
| bit = module->addWire(NEW_ID); | |
| auto gate = module->addNandGate(NEW_ID, A, B, bit); | |
| if (select_mode) | |
| new_sel.insert(gate->name); | |
| goto skip_inverter; | |
| } else { | |
| pair<int, int> key(node.left_parent, node.right_parent); | |
| if (and_cache.count(key)) | |
| bit = and_cache.at(key); | |
| else { | |
| bit = module->addWire(NEW_ID); | |
| auto gate = module->addAndGate(NEW_ID, A, B, bit); | |
| if (select_mode) | |
| new_sel.insert(gate->name); | |
| } | |
| } | |
| } | |
| if (node.inverter) { | |
| SigBit new_bit = module->addWire(NEW_ID); | |
| auto gate = module->addNotGate(NEW_ID, bit, new_bit); | |
| bit = new_bit; | |
| if (select_mode) | |
| new_sel.insert(gate->name); | |
| } | |
| skip_inverter: | |
| for (auto &op : node.outports) | |
| module->connect(cell->getPort(op.first)[op.second], bit); | |
| sigs.push_back(bit); | |
| } | |
| replaced_cells.push_back(cell); | |
| stat_replaced[cell->type]++; | |
| } | |
| if (not_replaced_count == 0 && replaced_cells.empty()) | |
| continue; | |
| log("Module %s: replaced %d cells with %d new cells, skipped %d cells.\n", log_id(module), | |
| GetSize(replaced_cells), GetSize(module->cells()) - orig_num_cells, not_replaced_count); | |
| if (!stat_replaced.empty()) { | |
| stat_replaced.sort(); | |
| log(" replaced %d cell types:\n", GetSize(stat_replaced)); | |
| for (auto &it : stat_replaced) | |
| log("%8d %s\n", it.second, log_id(it.first)); | |
| } | |
| if (!stat_not_replaced.empty()) { | |
| stat_not_replaced.sort(); | |
| log(" not replaced %d cell types:\n", GetSize(stat_not_replaced)); | |
| for (auto &it : stat_not_replaced) | |
| log("%8d %s\n", it.second, log_id(it.first)); | |
| } | |
| for (auto cell : replaced_cells) | |
| module->remove(cell); | |
| if (select_mode) { | |
| log_assert(!design->selection_stack.empty()); | |
| RTLIL::Selection& sel = design->selection_stack.back(); | |
| sel.selected_members[module->name] = std::move(new_sel); | |
| } | |
| } | |
| } | |
| } AigmapPass; | |
| PRIVATE_NAMESPACE_END |