diff --git a/passes/cmds/abstract.cc b/passes/cmds/abstract.cc index 27213a394..706636d59 100644 --- a/passes/cmds/abstract.cc +++ b/passes/cmds/abstract.cc @@ -5,58 +5,96 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool abstract_state(Module* mod, Cell* cell, Wire* enable, bool enable_pol) { - FfData ff(nullptr, cell); - if (ff.has_sr) - log_cmd_error("SR not supported\n"); - - // Normalize to simpler FF - ff.unmap_ce(); - ff.unmap_srst(); - if (ff.has_arst) - ff.arst_to_aload(); +struct EnableLogic { + Wire* wire; + bool pol; +}; +bool abstract_state_port(FfData& ff, SigSpec& port_sig, std::set offsets, EnableLogic enable) { // Construct abstract value - auto anyseq = mod->Anyseq(NEW_ID, ff.width); - - if (ff.has_aload) { - // ad := enable ? anyseq : ad - Wire* abstracted_ad = mod->addWire(NEW_ID, ff.sig_ad.size()); - SigSpec mux_a, mux_b; - if (enable_pol) { - mux_a = ff.sig_ad; - mux_b = anyseq; - } else { - mux_a = anyseq; - mux_b = ff.sig_ad; + auto anyseq = ff.module->Anyseq(NEW_ID, offsets.size()); + Wire* abstracted = ff.module->addWire(NEW_ID, offsets.size()); + SigSpec mux_input; + int abstracted_idx = 0; + for (int d_idx = 0; d_idx < ff.width; d_idx++) { + if (offsets.count(d_idx)) { + log_debug("bit %d: abstracted\n", d_idx); + mux_input.append(port_sig[d_idx]); + port_sig[d_idx].wire = abstracted; + port_sig[d_idx].offset = abstracted_idx; + log_assert(abstracted_idx < abstracted->width); + abstracted_idx++; } - (void)mod->addMux(NEW_ID, - mux_a, - mux_b, - enable, - abstracted_ad); - ff.sig_ad = abstracted_ad; } - // d := enable ? anyseq : d - Wire* abstracted_d = mod->addWire(NEW_ID, ff.sig_d.size()); SigSpec mux_a, mux_b; - if (enable_pol) { - mux_a = ff.sig_d; + if (enable.pol) { + mux_a = mux_input; mux_b = anyseq; } else { mux_a = anyseq; - mux_b = ff.sig_d; + mux_b = mux_input; } - (void)mod->addMux(NEW_ID, + (void)ff.module->addMux(NEW_ID, mux_a, mux_b, - enable, - abstracted_d); - ff.sig_d = abstracted_d; + enable.wire, + abstracted); (void)ff.emit(); return true; } +unsigned int abstract_state(Module* mod, EnableLogic enable) { + CellTypes ct; + ct.setup_internals_ff(); + SigMap sigmap(mod); + pool selected_representatives; + + // Collect reps for all wire bits of selected wires + for (auto wire : mod->selected_wires()) + for (auto bit : sigmap(wire)) + selected_representatives.insert(bit); + + // Collect reps for all output wire bits of selected cells + for (auto cell : mod->selected_cells()) + for (auto conn : cell->connections()) + if (cell->output(conn.first)) + for (auto bit : conn.second.bits()) + selected_representatives.insert(sigmap(bit)); + + unsigned int changed = 0; + std::vector ffs; + // Abstract flop inputs if they're driving a selected output rep + for (auto cell : mod->cells()) { + if (!ct.cell_types.count(cell->type)) + continue; + FfData ff(nullptr, cell); + if (ff.has_sr) + log_cmd_error("SR not supported\n"); + ffs.push_back(ff); + } + for (auto ff : ffs) { + // A bit inefficient + std::set offsets_to_abstract; + for (auto bit : ff.sig_q) + if (selected_representatives.count(sigmap(bit))) + offsets_to_abstract.insert(bit.offset); + + if (offsets_to_abstract.empty()) + continue; + + // Normalize to simpler FF + ff.unmap_ce(); + ff.unmap_srst(); + if (ff.has_arst) + ff.arst_to_aload(); + + if (ff.has_aload) + changed += abstract_state_port(ff, ff.sig_ad, offsets_to_abstract, enable); + changed += abstract_state_port(ff, ff.sig_d, offsets_to_abstract, enable); + } + return changed; +} + struct AbstractPortCtx { Module* mod; SigMap sigmap; @@ -75,7 +113,7 @@ void collect_selected_ports(AbstractPortCtx& ctx) { } } -unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) { +unsigned int abstract_value(Module* mod, EnableLogic enable) { AbstractPortCtx ctx {mod, SigMap(mod), {}}; collect_selected_ports(ctx); unsigned int changed = 0; @@ -89,7 +127,7 @@ unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) { // in that we reuse the original signal as the mux output, // not input SigSpec mux_a, mux_b; - if (enable_pol) { + if (enable.pol) { mux_a = original; mux_b = anyseq; } else { @@ -99,7 +137,7 @@ unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) { (void)mod->addMux(NEW_ID, mux_a, mux_b, - enable, + enable.wire, sig); changed++; } @@ -174,25 +212,24 @@ struct AbstractPass : public Pass { } extra_args(args, argidx, design); - design->bufNormalize(true); + if (mode != State) + design->bufNormalize(true); + unsigned int changed = 0; if ((mode == State) || (mode == Value)) { if (!enable_name.length()) log_cmd_error("Unspecified enable wire\n"); - CellTypes ct; - if (mode == State) - ct.setup_internals_ff(); for (auto mod : design->selected_modules()) { log_debug("module %s\n", mod->name.c_str()); Wire *enable_wire = mod->wire("\\" + enable_name); if (!enable_wire) log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str()); if (mode == State) { - for (auto cell : mod->selected_cells()) - if (ct.cell_types.count(cell->type)) - changed += abstract_state(mod, cell, enable_wire, enable_pol); + // for (auto cell : mod->selected_cells()) + // if (ct.cell_types.count(cell->type)) + changed += abstract_state(mod, {enable_wire, enable_pol}); } else { - changed += abstract_value(mod, enable_wire, enable_pol); + changed += abstract_value(mod, {enable_wire, enable_pol}); } } if (mode == State) @@ -207,7 +244,8 @@ struct AbstractPass : public Pass { } else { log_cmd_error("No mode selected, see help message\n"); } - design->bufNormalize(false); + if (mode != State) + design->bufNormalize(false); } } AbstractPass; diff --git a/tests/various/abstract.ys b/tests/various/abstract.ys index b122c7dc6..0892ca1c4 100644 --- a/tests/various/abstract.ys +++ b/tests/various/abstract.ys @@ -15,6 +15,27 @@ abstract -state -enablen magic check -assert # show -prefix after_base +design -reset +read_verilog <