3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-05-25 19:36:21 +00:00

Remove eqbits flag.

This commit is contained in:
nella 2026-05-25 14:16:55 +02:00
parent 386e63ae20
commit 68df0be7d2
2 changed files with 64 additions and 54 deletions

View file

@ -42,7 +42,6 @@ struct OptDffOptions
bool simple_dffe;
bool sat;
bool keepdc;
bool eqbits;
};
struct OptDffWorker
@ -977,15 +976,9 @@ struct OptDffWorker
return v == State::S1 ? qcsat.ez->CONST_TRUE : qcsat.ez->CONST_FALSE;
}
bool run_eqbits()
std::vector<std::vector<int>> gather_initial_eq_classes(std::vector<EqBit> &bits, dict<Cell *, FfData> &ff_for_cell)
{
if(!opt.eqbits) {
return false;
}
std::vector<EqBit> bits;
std::vector<SigKey> keys;
dict<Cell*, FfData> ff_for_cell;
// Collect FF bits eligible for merging
for (auto cell : module->selected_cells()) {
@ -1050,27 +1043,26 @@ struct OptDffWorker
}
}
if (GetSize(bits) < 2)
return false;
// Group bits by control signature
dict<SigKey, std::vector<int>> buckets;
for (int i = 0; i < GetSize(bits); i++)
buckets[keys[i]].push_back(i);
std::vector<std::vector<int>> classes;
classes.reserve(GetSize(buckets));
for (auto &kv : buckets)
if (GetSize(kv.second) >= 2)
classes.push_back(std::move(kv.second));
if (classes.empty())
return false;
return classes;
}
ModWalker modwalker(module->design, module);
std::vector<std::vector<int>> filter_classes_sim(
const std::vector<std::vector<int>> &classes,
const std::vector<EqBit> &bits,
const dict<Cell *, FfData> &ff_for_cell,
ModWalker &modwalker
) {
BitSim sim(module, sigmap, modwalker);
// Simulation prepass
// Assume same class
for (auto &cls : classes) {
uint64_t class_q_val = sim.xorshift64();
@ -1080,15 +1072,13 @@ struct OptDffWorker
}
std::vector<std::vector<int>> refined_classes;
for (auto &cls : classes) {
dict<uint64_t, std::vector<int>> sim_buckets;
for (int idx : cls) {
const EqBit &eb = bits[idx];
const FfData &ff = ff_for_cell.at(eb.cell);
uint64_t n_val = sim.eval_bit(ff.sig_d[eb.idx]);
if (ff.has_aload) {
uint64_t al = sim.eval_bit(ff.sig_aload);
if (!ff.pol_aload) al = ~al;
@ -1118,17 +1108,20 @@ struct OptDffWorker
sim_buckets[n_val].push_back(idx);
}
for (auto &kv : sim_buckets) {
if (GetSize(kv.second) >= 2) {
for (auto &kv : sim_buckets)
if (GetSize(kv.second) >= 2)
refined_classes.push_back(std::move(kv.second));
}
}
}
classes = std::move(refined_classes);
if (classes.empty())
return false;
return refined_classes;
}
std::vector<std::vector<int>> filter_classes_sat(
std::vector<std::vector<int>> classes,
const std::vector<EqBit> &bits,
const dict<Cell *, FfData> &ff_for_cell,
ModWalker &modwalker
) {
QuickConeSat qcsat(modwalker);
std::vector<int> q_lit(bits.size(), -1);
std::vector<int> n_lit(bits.size(), -1);
@ -1144,8 +1137,7 @@ struct OptDffWorker
if (ff.has_aload) {
int al = qcsat.importSigBit(ff.sig_aload);
if (!ff.pol_aload) al = qcsat.ez->NOT(al);
int ad = qcsat.importSigBit(ff.sig_ad[eb.idx]);
n = sat_mux(qcsat, al, ad, n);
n = sat_mux(qcsat, al, qcsat.importSigBit(ff.sig_ad[eb.idx]), n);
}
if (ff.has_arst) {
int ar = qcsat.importSigBit(ff.sig_arst);
@ -1170,13 +1162,11 @@ struct OptDffWorker
}
qcsat.prepare();
bool any_change = false;
std::vector<int> worklist;
std::vector<bool> in_worklist(GetSize(classes), true);
for (int i = 0; i < GetSize(classes); i++) {
for (int i = 0; i < GetSize(classes); i++)
worklist.push_back(i);
}
while (!worklist.empty()) {
int cls_idx = worklist.back();
@ -1190,9 +1180,8 @@ struct OptDffWorker
for (auto &c : classes) {
if (GetSize(c) < 2) continue;
int rep = c[0];
for (int k = 1; k < GetSize(c); k++) {
for (int k = 1; k < GetSize(c); k++)
assumptions.push_back(qcsat.ez->IFF(q_lit[rep], q_lit[c[k]]));
}
}
// Split at counterexamples
@ -1204,14 +1193,12 @@ struct OptDffWorker
int query = qcsat.ez->NOT(qcsat.ez->IFF(n_lit[rep], n_lit[cls[i]]));
std::vector<int> modelExprs;
for (int b : cls) {
for (int b : cls)
modelExprs.push_back(n_lit[b]);
}
std::vector<bool> modelVals;
assumptions.push_back(query);
if (qcsat.ez->solve(modelExprs, modelVals, assumptions)) {
// SAT -> partition entire class
std::vector<int> sub0;
@ -1243,9 +1230,12 @@ struct OptDffWorker
}
}
if (classes.empty())
return any_change;
return classes;
}
bool apply_eq_merges(const std::vector<std::vector<int>> &classes, const std::vector<EqBit> &bits, dict<Cell *, FfData> &ff_for_cell)
{
bool any_change = false;
dict<Cell *, std::set<int>> remove_bits;
// Drive every non-rep Q from its class rep, drop merged bits from their FFs
@ -1283,6 +1273,33 @@ struct OptDffWorker
return any_change;
}
bool run_eqbits()
{
if (!opt.sat)
return false;
std::vector<EqBit> bits;
dict<Cell *, FfData> ff_for_cell;
std::vector<std::vector<int>> classes = gather_initial_eq_classes(bits, ff_for_cell);
if (classes.empty())
return false;
ModWalker modwalker(module->design, module);
// Simulation prepass
classes = filter_classes_sim(classes, bits, ff_for_cell, modwalker);
if (classes.empty())
return false;
// SAT prove
classes = filter_classes_sat(std::move(classes), bits, ff_for_cell, modwalker);
if (classes.empty())
return false;
return apply_eq_merges(classes, bits, ff_for_cell);
}
};
struct OptDffPass : public Pass {
@ -1320,11 +1337,6 @@ struct OptDffPass : public Pass {
log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
log(" -eqbits\n");
log(" finds groups of flip flop bits provably holding always-equal values\n");
log(" across cycles and collapses each group to a single bit, potentially\n");
log(" reducing the number of required flip flops.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@ -1337,7 +1349,6 @@ struct OptDffPass : public Pass {
opt.simple_dffe = false;
opt.keepdc = false;
opt.sat = false;
opt.eqbits = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@ -1346,7 +1357,6 @@ struct OptDffPass : public Pass {
if (args[argidx] == "-simple-dffe") { opt.simple_dffe = true; continue; }
if (args[argidx] == "-keepdc") { opt.keepdc = true; continue; }
if (args[argidx] == "-sat") { opt.sat = true; continue; }
if (args[argidx] == "-eqbits") { opt.eqbits = true; continue; }
break;
}
extra_args(args, argidx, design);

View file

@ -3,9 +3,9 @@ design -reset
read_verilog -sv opt_dff_eqbits_small.sv
hierarchy -top test_case
techmap
opt_dff -sat -eqbits
opt_dff -sat
synth
opt_dff -sat -eqbits
opt_dff -sat
opt_clean -purge
select -assert-count 2 t:$_SDFF_PN0_
@ -17,7 +17,7 @@ hierarchy -top test_case
prep
design -save gold
opt_dff -sat -eqbits
opt_dff -sat
design -save gate
design -copy-from gold -as gold test_case
@ -32,9 +32,9 @@ design -reset
read_verilog -sv opt_dff_eqbits_large.sv
hierarchy -top test_case
techmap
opt_dff -sat -eqbits
opt_dff -sat
synth
opt_dff -sat -eqbits
opt_dff -sat
opt_clean -purge
select -assert-count 6 t:$_SDFFE_PN0P_
@ -46,7 +46,7 @@ hierarchy -top test_case
prep
design -save gold
opt_dff -sat -eqbits
opt_dff -sat
design -save gate
design -copy-from gold -as gold test_case