Skip to content

opt_clean: handle undriven and x-bit driven bits consistently #5004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 58 additions & 11 deletions passes/opt/opt_clean.cc
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, 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)
Expand Down Expand Up @@ -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<SigSpec> 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
Expand Down Expand Up @@ -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());
Expand All @@ -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 {
Expand All @@ -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<std::string> 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();
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -712,13 +754,18 @@ struct CleanPass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool purge_mode = false;
bool x_mode = false;

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-purge") {
purge_mode = true;
continue;
}
if (args[argidx] == "-x") {
x_mode = true;
continue;
}
break;
}
extra_args(args, argidx, design);
Expand All @@ -737,7 +784,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_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();
Expand Down
Loading