aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMarcelina Kościelnicka <mwk@0x04.net>2021-10-01 23:50:48 +0200
committerMarcelina Kościelnicka <mwk@0x04.net>2021-10-02 20:19:48 +0200
commit63b9df8693840d17def8abcb0e848112283b0231 (patch)
tree7cb46fa0119760ef17d9d8d3999090cb71342d40 /kernel
parentec2b5548fe9b8d291365a84a0c3fc87654643359 (diff)
downloadyosys-63b9df8693840d17def8abcb0e848112283b0231.tar.gz
yosys-63b9df8693840d17def8abcb0e848112283b0231.tar.bz2
yosys-63b9df8693840d17def8abcb0e848112283b0231.zip
kernel/ff: Refactor FfData to enable FFs with async load.
- *_en is split into *_ce (clock enable) and *_aload (async load aka latch gate enable), so both can be present at once - has_d is removed - has_gclk is added (to have a clear marker for $ff) - d_is_const and val_d leftovers are removed - async2sync, clk2fflogic, opt_dff are updated to operate correctly on FFs with async load
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ff.h325
-rw-r--r--kernel/ffmerge.cc67
-rw-r--r--kernel/mem.cc15
-rw-r--r--kernel/satgen.cc20
4 files changed, 275 insertions, 152 deletions
diff --git a/kernel/ff.h b/kernel/ff.h
index e555e15f1..a06eb0a1c 100644
--- a/kernel/ff.h
+++ b/kernel/ff.h
@@ -25,55 +25,141 @@
YOSYS_NAMESPACE_BEGIN
+// Describes a flip-flop or a latch.
+//
+// If has_gclk, this is a formal verification FF with implicit global clock:
+// Q is simply previous cycle's D.
+//
+// Otherwise, the FF/latch can have any number of features selected by has_*
+// attributes that determine Q's value (in order of decreasing priority):
+//
+// - on start, register is initialized to val_init
+// - if has_sr is present:
+// - sig_clr is per-bit async clear, and sets the corresponding bit to 0
+// if active
+// - sig_set is per-bit async set, and sets the corresponding bit to 1
+// if active
+// - if has_arst is present:
+// - sig_arst is whole-reg async reset, and sets the whole register to val_arst
+// - if has_aload is present:
+// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole
+// register to sig_ad
+// - if has_clk is present, and we're currently on a clock edge:
+// - if has_ce is present and ce_over_srst is true:
+// - ignore clock edge (don't change value) unless sig_ce is active
+// - if has_srst is present:
+// - sig_srst is whole-reg sync reset and sets the register to val_srst
+// - if has_ce is present and ce_over_srst is false:
+// - ignore clock edge (don't change value) unless sig_ce is active
+// - set whole reg to sig_d
+// - if nothing of the above applies, the reg value remains unchanged
+//
+// Since the yosys FF cell library isn't fully generic, not all combinations
+// of the features above can be supported:
+//
+// - only one of has_srst, has_arst, has_sr can be used
+// - if has_clk is used together with has_aload, then has_srst, has_arst,
+// has_sr cannot be used
+//
+// The valid feature combinations are thus:
+//
+// - has_clk + optional has_ce [dff/dffe]
+// - has_clk + optional has_ce + has_arst [adff/adffe]
+// - has_clk + optional has_ce + has_aload [aldff/aldffe]
+// - has_clk + optional has_ce + has_sr [dffsr/dffsre]
+// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce]
+// - has_aload [dlatch]
+// - has_aload + has_arst [adlatch]
+// - has_aload + has_sr [dlatchsr]
+// - has_sr [sr]
+// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
+// - empty set [not a cell — will be emitted as a simple direct connection]
+
struct FfData {
FfInitVals *initvals;
+ // The FF output.
SigSpec sig_q;
+ // The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
+ // The async data input, present if has_aload.
+ SigSpec sig_ad;
+ // The sync clock, present if has_clk.
SigSpec sig_clk;
- SigSpec sig_en;
+ // The clock enable, present if has_ce.
+ SigSpec sig_ce;
+ // The async load enable, present if has_aload.
+ SigSpec sig_aload;
+ // The async reset, preset if has_arst.
SigSpec sig_arst;
+ // The sync reset, preset if has_srst.
SigSpec sig_srst;
+ // The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
+ // The async set (per-lane), present if has_sr.
SigSpec sig_set;
- bool has_d;
+ // True if this is a clocked (edge-sensitive) flip-flop.
bool has_clk;
- bool has_en;
+ // True if this is a $ff, exclusive with every other has_*.
+ bool has_gclk;
+ // True if this FF has a clock enable. Depends on has_clk.
+ bool has_ce;
+ // True if this FF has async load function — this includes D latches.
+ // If this and has_clk are both set, has_arst and has_sr cannot be set.
+ bool has_aload;
+ // True if this FF has sync set/reset. Depends on has_clk, exclusive
+ // with has_arst, has_sr, has_aload.
bool has_srst;
+ // True if this FF has async set/reset. Exclusive with has_srst,
+ // has_sr. If this and has_clk are both set, has_aload cannot be set.
bool has_arst;
+ // True if this FF has per-bit async set + clear. Exclusive with
+ // has_srst, has_arst. If this and has_clk are both set, has_aload
+ // cannot be set.
bool has_sr;
+ // If has_ce and has_srst are both set, determines their relative
+ // priorities: if true, inactive ce disables srst; if false, srst
+ // operates independent of ce.
bool ce_over_srst;
+ // True if this FF is a fine cell, false if it is a coarse cell.
+ // If true, width must be 1.
bool is_fine;
+ // Polarities, corresponding to sig_*. True means active-high, false
+ // means active-low.
bool pol_clk;
- bool pol_en;
+ bool pol_ce;
+ bool pol_aload;
bool pol_arst;
bool pol_srst;
bool pol_clr;
bool pol_set;
+ // The value loaded by sig_arst.
Const val_arst;
+ // The value loaded by sig_srst.
Const val_srst;
+ // The initial value at power-up.
Const val_init;
- Const val_d;
- bool d_is_const;
+ // The FF data width in bits.
int width;
dict<IdString, Const> attributes;
FfData(FfInitVals *initvals = nullptr, Cell *cell = nullptr) : initvals(initvals) {
width = 0;
- has_d = true;
has_clk = false;
- has_en = false;
+ has_gclk = false;
+ has_ce = false;
+ has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
pol_clk = false;
- pol_en = false;
+ pol_aload = false;
+ pol_ce = false;
pol_arst = false;
pol_srst = false;
pol_clr = false;
pol_set = false;
- d_is_const = false;
if (!cell)
return;
@@ -88,20 +174,26 @@ struct FfData {
std::string type_str = cell->type.str();
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
- if (cell->type == ID($sr)) {
- has_d = false;
- } else {
+ if (cell->type == ID($ff)) {
+ has_gclk = true;
sig_d = cell->getPort(ID::D);
- }
- if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+ } else if (cell->type == ID($sr)) {
+ // No data input at all.
+ } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
+ has_aload = true;
+ sig_aload = cell->getPort(ID::EN);
+ pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
+ sig_ad = cell->getPort(ID::D);
+ } else {
has_clk = true;
sig_clk = cell->getPort(ID::CLK);
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
+ sig_d = cell->getPort(ID::D);
}
- if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
- has_en = true;
- sig_en = cell->getPort(ID::EN);
- pol_en = cell->getParam(ID::EN_POLARITY).as_bool();
+ if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce))) {
+ has_ce = true;
+ sig_ce = cell->getPort(ID::EN);
+ pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
}
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
has_sr = true;
@@ -125,10 +217,10 @@ struct FfData {
}
} else if (cell->type == ID($_FF_)) {
is_fine = true;
+ has_gclk = true;
sig_d = cell->getPort(ID::D);
} else if (type_str.substr(0, 5) == "$_SR_") {
is_fine = true;
- has_d = false;
has_sr = true;
pol_set = type_str[5] == 'P';
pol_clr = type_str[6] == 'P';
@@ -146,9 +238,9 @@ struct FfData {
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
- has_en = true;
- pol_en = type_str[8] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_ce = true;
+ pol_ce = type_str[8] == 'P';
+ sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
@@ -169,9 +261,9 @@ struct FfData {
pol_arst = type_str[8] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
- has_en = true;
- pol_en = type_str[10] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_ce = true;
+ pol_ce = type_str[10] == 'P';
+ sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
@@ -194,9 +286,9 @@ struct FfData {
pol_clr = type_str[11] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
- has_en = true;
- pol_en = type_str[12] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_ce = true;
+ pol_ce = type_str[12] == 'P';
+ sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
@@ -217,9 +309,9 @@ struct FfData {
pol_srst = type_str[9] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
- has_en = true;
- pol_en = type_str[11] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_ce = true;
+ pol_ce = type_str[11] == 'P';
+ sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
@@ -230,32 +322,35 @@ struct FfData {
pol_srst = type_str[10] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
- has_en = true;
- pol_en = type_str[12] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_ce = true;
+ pol_ce = type_str[12] == 'P';
+ sig_ce = cell->getPort(ID::E);
ce_over_srst = true;
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
is_fine = true;
- sig_d = cell->getPort(ID::D);
- has_en = true;
- pol_en = type_str[9] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_aload = true;
+ sig_ad = cell->getPort(ID::D);
+ has_aload = true;
+ pol_aload = type_str[9] == 'P';
+ sig_aload = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
is_fine = true;
- sig_d = cell->getPort(ID::D);
- has_en = true;
- pol_en = type_str[9] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_aload = true;
+ sig_ad = cell->getPort(ID::D);
+ has_aload = true;
+ pol_aload = type_str[9] == 'P';
+ sig_aload = cell->getPort(ID::E);
has_arst = true;
pol_arst = type_str[10] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
is_fine = true;
- sig_d = cell->getPort(ID::D);
- has_en = true;
- pol_en = type_str[11] == 'P';
- sig_en = cell->getPort(ID::E);
+ has_aload = true;
+ sig_ad = cell->getPort(ID::D);
+ has_aload = true;
+ pol_aload = type_str[11] == 'P';
+ sig_aload = cell->getPort(ID::E);
has_sr = true;
pol_set = type_str[12] == 'P';
pol_clr = type_str[13] == 'P';
@@ -264,17 +359,13 @@ struct FfData {
} else {
log_assert(0);
}
- if (has_d && sig_d.is_fully_const()) {
- d_is_const = true;
- val_d = sig_d.as_const();
- if (has_en && !has_clk && !has_sr && !has_arst) {
- // Plain D latches with const D treated specially.
- has_en = has_d = false;
- has_arst = true;
- sig_arst = sig_en;
- pol_arst = pol_en;
- val_arst = val_d;
- }
+ if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
+ // Plain D latches with const D treated specially.
+ has_aload = false;
+ has_arst = true;
+ sig_arst = sig_aload;
+ pol_arst = pol_aload;
+ val_arst = sig_ad.as_const();
}
}
@@ -282,19 +373,22 @@ struct FfData {
FfData slice(const std::vector<int> &bits) {
FfData res(initvals);
res.sig_clk = sig_clk;
- res.sig_en = sig_en;
+ res.sig_ce = sig_ce;
+ res.sig_aload = sig_aload;
res.sig_arst = sig_arst;
res.sig_srst = sig_srst;
- res.has_d = has_d;
res.has_clk = has_clk;
- res.has_en = has_en;
+ res.has_gclk = has_gclk;
+ res.has_ce = has_ce;
+ res.has_aload = has_aload;
res.has_arst = has_arst;
res.has_srst = has_srst;
res.has_sr = has_sr;
res.ce_over_srst = ce_over_srst;
res.is_fine = is_fine;
res.pol_clk = pol_clk;
- res.pol_en = pol_en;
+ res.pol_ce = pol_ce;
+ res.pol_aload = pol_aload;
res.pol_arst = pol_arst;
res.pol_srst = pol_srst;
res.pol_clr = pol_clr;
@@ -302,8 +396,10 @@ struct FfData {
res.attributes = attributes;
for (int i : bits) {
res.sig_q.append(sig_q[i]);
- if (has_d)
+ if (has_clk || has_gclk)
res.sig_d.append(sig_d[i]);
+ if (has_aload)
+ res.sig_ad.append(sig_ad[i]);
if (has_sr) {
res.sig_clr.append(sig_clr[i]);
res.sig_set.append(sig_set[i]);
@@ -316,39 +412,34 @@ struct FfData {
res.val_init.bits.push_back(val_init[i]);
}
res.width = GetSize(res.sig_q);
- // Slicing bits out may cause D to become const.
- if (has_d && res.sig_d.is_fully_const()) {
- res.d_is_const = true;
- res.val_d = res.sig_d.as_const();
- }
return res;
}
void unmap_ce(Module *module) {
- if (!has_en)
+ if (!has_ce)
return;
log_assert(has_clk);
if (has_srst && ce_over_srst)
unmap_srst(module);
if (!is_fine) {
- if (pol_en)
- sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
+ if (pol_ce)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
else
- sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
+ sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
} else {
- if (pol_en)
- sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
+ if (pol_ce)
+ sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
else
- sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
+ sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
}
- has_en = false;
+ has_ce = false;
}
void unmap_srst(Module *module) {
if (!has_srst)
return;
- if (has_en && !ce_over_srst)
+ if (has_ce && !ce_over_srst)
unmap_ce(module);
if (!is_fine) {
@@ -373,14 +464,14 @@ struct FfData {
Cell *emit(Module *module, IdString name) {
if (!width)
return nullptr;
- if (!has_d && !has_sr) {
+ if (!has_aload && !has_clk && !has_gclk && !has_sr) {
if (has_arst) {
// Convert this case to a D latch.
- has_d = has_en = true;
+ has_aload = true;
has_arst = false;
- sig_d = val_arst;
- sig_en = sig_arst;
- pol_en = pol_arst;
+ sig_ad = val_arst;
+ sig_aload = sig_arst;
+ pol_aload = pol_arst;
} else {
// No control inputs left. Turn into a const driver.
if (initvals)
@@ -393,87 +484,93 @@ struct FfData {
initvals->set_init(sig_q, val_init);
Cell *cell;
if (!is_fine) {
- if (!has_d) {
- log_assert(has_sr);
- cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
- } else if (!has_clk && !has_en) {
+ if (has_gclk) {
+ log_assert(!has_clk);
+ log_assert(!has_ce);
+ log_assert(!has_aload);
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFf(name, sig_d, sig_q);
+ } else if (!has_aload && !has_clk) {
+ log_assert(has_sr);
+ cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
- cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+ cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
else if (has_arst)
- cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
+ cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
else
- cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
+ cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
} else {
if (has_sr) {
- if (has_en)
- cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
+ if (has_ce)
+ cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
else
cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
- if (has_en)
- cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
+ if (has_ce)
+ cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
else
cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
} else if (has_srst) {
- if (has_en)
+ if (has_ce)
if (ce_over_srst)
- cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+ cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
else
- cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+ cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
else
cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
} else {
- if (has_en)
- cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+ if (has_ce)
+ cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
else
cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
}
}
} else {
- if (!has_d) {
- log_assert(has_sr);
- cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
- } else if (!has_clk && !has_en) {
+ if (has_gclk) {
+ log_assert(!has_clk);
+ log_assert(!has_ce);
+ log_assert(!has_aload);
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
cell = module->addFfGate(name, sig_d, sig_q);
+ } else if (!has_aload && !has_clk) {
+ log_assert(has_sr);
+ cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
} else if (!has_clk) {
log_assert(!has_srst);
if (has_sr)
- cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+ cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
else if (has_arst)
- cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
+ cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
else
- cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
+ cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
} else {
if (has_sr) {
- if (has_en)
- cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
+ if (has_ce)
+ cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
else
cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
} else if (has_arst) {
- if (has_en)
- cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, pol_arst);
+ if (has_ce)
+ cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
else
cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
} else if (has_srst) {
- if (has_en)
+ if (has_ce)
if (ce_over_srst)
- cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
+ cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
else
- cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
+ cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
else
cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
} else {
- if (has_en)
- cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+ if (has_ce)
+ cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
else
cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
}
diff --git a/kernel/ffmerge.cc b/kernel/ffmerge.cc
index 6a29acc96..7d62a88cf 100644
--- a/kernel/ffmerge.cc
+++ b/kernel/ffmerge.cc
@@ -62,22 +62,28 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
FfData cur_ff(initvals, cell);
- log_assert(cur_ff.has_d);
+ // Reject latches and $ff.
+ if (!cur_ff.has_clk)
+ return false;
+
log_assert((*sigmap)(cur_ff.sig_d[idx]) == bit);
if (!found) {
ff.sig_clk = cur_ff.sig_clk;
- ff.sig_en = cur_ff.sig_en;
+ ff.sig_ce = cur_ff.sig_ce;
+ ff.sig_aload = cur_ff.sig_aload;
ff.sig_srst = cur_ff.sig_srst;
ff.sig_arst = cur_ff.sig_arst;
ff.has_clk = cur_ff.has_clk;
- ff.has_en = cur_ff.has_en;
+ ff.has_ce = cur_ff.has_ce;
+ ff.has_aload = cur_ff.has_aload;
ff.has_srst = cur_ff.has_srst;
ff.has_arst = cur_ff.has_arst;
ff.has_sr = cur_ff.has_sr;
ff.ce_over_srst = cur_ff.ce_over_srst;
ff.pol_clk = cur_ff.pol_clk;
- ff.pol_en = cur_ff.pol_en;
+ ff.pol_ce = cur_ff.pol_ce;
+ ff.pol_aload = cur_ff.pol_aload;
ff.pol_arst = cur_ff.pol_arst;
ff.pol_srst = cur_ff.pol_srst;
ff.pol_clr = cur_ff.pol_clr;
@@ -85,7 +91,9 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
} else {
if (ff.has_clk != cur_ff.has_clk)
return false;
- if (ff.has_en != cur_ff.has_en)
+ if (ff.has_ce != cur_ff.has_ce)
+ return false;
+ if (ff.has_aload != cur_ff.has_aload)
return false;
if (ff.has_srst != cur_ff.has_srst)
return false;
@@ -99,10 +107,16 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
if (ff.pol_clk != cur_ff.pol_clk)
return false;
}
- if (ff.has_en) {
- if (ff.sig_en != cur_ff.sig_en)
+ if (ff.has_ce) {
+ if (ff.sig_ce != cur_ff.sig_ce)
+ return false;
+ if (ff.pol_ce != cur_ff.pol_ce)
+ return false;
+ }
+ if (ff.has_aload) {
+ if (ff.sig_aload != cur_ff.sig_aload)
return false;
- if (ff.pol_en != cur_ff.pol_en)
+ if (ff.pol_aload != cur_ff.pol_aload)
return false;
}
if (ff.has_srst) {
@@ -110,7 +124,7 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
return false;
if (ff.pol_srst != cur_ff.pol_srst)
return false;
- if (ff.has_en && ff.ce_over_srst != cur_ff.ce_over_srst)
+ if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
return false;
}
if (ff.has_arst) {
@@ -129,6 +143,7 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
ff.width++;
ff.sig_d.append(cur_ff.sig_d[idx]);
+ ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
ff.sig_q.append(cur_ff.sig_q[idx]);
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
@@ -179,28 +194,33 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
if (!found) {
ff.sig_clk = cur_ff.sig_clk;
- ff.sig_en = cur_ff.sig_en;
+ ff.sig_ce = cur_ff.sig_ce;
+ ff.sig_aload = cur_ff.sig_aload;
ff.sig_srst = cur_ff.sig_srst;
ff.sig_arst = cur_ff.sig_arst;
- ff.has_d = cur_ff.has_d;
ff.has_clk = cur_ff.has_clk;
- ff.has_en = cur_ff.has_en;
+ ff.has_gclk = cur_ff.has_gclk;
+ ff.has_ce = cur_ff.has_ce;
+ ff.has_aload = cur_ff.has_aload;
ff.has_srst = cur_ff.has_srst;
ff.has_arst = cur_ff.has_arst;
ff.has_sr = cur_ff.has_sr;
ff.ce_over_srst = cur_ff.ce_over_srst;
ff.pol_clk = cur_ff.pol_clk;
- ff.pol_en = cur_ff.pol_en;
+ ff.pol_ce = cur_ff.pol_ce;
+ ff.pol_aload = cur_ff.pol_aload;
ff.pol_arst = cur_ff.pol_arst;
ff.pol_srst = cur_ff.pol_srst;
ff.pol_clr = cur_ff.pol_clr;
ff.pol_set = cur_ff.pol_set;
} else {
- if (ff.has_d != cur_ff.has_d)
+ if (ff.has_gclk != cur_ff.has_gclk)
return false;
if (ff.has_clk != cur_ff.has_clk)
return false;
- if (ff.has_en != cur_ff.has_en)
+ if (ff.has_ce != cur_ff.has_ce)
+ return false;
+ if (ff.has_aload != cur_ff.has_aload)
return false;
if (ff.has_srst != cur_ff.has_srst)
return false;
@@ -214,10 +234,16 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
if (ff.pol_clk != cur_ff.pol_clk)
return false;
}
- if (ff.has_en) {
- if (ff.sig_en != cur_ff.sig_en)
+ if (ff.has_ce) {
+ if (ff.sig_ce != cur_ff.sig_ce)
+ return false;
+ if (ff.pol_ce != cur_ff.pol_ce)
+ return false;
+ }
+ if (ff.has_aload) {
+ if (ff.sig_aload != cur_ff.sig_aload)
return false;
- if (ff.pol_en != cur_ff.pol_en)
+ if (ff.pol_aload != cur_ff.pol_aload)
return false;
}
if (ff.has_srst) {
@@ -225,7 +251,7 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
return false;
if (ff.pol_srst != cur_ff.pol_srst)
return false;
- if (ff.has_en && ff.ce_over_srst != cur_ff.ce_over_srst)
+ if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
return false;
}
if (ff.has_arst) {
@@ -243,7 +269,8 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
}
ff.width++;
- ff.sig_d.append(ff.has_d ? cur_ff.sig_d[idx] : State::Sx);
+ ff.sig_d.append((ff.has_clk || ff.has_gclk) ? cur_ff.sig_d[idx] : State::Sx);
+ ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
ff.sig_q.append(cur_ff.sig_q[idx]);
ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
diff --git a/kernel/mem.cc b/kernel/mem.cc
index b176e4057..40659b15b 100644
--- a/kernel/mem.cc
+++ b/kernel/mem.cc
@@ -961,9 +961,9 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
ff.sig_clk = port.clk;
ff.pol_clk = port.clk_polarity;
if (port.en != State::S1) {
- ff.has_en = true;
- ff.pol_en = true;
- ff.sig_en = port.en;
+ ff.has_ce = true;
+ ff.pol_ce = true;
+ ff.sig_ce = port.en;
}
if (port.arst != State::S0) {
ff.has_arst = true;
@@ -976,7 +976,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
ff.pol_srst = true;
ff.sig_srst = port.srst;
ff.val_srst = port.srst_value;
- ff.ce_over_srst = ff.has_en && port.ce_over_srst;
+ ff.ce_over_srst = ff.has_ce && port.ce_over_srst;
}
ff.sig_d = sig_d;
ff.sig_q = port.data;
@@ -1163,15 +1163,14 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) {
FfData ff(initvals);
ff.width = 1;
ff.sig_q = cond_q;
- ff.has_d = true;
ff.sig_d = cond;
ff.has_clk = true;
ff.sig_clk = rport.clk;
ff.pol_clk = rport.clk_polarity;
if (rport.en != State::S1) {
- ff.has_en = true;
- ff.sig_en = rport.en;
- ff.pol_en = true;
+ ff.has_ce = true;
+ ff.sig_ce = rport.en;
+ ff.pol_ce = true;
}
if (rport.arst != State::S0) {
ff.has_arst = true;
diff --git a/kernel/satgen.cc b/kernel/satgen.cc
index 7ad56c117..214826f5a 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -1081,7 +1081,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
FfData ff(nullptr, cell);
// Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first.
- if (!ff.has_d || ff.has_arst || ff.has_sr || (ff.has_en && !ff.has_clk))
+ if (ff.has_aload || ff.has_arst || ff.has_sr)
return false;
if (timestep == 1)
@@ -1094,7 +1094,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_d;
if (model_undef)
undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
- if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
+ if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
int undef_srst;
@@ -1108,21 +1108,21 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
else
std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
}
- if (ff.has_en) {
- int en = importDefSigSpec(ff.sig_en, timestep-1).at(0);
+ if (ff.has_ce) {
+ int ce = importDefSigSpec(ff.sig_ce, timestep-1).at(0);
std::vector<int> old_q = importDefSigSpec(ff.sig_q, timestep-1);
- int undef_en;
+ int undef_ce;
std::vector<int> undef_old_q;
if (model_undef) {
- undef_en = importUndefSigSpec(ff.sig_en, timestep-1).at(0);
+ undef_ce = importUndefSigSpec(ff.sig_ce, timestep-1).at(0);
undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1);
}
- if (ff.pol_en)
- std::tie(d, undef_d) = mux(en, undef_en, old_q, undef_old_q, d, undef_d);
+ if (ff.pol_ce)
+ std::tie(d, undef_d) = mux(ce, undef_ce, old_q, undef_old_q, d, undef_d);
else
- std::tie(d, undef_d) = mux(en, undef_en, d, undef_d, old_q, undef_old_q);
+ std::tie(d, undef_d) = mux(ce, undef_ce, d, undef_d, old_q, undef_old_q);
}
- if (ff.has_srst && !(ff.has_en && ff.ce_over_srst)) {
+ if (ff.has_srst && !(ff.has_ce && ff.ce_over_srst)) {
int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
int undef_srst;