diff --git a/kernel/bitsim.h b/kernel/bitsim.h new file mode 100644 index 000000000..a0915e28b --- /dev/null +++ b/kernel/bitsim.h @@ -0,0 +1,79 @@ +#ifndef BITSIM_H +#define BITSIM_H + +#include "kernel/modtools.h" + +YOSYS_NAMESPACE_BEGIN + +struct BitSim { + Module *module; + SigMap &sigmap; + ModWalker &modwalker; + dict sim_vals; + uint64_t rng_state; + + BitSim(Module *m, SigMap &sm, ModWalker &mw) + : module(m), sigmap(sm), modwalker(mw), rng_state(1337) {} + + uint64_t xorshift64() { + rng_state ^= rng_state << 13; + rng_state ^= rng_state >> 7; + rng_state ^= rng_state << 17; + return rng_state; + } + + uint64_t eval_bit(SigBit b) { + SigBit mapped = sigmap(b); + if (mapped == State::S0) return 0ULL; + if (mapped == State::S1) return ~0ULL; + if (mapped == State::Sx || mapped == State::Sz) return 0ULL; + + auto it = sim_vals.find(mapped); + if (it != sim_vals.end()) return it->second; + sim_vals[mapped] = 0; + uint64_t res = 0; + + if (!modwalker.has_drivers(mapped)) { + res = xorshift64(); + } else { + auto &drivers = modwalker.signal_drivers[mapped]; + if (drivers.empty()) { + res = xorshift64(); + } else { + auto driver = *drivers.begin(); + Cell *cell = driver.cell; + + if (cell->is_builtin_ff()) { + res = xorshift64(); + } else if (cell->type == ID($_AND_)) { + res = eval_bit(cell->getPort(ID::A)[0]) & eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_OR_)) { + res = eval_bit(cell->getPort(ID::A)[0]) | eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_XOR_)) { + res = eval_bit(cell->getPort(ID::A)[0]) ^ eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_NOT_)) { + res = ~eval_bit(cell->getPort(ID::A)[0]); + } else if (cell->type == ID($_MUX_)) { + uint64_t s = eval_bit(cell->getPort(ID::S)[0]); + uint64_t a = eval_bit(cell->getPort(ID::A)[0]); + uint64_t b = eval_bit(cell->getPort(ID::B)[0]); + res = (a & ~s) | (b & s); + } else if (cell->type == ID($mux)) { + uint64_t s = eval_bit(cell->getPort(ID::S)[0]); + uint64_t a = eval_bit(cell->getPort(ID::A)[driver.offset]); + uint64_t b = eval_bit(cell->getPort(ID::B)[driver.offset]); + res = (a & ~s) | (b & s); + } else { + res = xorshift64(); + } + } + } + + sim_vals[mapped] = res; + return res; + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index e657a8a2d..dbe0e521a 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -26,6 +26,7 @@ #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" +#include "kernel/bitsim.h" #include "kernel/pattern.h" #include "passes/techmap/simplemap.h" #include @@ -1067,6 +1068,67 @@ struct OptDffWorker return false; ModWalker modwalker(module->design, module); + BitSim sim(module, sigmap, modwalker); + + // Simulation prepass + // Assume same class + for (auto &cls : classes) { + uint64_t class_q_val = sim.xorshift64(); + for (int idx : cls) { + sim.sim_vals[sigmap(bits[idx].q)] = class_q_val; + } + } + + std::vector> refined_classes; + + for (auto &cls : classes) { + dict> 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; + uint64_t ad = sim.eval_bit(ff.sig_ad[eb.idx]); + n_val = (n_val & ~al) | (ad & al); + } + if (ff.has_arst) { + uint64_t ar = sim.eval_bit(ff.sig_arst); + if (!ff.pol_arst) ar = ~ar; + uint64_t ar_val = (ff.val_arst[eb.idx] == State::S1) ? ~0ULL : 0ULL; + n_val = (n_val & ~ar) | (ar_val & ar); + } + if (ff.has_sr) { + uint64_t clr = sim.eval_bit(ff.sig_clr[eb.idx]); + if (!ff.pol_clr) clr = ~clr; + uint64_t set = sim.eval_bit(ff.sig_set[eb.idx]); + if (!ff.pol_set) set = ~set; + n_val = ~clr & (set | n_val); + } + if (ff.has_srst) { + uint64_t srst = sim.eval_bit(ff.sig_srst); + if (!ff.pol_srst) srst = ~srst; + uint64_t srst_val = (ff.val_srst[eb.idx] == State::S1) ? ~0ULL : 0ULL; + n_val = (n_val & ~srst) | (srst_val & srst); + } + + sim_buckets[n_val].push_back(idx); + } + + 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; + QuickConeSat qcsat(modwalker); std::vector q_lit(bits.size(), -1); std::vector n_lit(bits.size(), -1); @@ -1136,7 +1198,7 @@ struct OptDffWorker // Split at counterexamples int rep = cls[0]; for (int i = 1; i < GetSize(cls); i++) { - // Trivially eqivalent + // Trivially equivalent if (n_lit[rep] == n_lit[cls[i]]) continue;