diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 620b38813..9eac23c94 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -267,8 +267,8 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool ®s, SigPoo return regs.check(s2); if (direct_wires.count(w1) != direct_wires.count(w2)) return direct_wires.count(w2) != 0; - if (conns.check_any(s1) != conns.check_any(s2)) - return conns.check_any(s2); + if (conns.check(s1) != conns.check(s2)) + return conns.check(s2); } if (w1->port_output != w2->port_output) @@ -298,26 +298,60 @@ bool check_public_name(RTLIL::IdString id) return true; } -bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool x_mode, bool verbose) { // `register_signals` and `connected_signals` will help us decide later on // on picking representatives out of groups of connected signals SigPool register_signals; SigPool connected_signals; + std::vector maybe_driven_signals; if (!purge_mode) for (auto &it : module->cells_) { RTLIL::Cell *cell = it.second; if (ct_reg.cell_known(cell->type)) { bool clk2fflogic = cell->get_bool_attribute(ID(clk2fflogic)); for (auto &it2 : cell->connections()) - if (clk2fflogic ? it2.first == ID::D : ct_reg.cell_output(cell->type, it2.first)) - register_signals.add(it2.second); + if (clk2fflogic ? it2.first == ID::D : ct_reg.cell_output(cell->type, it2.first)) + register_signals.add(it2.second); } for (auto &it2 : cell->connections()) - connected_signals.add(it2.second); + connected_signals.add(it2.second); } SigMap assign_map(module); + if (x_mode) { + for (auto [_, cell] : module->cells_) + for (auto [port, sig] : cell->connections()) + if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, port)) { + log_debug("cell %s drives sig %s\n", log_id(cell), log_signal(sig)); + maybe_driven_signals.push_back(sig); + } + + SigPool maybe_driven_signals_bits; + + for (auto sig : maybe_driven_signals) { + for (auto bit : sig) { + maybe_driven_signals_bits.add(assign_map(bit)); + log_debug("bit %s (rep %s) is driven by cell output\n", log_signal(sig), log_signal(assign_map(sig))); + } + } + for (auto &it : module->wires_) { + RTLIL::SigSpec sig = it.second; + if (it.second->port_id != 0) { + maybe_driven_signals_bits.add(assign_map(sig)); + log_debug("bit %s (rep %s) is driven by port input\n", log_signal(sig), log_signal(assign_map(sig))); + } + } + for (auto &it : module->wires_) { + RTLIL::SigSpec sig = it.second; + for (auto bit : sig) { + if (!maybe_driven_signals_bits.check(assign_map(bit))) { + log_debug("add conn %s <-> %s to assign_map\n", log_signal(bit), log_signal(SigBit(State::Sx))); + assign_map.add(bit, SigBit(State::Sx)); + } + } + } + } // construct a pool of wires which are directly driven by a known celltype, // this will influence our choice of representatives @@ -594,7 +628,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool verbose) return did_something; } -void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rminit) +void rmunused_module(RTLIL::Module *module, bool purge_mode, bool x_mode, bool verbose, bool rminit) { if (verbose) log("Finding unused cells or wires in module %s..\n", module->name.c_str()); @@ -619,10 +653,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool module->design->scratchpad_set_bool("opt.did_something", true); rmunused_module_cells(module, verbose); - while (rmunused_module_signals(module, purge_mode, verbose)) { } + while (rmunused_module_signals(module, purge_mode, x_mode, verbose)) { } if (rminit && rmunused_module_init(module, verbose)) - while (rmunused_module_signals(module, purge_mode, verbose)) { } + while (rmunused_module_signals(module, purge_mode, x_mode, verbose)) { } } struct OptCleanPass : public Pass { @@ -643,10 +677,14 @@ struct OptCleanPass : public Pass { log(" -purge\n"); log(" also remove internal nets if they have a public name\n"); log("\n"); + log(" -x\n"); + log(" handle unconnected bits as x-bit driven\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool purge_mode = false; + bool x_mode = false; log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n"); log_push(); @@ -657,6 +695,10 @@ struct OptCleanPass : public Pass { purge_mode = true; continue; } + if (args[argidx] == "-x") { + x_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -675,7 +717,7 @@ struct OptCleanPass : public Pass { for (auto module : design->selected_whole_modules_warn()) { if (module->has_processes_warn()) continue; - rmunused_module(module, purge_mode, true, true); + rmunused_module(module, purge_mode, x_mode, true, true); } if (count_rm_cells > 0 || count_rm_wires > 0) @@ -712,6 +754,7 @@ struct CleanPass : public Pass { void execute(std::vector args, RTLIL::Design *design) override { bool purge_mode = false; + bool x_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -719,6 +762,10 @@ struct CleanPass : public Pass { purge_mode = true; continue; } + if (args[argidx] == "-x") { + x_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -737,7 +784,7 @@ struct CleanPass : public Pass { for (auto module : design->selected_unboxed_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, ys_debug(), true); + rmunused_module(module, purge_mode, x_mode, ys_debug(), true); } log_suppressed();