diff options
Diffstat (limited to 'passes/cmds/setundef.cc')
-rw-r--r-- | passes/cmds/setundef.cc | 157 |
1 files changed, 141 insertions, 16 deletions
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 172b1c3f8..0825cf83e 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -26,6 +26,70 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static RTLIL::Wire * add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output, bool flag_global) +{ + RTLIL::Wire *wire = NULL; + name = RTLIL::escape_id(name); + + if (module->count_id(name) != 0) + { + if (module->wires_.count(name) > 0) + wire = module->wires_.at(name); + + if (wire != NULL && wire->width != width) + wire = NULL; + + if (wire != NULL && wire->port_input != flag_input) + wire = NULL; + + if (wire != NULL && wire->port_output != flag_output) + wire = NULL; + + if (wire == NULL) { + return wire; + log_cmd_error("Found incompatible object %s with same name in module %s!\n", name.c_str(), module->name.c_str()); + } + + log("Module %s already has such an object %s.\n", module->name.c_str(), name.c_str()); + } + else + { + wire = module->addWire(name, width); + wire->port_input = flag_input; + wire->port_output = flag_output; + + if (flag_input || flag_output) { + wire->port_id = module->wires_.size(); + module->fixup_ports(); + } + + log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str()); + } + + if (!flag_global) + return wire; + + for (auto &it : module->cells_) + { + if (design->modules_.count(it.second->type) == 0) + continue; + + RTLIL::Module *mod = design->modules_.at(it.second->type); + if (!design->selected_whole_module(mod->name)) + continue; + if (mod->get_bool_attribute("\\blackbox")) + continue; + if (it.second->hasPort(name)) + continue; + + it.second->setPort(name, wire); + log("Added connection %s to cell %s.%s (%s).\n", name.c_str(), module->name.c_str(), it.first.c_str(), it.second->type.c_str()); + } + + return wire; +} + + struct SetundefWorker { int next_bit_mode; @@ -178,31 +242,92 @@ struct SetundefPass : public Pass { if (!module->processes.empty()) log_error("The 'setundef' command can't operate in -undriven mode on modules with processes. Run 'proc' first.\n"); - SigMap sigmap(module); - SigPool undriven_signals; + if (expose_mode) { + SigMap sigmap(module); + dict<SigBit, bool> wire_drivers; + pool<SigBit> used_wires; + SigPool undriven_signals; + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) { + SigSpec sig = sigmap(conn.second); + if (cell->input(conn.first)) + for (auto bit : sig) + if (bit.wire) { + used_wires.insert(bit); + } + if (cell->output(conn.first)) + for (int i = 0; i < GetSize(sig); i++) { + if (sig[i].wire) + wire_drivers[sig[i]] = true; + } + } + + for (auto wire : module->wires()) { + if (wire->port_input) { + SigSpec sig = sigmap(wire); + for (int i = 0; i < GetSize(sig); i++) + wire_drivers[sig[i]] = true; + } + if (wire->port_output) + for (auto bit : sigmap(wire)) + if (bit.wire) used_wires.insert(bit); + } - for (auto &it : module->wires_) - undriven_signals.add(sigmap(it.second)); + pool<RTLIL::Wire*> undriven_wires; + for (auto bit : used_wires) { + if (!wire_drivers.count(bit)) { + undriven_wires.insert(bit.wire); + } + } - for (auto &it : module->wires_) - if (it.second->port_input) - undriven_signals.del(sigmap(it.second)); + for (auto &it : undriven_wires) + undriven_signals.add(sigmap(it)); - CellTypes ct(design); - for (auto &it : module->cells_) - for (auto &conn : it.second->connections()) - if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) - undriven_signals.del(sigmap(conn.second)); + for (auto &it : undriven_wires) + if (it->port_input) + undriven_signals.del(sigmap(it)); - RTLIL::SigSpec sig = undriven_signals.export_all(); - if (expose_mode) { + CellTypes ct(design); + for (auto &it : module->cells_) + for (auto &conn : it.second->connections()) + if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) + undriven_signals.del(sigmap(conn.second)); + + RTLIL::SigSpec sig = undriven_signals.export_all(); for (auto &c : sig.chunks()) { - c.wire->port_input = true; - log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(c.wire->name)); + RTLIL::Wire * wire; + if (c.wire->width == c.width) { + wire = c.wire; + wire->port_input = true; + } + else { + string name = c.wire->name.str() + "$[" + std::to_string(c.width + c.offset) + ":" + std::to_string(c.offset) + "]"; + wire = add_wire(design, module, name, c.width, true, false, false); + module->connect(RTLIL::SigSig(c.wire, wire)); + } + log("Exposing undriven wire %s as input.\n", wire->name.c_str()); } module->fixup_ports(); } else { + SigMap sigmap(module); + SigPool undriven_signals; + + for (auto &it : module->wires_) + undriven_signals.add(sigmap(it.second)); + + for (auto &it : module->wires_) + if (it.second->port_input) + undriven_signals.del(sigmap(it.second)); + + CellTypes ct(design); + for (auto &it : module->cells_) + for (auto &conn : it.second->connections()) + if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) + undriven_signals.del(sigmap(conn.second)); + + RTLIL::SigSpec sig = undriven_signals.export_all(); for (auto &c : sig.chunks()) { RTLIL::SigSpec bits; for (int i = 0; i < c.width; i++) |