diff options
author | Marcelina KoĆcielnicka <mwk@0x04.net> | 2020-07-22 12:27:15 +0200 |
---|---|---|
committer | Marcelina KoĆcielnicka <mwk@0x04.net> | 2020-07-30 22:26:09 +0200 |
commit | 8501342fc5898ea1e6aadc33a27df54fa82d9107 (patch) | |
tree | f800244288989c3d848a0a283a9d1b4975d4f686 /passes/pmgen/xilinx_dsp_cascade.pmg | |
parent | 4a05cad7f8a6ee57292e5360eb06305e13fc308b (diff) | |
download | yosys-8501342fc5898ea1e6aadc33a27df54fa82d9107.tar.gz yosys-8501342fc5898ea1e6aadc33a27df54fa82d9107.tar.bz2 yosys-8501342fc5898ea1e6aadc33a27df54fa82d9107.zip |
synth_xilinx: Use opt_dff.
The main part is converting xilinx_dsp to recognize the new FF types
created in opt_dff instead of trying to recognize the patterns on its
own.
The fsm call has been moved upwards because the passes cannot deal with
$dffe/$sdff*, and other optimizations don't help it much anyway.
Diffstat (limited to 'passes/pmgen/xilinx_dsp_cascade.pmg')
-rw-r--r-- | passes/pmgen/xilinx_dsp_cascade.pmg | 125 |
1 files changed, 24 insertions, 101 deletions
diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 8babb88e6..06601554c 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -51,12 +51,10 @@ state <int> AREG BREG // Variables used for subpatterns state <SigSpec> argQ argD -state <bool> ffcepol ffrstpol state <int> ffoffset udata <SigSpec> dffD dffQ udata <SigBit> dffclock -udata <Cell*> dff dffcemux dffrstmux -udata <bool> dffcepol dffrstpol +udata <Cell*> dff code #define MAX_DSP_CASCADE 20 @@ -254,9 +252,9 @@ code argQ clock AREG clock = port(prev, \CLK); subpattern(in_dffe); if (dff) { - if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0) + if (!dff->type.in($sdff, $sdffe) && port(prev, \RSTA, State::S0) != State::S0) goto reject_AREG; - if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0)) + if (dff->type.in($sdff, $sdffe) && (port(dff, \SRST) != port(prev, \RSTA, State::S0) || !param(dff, \SRST_POLARITY).as_bool())) goto reject_AREG; IdString CEA; if (param(prev, \AREG) == 1) @@ -264,9 +262,9 @@ code argQ clock AREG else if (param(prev, \AREG) == 2) CEA = \CEA1; else log_abort(); - if (!dffcemux && port(prev, CEA, State::S0) != State::S1) + if (!dff->type.in($dffe, $sdffe) && port(prev, CEA, State::S0) != State::S1) goto reject_AREG; - if (dffcemux && port(dffcemux, \S) != port(prev, CEA, State::S0)) + if (dff->type.in($dffe, $sdffe) && (port(dff, \EN) != port(prev, CEA, State::S0) || !param(dff, \EN_POLARITY).as_bool())) goto reject_AREG; if (dffD == unextend(port(prev, \A))) AREG = 1; @@ -295,9 +293,9 @@ code argQ clock BREG clock = port(prev, \CLK); subpattern(in_dffe); if (dff) { - if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0) + if (!dff->type.in($sdff, $sdffe) && port(prev, \RSTB, State::S0) != State::S0) goto reject_BREG; - if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0)) + if (dff->type.in($sdff, $sdffe) && (port(dff, \SRST) != port(prev, \RSTB, State::S0) || !param(dff, \SRST_POLARITY).as_bool())) goto reject_BREG; IdString CEB; if (next->type.in(\DSP48A, \DSP48A1)) @@ -310,9 +308,9 @@ code argQ clock BREG else log_abort(); } else log_abort(); - if (!dffcemux && port(prev, CEB, State::S0) != State::S1) + if (!dff->type.in($dffe, $sdffe) && port(prev, CEB, State::S0) != State::S1) goto reject_BREG; - if (dffcemux && port(dffcemux, \S) != port(prev, CEB, State::S0)) + if (dff->type.in($dffe, $sdffe) && (port(dff, \EN) != port(prev, CEB, State::S0) || !param(dff, \EN_POLARITY).as_bool())) goto reject_BREG; if (dffD == unextend(port(prev, \B))) { if (next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG) != 0) @@ -357,25 +355,14 @@ endcode // ####################### // Subpattern for matching against input registers, based on knowledge of the -// 'Q' input. Typically, identifying registers with clock-enable and reset -// capability would be a task would be handled by other Yosys passes such as -// dff2dffe, but since DSP inference happens much before this, these patterns -// have to be manually identified. -// At a high level: -// (1) Starting from a $dff cell that (partially or fully) drives the given -// 'Q' argument -// (2) Match for a $mux cell implementing synchronous reset semantics --- -// one that exclusively drives the 'D' input of the $dff, with one of its -// $mux inputs being fully zero -// (3) Match for a $mux cell implement clock enable semantics --- one that -// exclusively drives the 'D' input of the $dff (or the other input of -// the reset $mux) and where one of this $mux's inputs is connected to -// the 'Q' output of the $dff +// 'Q' input. subpattern in_dffe -arg argD argQ clock +arg argQ clock code dff = nullptr; + if (argQ.empty()) + reject; for (const auto &c : argQ.chunks()) { // Abandon matches when 'Q' is a constant if (!c.wire) @@ -386,19 +373,21 @@ code // Abandon matches when 'Q' has a non-zero init attribute set // (not supported by DSP48E1) Const init = c.wire->attributes.at(\init, Const()); - for (auto b : init.extract(c.offset, c.width)) - if (b != State::Sx && b != State::S0) - reject; + if (!init.empty()) + for (auto b : init.extract(c.offset, c.width)) + if (b != State::Sx && b != State::S0) + reject; } endcode -// (1) Starting from a $dff cell that (partially or fully) drives the given -// 'Q' argument match ff - select ff->type.in($dff) + select ff->type.in($dff, $dffe, $sdff, $sdffe) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() + // Check that reset value, if present, is fully 0. + filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero() + slice offset GetSize(port(ff, \D)) index <SigBit> port(ff, \Q)[offset] === argQ[0] @@ -407,80 +396,14 @@ match ff filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ filter clock == SigBit() || port(ff, \CLK) == clock - - set ffoffset offset endmatch -code argQ argD +code argQ SigSpec Q = port(ff, \Q); dff = ff; dffclock = port(ff, \CLK); dffD = argQ; - argD = port(ff, \D); + SigSpec D = 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 - -// (2) Match for a $mux cell implementing synchronous reset semantics --- -// exclusively drives the 'D' input of the $dff, with one of the $mux -// inputs being fully zero -match ffrstmux - 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 ffcemux 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 - -// (3) Match for a $mux cell implement clock enable semantics --- one that -// exclusively drives the 'D' input of the $dff (or the other input of -// the reset $mux) and where one of this $mux's inputs is connected to -// the 'Q' output of the $dff -match ffcemux - if !argD.empty() - select ffcemux->type.in($mux) - index <SigSpec> port(ffcemux, \Y) === argD - choice <IdString> AB {\A, \B} - index <SigSpec> port(ffcemux, AB) === argQ - define <bool> pol (AB == \A) - set ffcepol pol - semioptional -endmatch - -code argD - if (ffcemux) { - dffcemux = ffcemux; - dffcepol = ffcepol; - argD = port(ffcemux, ffcepol ? \B : \A); - dffD.replace(port(ffcemux, \Y), argD); - } - else - dffcemux = nullptr; + dffD.replace(argQ, D); endcode |