/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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/rtlil.h" #include "kernel/log.h" static bool consider_wire(RTLIL::Wire *wire) { if (wire->name[0] == '$') return false; if (wire->port_input) return false; return true; } static bool consider_cell(RTLIL::Design *design, RTLIL::Cell *cell) { if (cell->name[0] == '$') return false; if (design->modules.count(cell->type) == 0) return false; return true; } static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2) { log_assert(wire1->name == wire2->name); if (wire1->width != wire2->width) return false; return true; } static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2) { log_assert(cell1->name == cell2->name); if (cell1->type != cell2->type) return false; if (cell1->parameters != cell2->parameters) return false; return true; } struct ExposePass : public Pass { ExposePass() : Pass("expose", "convert internal signals to module ports") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" expose [options] [selection]\n"); log("\n"); log("This command exposes all selected internal signals of a module as additional\n"); log("outputs.\n"); log("\n"); log(" -shared\n"); log(" only expose those signals that are shared ammong the selected modules.\n"); log(" this is useful for preparing modules for equivialence checking.\n"); log("\n"); log(" -evert\n"); log(" also turn connections to instances of other modules to additional\n"); log(" inputs and outputs and remove the module instances.\n"); log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { bool flag_shared = false; bool flag_evert = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-shared") { flag_shared = true; continue; } if (args[argidx] == "-evert") { flag_evert = true; continue; } break; } extra_args(args, argidx, design); std::set shared_wires, shared_cells; std::set used_names; if (flag_shared) { RTLIL::Module *first_module = NULL; for (auto &mod_it : design->modules) { RTLIL::Module *module = mod_it.second; if (!design->selected(module)) continue; if (first_module == NULL) { for (auto &it : module->wires) if (design->selected(module, it.second) && consider_wire(it.second)) shared_wires.insert(it.first); if (flag_evert) for (auto &it : module->cells) if (design->selected(module, it.second) && consider_cell(design, it.second)) shared_cells.insert(it.first); first_module = module; } else { std::vector delete_shared_wires, delete_shared_cells; for (auto &it : shared_wires) { RTLIL::Wire *wire; if (module->wires.count(it) == 0) goto delete_shared_wire; wire = module->wires.at(it); if (!design->selected(module, wire)) goto delete_shared_wire; if (!consider_wire(wire)) goto delete_shared_wire; if (!compare_wires(first_module->wires.at(it), wire)) goto delete_shared_wire; if (0) delete_shared_wire: delete_shared_wires.push_back(it); } if (flag_evert) for (auto &it : shared_cells) { RTLIL::Cell *cell; if (module->cells.count(it) == 0) goto delete_shared_cell; cell = module->cells.at(it); if (!design->selected(module, cell)) goto delete_shared_cell; if (!consider_cell(design, cell)) goto delete_shared_cell; if (!compare_cells(first_module->cells.at(it), cell)) goto delete_shared_cell; if (0) delete_shared_cell: delete_shared_cells.push_back(it); } for (auto &it : delete_shared_wires) shared_wires.erase(it); for (auto &it : delete_shared_cells) shared_cells.erase(it); } } } for (auto &mod_it : design->modules) { RTLIL::Module *module = mod_it.second; if (!design->selected(module)) continue; for (auto &it : module->wires) { if (flag_shared) { if (shared_wires.count(it.first) == 0) continue; } else { if (!design->selected(module, it.second) || !consider_wire(it.second)) continue; } if (!it.second->port_output) { it.second->port_output = true; log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name)); } } if (flag_evert) { std::vector delete_cells; for (auto &it : module->cells) { if (flag_shared) { if (shared_cells.count(it.first) == 0) continue; } else { if (!design->selected(module, it.second) || !consider_cell(design, it.second)) continue; } RTLIL::Cell *cell = it.second; RTLIL::Module *mod = design->modules.at(cell->type); for (auto &it : mod->wires) { RTLIL::Wire *p = it.second; if (!p->port_input && !p->port_output) continue; RTLIL::Wire *w = new RTLIL::Wire; w->name = cell->name + "." + RTLIL::unescape_id(p->name); w->width = p->width; if (p->port_input) w->port_output = true; if (p->port_output) w->port_input = true; module->add(w); log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name)); RTLIL::SigSpec sig; if (cell->connections.count(p->name) != 0) sig = cell->connections.at(p->name); sig.extend(w->width); if (w->port_input) module->connections.push_back(RTLIL::SigSig(sig, w)); else module->connections.push_back(RTLIL::SigSig(w, sig)); } delete_cells.push_back(cell->name); } for (auto &it : delete_cells) { log("Removing cell: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it)); delete module->cells.at(it); module->cells.erase(it); } } module->fixup_ports(); } } } ExposePass;