mirror of
https://github.com/YosysHQ/yosys
synced 2026-05-25 19:36:21 +00:00
Add prepass for bit simulation.
This commit is contained in:
parent
04a1611346
commit
386e63ae20
2 changed files with 142 additions and 1 deletions
79
kernel/bitsim.h
Normal file
79
kernel/bitsim.h
Normal file
|
|
@ -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<SigBit, uint64_t> 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
|
||||
|
|
@ -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 <stdio.h>
|
||||
|
|
@ -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<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;
|
||||
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<int> q_lit(bits.size(), -1);
|
||||
std::vector<int> 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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue