aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelina Koƛcielnicka <mwk@0x04.net>2021-10-27 10:14:07 +0200
committerMarcelina Koƛcielnicka <mwk@0x04.net>2021-10-27 14:14:01 +0200
commit0a0df8d38c8ef74b95d9649be5a78c18a928bf4d (patch)
tree902501d865bf045d73e4711c5d509b3038499683
parentbdf153d06c3673b93bbc3fd07999e0a19747417b (diff)
downloadyosys-0a0df8d38c8ef74b95d9649be5a78c18a928bf4d.tar.gz
yosys-0a0df8d38c8ef74b95d9649be5a78c18a928bf4d.tar.bz2
yosys-0a0df8d38c8ef74b95d9649be5a78c18a928bf4d.zip
dfflegalize: Refactor, add aldff support.
-rw-r--r--kernel/ff.cc192
-rw-r--r--kernel/ff.h17
-rw-r--r--passes/techmap/dfflegalize.cc1862
-rw-r--r--tests/techmap/dfflegalize_adff_init.ys26
-rw-r--r--tests/techmap/dfflegalize_adlatch_init.ys4
-rw-r--r--tests/techmap/dfflegalize_dff.ys17
-rw-r--r--tests/techmap/dfflegalize_dff_init.ys40
-rw-r--r--tests/techmap/dfflegalize_dlatch_const.ys8
-rw-r--r--tests/techmap/dfflegalize_dlatchsr_init.ys8
-rw-r--r--tests/techmap/dfflegalize_minsrst.ys4
-rw-r--r--tests/techmap/dfflegalize_sr.ys2
-rw-r--r--tests/techmap/dfflegalize_sr_init.ys10
12 files changed, 1137 insertions, 1053 deletions
diff --git a/kernel/ff.cc b/kernel/ff.cc
index c2f1a75a0..c43482bd2 100644
--- a/kernel/ff.cc
+++ b/kernel/ff.cc
@@ -303,6 +303,190 @@ FfData FfData::slice(const std::vector<int> &bits) {
return res;
}
+void FfData::add_dummy_ce() {
+ if (has_ce)
+ return;
+ has_ce = true;
+ pol_ce = true;
+ sig_ce = State::S1;
+ ce_over_srst = false;
+}
+
+void FfData::add_dummy_srst() {
+ if (has_srst)
+ return;
+ has_srst = true;
+ pol_srst = true;
+ sig_srst = State::S0;
+ val_srst = Const(State::Sx, width);
+ ce_over_srst = false;
+}
+
+void FfData::add_dummy_arst() {
+ if (has_arst)
+ return;
+ has_arst = true;
+ pol_arst = true;
+ sig_arst = State::S0;
+ val_arst = Const(State::Sx, width);
+}
+
+void FfData::add_dummy_aload() {
+ if (has_aload)
+ return;
+ has_aload = true;
+ pol_aload = true;
+ sig_aload = State::S0;
+ sig_ad = Const(State::Sx, width);
+}
+
+void FfData::add_dummy_sr() {
+ if (has_sr)
+ return;
+ has_sr = true;
+ pol_clr = true;
+ pol_set = true;
+ sig_clr = Const(State::S0, width);
+ sig_set = Const(State::S0, width);
+}
+
+void FfData::add_dummy_clk() {
+ if (has_clk)
+ return;
+ has_clk = true;
+ pol_clk = true;
+ sig_clk = State::S0;
+ sig_d = Const(State::Sx, width);
+}
+
+void FfData::arst_to_aload() {
+ log_assert(has_arst);
+ log_assert(!has_aload);
+ pol_aload = pol_arst;
+ sig_aload = sig_arst;
+ sig_ad = val_arst;
+ has_aload = true;
+ has_arst = false;
+}
+
+void FfData::arst_to_sr() {
+ log_assert(has_arst);
+ log_assert(!has_sr);
+ pol_clr = pol_arst;
+ pol_set = pol_arst;
+ sig_clr = Const(pol_arst ? State::S0 : State::S1, width);
+ sig_set = Const(pol_arst ? State::S0 : State::S1, width);
+ has_sr = true;
+ has_arst = false;
+ for (int i = 0; i < width; i++) {
+ if (val_arst[i] == State::S1)
+ sig_set[i] = sig_arst;
+ else
+ sig_clr[i] = sig_arst;
+ }
+}
+
+void FfData::aload_to_sr() {
+ log_assert(has_aload);
+ log_assert(!has_sr);
+ has_sr = true;
+ has_aload = false;
+ if (!is_fine) {
+ pol_clr = false;
+ pol_set = true;
+ if (pol_aload) {
+ sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload);
+ sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload);
+ } else {
+ sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload);
+ sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload);
+ }
+ } else {
+ pol_clr = pol_aload;
+ pol_set = pol_aload;
+ if (pol_aload) {
+ sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad);
+ sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad);
+ } else {
+ sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad);
+ sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad);
+ }
+ }
+}
+
+void FfData::convert_ce_over_srst(bool val) {
+ if (!has_ce || !has_srst || ce_over_srst == val)
+ return;
+ if (val) {
+ // sdffe to sdffce
+ if (!is_fine) {
+ if (pol_ce) {
+ if (pol_srst) {
+ sig_ce = module->Or(NEW_ID, sig_ce, sig_srst);
+ } else {
+ SigSpec tmp = module->Not(NEW_ID, sig_srst);
+ sig_ce = module->Or(NEW_ID, sig_ce, tmp);
+ }
+ } else {
+ if (pol_srst) {
+ SigSpec tmp = module->Not(NEW_ID, sig_srst);
+ sig_ce = module->And(NEW_ID, sig_ce, tmp);
+ } else {
+ sig_ce = module->And(NEW_ID, sig_ce, sig_srst);
+ }
+ }
+ } else {
+ if (pol_ce) {
+ if (pol_srst) {
+ sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst);
+ } else {
+ sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst);
+ }
+ } else {
+ if (pol_srst) {
+ sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst);
+ } else {
+ sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst);
+ }
+ }
+ }
+ } else {
+ // sdffce to sdffe
+ if (!is_fine) {
+ if (pol_srst) {
+ if (pol_ce) {
+ sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce);
+ } else {
+ SigSpec tmp = module->Not(NEW_ID, sig_ce);
+ sig_srst = cell->module->And(NEW_ID, sig_srst, tmp);
+ }
+ } else {
+ if (pol_ce) {
+ SigSpec tmp = module->Not(NEW_ID, sig_ce);
+ sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp);
+ } else {
+ sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce);
+ }
+ }
+ } else {
+ if (pol_srst) {
+ if (pol_ce) {
+ sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce);
+ } else {
+ sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce);
+ }
+ } else {
+ if (pol_ce) {
+ sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce);
+ } else {
+ sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce);
+ }
+ }
+ }
+ }
+ ce_over_srst = val;
+}
+
void FfData::unmap_ce() {
if (!has_ce)
return;
@@ -351,11 +535,7 @@ Cell *FfData::emit() {
if (!has_aload && !has_clk && !has_gclk && !has_sr) {
if (has_arst) {
// Convert this case to a D latch.
- has_aload = true;
- has_arst = false;
- sig_ad = val_arst;
- sig_aload = sig_arst;
- pol_aload = pol_arst;
+ arst_to_aload();
} else {
// No control inputs left. Turn into a const driver.
module->connect(sig_q, val_init);
@@ -506,7 +686,7 @@ void FfData::flip_bits(const pool<int> &bits) {
}
if (has_sr && cell) {
- log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].", log_id(module->name), log_id(cell->name), log_id(cell->type));
+ log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
}
if (is_fine) {
diff --git a/kernel/ff.h b/kernel/ff.h
index 3125f67c6..5a629d5dd 100644
--- a/kernel/ff.h
+++ b/kernel/ff.h
@@ -170,8 +170,23 @@ struct FfData {
// Returns a FF identical to this one, but only keeping bit indices from the argument.
FfData slice(const std::vector<int> &bits);
- void unmap_ce();
+ void add_dummy_ce();
+ void add_dummy_srst();
+ void add_dummy_arst();
+ void add_dummy_aload();
+ void add_dummy_sr();
+ void add_dummy_clk();
+
+ void arst_to_aload();
+ void arst_to_sr();
+
+ void aload_to_sr();
+ // Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and
+ // fixes up control signals appropriately to preserve semantics.
+ void convert_ce_over_srst(bool val);
+
+ void unmap_ce();
void unmap_srst();
void unmap_ce_srst() {
diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc
index 5210d01eb..1d99caa3a 100644
--- a/passes/techmap/dfflegalize.cc
+++ b/passes/techmap/dfflegalize.cc
@@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -27,38 +28,42 @@ PRIVATE_NAMESPACE_BEGIN
enum FfType {
FF_DFF,
FF_DFFE,
- FF_ADFF0,
- FF_ADFF1,
- FF_ADFFE0,
- FF_ADFFE1,
+ FF_ADFF,
+ FF_ADFFE,
+ FF_ALDFF,
+ FF_ALDFFE,
FF_DFFSR,
FF_DFFSRE,
- FF_SDFF0,
- FF_SDFF1,
- FF_SDFFE0,
- FF_SDFFE1,
- FF_SDFFCE0,
- FF_SDFFCE1,
+ FF_SDFF,
+ FF_SDFFE,
+ FF_SDFFCE,
+ FF_RLATCH,
FF_SR,
FF_DLATCH,
- FF_ADLATCH0,
- FF_ADLATCH1,
+ FF_ADLATCH,
FF_DLATCHSR,
NUM_FFTYPES,
};
enum FfNeg {
- NEG_R = 0x1,
- NEG_S = 0x2,
- NEG_E = 0x4,
- NEG_C = 0x8,
- NUM_NEG = 0x10,
+ NEG_CE = 0x1,
+ NEG_R = 0x2,
+ NEG_S = 0x4,
+ NEG_L = 0x8,
+ NEG_C = 0x10,
+ NUM_NEG = 0x20,
};
enum FfInit {
INIT_X = 0x1,
INIT_0 = 0x2,
INIT_1 = 0x4,
+ INIT_X_R0 = 0x10,
+ INIT_0_R0 = 0x20,
+ INIT_1_R0 = 0x40,
+ INIT_X_R1 = 0x100,
+ INIT_0_R1 = 0x200,
+ INIT_1_R1 = 0x400,
};
struct DffLegalizePass : public Pass {
@@ -101,6 +106,8 @@ struct DffLegalizePass : public Pass {
log("- $_DFFE_[NP][NP]_\n");
log("- $_DFF_[NP][NP][01]_\n");
log("- $_DFFE_[NP][NP][01][NP]_\n");
+ log("- $_ALDFF_[NP][NP]_\n");
+ log("- $_ALDFFE_[NP][NP][NP]_\n");
log("- $_DFFSR_[NP][NP][NP]_\n");
log("- $_DFFSRE_[NP][NP][NP][NP]_\n");
log("- $_SDFF_[NP][NP][01]_\n");
@@ -151,18 +158,30 @@ struct DffLegalizePass : public Pass {
int supported_cells[NUM_FFTYPES];
// Aggregated for all *dff* cells.
int supported_dff;
+ // Aggregated for all *dffe* cells.
+ int supported_dffe;
// Aggregated for all dffsr* cells.
int supported_dffsr;
- // Aggregated for all adff* cells.
- int supported_adff0;
- int supported_adff1;
+ // Aggregated for all aldff cells.
+ int supported_aldff;
+ // Aggregated for all aldffe cells.
+ int supported_aldffe;
+ // Aggregated for all adff* cells and trivial emulations.
+ int supported_adff;
+ // Aggregated for all adffe* cells and trivial emulations.
+ int supported_adffe;
// Aggregated for all sdff* cells.
- int supported_sdff0;
- int supported_sdff1;
+ int supported_sdff;
// Aggregated for all ways to obtain a SR latch.
int supported_sr;
+ int supported_sr_plain;
// Aggregated for all *dlatch* cells.
int supported_dlatch;
+ int supported_dlatch_plain;
+ // Aggregated for all ways to obtain an R latch.
+ int supported_rlatch;
+ // Aggregated for all adlatch cells and trivial emulations.
+ int supported_adlatch;
int mince;
int minsrst;
@@ -179,732 +198,794 @@ struct DffLegalizePass : public Pass {
res |= INIT_1;
if (mask & INIT_1)
res |= INIT_0;
+ if (mask & INIT_X_R0)
+ res |= INIT_X_R1;
+ if (mask & INIT_0_R0)
+ res |= INIT_1_R1;
+ if (mask & INIT_1_R0)
+ res |= INIT_0_R1;
+ if (mask & INIT_X_R1)
+ res |= INIT_X_R0;
+ if (mask & INIT_0_R1)
+ res |= INIT_1_R0;
+ if (mask & INIT_1_R1)
+ res |= INIT_0_R0;
return res;
}
- void handle_ff(Cell *cell) {
- std::string type_str = cell->type.str();
-
- FfType ff_type;
- int ff_neg = 0;
- SigSpec sig_d;
- SigSpec sig_q;
- SigSpec sig_c;
- SigSpec sig_e;
- SigSpec sig_r;
- SigSpec sig_s;
- bool has_srst = false;
-
- if (cell->hasPort(ID::D))
- sig_d = cell->getPort(ID::D);
- if (cell->hasPort(ID::Q))
- sig_q = cell->getPort(ID::Q);
- if (cell->hasPort(ID::C))
- sig_c = cell->getPort(ID::C);
- if (cell->hasPort(ID::E))
- sig_e = cell->getPort(ID::E);
- if (cell->hasPort(ID::R))
- sig_r = cell->getPort(ID::R);
- if (cell->hasPort(ID::S))
- sig_s = cell->getPort(ID::S);
-
- if (type_str.substr(0, 5) == "$_SR_") {
- ff_type = FF_SR;
- if (type_str[5] == 'N')
- ff_neg |= NEG_S;
- if (type_str[6] == 'N')
- ff_neg |= NEG_R;
- } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
- ff_type = FF_DFF;
- if (type_str[6] == 'N')
- ff_neg |= NEG_C;
- } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
- ff_type = FF_DFFE;
- if (type_str[7] == 'N')
- ff_neg |= NEG_C;
- if (type_str[8] == 'N')
- ff_neg |= NEG_E;
- } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
- ff_type = type_str[8] == '1' ? FF_ADFF1 : FF_ADFF0;
- if (type_str[6] == 'N')
- ff_neg |= NEG_C;
- if (type_str[7] == 'N')
- ff_neg |= NEG_R;
- } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
- ff_type = type_str[9] == '1' ? FF_ADFFE1 : FF_ADFFE0;
- if (type_str[7] == 'N')
- ff_neg |= NEG_C;
- if (type_str[8] == 'N')
- ff_neg |= NEG_R;
- if (type_str[10] == 'N')
- ff_neg |= NEG_E;
- } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
- ff_type = FF_DFFSR;
- if (type_str[8] == 'N')
- ff_neg |= NEG_C;
- if (type_str[9] == 'N')
- ff_neg |= NEG_S;
- if (type_str[10] == 'N')
- ff_neg |= NEG_R;
- } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
- ff_type = FF_DFFSRE;
- if (type_str[9] == 'N')
- ff_neg |= NEG_C;
- if (type_str[10] == 'N')
- ff_neg |= NEG_S;
- if (type_str[11] == 'N')
- ff_neg |= NEG_R;
- if (type_str[12] == 'N')
- ff_neg |= NEG_E;
- } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
- ff_type = type_str[9] == '1' ? FF_SDFF1 : FF_SDFF0;
- if (type_str[7] == 'N')
- ff_neg |= NEG_C;
- if (type_str[8] == 'N')
- ff_neg |= NEG_R;
- has_srst = true;
- } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
- ff_type = type_str[10] == '1' ? FF_SDFFE1 : FF_SDFFE0;
- if (type_str[8] == 'N')
- ff_neg |= NEG_C;
- if (type_str[9] == 'N')
- ff_neg |= NEG_R;
- if (type_str[11] == 'N')
- ff_neg |= NEG_E;
- has_srst = true;
- } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
- ff_type = type_str[11] == '1' ? FF_SDFFCE1 : FF_SDFFCE0;
- if (type_str[9] == 'N')
- ff_neg |= NEG_C;
- if (type_str[10] == 'N')
- ff_neg |= NEG_R;
- if (type_str[12] == 'N')
- ff_neg |= NEG_E;
- has_srst = true;
- } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
- ff_type = FF_DLATCH;
- if (type_str[9] == 'N')
- ff_neg |= NEG_E;
- } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
- ff_type = type_str[11] == '1' ? FF_ADLATCH1 : FF_ADLATCH0;
- if (type_str[9] == 'N')
- ff_neg |= NEG_E;
- if (type_str[10] == 'N')
- ff_neg |= NEG_R;
- } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
- ff_type = FF_DLATCHSR;
- if (type_str[11] == 'N')
- ff_neg |= NEG_E;
- if (type_str[12] == 'N')
- ff_neg |= NEG_S;
- if (type_str[13] == 'N')
- ff_neg |= NEG_R;
+ int get_ff_type(const FfData &ff) {
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ return ff.has_ce ? FF_DFFSRE : FF_DFFSR;
+ } else if (ff.has_arst) {
+ return ff.has_ce ? FF_ADFFE : FF_ADFF;
+ } else if (ff.has_aload) {
+ return ff.has_ce ? FF_ALDFFE : FF_ALDFF;
+ } else if (ff.has_srst) {
+ if (ff.has_ce)
+ return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE;
+ else
+ return FF_SDFF;
+ } else {
+ return ff.has_ce ? FF_DFFE : FF_DFF;
+ }
} else {
- log_warning("Ignoring unknown ff type %s [%s.%s].\n", log_id(cell->type), log_id(cell->module->name), log_id(cell->name));
- return;
+ if (ff.has_aload) {
+ if (ff.has_sr)
+ return FF_DLATCHSR;
+ else if (ff.has_arst)
+ return FF_ADLATCH;
+ else
+ return FF_DLATCH;
+ } else {
+ if (ff.has_sr) {
+ return FF_SR;
+ } else if (ff.has_arst) {
+ return FF_RLATCH;
+ } else {
+ log_assert(0);
+ return 0;
+ }
+ }
}
+ }
- State initval = initvals(sig_q[0]);
-
- FfInit initmask = INIT_X;
- if (initval == State::S0)
- initmask = INIT_0;
- else if (initval == State::S1)
- initmask = INIT_1;
- const char *reason;
+ int get_initmask(FfData &ff) {
+ int res = 0;
+ if (ff.val_init[0] == State::S0)
+ res = INIT_0;
+ else if (ff.val_init[0] == State::S1)
+ res = INIT_1;
+ else
+ res = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_arst[0] == State::S1)
+ res <<= 8;
+ } else if (ff.has_srst) {
+ if (ff.val_srst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_srst[0] == State::S1)
+ res <<= 8;
+ }
+ return res;
+ }
- bool kill_ce = mince && GetSize(sig_c) && GetSize(sig_e) && sig_e[0].wire && ce_used[sig_e[0]] < mince;
- bool kill_srst = minsrst && has_srst && sig_r[0].wire && srst_used[sig_r[0]] < minsrst;
+ void fail_ff(const FfData &ff, const char *reason) {
+ log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason);
+ }
- while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) {
- // Well, cell is not directly supported. Decide how to deal with it.
+ bool try_flip(FfData &ff, int supported_mask) {
+ int initmask = get_initmask(ff);
+ if (supported_mask & initmask)
+ return true;
+ if (supported_mask & flip_initmask(initmask)) {
+ ff.flip_bits({0});
+ return true;
+ }
+ return false;
+ }
- if (ff_type == FF_DFF || ff_type == FF_DFFE) {
- if (kill_ce) {
- ff_type = FF_DFF;
- goto unmap_enable;
- }
- if (!(supported_dff & initmask)) {
- // This init value is not supported at all...
- if (supported_dff & flip_initmask(initmask)) {
- // The other one is, though. Negate D, Q, and init.
-flip_dqi:
- if (initval == State::S0) {
- initval = State::S1;
- initmask = INIT_1;
- } else if (initval == State::S1) {
- initval = State::S0;
- initmask = INIT_0;
- }
- if (ff_type != FF_SR)
- sig_d = cell->module->NotGate(NEW_ID, sig_d[0]);
- SigBit new_q = SigSpec(cell->module->addWire(NEW_ID))[0];
- cell->module->addNotGate(NEW_ID, new_q, sig_q[0]);
- initvals.remove_init(sig_q[0]);
- initvals.set_init(new_q, initval);
- sig_q = new_q;
- continue;
- }
- if (!supported_dff)
- reason = "dffs are not supported";
- else
- reason = "initialized dffs are not supported";
- goto error;
- }
+ void emulate_split_init_arst(FfData &ff) {
+ ff.remove();
- // Some DFF is supported with this init val. Just pick a type.
- if (ff_type == FF_DFF) {
- // Try adding a set or reset pin.
- for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1})
- if (supported_cells[new_type] & initmask) {
- ff_type = new_type;
- sig_r = State::S0;
- goto cell_ok;
- }
- // Try adding both.
- if (supported_cells[FF_DFFSR] & initmask) {
- ff_type = FF_DFFSR;
- sig_r = State::S0;
- sig_s = State::S0;
- break;
- }
- // Nope. Will need to add enable and go the DFFE route.
- sig_e = State::S1;
- if (supported_cells[FF_DFFE] & initmask) {
- ff_type = FF_DFFE;
- break;
- }
- }
- // Try adding a set or reset pin.
- for (auto new_type: {FF_SDFFE0, FF_SDFFE1, FF_SDFFCE0, FF_SDFFCE1, FF_ADFFE0, FF_ADFFE1})
- if (supported_cells[new_type] & initmask) {
- ff_type = new_type;
- sig_r = State::S0;
- goto cell_ok;
- }
- // Try adding both.
- if (supported_cells[FF_DFFSRE] & initmask) {
- ff_type = FF_DFFSRE;
- sig_r = State::S0;
- sig_s = State::S0;
- break;
- }
+ FfData ff_dff(ff.module, &initvals, NEW_ID);
+ ff_dff.width = ff.width;
+ ff_dff.has_aload = ff.has_aload;
+ ff_dff.sig_aload = ff.sig_aload;
+ ff_dff.pol_aload = ff.pol_aload;
+ ff_dff.sig_ad = ff.sig_ad;
+ ff_dff.has_clk = ff.has_clk;
+ ff_dff.sig_clk = ff.sig_clk;
+ ff_dff.pol_clk = ff.pol_clk;
+ ff_dff.sig_d = ff.sig_d;
+ ff_dff.has_ce = ff.has_ce;
+ ff_dff.sig_ce = ff.sig_ce;
+ ff_dff.pol_ce = ff.pol_ce;
+ ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_dff.val_init = ff.val_init;
+ ff_dff.is_fine = ff.is_fine;
+
+ FfData ff_adff(ff.module, &initvals, NEW_ID);
+ ff_adff.width = ff.width;
+ ff_adff.has_aload = ff.has_aload;
+ ff_adff.sig_aload = ff.sig_aload;
+ ff_adff.pol_aload = ff.pol_aload;
+ ff_adff.sig_ad = ff.sig_ad;
+ ff_adff.has_clk = ff.has_clk;
+ ff_adff.sig_clk = ff.sig_clk;
+ ff_adff.pol_clk = ff.pol_clk;
+ ff_adff.sig_d = ff.sig_d;
+ ff_adff.has_ce = ff.has_ce;
+ ff_adff.sig_ce = ff.sig_ce;
+ ff_adff.pol_ce = ff.pol_ce;
+ ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_adff.val_init = Const(State::Sx, ff.width);
+ ff_adff.has_arst = true;
+ ff_adff.sig_arst = ff.sig_arst;
+ ff_adff.pol_arst = ff.pol_arst;
+ ff_adff.val_arst = ff.val_arst;
+ ff_adff.is_fine = ff.is_fine;
+
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = 1;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID);
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = ff.sig_arst;
+ ff_sel.pol_arst = ff.pol_arst;
+ ff_sel.val_arst = State::S1;
+ ff_sel.val_init = State::S0;
+ ff_sel.is_fine = ff.is_fine;
- // Seems that no DFFs with enable are supported.
- // The enable input needs to be unmapped.
- // This should not be reached if we started from plain DFF.
- log_assert(ff_type == FF_DFFE);
- ff_type = FF_DFF;
-unmap_enable:
- if (ff_neg & NEG_E)
- sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], sig_q[0], sig_e[0]);
+ if (ff.is_fine)
+ ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_dff);
+ legalize_ff(ff_adff);
+ legalize_ff(ff_sel);
+ }
+
+ void emulate_split_set_clr(FfData &ff) {
+ // No native DFFSR. However, if we can conjure
+ // a SR latch and ADFF, it can still be emulated.
+ int initmask = get_initmask(ff);
+ int flipmask = flip_initmask(initmask);
+ bool init_clr = true;
+ bool init_set = true;
+ State initsel = State::Sx;
+ int supported_arst = ff.has_clk ? supported_adff : supported_adlatch;
+ bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8);
+ bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4);
+ if (init_clr_ok && init_set_ok && supported_sr) {
+ // OK
+ } else if (init_clr_ok && (supported_sr & INIT_0)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_1)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else if (init_clr_ok && (supported_sr & INIT_1)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_0)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else {
+ if (ff.has_clk) {
+ if (!supported_dffsr)
+ fail_ff(ff, "dffs with async set and reset are not supported");
else
- sig_d = cell->module->MuxGate(NEW_ID, sig_q[0], sig_d[0], sig_e[0]);
- ff_neg &= ~NEG_E;
- sig_e = SigSpec();
- kill_ce = false;
- // Now try again as plain DFF.
- continue;
- } else if (ff_type == FF_ADFF0 || ff_type == FF_ADFF1 || ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1) {
- bool has_set = ff_type == FF_ADFF1 || ff_type == FF_ADFFE1;
- bool has_en = ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1;
- if (kill_ce) {
- ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
- goto unmap_enable;
- }
- if (!has_en && (supported_cells[has_set ? FF_ADFFE1 : FF_ADFFE0] & initmask)) {
- // Just add enable.
- sig_e = State::S1;
- ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0;
- break;
- }
- if (supported_cells[has_en ? FF_DFFSRE : FF_DFFSR] & initmask) {
-adff_to_dffsr:
- // Throw in a set/reset, retry in DFFSR/DFFSRE branch.
- if (has_set) {
- sig_s = sig_r;
- sig_r = State::S0;
- if (ff_neg & NEG_R) {
- ff_neg &= ~NEG_R;
- ff_neg |= NEG_S;
- }
- } else {
- sig_s = State::S0;
- }
- if (has_en)
- ff_type = FF_DFFSRE;
- else
- ff_type = FF_DFFSR;
- continue;
- }
- if (has_en && (supported_cells[has_set ? FF_ADFF1 : FF_ADFF0] & initmask)) {
- // Unmap enable.
- ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
- goto unmap_enable;
- }
- if (supported_dffsr & initmask) {
- goto adff_to_dffsr;
- }
- log_assert(!((has_set ? supported_adff1 : supported_adff0) & initmask));
- // Alright, so this particular combination of initval and
- // resetval is not natively supported. First, try flipping
- // them both to see whether this helps.
- int flipmask = flip_initmask(initmask);
- if ((has_set ? supported_adff0 : supported_adff1) & flipmask) {
- // Checks out, do it.
- ff_type = has_en ? (has_set ? FF_ADFFE0 : FF_ADFFE1) : (has_set ? FF_ADFF0 : FF_ADFF1);
- goto flip_dqi;
- }
+ fail_ff(ff, "initialized dffs with async set and reset are not supported");
+ } else {
+ if (!supported_cells[FF_DLATCHSR])
+ fail_ff(ff, "dlatch with async set and reset are not supported");
+ else
+ fail_ff(ff, "initialized dlatch with async set and reset are not supported");
+ }
+ }
- if (!supported_adff0 && !supported_adff1) {
- reason = "dffs with async set or reset are not supported";
- goto error;
- }
- if (!(supported_dff & ~INIT_X)) {
- reason = "initialized dffs are not supported";
- goto error;
- }
- // If we got here, initialized dff is supported, but not this
- // particular reset+init combination (nor its negation).
- // The only hope left is breaking down to adff + dff + dlatch + mux.
- if (!(supported_dlatch & ~INIT_X)) {
- reason = "unsupported initial value and async reset value combination";
- goto error;
- }
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
- // If we have to unmap enable anyway, do it before breakdown.
- if (has_en && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
- ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
- goto unmap_enable;
- }
+ log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
- log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
- initvals.remove_init(sig_q[0]);
- Wire *adff_q = cell->module->addWire(NEW_ID);
- Wire *dff_q = cell->module->addWire(NEW_ID);
- Wire *sel_q = cell->module->addWire(NEW_ID);
- initvals.set_init(SigBit(dff_q, 0), initval);
- initvals.set_init(SigBit(sel_q, 0), State::S0);
- Cell *cell_dff;
- Cell *cell_adff;
- Cell *cell_sel;
- if (!has_en) {
- cell_dff = cell->module->addDffGate(NEW_ID, sig_c, sig_d, dff_q, !(ff_neg & NEG_C));
- cell_adff = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
- } else {
- cell_dff = cell->module->addDffeGate(NEW_ID, sig_c, sig_e, sig_d, dff_q, !(ff_neg & NEG_C), !(ff_neg & NEG_E));
- cell_adff = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
- }
- cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
- cell->module->addMuxGate(NEW_ID, dff_q, adff_q, sel_q, sig_q);
-
- // Bye, cell.
- cell->module->remove(cell);
- handle_ff(cell_dff);
- handle_ff(cell_adff);
- handle_ff(cell_sel);
- return;
- } else if (ff_type == FF_DFFSR || ff_type == FF_DFFSRE) {
- if (kill_ce) {
- ff_type = FF_DFFSR;
- goto unmap_enable;
- }
- // First, see if mapping/unmapping enable will help.
- if (supported_cells[FF_DFFSRE] & initmask) {
- ff_type = FF_DFFSRE;
- sig_e = State::S1;
- break;
- }
- if (supported_cells[FF_DFFSR] & initmask) {
- ff_type = FF_DFFSR;
- goto unmap_enable;
- }
- if (supported_dffsr & flip_initmask(initmask)) {
-flip_dqisr:;
- log_warning("Flipping D/Q/init and inserting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type));
- SigSpec new_r;
- bool neg_r = (ff_neg & NEG_R);
- bool neg_s = (ff_neg & NEG_S);
- if (!(ff_neg & NEG_S)) {
- if (!(ff_neg & NEG_R))
- new_r = cell->module->AndnotGate(NEW_ID, sig_s, sig_r);
- else
- new_r = cell->module->AndGate(NEW_ID, sig_s, sig_r);
- } else {
- if (!(ff_neg & NEG_R))
- new_r = cell->module->OrGate(NEW_ID, sig_s, sig_r);
- else
- new_r = cell->module->OrnotGate(NEW_ID, sig_s, sig_r);
- }
- ff_neg &= ~(NEG_R | NEG_S);
- if (neg_r)
- ff_neg |= NEG_S;
- if (neg_s)
- ff_neg |= NEG_R;
- sig_s = sig_r;
- sig_r = new_r;
- goto flip_dqi;
- }
- // No native DFFSR. However, if we can conjure
- // a SR latch and ADFF, it can still be emulated.
- int flipmask = flip_initmask(initmask);
- bool init0 = true;
- bool init1 = true;
- State initsel = State::Sx;
- if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && ((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && supported_sr) {
- // OK
- } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_0)) {
- init1 = false;
- initsel = State::S0;
- } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_1)) {
- init0 = false;
- initsel = State::S1;
- } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_1)) {
- init1 = false;
- initsel = State::S0;
- } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_0)) {
- init0 = false;
- initsel = State::S1;
- } else {
- if (!supported_dffsr)
- reason = "dffs with async set and reset are not supported";
- else
- reason = "initialized dffs with async set and reset are not supported";
- goto error;
- }
+ log_assert(ff.width == 1);
+ ff.remove();
- // If we have to unmap enable anyway, do it before breakdown.
- if (ff_type == FF_DFFSRE && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
- ff_type = FF_DFFSR;
- goto unmap_enable;
- }
+ FfData ff_clr(ff.module, &initvals, NEW_ID);
+ ff_clr.width = ff.width;
+ ff_clr.has_aload = ff.has_aload;
+ ff_clr.sig_aload = ff.sig_aload;
+ ff_clr.pol_aload = ff.pol_aload;
+ ff_clr.sig_ad = ff.sig_ad;
+ ff_clr.has_clk = ff.has_clk;
+ ff_clr.sig_clk = ff.sig_clk;
+ ff_clr.pol_clk = ff.pol_clk;
+ ff_clr.sig_d = ff.sig_d;
+ ff_clr.has_ce = ff.has_ce;
+ ff_clr.sig_ce = ff.sig_ce;
+ ff_clr.pol_ce = ff.pol_ce;
+ ff_clr.has_arst = true;
+ ff_clr.sig_arst = ff.sig_clr;
+ ff_clr.pol_arst = ff.pol_clr;
+ ff_clr.val_arst = Const(State::S0, ff.width);
+ ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width);
+ ff_clr.is_fine = ff.is_fine;
- log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
- initvals.remove_init(sig_q[0]);
- Wire *adff0_q = cell->module->addWire(NEW_ID);
- Wire *adff1_q = cell->module->addWire(NEW_ID);
- Wire *sel_q = cell->module->addWire(NEW_ID);
- if (init0)
- initvals.set_init(SigBit(adff0_q, 0), initval);
- if (init1)
- initvals.set_init(SigBit(adff1_q, 0), initval);
- initvals.set_init(SigBit(sel_q, 0), initsel);
- Cell *cell_adff0;
- Cell *cell_adff1;
- Cell *cell_sel;
- if (ff_type == FF_DFFSR) {
- cell_adff0 = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
- cell_adff1 = cell->module->addAdffGate(NEW_ID, sig_c, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_S));
- } else {
- cell_adff0 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
- cell_adff1 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_S));
- }
- cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
- cell->module->addMuxGate(NEW_ID, adff0_q, adff1_q, sel_q, sig_q);
-
- // Bye, cell.
- cell->module->remove(cell);
- handle_ff(cell_adff0);
- handle_ff(cell_adff1);
- handle_ff(cell_sel);
+ FfData ff_set(ff.module, &initvals, NEW_ID);
+ ff_set.width = ff.width;
+ ff_set.has_aload = ff.has_aload;
+ ff_set.sig_aload = ff.sig_aload;
+ ff_set.pol_aload = ff.pol_aload;
+ ff_set.sig_ad = ff.sig_ad;
+ ff_set.has_clk = ff.has_clk;
+ ff_set.sig_clk = ff.sig_clk;
+ ff_set.pol_clk = ff.pol_clk;
+ ff_set.sig_d = ff.sig_d;
+ ff_set.has_ce = ff.has_ce;
+ ff_set.sig_ce = ff.sig_ce;
+ ff_set.pol_ce = ff.pol_ce;
+ ff_set.has_arst = true;
+ ff_set.sig_arst = ff.sig_set;
+ ff_set.pol_arst = ff.pol_set;
+ ff_set.val_arst = Const(State::S1, ff.width);
+ ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width);
+ ff_set.is_fine = ff.is_fine;
+
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = ff.width;
+ ff_sel.has_sr = true;
+ ff_sel.pol_clr = ff.pol_clr;
+ ff_sel.pol_set = ff.pol_set;
+ ff_sel.sig_clr = ff.sig_clr;
+ ff_sel.sig_set = ff.sig_set;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_sel.val_init = Const(initsel, ff.width);
+ ff_sel.is_fine = ff.is_fine;
+
+ if (!ff.is_fine)
+ ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_clr);
+ legalize_ff(ff_set);
+ legalize_ff(ff_sel);
+ }
+
+ void legalize_dff(FfData &ff) {
+ if (!try_flip(ff, supported_dff)) {
+ if (!supported_dff)
+ fail_ff(ff, "D flip-flops are not supported");
+ else
+ fail_ff(ff, "initialized D flip-flops are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DFF is supported with this init val. Just pick a type.
+ if (ff.has_ce && !(supported_dffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFF] & initmask) {
+ legalize_finish(ff);
return;
- } else if (ff_type == FF_SR) {
- if (supported_cells[FF_ADLATCH0] & initmask || supported_cells[FF_ADLATCH1] & flip_initmask(initmask)) {
- // Convert to ADLATCH0. May get converted to ADLATCH1.
- ff_type = FF_ADLATCH0;
- sig_e = sig_s;
- sig_d = State::S1;
- if (ff_neg & NEG_S) {
- ff_neg &= ~NEG_S;
- ff_neg |= NEG_E;
- }
- continue;
- } else if (supported_cells[FF_DLATCHSR] & initmask) {
- // Upgrade to DLATCHSR.
- ff_type = FF_DLATCHSR;
- sig_e = State::S0;
- sig_d = State::Sx;
- break;
- } else if (supported_dffsr & initmask) {
- // Upgrade to DFFSR. May get further upgraded to DFFSRE.
- ff_type = FF_DFFSR;
- sig_c = State::S0;
- sig_d = State::Sx;
- continue;
- } else if (supported_sr & flip_initmask(initmask)) {
- goto flip_dqisr;
- } else {
- if (!supported_sr)
- reason = "sr latches are not supported";
- else
- reason = "initialized sr latches are not supported";
- goto error;
- }
- } else if (ff_type == FF_DLATCH) {
- if (!(supported_dlatch & initmask)) {
- // This init value is not supported at all...
- if (supported_dlatch & flip_initmask(initmask))
- goto flip_dqi;
-
- if ((sig_d == State::S0 && (supported_adff0 & initmask)) ||
- (sig_d == State::S1 && (supported_adff1 & initmask)) ||
- (sig_d == State::S0 && (supported_adff1 & flip_initmask(initmask))) ||
- (sig_d == State::S1 && (supported_adff0 & flip_initmask(initmask)))
- ) {
- // Special case: const-D dlatch can be converted into adff with const clock.
- ff_type = (sig_d == State::S0) ? FF_ADFF0 : FF_ADFF1;
- if (ff_neg & NEG_E) {
- ff_neg &= ~NEG_E;
- ff_neg |= NEG_R;
- }
- sig_r = sig_e;
- sig_d = State::Sx;
- sig_c = State::S1;
- continue;
- }
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFF] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFF] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ // Nope. Will need to add enable and go the DFFE route.
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_DFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_srst();
+ ff.ce_over_srst = true;
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
- if (!supported_dlatch)
- reason = "dlatch are not supported";
- else
- reason = "initialized dlatch are not supported";
- goto error;
- }
+ void legalize_sdffce(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
- // Some DLATCH is supported with this init val. Just pick a type.
- if (supported_cells[FF_ADLATCH0] & initmask) {
- ff_type = FF_ADLATCH0;
- sig_r = State::S0;
- break;
- }
- if (supported_cells[FF_ADLATCH1] & initmask) {
- ff_type = FF_ADLATCH1;
- sig_r = State::S0;
- break;
- }
- if (supported_cells[FF_DLATCHSR] & initmask) {
- ff_type = FF_DLATCHSR;
- sig_r = State::S0;
- sig_s = State::S0;
- break;
- }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.convert_ce_over_srst(false);
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_sdff(FfData &ff) {
+ if (!try_flip(ff, supported_sdff)) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (!ff.has_ce) {
+ if (supported_cells[FF_SDFF] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_ce();
+ ff.ce_over_srst = true;
+ } else {
log_assert(0);
- } else if (ff_type == FF_ADLATCH0 || ff_type == FF_ADLATCH1) {
- if (supported_cells[FF_DLATCHSR] & initmask) {
- if (ff_type == FF_ADLATCH1) {
- sig_s = sig_r;
- sig_r = State::S0;
- if (ff_neg & NEG_R) {
- ff_neg &= ~NEG_R;
- ff_neg |= NEG_S;
- }
- } else {
- sig_s = State::S0;
- }
- ff_type = FF_DLATCHSR;
- break;
- }
- FfType flip_type = ff_type == FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0;
- if ((supported_cells[flip_type] | supported_cells[FF_DLATCHSR]) & flip_initmask(initmask)) {
- ff_type = flip_type;
- goto flip_dqi;
- }
+ }
+ } else {
+ log_assert(!ff.ce_over_srst);
+ if (supported_cells[FF_SDFFE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.convert_ce_over_srst(true);
+ } else if (supported_cells[FF_SDFF] & initmask) {
+ ff.unmap_ce();
+ } else {
+ log_assert(0);
+ }
+ }
+ legalize_finish(ff);
+ }
- if (!supported_cells[FF_ADLATCH0] && !supported_cells[FF_ADLATCH1] && !supported_cells[FF_DLATCHSR]) {
- reason = "dlatch with async set or reset are not supported";
- goto error;
- }
- if (!(supported_dlatch & ~INIT_X)) {
- reason = "initialized dlatch are not supported";
- goto error;
- }
+ void legalize_adff(FfData &ff) {
+ if (!try_flip(ff, supported_adff)) {
+ if (!supported_adff)
+ fail_ff(ff, "dffs with async set or reset are not supported");
+ if (!(supported_dff & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized dffs are not supported");
+
+ // If we got here, initialized dff is supported, but not this
+ // particular reset+init combination (nor its negation).
+ // The only hope left is breaking down to adff + dff + dlatch + mux.
+
+ if (!((supported_rlatch) & (INIT_0_R1 | INIT_1_R0)))
+ fail_ff(ff, "unsupported initial value and async reset value combination");
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ emulate_split_init_arst(ff);
+ return;
+ }
- // If we got here, initialized dlatch is supported, but not this
- // particular reset+init combination (nor its negation).
- // The only hope left is breaking down to adff + dff + dlatch + mux.
-
- log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
- initvals.remove_init(sig_q[0]);
- Wire *adlatch_q = cell->module->addWire(NEW_ID);
- Wire *dlatch_q = cell->module->addWire(NEW_ID);
- Wire *sel_q = cell->module->addWire(NEW_ID);
- initvals.set_init(SigBit(dlatch_q, 0), initval);
- initvals.set_init(SigBit(sel_q, 0), State::S0);
- Cell *cell_dlatch;
- Cell *cell_adlatch;
- Cell *cell_sel;
- cell_dlatch = cell->module->addDlatchGate(NEW_ID, sig_e, sig_d, dlatch_q, !(ff_neg & NEG_E));
- cell_adlatch = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch_q, ff_type == FF_ADLATCH1, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
- cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
- cell->module->addMuxGate(NEW_ID, dlatch_q, adlatch_q, sel_q, sig_q);
-
- // Bye, cell.
- cell->module->remove(cell);
- handle_ff(cell_dlatch);
- handle_ff(cell_adlatch);
- handle_ff(cell_sel);
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_adffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ADFF] & initmask) {
+ legalize_finish(ff);
return;
- } else if (ff_type == FF_DLATCHSR) {
- if (supported_cells[FF_DLATCHSR] & flip_initmask(initmask)) {
- goto flip_dqisr;
- }
- // No native DFFSR. However, if we can conjure
- // a SR latch and ADFF, it can still be emulated.
- int flipmask = flip_initmask(initmask);
- bool init0 = true;
- bool init1 = true;
- State initsel = State::Sx;
- if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && ((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && supported_sr) {
- // OK
- } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_0)) {
- init1 = false;
- initsel = State::S0;
- } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_1)) {
- init0 = false;
- initsel = State::S1;
- } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_1)) {
- init1 = false;
- initsel = State::S0;
- } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_0)) {
- init0 = false;
- initsel = State::S1;
- } else {
- if (!supported_cells[FF_DLATCHSR])
- reason = "dlatch with async set and reset are not supported";
- else
- reason = "initialized dlatch with async set and reset are not supported";
- goto error;
- }
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
+
+ void legalize_aldff(FfData &ff) {
+ if (!try_flip(ff, supported_aldff)) {
+ ff.aload_to_sr();
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_aldffe & initmask)) {
+ ff.unmap_ce();
+ }
- log_warning("Emulating async set + reset with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
- initvals.remove_init(sig_q[0]);
- Wire *adlatch0_q = cell->module->addWire(NEW_ID);
- Wire *adlatch1_q = cell->module->addWire(NEW_ID);
- Wire *sel_q = cell->module->addWire(NEW_ID);
- if (init0)
- initvals.set_init(SigBit(adlatch0_q, 0), initval);
- if (init1)
- initvals.set_init(SigBit(adlatch1_q, 0), initval);
- initvals.set_init(SigBit(sel_q, 0), initsel);
- Cell *cell_adlatch0;
- Cell *cell_adlatch1;
- Cell *cell_sel;
- cell_adlatch0 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch0_q, false, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
- cell_adlatch1 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_s, sig_d, adlatch1_q, true, !(ff_neg & NEG_E), !(ff_neg & NEG_S));
- cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
- cell->module->addMuxGate(NEW_ID, adlatch0_q, adlatch1_q, sel_q, sig_q);
-
- // Bye, cell.
- cell->module->remove(cell);
- handle_ff(cell_adlatch0);
- handle_ff(cell_adlatch1);
- handle_ff(cell_sel);
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ALDFF] & initmask) {
+ legalize_finish(ff);
return;
- } else if (ff_type == FF_SDFF0 || ff_type == FF_SDFF1 || ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1) {
- bool has_set = ff_type == FF_SDFF1 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE1;
- bool has_en = ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1;
- bool has_ce = ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1;
-
- if (has_en) {
- if (kill_ce || kill_srst) {
- ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
- goto unmap_enable;
- }
- } else if (has_ce) {
- if (kill_ce || kill_srst)
- goto unmap_srst;
- } else {
- log_assert(!kill_ce);
- if (kill_srst)
- goto unmap_srst;
- }
+ }
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
- if (!has_ce) {
- if (!has_en && (supported_cells[has_set ? FF_SDFFE1 : FF_SDFFE0] & initmask)) {
- // Just add enable.
- sig_e = State::S1;
- ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
- break;
- }
- if (!has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
- // Just add enable.
- sig_e = State::S1;
- ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
- break;
- }
- if (has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
- // Convert sdffe to sdffce
- if (!(ff_neg & NEG_E)) {
- if (!(ff_neg & NEG_R))
- sig_e = cell->module->OrGate(NEW_ID, sig_e, sig_r);
- else
- sig_e = cell->module->OrnotGate(NEW_ID, sig_e, sig_r);
- } else {
- if (!(ff_neg & NEG_R))
- sig_e = cell->module->AndnotGate(NEW_ID, sig_e, sig_r);
- else
- sig_e = cell->module->AndGate(NEW_ID, sig_e, sig_r);
- }
- ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
- break;
- }
- if (has_en && (supported_cells[has_set ? FF_SDFF1 : FF_SDFF0] & initmask)) {
- // Unmap enable.
- ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
- goto unmap_enable;
- }
- log_assert(!((has_set ? supported_sdff1 : supported_sdff0) & initmask));
- } else {
- if ((has_set ? supported_sdff1 : supported_sdff0) & initmask) {
- // Convert sdffce to sdffe, which may be further converted to sdff.
- if (!(ff_neg & NEG_R)) {
- if (!(ff_neg & NEG_E))
- sig_r = cell->module->AndGate(NEW_ID, sig_r, sig_e);
- else
- sig_r = cell->module->AndnotGate(NEW_ID, sig_r, sig_e);
- } else {
- if (!(ff_neg & NEG_E))
- sig_r = cell->module->OrnotGate(NEW_ID, sig_r, sig_e);
- else
- sig_r = cell->module->OrGate(NEW_ID, sig_r, sig_e);
- }
- ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
- continue;
- }
+ void legalize_dffsr(FfData &ff) {
+ if (!try_flip(ff, supported_dffsr)) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFFSR] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+
+ log_assert(supported_cells[FF_DFFSRE] & initmask);
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatch(FfData &ff) {
+ if (!try_flip(ff, supported_dlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DLATCH is supported with this init val. Just pick a type.
+ if (supported_cells[FF_DLATCH] & initmask) {
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ADLATCH] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_clk();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ legalize_finish(ff);
+ } else if (supported_sr & initmask) {
+ ff.aload_to_sr();
+ legalize_sr(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_adlatch(FfData &ff) {
+ if (!try_flip(ff, supported_adlatch)) {
+ if (!supported_adlatch)
+ fail_ff(ff, "D latches with async set or reset are not supported");
+ if (!(supported_dlatch & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized D latches are not supported");
+
+ // If we got here, initialized dlatch is supported, but not this
+ // particular reset+init combination (nor its negation).
+ // The only hope left is breaking down to adlatch + dlatch + dlatch + mux.
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ ff.remove();
+
+ emulate_split_init_arst(ff);
+ return;
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_ADLATCH] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.arst_to_sr();
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatchsr(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_DLATCHSR])) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_rlatch(FfData &ff) {
+ if (!try_flip(ff, supported_rlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ if (((supported_dlatch_plain & 7) * 0x111) & initmask) {
+ ff.arst_to_aload();
+ legalize_dlatch(ff);
+ } else if (supported_sr & initmask) {
+ ff.arst_to_sr();
+ legalize_sr(ff);
+ } else if (supported_adff & initmask) {
+ ff.add_dummy_clk();
+ legalize_adff(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_sr(FfData &ff) {
+ if (!try_flip(ff, supported_sr)) {
+ if (!supported_sr)
+ fail_ff(ff, "sr latches are not supported");
+ else
+ fail_ff(ff, "initialized sr latches are not supported");
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SR] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ // Upgrade to DLATCHSR.
+ ff.add_dummy_aload();
+ } else if (supported_cells[FF_DFFSR] & initmask) {
+ // Upgrade to DFFSR.
+ ff.add_dummy_clk();
+ } else if (supported_cells[FF_DFFSRE] & initmask) {
+ // Upgrade to DFFSRE.
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_ADLATCH] & (initmask << 4)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S1;
+ ff.val_arst = State::S0;
+ } else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S0;
+ ff.val_arst = State::S1;
+ ff.remove_init();
+ Wire *new_q = ff.module->addWire(NEW_ID);
+ if (ff.is_fine)
+ ff.module->addNotGate(NEW_ID, new_q, ff.sig_q);
+ else
+ ff.module->addNot(NEW_ID, new_q, ff.sig_q);
+ ff.sig_q = new_q;
+ if (ff.val_init == State::S0)
+ ff.val_init = State::S1;
+ else if (ff.val_init == State::S1)
+ ff.val_init = State::S0;
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void fixup_reset_x(FfData &ff, int supported) {
+ for (int i = 0; i < ff.width; i++) {
+ int mask;
+ if (ff.val_init[i] == State::S0)
+ mask = INIT_0;
+ else if (ff.val_init[i] == State::S1)
+ mask = INIT_1;
+ else
+ mask = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_arst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_arst[i] = State::S1;
}
- // Alright, so this particular combination of initval and
- // resetval is not natively supported. First, try flipping
- // them both to see whether this helps.
- if ((has_set ? supported_sdff0 : supported_sdff1) & flip_initmask(initmask)) {
- // Checks out, do it.
- ff_type = has_ce ? (has_set ? FF_SDFFCE0 : FF_SDFFCE1) : has_en ? (has_set ? FF_SDFFE0 : FF_SDFFE1) : (has_set ? FF_SDFF0 : FF_SDFF1);
- goto flip_dqi;
+ }
+ if (ff.has_srst) {
+ if (ff.val_srst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_srst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_srst[i] = State::S1;
}
+ }
+ }
+ }
- // Nope. No way to get SDFF* of the right kind, so unmap it.
- // For SDFFE, the enable has to be unmapped first.
- if (has_en) {
- ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
- goto unmap_enable;
- }
-unmap_srst:
- if (has_ce)
- ff_type = FF_DFFE;
- else
- ff_type = FF_DFF;
- if (ff_neg & NEG_R)
- sig_d = cell->module->MuxGate(NEW_ID, has_set ? State::S1 : State::S0, sig_d[0], sig_r[0]);
+ void legalize_ff(FfData &ff) {
+ if (ff.has_gclk)
+ return;
+
+ // TODO: consider supporting coarse as well.
+ if (!ff.is_fine)
+ return;
+
+ if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince)
+ ff.unmap_ce();
+ if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst)
+ ff.unmap_srst();
+
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ legalize_dffsr(ff);
+ } else if (ff.has_aload) {
+ legalize_aldff(ff);
+ } else if (ff.has_arst) {
+ legalize_adff(ff);
+ } else if (ff.has_srst) {
+ if (ff.has_ce && ff.ce_over_srst)
+ legalize_sdffce(ff);
else
- sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], has_set ? State::S1 : State::S0, sig_r[0]);
- ff_neg &= ~NEG_R;
- sig_r = SigSpec();
- kill_srst = false;
- continue;
+ legalize_sdff(ff);
+ } else {
+ legalize_dff(ff);
+ }
+ } else if (ff.has_aload) {
+ if (ff.has_sr) {
+ legalize_dlatchsr(ff);
+ } else if (ff.has_arst) {
+ legalize_adlatch(ff);
+ } else {
+ legalize_dlatch(ff);
+ }
+ } else {
+ if (ff.has_sr) {
+ legalize_sr(ff);
+ } else if (ff.has_arst) {
+ legalize_rlatch(ff);
} else {
log_assert(0);
}
}
-cell_ok:
+ }
+
+ void flip_pol(FfData &ff, SigSpec &sig, bool &pol) {
+ if (sig == State::S0) {
+ sig = State::S1;
+ } else if (sig == State::S1) {
+ sig = State::S0;
+ } else if (ff.is_fine) {
+ sig = ff.module->NotGate(NEW_ID, sig);
+ } else {
+ sig = ff.module->Not(NEW_ID, sig);
+ }
+ pol = !pol;
+ }
+ void legalize_finish(FfData &ff) {
+ int ff_type = get_ff_type(ff);
+ int initmask = get_initmask(ff);
+ log_assert(supported_cells[ff_type] & initmask);
+ int ff_neg = 0;
+ if (ff.has_sr) {
+ if (!ff.pol_clr)
+ ff_neg |= NEG_R;
+ if (!ff.pol_set)
+ ff_neg |= NEG_S;
+ }
+ if (ff.has_arst) {
+ if (!ff.pol_arst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_srst) {
+ if (!ff.pol_srst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_aload) {
+ if (!ff.pol_aload)
+ ff_neg |= NEG_L;
+ }
+ if (ff.has_clk) {
+ if (!ff.pol_clk)
+ ff_neg |= NEG_C;
+ }
+ if (ff.has_ce) {
+ if (!ff.pol_ce)
+ ff_neg |= NEG_CE;
+ }
if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) {
// Cell is supported, but not with those polarities.
// Will need to add some inverters.
@@ -917,182 +998,27 @@ cell_ok:
if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask)
break;
log_assert(xneg < NUM_NEG);
- if (xneg & NEG_R)
- sig_r = cell->module->NotGate(NEW_ID, sig_r[0]);
- if (xneg & NEG_S)
- sig_s = cell->module->NotGate(NEW_ID, sig_s[0]);
- if (xneg & NEG_E)
- sig_e = cell->module->NotGate(NEW_ID, sig_e[0]);
+ if (xneg & NEG_CE)
+ flip_pol(ff, ff.sig_ce, ff.pol_ce);
+ if (ff.has_sr) {
+ if (xneg & NEG_R)
+ flip_pol(ff, ff.sig_clr, ff.pol_clr);
+ if (xneg & NEG_S)
+ flip_pol(ff, ff.sig_set, ff.pol_set);
+ }
+ if (ff.has_arst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_arst, ff.pol_arst);
+ if (ff.has_srst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_srst, ff.pol_srst);
+ if (xneg & NEG_L)
+ flip_pol(ff, ff.sig_aload, ff.pol_aload);
if (xneg & NEG_C)
- sig_c = cell->module->NotGate(NEW_ID, sig_c[0]);
+ flip_pol(ff, ff.sig_clk, ff.pol_clk);
ff_neg ^= xneg;
}
- cell->unsetPort(ID::D);
- cell->unsetPort(ID::Q);
- cell->unsetPort(ID::C);
- cell->unsetPort(ID::E);
- cell->unsetPort(ID::S);
- cell->unsetPort(ID::R);
- switch (ff_type) {
- case FF_DFF:
- cell->type = IdString(stringf("$_DFF_%c_",
- (ff_neg & NEG_C) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- break;
- case FF_DFFE:
- cell->type = IdString(stringf("$_DFFE_%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::E, sig_e);
- break;
- case FF_ADFF0:
- case FF_ADFF1:
- cell->type = IdString(stringf("$_DFF_%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_ADFF1) ? '1' : '0'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_ADFFE0:
- case FF_ADFFE1:
- cell->type = IdString(stringf("$_DFFE_%c%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_ADFFE1) ? '1' : '0',
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_DFFSR:
- cell->type = IdString(stringf("$_DFFSR_%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_S) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::S, sig_s);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_DFFSRE:
- cell->type = IdString(stringf("$_DFFSRE_%c%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_S) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::S, sig_s);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_SDFF0:
- case FF_SDFF1:
- cell->type = IdString(stringf("$_SDFF_%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_SDFF1) ? '1' : '0'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_SDFFE0:
- case FF_SDFFE1:
- cell->type = IdString(stringf("$_SDFFE_%c%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_SDFFE1) ? '1' : '0',
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_SDFFCE0:
- case FF_SDFFCE1:
- cell->type = IdString(stringf("$_SDFFCE_%c%c%c%c_",
- (ff_neg & NEG_C) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_SDFFCE1) ? '1' : '0',
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::C, sig_c);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_DLATCH:
- cell->type = IdString(stringf("$_DLATCH_%c_",
- (ff_neg & NEG_E) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::E, sig_e);
- break;
- case FF_ADLATCH0:
- case FF_ADLATCH1:
- cell->type = IdString(stringf("$_DLATCH_%c%c%c_",
- (ff_neg & NEG_E) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P',
- (ff_type == FF_ADLATCH1) ? '1' : '0'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_DLATCHSR:
- cell->type = IdString(stringf("$_DLATCHSR_%c%c%c_",
- (ff_neg & NEG_E) ? 'N' : 'P',
- (ff_neg & NEG_S) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P'
- ));
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::E, sig_e);
- cell->setPort(ID::S, sig_s);
- cell->setPort(ID::R, sig_r);
- break;
- case FF_SR:
- cell->type = IdString(stringf("$_SR_%c%c_",
- (ff_neg & NEG_S) ? 'N' : 'P',
- (ff_neg & NEG_R) ? 'N' : 'P'
- ));
- cell->setPort(ID::Q, sig_q);
- cell->setPort(ID::S, sig_s);
- cell->setPort(ID::R, sig_r);
- break;
- default:
- log_assert(0);
- }
- return;
-
-error:
- log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type), reason);
+ fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]);
+ ff.emit();
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@@ -1114,79 +1040,83 @@ error:
if (args[argidx] == "-cell" && argidx + 2 < args.size()) {
std::string celltype = args[++argidx];
std::string inittype = args[++argidx];
- enum FfType ff_type[2] = {NUM_FFTYPES, NUM_FFTYPES};
+ enum FfType ff_type;
char pol_c = 0;
- char pol_e = 0;
+ char pol_l = 0;
char pol_s = 0;
char pol_r = 0;
+ char pol_ce = 0;
char srval = 0;
if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
- ff_type[0] = FF_SR;
+ ff_type = FF_SR;
pol_s = celltype[5];
pol_r = celltype[6];
} else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') {
- ff_type[0] = FF_DFF;
+ ff_type = FF_DFF;
pol_c = celltype[6];
} else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
- ff_type[0] = FF_DFFE;
+ ff_type = FF_DFFE;
pol_c = celltype[7];
- pol_e = celltype[8];
+ pol_ce = celltype[8];
} else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
- ff_type[0] = FF_ADFF0;
- ff_type[1] = FF_ADFF1;
+ ff_type = FF_ADFF;
pol_c = celltype[6];
pol_r = celltype[7];
srval = celltype[8];
} else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') {
- ff_type[0] = FF_ADFFE0;
- ff_type[1] = FF_ADFFE1;
+ ff_type = FF_ADFFE;
pol_c = celltype[7];
pol_r = celltype[8];
srval = celltype[9];
- pol_e = celltype[10];
+ pol_ce = celltype[10];
+ } else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type = FF_ALDFF;
+ pol_c = celltype[8];
+ pol_l = celltype[9];
+ } else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type = FF_ALDFFE;
+ pol_c = celltype[9];
+ pol_l = celltype[10];
+ pol_ce = celltype[11];
} else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
- ff_type[0] = FF_DFFSR;
+ ff_type = FF_DFFSR;
pol_c = celltype[8];
pol_s = celltype[9];
pol_r = celltype[10];
} else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') {
- ff_type[0] = FF_DFFSRE;
+ ff_type = FF_DFFSRE;
pol_c = celltype[9];
pol_s = celltype[10];
pol_r = celltype[11];
- pol_e = celltype[12];
+ pol_ce = celltype[12];
} else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
- ff_type[0] = FF_SDFF0;
- ff_type[1] = FF_SDFF1;
+ ff_type = FF_SDFF;
pol_c = celltype[7];
pol_r = celltype[8];
srval = celltype[9];
} else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
- ff_type[0] = FF_SDFFE0;
- ff_type[1] = FF_SDFFE1;
+ ff_type = FF_SDFFE;
pol_c = celltype[8];
pol_r = celltype[9];
srval = celltype[10];
- pol_e = celltype[11];
+ pol_ce = celltype[11];
} else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
- ff_type[0] = FF_SDFFCE0;
- ff_type[1] = FF_SDFFCE1;
+ ff_type = FF_SDFFCE;
pol_c = celltype[9];
pol_r = celltype[10];
srval = celltype[11];
- pol_e = celltype[12];
+ pol_ce = celltype[12];
} else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
- ff_type[0] = FF_DLATCH;
- pol_e = celltype[9];
+ ff_type = FF_DLATCH;
+ pol_l = celltype[9];
} else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') {
- ff_type[0] = FF_ADLATCH0;
- ff_type[1] = FF_ADLATCH1;
- pol_e = celltype[9];
+ ff_type = FF_ADLATCH;
+ pol_l = celltype[9];
pol_r = celltype[10];
srval = celltype[11];
} else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') {
- ff_type[0] = FF_DLATCHSR;
- pol_e = celltype[11];
+ ff_type = FF_DLATCHSR;
+ pol_l = celltype[11];
pol_s = celltype[12];
pol_r = celltype[13];
} else {
@@ -1197,9 +1127,10 @@ unrecognized:
int match = 0;
for (auto pair : {
std::make_pair(pol_c, NEG_C),
- std::make_pair(pol_e, NEG_E),
+ std::make_pair(pol_l, NEG_L),
std::make_pair(pol_s, NEG_S),
std::make_pair(pol_r, NEG_R),
+ std::make_pair(pol_ce, NEG_CE),
}) {
if (pair.first == 'N') {
mask |= pair.second;
@@ -1210,40 +1141,33 @@ unrecognized:
goto unrecognized;
}
}
+ int initmask;
+ if (inittype == "x") {
+ initmask = 0x111;
+ } else if (inittype == "0") {
+ initmask = 0x333;
+ } else if (inittype == "1") {
+ initmask = 0x555;
+ } else if (inittype == "r") {
+ if (srval == 0)
+ log_error("init type r not valid for cell type %s.\n", celltype.c_str());
+ initmask = 0x537;
+ } else if (inittype == "01") {
+ initmask = 0x777;
+ } else {
+ log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
+ }
if (srval == '0') {
- ff_type[1] = NUM_FFTYPES;
+ initmask &= 0x0ff;
} else if (srval == '1') {
- ff_type[0] = NUM_FFTYPES;
+ initmask &= 0xf0f;
} else if (srval != 0 && srval != '?') {
goto unrecognized;
}
- for (int i = 0; i < 2; i++) {
- if (ff_type[i] == NUM_FFTYPES)
- continue;
- int initmask;
- if (inittype == "x") {
- initmask = INIT_X;
- } else if (inittype == "0") {
- initmask = INIT_X | INIT_0;
- } else if (inittype == "1") {
- initmask = INIT_X | INIT_1;
- } else if (inittype == "r") {
- if (srval == 0)
- log_error("init type r not valid for cell type %s.\n", celltype.c_str());
- if (i == 0)
- initmask = INIT_X | INIT_0;
- else
- initmask = INIT_X | INIT_1;
- } else if (inittype == "01") {
- initmask = INIT_X | INIT_0 | INIT_1;
- } else {
- log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
- }
- for (int neg = 0; neg < NUM_NEG; neg++)
- if ((neg & mask) == match)
- supported_cells_neg[ff_type[i]][neg] |= initmask;
- supported_cells[ff_type[i]] |= initmask;
- }
+ for (int neg = 0; neg < NUM_NEG; neg++)
+ if ((neg & mask) == match)
+ supported_cells_neg[ff_type][neg] |= initmask;
+ supported_cells[ff_type] |= initmask;
continue;
} else if (args[argidx] == "-mince" && argidx + 1 < args.size()) {
mince = atoi(args[++argidx].c_str());
@@ -1256,13 +1180,21 @@ unrecognized:
}
extra_args(args, argidx, design);
supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE];
- supported_adff0 = supported_cells[FF_ADFF0] | supported_cells[FF_ADFFE0] | supported_dffsr;
- supported_adff1 = supported_cells[FF_ADFF1] | supported_cells[FF_ADFFE1] | supported_dffsr;
- supported_sdff0 = supported_cells[FF_SDFF0] | supported_cells[FF_SDFFE0] | supported_cells[FF_SDFFCE0];
- supported_sdff1 = supported_cells[FF_SDFF1] | supported_cells[FF_SDFFE1] | supported_cells[FF_SDFFCE1];
- supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1;
- supported_sr = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR] | supported_cells[FF_ADLATCH0] | flip_initmask(supported_cells[FF_ADLATCH1]);
- supported_dlatch = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH0] | supported_cells[FF_ADLATCH1] | supported_cells[FF_DLATCHSR];
+ supported_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr;
+ supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff;
+ supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff;
+ supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR];
+ supported_sr = supported_sr_plain;
+ supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111;
+ supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111;
+ supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE];
+ supported_dlatch = supported_dlatch_plain | supported_sr_plain;
+ supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111;
+ supported_adlatch = supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR];
for (auto module : design->selected_modules())
{
@@ -1277,36 +1209,20 @@ unrecognized:
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
- if (cell->hasPort(ID::C) && cell->hasPort(ID::E)) {
- SigSpec sig = cell->getPort(ID::E);
- // Do not count const enable signals.
- if (GetSize(sig) == 1 && sig[0].wire)
- ce_used[sig[0]]++;
- }
- if (cell->type.str().substr(0, 6) == "$_SDFF") {
- SigSpec sig = cell->getPort(ID::R);
- // Do not count const srst signals.
- if (GetSize(sig) == 1 && sig[0].wire)
- srst_used[sig[0]]++;
- }
+ FfData ff(&initvals, cell);
+ if (ff.has_ce && ff.sig_ce[0].wire)
+ ce_used[ff.sig_ce[0]] += ff.width;
+ if (ff.has_srst && ff.sig_srst[0].wire)
+ srst_used[ff.sig_srst[0]] += ff.width;
}
}
-
- // First gather FF cells, then iterate over them later.
- // We may need to split an FF into several cells.
- std::vector<Cell *> ff_cells;
-
for (auto cell : module->selected_cells())
{
- // Early exit for non-FFs.
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
-
- ff_cells.push_back(cell);
+ FfData ff(&initvals, cell);
+ legalize_ff(ff);
}
-
- for (auto cell: ff_cells)
- handle_ff(cell);
}
sigmap.clear();
diff --git a/tests/techmap/dfflegalize_adff_init.ys b/tests/techmap/dfflegalize_adff_init.ys
index 7764e15a5..27798ac52 100644
--- a/tests/techmap/dfflegalize_adff_init.ys
+++ b/tests/techmap/dfflegalize_adff_init.ys
@@ -144,9 +144,9 @@ design -load orig
dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_DLATCH_P_ 1
select -assert-count 2 adff0/t:$_NOT_
-select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 13 adff1/t:$_NOT_
select -assert-count 3 adffe0/t:$_NOT_
-select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 18 adffe1/t:$_NOT_
select -assert-count 0 adff0/t:$_MUX_
select -assert-count 3 adff1/t:$_MUX_
select -assert-count 0 adffe0/t:$_MUX_
@@ -164,9 +164,9 @@ select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t
design -load orig
dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1
-select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 13 adff0/t:$_NOT_
select -assert-count 8 adff1/t:$_NOT_
-select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 18 adffe0/t:$_NOT_
select -assert-count 11 adffe1/t:$_NOT_
select -assert-count 3 adff0/t:$_MUX_
select -assert-count 0 adff1/t:$_MUX_
@@ -185,31 +185,27 @@ select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t
design -load orig
dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1
-select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 10 adff0/t:$_NOT_
select -assert-count 2 adff1/t:$_NOT_
-select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 14 adffe0/t:$_NOT_
select -assert-count 3 adffe1/t:$_NOT_
select -assert-count 3 adff0/t:$_MUX_
select -assert-count 0 adff1/t:$_MUX_
select -assert-count 4 adffe0/t:$_MUX_
select -assert-count 0 adffe1/t:$_MUX_
-select -assert-count 6 adff0/t:$_DFFE_PP1P_
+select -assert-count 9 adff0/t:$_DFFE_PP1P_
select -assert-count 3 adff1/t:$_DFFE_PP1P_
-select -assert-count 8 adffe0/t:$_DFFE_PP1P_
+select -assert-count 12 adffe0/t:$_DFFE_PP1P_
select -assert-count 4 adffe1/t:$_DFFE_PP1P_
-select -assert-count 3 adff0/t:$_DLATCH_P_
-select -assert-count 0 adff1/t:$_DLATCH_P_
-select -assert-count 4 adffe0/t:$_DLATCH_P_
-select -assert-count 0 adffe1/t:$_DLATCH_P_
-select -assert-none t:$_DFFE_PP1P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+select -assert-none t:$_DFFE_PP1P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
design -load orig
dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1
select -assert-count 8 adff0/t:$_NOT_
-select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 13 adff1/t:$_NOT_
select -assert-count 11 adffe0/t:$_NOT_
-select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 18 adffe1/t:$_NOT_
select -assert-count 0 adff0/t:$_MUX_
select -assert-count 3 adff1/t:$_MUX_
select -assert-count 0 adffe0/t:$_MUX_
diff --git a/tests/techmap/dfflegalize_adlatch_init.ys b/tests/techmap/dfflegalize_adlatch_init.ys
index 7b22ea0c0..a55082d1d 100644
--- a/tests/techmap/dfflegalize_adlatch_init.ys
+++ b/tests/techmap/dfflegalize_adlatch_init.ys
@@ -45,7 +45,7 @@ select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
design -load orig
dfflegalize -cell $_DLATCH_PP0_ 1
-select -assert-count 16 adlatch0/t:$_NOT_
+select -assert-count 13 adlatch0/t:$_NOT_
select -assert-count 8 adlatch1/t:$_NOT_
select -assert-count 3 adlatch0/t:$_MUX_
select -assert-count 0 adlatch1/t:$_MUX_
@@ -68,7 +68,7 @@ design -load orig
dfflegalize -cell $_DLATCH_PP1_ 1
select -assert-count 8 adlatch0/t:$_NOT_
-select -assert-count 16 adlatch1/t:$_NOT_
+select -assert-count 13 adlatch1/t:$_NOT_
select -assert-count 0 adlatch0/t:$_MUX_
select -assert-count 3 adlatch1/t:$_MUX_
select -assert-count 3 adlatch0/t:$_DLATCH_PP1_
diff --git a/tests/techmap/dfflegalize_dff.ys b/tests/techmap/dfflegalize_dff.ys
index 63ab47865..4022da5f4 100644
--- a/tests/techmap/dfflegalize_dff.ys
+++ b/tests/techmap/dfflegalize_dff.ys
@@ -237,25 +237,18 @@ select -assert-count 2 sdff0/t:$_NOT_
select -assert-count 8 sdff1/t:$_NOT_
select -assert-count 2 sdffe0/t:$_NOT_
select -assert-count 10 sdffe1/t:$_NOT_
-select -assert-count 2 sdffce0/t:$_NOT_
-select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
select -assert-count 0 dff/t:$_MUX_
select -assert-count 3 dffe/t:$_MUX_
select -assert-count 0 sdff0/t:$_MUX_
select -assert-count 0 sdff1/t:$_MUX_
select -assert-count 4 sdffe0/t:$_MUX_
select -assert-count 4 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* sdffce1/* %u %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
# Convert everything to SDFFEs.
diff --git a/tests/techmap/dfflegalize_dff_init.ys b/tests/techmap/dfflegalize_dff_init.ys
index 741ac39d0..ccde4c324 100644
--- a/tests/techmap/dfflegalize_dff_init.ys
+++ b/tests/techmap/dfflegalize_dff_init.ys
@@ -476,7 +476,7 @@ select -assert-count 2 sdff0/t:$_NOT_
select -assert-count 1 sdff1/t:$_NOT_
select -assert-count 2 sdffe0/t:$_NOT_
select -assert-count 1 sdffe1/t:$_NOT_
-select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
select -assert-count 1 sdffce1/t:$_NOT_
select -assert-count 0 dff/t:$_MUX_
select -assert-count 3 dffe/t:$_MUX_
@@ -484,14 +484,10 @@ select -assert-count 0 sdff0/t:$_MUX_
select -assert-count 3 sdff1/t:$_MUX_
select -assert-count 4 sdffe0/t:$_MUX_
select -assert-count 8 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
select -assert-count 8 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
design -load orig
dfflegalize -cell $_SDFF_PP0_ 1
@@ -503,7 +499,7 @@ select -assert-count 8 sdff1/t:$_NOT_
select -assert-count 9 sdffe0/t:$_NOT_
select -assert-count 10 sdffe1/t:$_NOT_
select -assert-count 9 sdffce0/t:$_NOT_
-select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
select -assert-count 0 dff/t:$_MUX_
select -assert-count 3 dffe/t:$_MUX_
select -assert-count 3 sdff0/t:$_MUX_
@@ -511,13 +507,9 @@ select -assert-count 0 sdff1/t:$_MUX_
select -assert-count 8 sdffe0/t:$_MUX_
select -assert-count 4 sdffe1/t:$_MUX_
select -assert-count 8 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce1/t:$_MUX_
select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
design -load orig
dfflegalize -cell $_SDFF_PP1_ 0
@@ -529,7 +521,7 @@ select -assert-count 2 sdff1/t:$_NOT_
select -assert-count 1 sdffe0/t:$_NOT_
select -assert-count 2 sdffe1/t:$_NOT_
select -assert-count 1 sdffce0/t:$_NOT_
-select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
select -assert-count 0 dff/t:$_MUX_
select -assert-count 3 dffe/t:$_MUX_
select -assert-count 3 sdff0/t:$_MUX_
@@ -537,13 +529,9 @@ select -assert-count 0 sdff1/t:$_MUX_
select -assert-count 8 sdffe0/t:$_MUX_
select -assert-count 4 sdffe1/t:$_MUX_
select -assert-count 8 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce1/t:$_MUX_
select -assert-count 27 t:$_SDFF_PP1_
-select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
design -load orig
dfflegalize -cell $_SDFF_PP1_ 1
@@ -554,7 +542,7 @@ select -assert-count 8 sdff0/t:$_NOT_
select -assert-count 7 sdff1/t:$_NOT_
select -assert-count 10 sdffe0/t:$_NOT_
select -assert-count 9 sdffe1/t:$_NOT_
-select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
select -assert-count 9 sdffce1/t:$_NOT_
select -assert-count 0 dff/t:$_MUX_
select -assert-count 3 dffe/t:$_MUX_
@@ -562,14 +550,10 @@ select -assert-count 0 sdff0/t:$_MUX_
select -assert-count 3 sdff1/t:$_MUX_
select -assert-count 4 sdffe0/t:$_MUX_
select -assert-count 8 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
select -assert-count 8 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
select -assert-count 27 t:$_SDFF_PP1_
-select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
# Convert everything to SDFFEs.
diff --git a/tests/techmap/dfflegalize_dlatch_const.ys b/tests/techmap/dfflegalize_dlatch_const.ys
index f30a534fd..159692249 100644
--- a/tests/techmap/dfflegalize_dlatch_const.ys
+++ b/tests/techmap/dfflegalize_dlatch_const.ys
@@ -24,14 +24,14 @@ equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
design -load orig
dfflegalize -cell $_DFF_PP0_ 01
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
select -assert-count 8 t:$_DFF_PP0_
select -assert-none t:$_DFF_PP0_ t:$_NOT_ %% %n t:* %i
design -load orig
dfflegalize -cell $_DFF_PP?_ 0
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
select -assert-count 4 t:$_DFF_PP0_
select -assert-count 4 t:$_DFF_PP1_
select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_NOT_ %% %n t:* %i
@@ -41,13 +41,13 @@ select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_NOT_ %% %n t:* %i
design -load orig
dfflegalize -cell $_DFFSRE_PPPP_ 0
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
select -assert-count 8 t:$_DFFSRE_PPPP_
select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
design -load orig
dfflegalize -cell $_DFFSRE_PPPP_ 1
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
select -assert-count 8 t:$_DFFSRE_PPPP_
select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatchsr_init.ys b/tests/techmap/dfflegalize_dlatchsr_init.ys
index 2d33634d1..b38a9eb3b 100644
--- a/tests/techmap/dfflegalize_dlatchsr_init.ys
+++ b/tests/techmap/dfflegalize_dlatchsr_init.ys
@@ -66,8 +66,8 @@ select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_O
design -load orig
dfflegalize -cell $_DLATCH_PP1_ 0
-select -assert-count 22 dlatchsr0/t:$_NOT_
-select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 18 dlatchsr0/t:$_NOT_
+select -assert-count 22 dlatchsr1/t:$_NOT_
select -assert-count 4 dlatchsr0/t:$_MUX_
select -assert-count 4 dlatchsr1/t:$_MUX_
select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
@@ -81,8 +81,8 @@ select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_O
design -load orig
dfflegalize -cell $_DLATCH_PP1_ 1
-select -assert-count 22 dlatchsr0/t:$_NOT_
-select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 18 dlatchsr0/t:$_NOT_
+select -assert-count 22 dlatchsr1/t:$_NOT_
select -assert-count 4 dlatchsr0/t:$_MUX_
select -assert-count 4 dlatchsr1/t:$_MUX_
select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
diff --git a/tests/techmap/dfflegalize_minsrst.ys b/tests/techmap/dfflegalize_minsrst.ys
index 0fc40dc08..689066147 100644
--- a/tests/techmap/dfflegalize_minsrst.ys
+++ b/tests/techmap/dfflegalize_minsrst.ys
@@ -23,9 +23,9 @@ design -load postopt
select -assert-count 5 t:$_SDFF_PP0_
select -assert-count 1 t:$_SDFF_PP1_
-select -assert-count 3 t:$_SDFFE_PP0P_
+select -assert-count 1 t:$_SDFFE_PP0P_
select -assert-count 1 t:$_SDFFE_PP1P_
-select -assert-count 1 t:$_SDFFCE_PP0P_
+select -assert-count 3 t:$_SDFFCE_PP0P_
select -assert-count 1 t:$_SDFFCE_PP1P_
select -assert-count 8 t:$_MUX_
select -assert-count 0 n:ff0 %ci %ci t:$_MUX_ %i
diff --git a/tests/techmap/dfflegalize_sr.ys b/tests/techmap/dfflegalize_sr.ys
index 27e83be91..ee59a6e3c 100644
--- a/tests/techmap/dfflegalize_sr.ys
+++ b/tests/techmap/dfflegalize_sr.ys
@@ -39,7 +39,7 @@ select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
design -load orig
dfflegalize -cell $_DLATCH_PP1_ x
-select -assert-count 8 t:$_NOT_
+select -assert-count 5 t:$_NOT_
select -assert-count 3 t:$_DLATCH_PP1_
select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_sr_init.ys b/tests/techmap/dfflegalize_sr_init.ys
index 52b797b9e..9d724de29 100644
--- a/tests/techmap/dfflegalize_sr_init.ys
+++ b/tests/techmap/dfflegalize_sr_init.ys
@@ -12,7 +12,7 @@ $_SR_PN_ ff1 (.R(R), .S(S), .Q(Q[1]));
$_SR_NP_ ff2 (.R(R), .S(S), .Q(Q[2]));
endmodule
-module top(input C, E, R, D, output [5:0] Q);
+module top(input R, S, output [5:0] Q);
sr0 sr0_(.S(S), .R(R), .Q(Q[2:0]));
sr1 sr1_(.S(S), .R(R), .Q(Q[5:3]));
endmodule
@@ -103,8 +103,8 @@ select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/*
design -load orig
dfflegalize -cell $_DLATCH_PP1_ 0
-select -assert-count 11 sr0/t:$_NOT_
-select -assert-count 8 sr1/t:$_NOT_
+select -assert-count 8 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
select -assert-count 3 sr0/t:$_DLATCH_PP1_
select -assert-count 3 sr1/t:$_DLATCH_PP1_
select -assert-count 1 sr0/t:$_ANDNOT_
@@ -118,8 +118,8 @@ select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/*
design -load orig
dfflegalize -cell $_DLATCH_PP1_ 1
-select -assert-count 8 sr0/t:$_NOT_
-select -assert-count 11 sr1/t:$_NOT_
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 8 sr1/t:$_NOT_
select -assert-count 3 sr0/t:$_DLATCH_PP1_
select -assert-count 3 sr1/t:$_DLATCH_PP1_
select -assert-count 0 sr0/t:$_ANDNOT_