diff options
Diffstat (limited to 'passes/cmds')
-rw-r--r-- | passes/cmds/setundef.cc | 196 |
1 files changed, 168 insertions, 28 deletions
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 0c51c3f06..eac1f6236 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -33,6 +33,69 @@ 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; @@ -90,6 +153,9 @@ struct SetundefPass : public Pass { log(" -undriven\n"); log(" also set undriven nets to constant values\n"); log("\n"); + log(" -expose\n"); + log(" also expose undriven nets as inputs (use with -undriven)\n"); + log("\n"); log(" -zero\n"); log(" replace with bits cleared (0)\n"); log("\n"); @@ -117,6 +183,7 @@ struct SetundefPass : public Pass { { bool got_value = false; bool undriven_mode = false; + bool expose_mode = false; bool init_mode = false; SetundefWorker worker; @@ -129,6 +196,11 @@ struct SetundefPass : public Pass { undriven_mode = true; continue; } + if (args[argidx] == "-expose") { + got_value = true; + expose_mode = true; + continue; + } if (args[argidx] == "-zero") { got_value = true; worker.next_bit_mode = MODE_ZERO; @@ -175,6 +247,8 @@ struct SetundefPass : public Pass { } extra_args(args, argidx, design); + if (expose_mode && !undriven_mode) + log_cmd_error("Option -expose must be used with option -undriven.\n"); if (!got_value) log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n"); @@ -188,34 +262,100 @@ 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; - - 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; - if (worker.next_bit_mode == MODE_ANYSEQ) - bits = module->Anyseq(NEW_ID, c.width); - else if (worker.next_bit_mode == MODE_ANYCONST) - bits = module->Anyconst(NEW_ID, c.width); - else - for (int i = 0; i < c.width; i++) - bits.append(worker.next_bit()); - module->connect(RTLIL::SigSig(c, bits)); - } + 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); + } + + pool<RTLIL::Wire*> undriven_wires; + for (auto bit : used_wires) { + if (!wire_drivers.count(bit)) { + undriven_wires.insert(bit.wire); + } + } + + for (auto &it : undriven_wires) + undriven_signals.add(sigmap(it)); + + for (auto &it : undriven_wires) + if (it->port_input) + undriven_signals.del(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)); + + RTLIL::SigSpec sig = undriven_signals.export_all(); + for (auto &c : sig.chunks()) { + 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)); + } + log("Exposing undriven wire %s as input.\n", wire->name.c_str()); + } + module->fixup_ports(); + continue; + } + 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++) + bits.append(worker.next_bit()); + module->connect(RTLIL::SigSig(c, bits)); + } + } } if (init_mode) |