log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
- log_debug("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--"));
- log_debug("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--"));
- log_debug("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--"));
+ log_debug("ffA: %s\n", log_id(st.ffA, "--"));
+ log_debug("ffB: %s\n", log_id(st.ffB, "--"));
+ log_debug("ffCD: %s\n", log_id(st.ffCD, "--"));
log_debug("mul: %s\n", log_id(st.mul, "--"));
log_debug("ffFJKG: %s\n", log_id(st.ffFJKG, "--"));
log_debug("ffH: %s\n", log_id(st.ffH, "--"));
log_debug("add: %s\n", log_id(st.add, "--"));
log_debug("mux: %s\n", log_id(st.mux, "--"));
- log_debug("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--"));
+ log_debug("ffO: %s\n", log_id(st.ffO, "--"));
log_debug("\n");
if (GetSize(st.sigA) > 16) {
cell->setParam(ID(D_REG), st.ffCD ? State::S1 : State::S0);
SigSpec AHOLD, BHOLD, CDHOLD;
- if (st.ffAholdmux)
- AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffAholdmux->getPort(ID::S));
+ if (st.ffA && st.ffA->hasPort(ID::EN))
+ AHOLD = st.ffA->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffA->getPort(ID::EN)) : st.ffA->getPort(ID::EN);
else
AHOLD = State::S0;
- if (st.ffBholdmux)
- BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBholdmux->getPort(ID::S));
+ if (st.ffB && st.ffB->hasPort(ID::EN))
+ BHOLD = st.ffB->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffB->getPort(ID::EN)) : st.ffB->getPort(ID::EN);
else
BHOLD = State::S0;
- if (st.ffCDholdmux)
- CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort(ID::S));
+ if (st.ffCD && st.ffCD->hasPort(ID::EN))
+ CDHOLD = st.ffCD->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffCD->getPort(ID::EN)) : st.ffCD->getPort(ID::EN);
else
CDHOLD = State::S0;
cell->setPort(ID(AHOLD), AHOLD);
cell->setPort(ID(DHOLD), CDHOLD);
SigSpec IRSTTOP, IRSTBOT;
- if (st.ffArstmux)
- IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffArstmux->getPort(ID::S));
+ if (st.ffA && st.ffA->hasPort(ID::ARST))
+ IRSTTOP = st.ffA->getParam(ID::ARST_POLARITY).as_bool() ? st.ffA->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffA->getPort(ID::ARST));
else
IRSTTOP = State::S0;
- if (st.ffBrstmux)
- IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBrstmux->getPort(ID::S));
+ if (st.ffB && st.ffB->hasPort(ID::ARST))
+ IRSTBOT = st.ffB->getParam(ID::ARST_POLARITY).as_bool() ? st.ffB->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffB->getPort(ID::ARST));
else
IRSTBOT = State::S0;
cell->setPort(ID(IRSTTOP), IRSTTOP);
}
SigSpec OHOLD;
- if (st.ffOholdmux)
- OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOholdmux->getPort(ID::S));
+ if (st.ffO && st.ffO->hasPort(ID::EN))
+ OHOLD = st.ffO->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffO->getPort(ID::EN)) : st.ffO->getPort(ID::EN);
else
OHOLD = State::S0;
cell->setPort(ID(OHOLDTOP), OHOLD);
cell->setPort(ID(OHOLDBOT), OHOLD);
SigSpec ORST;
- if (st.ffOrstmux)
- ORST = st.ffOrstpol ? st.ffOrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOrstmux->getPort(ID::S));
+ if (st.ffO && st.ffO->hasPort(ID::ARST))
+ ORST = st.ffO->getParam(ID::ARST_POLARITY).as_bool() ? st.ffO->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::ARST));
else
ORST = State::S0;
cell->setPort(ID(ORSTTOP), ORST);
acc_reset = st.mux->getPort(ID::S);
else
acc_reset = pm.module->Not(NEW_ID, st.mux->getPort(ID::S));
+ } else if (st.ffO && st.ffO->hasPort(ID::SRST)) {
+ acc_reset = st.ffO->getParam(ID::SRST_POLARITY).as_bool() ? st.ffO->getPort(ID::SRST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::SRST));
}
cell->setPort(ID(OLOADTOP), acc_reset);
cell->setPort(ID(OLOADBOT), acc_reset);
state <Cell*> add mux
state <IdString> addAB muxAB
-state <bool> ffAholdpol ffBholdpol ffCDholdpol ffOholdpol
-state <bool> ffArstpol ffBrstpol ffCDrstpol ffOrstpol
-
-state <Cell*> ffA ffAholdmux ffArstmux ffB ffBholdmux ffBrstmux ffCD ffCDholdmux
-state <Cell*> ffFJKG ffH ffO ffOholdmux ffOrstmux
+state <Cell*> ffA ffB ffCD
+state <Cell*> ffFJKG ffH ffO
// subpattern
+state <bool> argSdff
state <SigSpec> argQ argD
-state <bool> ffholdpol ffrstpol
-state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffholdmux dffrstmux
-udata <bool> dffholdpol dffrstpol dffclock_pol
+udata <Cell*> dff
+udata <bool> dffclock_pol
match mul
select mul->type.in($mul, \SB_MAC16)
log_assert(nusers(O.extract_end(i)) <= 1);
endcode
-code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
+code argQ ffA sigA clock clock_pol
if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
argQ = sigA;
subpattern(in_dffe);
ffA = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffArstmux = dffrstmux;
- ffArstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffAholdmux = dffholdmux;
- ffAholdpol = dffholdpol;
- }
sigA = dffD;
}
}
endcode
-code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
+code argQ ffB sigB clock clock_pol
if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
argQ = sigB;
subpattern(in_dffe);
ffB = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffBrstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffBholdmux = dffholdmux;
- ffBholdpol = dffholdpol;
- }
sigB = dffD;
}
}
endcode
-code argD ffFJKG sigH clock clock_pol
+code argD argSdff ffFJKG sigH clock clock_pol
if (nusers(sigH) == 2 &&
(mul->type != \SB_MAC16 ||
(!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) {
argD = sigH;
+ argSdff = false;
subpattern(out_dffe);
if (dff) {
// F/J/K/G do not have a CE-like (hold) input
- if (dffholdmux)
+ if (dff->hasPort(\EN))
goto reject_ffFJKG;
// Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
// shared with A and B
- if ((ffArstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffFJKG;
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffFJKG;
- if (ffArstmux) {
- if (port(ffArstmux, \S) != port(dffrstmux, \S))
- goto reject_ffFJKG;
- if (ffArstpol != dffrstpol)
+ if (ffA) {
+ if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffFJKG;
+ if (ffA->hasPort(\ARST)) {
+ if (port(ffA, \ARST) != port(dff, \ARST))
+ goto reject_ffFJKG;
+ if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffFJKG;
+ }
}
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
- goto reject_ffFJKG;
- if (ffBrstpol != dffrstpol)
+ if (ffB) {
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffFJKG;
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
+ goto reject_ffFJKG;
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffFJKG;
+ }
}
ffFJKG = dff;
}
endcode
-code argD ffH sigH sigO clock clock_pol
+code argD argSdff ffH sigH sigO clock clock_pol
if (ffFJKG && nusers(sigH) == 2 &&
(mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
argD = sigH;
+ argSdff = false;
subpattern(out_dffe);
if (dff) {
// H does not have a CE-like (hold) input
- if (dffholdmux)
+ if (dff->hasPort(\EN))
goto reject_ffH;
// Reset signal of H (IRSTBOT) shared with B
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffH;
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
goto reject_ffH;
- if (ffBrstpol != dffrstpol)
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
goto reject_ffH;
}
sigO = port(mux, \Y);
endcode
-code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo
+code argD argSdff ffO sigO sigCD clock clock_pol cd_signed o_lo
if (mul->type != \SB_MAC16 ||
// Ensure that register is not already used
((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) &&
// First try entire sigO
if (nusers(sigO) == 2) {
argD = sigO;
+ argSdff = !mux;
subpattern(out_dffe);
}
if (!dff && GetSize(sigO) > 16) {
argD = sigO.extract(0, 16);
if (nusers(argD) == 2) {
+ argSdff = !mux;
subpattern(out_dffe);
o_lo = dff;
}
ffO = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffOrstmux = dffrstmux;
- ffOrstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffOholdmux = dffholdmux;
- ffOholdpol = dffholdpol;
- }
sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
}
reject;
sigCD = port(mux, muxAB == \B ? \A : \B);
+ cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
+ } else if (dff && dff->hasPort(\SRST)) {
+ if (sigCD != sigO)
+ reject;
+ sigCD = param(dff, \SRST_VALUE);
+
cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
}
}
endcode
-code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol
+code argQ ffCD sigCD clock clock_pol
if (!sigCD.empty() && sigCD != sigO &&
(mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
argQ = sigCD;
subpattern(in_dffe);
if (dff) {
- if (dffholdmux) {
- ffCDholdmux = dffholdmux;
- ffCDholdpol = dffholdpol;
- }
-
// Reset signal of C (IRSTTOP) and D (IRSTBOT)
// shared with A and B
- if ((ffArstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffCD;
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffCD;
- if (ffArstmux) {
- if (port(ffArstmux, \S) != port(dffrstmux, \S))
- goto reject_ffCD;
- if (ffArstpol != dffrstpol)
+ if (ffA) {
+ if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffCD;
+ if (ffA->hasPort(\ARST)) {
+ if (port(ffA, \ARST) != port(dff, \ARST))
+ goto reject_ffCD;
+ if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffCD;
+ }
}
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
- goto reject_ffCD;
- if (ffBrstpol != dffrstpol)
+ if (ffB) {
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffCD;
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
+ goto reject_ffCD;
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffCD;
+ }
}
ffCD = dff;
endcode
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
// Check that the rest of argQ is present
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
-
- set ffoffset offset
endmatch
code argQ argD
argD = port(ff, \D);
argQ = Q;
dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
}
endcode
-match ffrstmux
- if false /* TODO: ice40 resets are actually async */
-
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffholdmux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-match ffholdmux
- if !argD.empty()
- select ffholdmux->type.in($mux)
- index <SigSpec> port(ffholdmux, \Y) === argD
- choice <IdString> BA {\B, \A}
- index <SigSpec> port(ffholdmux, BA) === argQ
- define <bool> pol (BA == \B)
- set ffholdpol pol
- semioptional
-endmatch
-
-code argD
- if (ffholdmux) {
- dffholdmux = ffholdmux;
- dffholdpol = ffholdpol;
- argD = port(ffholdmux, ffholdpol ? \A : \B);
- dffD.replace(port(ffholdmux, \Y), argD);
- }
- else
- dffholdmux = nullptr;
-endcode
-
// #######################
subpattern out_dffe
-arg argD argQ clock clock_pol
+arg argD argSdff argQ clock clock_pol
code
dff = nullptr;
reject;
endcode
-match ffholdmux
- select ffholdmux->type.in($mux)
- // ffholdmux output must have two users: ffholdmux and ff.D
- select nusers(port(ffholdmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // keep-last-value net must have at least three users: ffholdmux, ff, downstream sink(s)
- select nusers(port(ffholdmux, BA)) >= 3
-
- slice offset GetSize(port(ffholdmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffholdmux, AB)[offset] === argD[0]
-
- // Check that the rest of argD is present
- filter GetSize(port(ffholdmux, AB)) >= offset + GetSize(argD)
- filter port(ffholdmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (BA == \B)
- set ffholdpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffholdmux = ffholdmux;
- if (ffholdmux) {
- SigSpec AB = port(ffholdmux, ffholdpol ? \A : \B);
- SigSpec Y = port(ffholdmux, \Y);
- argQ = argD;
- argD.replace(AB, Y);
- argQ.replace(AB, port(ffholdmux, ffholdpol ? \B : \A));
-
- dffholdmux = ffholdmux;
- dffholdpol = ffholdpol;
- }
-endcode
-
-match ffrstmux
- if false /* TODO: ice40 resets are actually async */
-
- select ffrstmux->type.in($mux)
- // ffrstmux output must have two users: ffrstmux and ff.D
- select nusers(port(ffrstmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- slice offset GetSize(port(ffrstmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
-
- // Check that offset is consistent
- filter !ffholdmux || ffoffset == offset
- // Check that the rest of argD is present
- filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
- filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffrstpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffrstmux = ffrstmux;
- if (ffrstmux) {
- SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
- SigSpec Y = port(ffrstmux, \Y);
- argD.replace(AB, Y);
-
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- }
-endcode
-
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffce)
// SB_MAC16 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \D)[offset] === argD[0]
- // Check that offset is consistent
- filter (!ffholdmux && !ffrstmux) || ffoffset == offset
+ // Only allow sync reset if requested.
+ filter argSdff || ff->type.in($dff, $dffe)
// Check that the rest of argD is present
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
- // Check that FF.Q is connected to CE-mux
- filter !ffholdmux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
-
- set ffoffset offset
endmatch
code argQ
}
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
- if (!ffholdmux) {
- argQ = argD;
- argQ.replace(D, Q);
- }
+ argQ = argD;
+ argQ.replace(D, Q);
for (auto c : argQ.chunks()) {
Const init = c.wire->attributes.at(\init, State::Sx);
dffclock = port(ff, \CLK);
dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
}
- // No enable/reset mux possible without flop
- else if (dffholdmux || dffrstmux)
- reject;
endcode
+++ /dev/null
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/yosys.h"
-#include "kernel/sigtools.h"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Ice40FfssrPass : public Pass {
- Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
- void help() override
- {
- log("\n");
- log(" ice40_ffssr [options] [selection]\n");
- log("\n");
- log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) override
- {
- log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-singleton") {
- // singleton_mode = true;
- // continue;
- // }
- break;
- }
- extra_args(args, argidx, design);
-
- pool<IdString> sb_dff_types;
- sb_dff_types.insert(ID(SB_DFF));
- sb_dff_types.insert(ID(SB_DFFE));
- sb_dff_types.insert(ID(SB_DFFN));
- sb_dff_types.insert(ID(SB_DFFNE));
-
- for (auto module : design->selected_modules())
- {
- log("Merging set/reset $_MUX_ cells into SB_FFs in %s.\n", log_id(module));
-
- SigMap sigmap(module);
- dict<SigBit, Cell*> sr_muxes;
- vector<Cell*> ff_cells;
-
- for (auto cell : module->selected_cells())
- {
- if (sb_dff_types.count(cell->type)) {
- ff_cells.push_back(cell);
- continue;
- }
-
- if (cell->type != ID($_MUX_))
- continue;
-
- SigBit bit_a = sigmap(cell->getPort(ID::A));
- SigBit bit_b = sigmap(cell->getPort(ID::B));
-
- if (bit_a.wire == nullptr || bit_b.wire == nullptr)
- sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
- }
-
- for (auto cell : ff_cells)
- {
- if (cell->get_bool_attribute(ID(dont_touch)))
- continue;
-
- SigSpec sig_d = cell->getPort(ID::D);
-
- if (GetSize(sig_d) < 1)
- continue;
-
- SigBit bit_d = sigmap(sig_d[0]);
-
- if (sr_muxes.count(bit_d) == 0)
- continue;
-
- Cell *mux_cell = sr_muxes.at(bit_d);
- SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
- SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
- SigBit bit_s = sigmap(mux_cell->getPort(ID::S));
-
- log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
- log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
-
- SigBit sr_val, sr_sig;
- if (bit_a.wire == nullptr) {
- bit_d = bit_b;
- sr_val = bit_a;
- sr_sig = module->NotGate(NEW_ID, bit_s);
- } else {
- log_assert(bit_b.wire == nullptr);
- bit_d = bit_a;
- sr_val = bit_b;
- sr_sig = bit_s;
- }
-
- if (sr_val == State::S1) {
- cell->type = cell->type.str() + "SS";
- cell->setPort(ID::S, sr_sig);
- cell->setPort(ID::D, bit_d);
- } else {
- cell->type = cell->type.str() + "SR";
- cell->setPort(ID::R, sr_sig);
- cell->setPort(ID::D, bit_d);
- }
- }
- }
- }
-} Ice40FfssrPass;
-
-PRIVATE_NAMESPACE_END