yosys/passes/cmds/abstract.cc

215 lines
5.1 KiB
C++
Raw Normal View History

2025-01-30 10:26:23 -06:00
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool abstract_state(Module* mod, Cell* cell, Wire* enable, bool enable_pol) {
FfData ff(nullptr, cell);
2025-02-03 11:31:33 -06:00
if (ff.has_sr)
log_cmd_error("SR not supported\n");
2025-01-30 10:26:23 -06:00
2025-02-03 11:31:33 -06:00
// Normalize to simpler FF
ff.unmap_ce();
ff.unmap_srst();
if (ff.has_arst)
ff.arst_to_aload();
// Construct abstract value
auto anyseq = mod->Anyseq(NEW_ID, ff.width);
if (ff.has_aload) {
2025-02-03 11:35:46 -06:00
// ad := enable ? anyseq : ad
2025-02-03 11:31:33 -06:00
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;
}
(void)mod->addMux(NEW_ID,
mux_a,
mux_b,
enable,
abstracted_ad);
ff.sig_ad = abstracted_ad;
}
2025-02-03 11:35:46 -06:00
// d := enable ? anyseq : d
2025-02-03 11:31:33 -06:00
Wire* abstracted_d = mod->addWire(NEW_ID, ff.sig_d.size());
2025-01-30 10:26:23 -06:00
SigSpec mux_a, mux_b;
if (enable_pol) {
2025-02-03 11:31:33 -06:00
mux_a = ff.sig_d;
mux_b = anyseq;
2025-01-30 10:26:23 -06:00
} else {
2025-02-03 11:31:33 -06:00
mux_a = anyseq;
mux_b = ff.sig_d;
2025-01-30 10:26:23 -06:00
}
2025-01-30 10:52:55 -06:00
(void)mod->addMux(NEW_ID,
2025-02-03 11:31:33 -06:00
mux_a,
mux_b,
enable,
abstracted_d);
ff.sig_d = abstracted_d;
(void)ff.emit();
2025-01-30 10:26:23 -06:00
return true;
}
struct AbstractPortCtx {
2025-02-03 15:25:09 -06:00
Module* mod;
SigMap sigmap;
pool<std::pair<Cell*, IdString>> outs;
2025-02-03 15:25:09 -06:00
};
void collect_selected_ports(AbstractPortCtx& ctx) {
for (Cell* cell : ctx.mod->cells()) {
for (auto& conn : cell->connections()) {
// we bufnorm
log_assert(conn.second.is_wire() || conn.second.is_fully_const());
if (conn.second.is_wire() && cell->output(conn.first))
if (ctx.mod->selected(cell) || ctx.mod->selected(conn.second.as_wire()))
ctx.outs.insert(std::make_pair(cell, conn.first));
2025-02-03 15:25:09 -06:00
}
}
}
unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) {
AbstractPortCtx ctx {mod, SigMap(mod), {}};
collect_selected_ports(ctx);
unsigned int changed = 0;
for (auto [cell, port] : ctx.outs) {
SigSpec sig = cell->getPort(port);
log_assert(sig.is_wire());
Wire* original = mod->addWire(NEW_ID, sig.size());
cell->setPort(port, original);
auto anyseq = mod->Anyseq(NEW_ID, sig.size());
// This code differs from abstract_state
// in that we reuse the original signal as the mux output,
// not input
SigSpec mux_a, mux_b;
if (enable_pol) {
mux_a = original;
mux_b = anyseq;
} else {
mux_a = anyseq;
mux_b = original;
2025-02-03 15:25:09 -06:00
}
(void)mod->addMux(NEW_ID,
mux_a,
mux_b,
enable,
sig);
changed++;
2025-02-03 15:25:09 -06:00
}
return changed;
2025-02-03 11:31:33 -06:00
}
2025-02-03 15:25:09 -06:00
unsigned int abstract_init(Module* mod) {
AbstractPortCtx ctx {mod, SigMap(mod), {}};
collect_selected_ports(ctx);
2025-02-03 15:25:09 -06:00
unsigned int changed = 0;
for (auto [cell, port] : ctx.outs) {
SigSpec sig = cell->getPort(port);
log_assert(sig.is_wire());
if (!sig.as_wire()->has_attribute(ID::init))
2025-02-03 15:25:09 -06:00
continue;
Const init = sig.as_wire()->attributes.at(ID::init);
sig.as_wire()->attributes.erase(ID::init);
changed += sig.size();
2025-02-03 15:25:09 -06:00
}
return changed;
}
2025-02-03 11:31:33 -06:00
2025-01-30 10:26:23 -06:00
struct AbstractPass : public Pass {
AbstractPass() : Pass("abstract", "extract clock gating out of flip flops") { }
void help() override {
// TODO
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing ABSTRACT pass.\n");
size_t argidx;
enum Mode {
None,
State,
Initial,
Value,
};
Mode mode;
std::string enable_name;
bool enable_pol; // true is high
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-state") {
mode = State;
continue;
}
if (arg == "-init") {
mode = Initial;
continue;
}
if (arg == "-value") {
mode = Value;
continue;
}
if (arg == "-enable") {
enable_name = args[++argidx];
enable_pol = true;
continue;
}
if (arg == "-enablen") {
enable_name = args[++argidx];
enable_pol = false;
continue;
}
break;
}
extra_args(args, argidx, design);
design->bufNormalize(true);
2025-02-03 11:31:33 -06:00
unsigned int changed = 0;
2025-01-30 10:26:23 -06:00
if ((mode == State) || (mode == Value)) {
if (!enable_name.length())
log_cmd_error("Unspecified enable wire\n");
2025-02-03 11:31:33 -06:00
CellTypes ct;
if (mode == State)
ct.setup_internals_ff();
2025-01-30 10:26:23 -06:00
for (auto mod : design->selected_modules()) {
2025-02-03 11:31:33 -06:00
log_debug("module %s\n", mod->name.c_str());
2025-01-30 10:26:23 -06:00
Wire *enable_wire = mod->wire("\\" + enable_name);
2025-01-30 10:52:55 -06:00
if (!enable_wire)
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
2025-01-30 10:26:23 -06:00
if (mode == State) {
2025-02-03 11:31:33 -06:00
for (auto cell : mod->selected_cells())
if (ct.cell_types.count(cell->type))
changed += abstract_state(mod, cell, enable_wire, enable_pol);
2025-01-30 10:26:23 -06:00
} else {
changed += abstract_value(mod, enable_wire, enable_pol);
2025-01-30 10:26:23 -06:00
}
}
if (mode == State)
log("Abstracted %d cells.\n", changed);
else
log("Abstracted %d values.\n", changed);
2025-01-30 10:26:23 -06:00
} else if (mode == Initial) {
2025-02-03 11:31:33 -06:00
for (auto mod : design->selected_modules()) {
2025-02-03 15:25:09 -06:00
changed += abstract_init(mod);
2025-02-03 11:31:33 -06:00
}
2025-02-03 15:25:09 -06:00
log("Abstracted %d bits.\n", changed);
2025-01-30 10:26:23 -06:00
} else {
log_cmd_error("No mode selected, see help message\n");
}
design->bufNormalize(false);
2025-01-30 10:26:23 -06:00
}
} AbstractPass;
PRIVATE_NAMESPACE_END