More comments, cleanup
[yosys.git] / passes / pmgen / xilinx_dsp_CREG.pmg
1 // This file describes the second of three pattern matcher setups that
2 // forms the `xilinx_dsp` pass described in xilinx_dsp.cc
3 // At a high level, it works as follows:
4 // (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
5 // and (b) uses the 'C' port
6 // (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
7 // (attached to at most two $mux cells that implement clock-enable or
8 // reset functionality, using a subpattern discussed below)
9 // Notes:
10 // - Separating out CREG packing is necessary since there is no guarantee
11 // that the cell ordering corresponds to the "expected" case (i.e. the order
12 // in which they appear in the source) thus the possiblity existed that a
13 // register got packed as a CREG into a downstream DSP that should have
14 // otherwise been a PREG of an upstream DSP that had not been visited yet
15 // - The reason this is separated out from the xilinx_dsp.pmg file is
16 // for efficiency --- each *.pmg file creates a class of the same basename,
17 // which when constructed, creates a custom database tailored to the
18 // pattern(s) contained within. Since the pattern in this file must be
19 // executed after the pattern contained in xilinx_dsp.pmg, it is necessary
20 // to reconstruct this database. Separating the two patterns into
21 // independent files causes two smaller, more specific, databases.
22
23 pattern xilinx_dsp_packC
24
25 udata <std::function<SigSpec(const SigSpec&)>> unextend
26 state <SigBit> clock
27 state <SigSpec> sigC sigP
28 state <bool> ffCcepol ffCrstpol
29 state <Cell*> ffC ffCcemux ffCrstmux
30
31 // subpattern
32 state <SigSpec> argQ argD
33 state <bool> ffcepol ffrstpol
34 state <int> ffoffset
35 udata <SigSpec> dffD dffQ
36 udata <SigBit> dffclock
37 udata <Cell*> dff dffcemux dffrstmux
38 udata <bool> dffcepol dffrstpol
39
40 // (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
41 // and (b) uses the 'C' port
42 match dsp
43 select dsp->type.in(\DSP48E1)
44 select param(dsp, \CREG, 1).as_int() == 0
45 select nusers(port(dsp, \C, SigSpec())) > 1
46 endmatch
47
48 code sigC sigP clock
49 unextend = [](const SigSpec &sig) {
50 int i;
51 for (i = GetSize(sig)-1; i > 0; i--)
52 if (sig[i] != sig[i-1])
53 break;
54 // Do not remove non-const sign bit
55 if (sig[i].wire)
56 ++i;
57 return sig.extract(0, i);
58 };
59 sigC = unextend(port(dsp, \C, SigSpec()));
60
61 SigSpec P = port(dsp, \P);
62 if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
63 // Only care about those bits that are used
64 int i;
65 for (i = 0; i < GetSize(P); i++) {
66 if (nusers(P[i]) <= 1)
67 break;
68 sigP.append(P[i]);
69 }
70 log_assert(nusers(P.extract_end(i)) <= 1);
71 }
72 else
73 sigP = P;
74
75 clock = port(dsp, \CLK, SigBit());
76 endcode
77
78 // (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
79 // (attached to at most two $mux cells that implement clock-enable or
80 // reset functionality, using the in_dffe subpattern)
81 code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
82 argQ = sigC;
83 subpattern(in_dffe);
84 if (dff) {
85 ffC = dff;
86 clock = dffclock;
87 if (dffrstmux) {
88 ffCrstmux = dffrstmux;
89 ffCrstpol = dffrstpol;
90 }
91 if (dffcemux) {
92 ffCcemux = dffcemux;
93 ffCcepol = dffcepol;
94 }
95 sigC = dffD;
96 }
97 endcode
98
99 code
100 if (ffC)
101 accept;
102 endcode
103
104 // #######################
105
106 // Subpattern for matching against input registers, based on knowledge of the
107 // 'Q' input.
108 // At a high level:
109 // (1) Starting from a $dff cell that (partially or fully) drives the given
110 // 'Q' argument
111 // (2) Match for a $mux cell implementing synchronous reset semantics ---
112 // one that exclusively drives the 'D' input of the $dff, with one of its
113 // $mux inputs being fully zero
114 // (3) Match for a $mux cell implement clock enable semantics --- one that
115 // exclusively drives the 'D' input of the $dff (or the other input of
116 // the reset $mux) and where one of this $mux's inputs is connected to
117 // the 'Q' output of the $dff
118 subpattern in_dffe
119 arg argD argQ clock
120
121 code
122 dff = nullptr;
123 for (const auto &c : argQ.chunks()) {
124 // Abandon matches when 'Q' is a constant
125 if (!c.wire)
126 reject;
127 // Abandon matches when 'Q' has the keep attribute set
128 if (c.wire->get_bool_attribute(\keep))
129 reject;
130 // Abandon matches when 'Q' has a non-zero init attribute set
131 // (not supported by DSP48E1)
132 Const init = c.wire->attributes.at(\init, Const());
133 for (auto b : init.extract(c.offset, c.width))
134 if (b != State::Sx && b != State::S0)
135 reject;
136 }
137 endcode
138
139 // (1) Starting from a $dff cell that (partially or fully) drives the given
140 // 'Q' argument
141 match ff
142 select ff->type.in($dff)
143 // DSP48E1 does not support clock inversion
144 select param(ff, \CLK_POLARITY).as_bool()
145
146 slice offset GetSize(port(ff, \D))
147 index <SigBit> port(ff, \Q)[offset] === argQ[0]
148
149 // Check that the rest of argQ is present
150 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
151 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
152
153 filter clock == SigBit() || port(ff, \CLK) == clock
154
155 set ffoffset offset
156 endmatch
157
158 code argQ argD
159 SigSpec Q = port(ff, \Q);
160 dff = ff;
161 dffclock = port(ff, \CLK);
162 dffD = argQ;
163 argD = port(ff, \D);
164 argQ = Q;
165 dffD.replace(argQ, argD);
166 // Only search for ffrstmux if dffD only
167 // has two (ff, ffrstmux) users
168 if (nusers(dffD) > 2)
169 argD = SigSpec();
170 endcode
171
172 // (2) Match for a $mux cell implementing synchronous reset semantics ---
173 // exclusively drives the 'D' input of the $dff, with one of the $mux
174 // inputs being fully zero
175 match ffrstmux
176 if !argD.empty()
177 select ffrstmux->type.in($mux)
178 index <SigSpec> port(ffrstmux, \Y) === argD
179
180 choice <IdString> BA {\B, \A}
181 // DSP48E1 only supports reset to zero
182 select port(ffrstmux, BA).is_fully_zero()
183
184 define <bool> pol (BA == \B)
185 set ffrstpol pol
186 semioptional
187 endmatch
188
189 code argD
190 if (ffrstmux) {
191 dffrstmux = ffrstmux;
192 dffrstpol = ffrstpol;
193 argD = port(ffrstmux, ffrstpol ? \A : \B);
194 dffD.replace(port(ffrstmux, \Y), argD);
195
196 // Only search for ffcemux if argQ has at
197 // least 3 users (ff, <upstream>, ffrstmux) and
198 // dffD only has two (ff, ffrstmux)
199 if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
200 argD = SigSpec();
201 }
202 else
203 dffrstmux = nullptr;
204 endcode
205
206 // (3) Match for a $mux cell implement clock enable semantics --- one that
207 // exclusively drives the 'D' input of the $dff (or the other input of
208 // the reset $mux) and where one of this $mux's inputs is connected to
209 // the 'Q' output of the $dff
210 match ffcemux
211 if !argD.empty()
212 select ffcemux->type.in($mux)
213 index <SigSpec> port(ffcemux, \Y) === argD
214 choice <IdString> AB {\A, \B}
215 index <SigSpec> port(ffcemux, AB) === argQ
216 define <bool> pol (AB == \A)
217 set ffcepol pol
218 semioptional
219 endmatch
220
221 code argD
222 if (ffcemux) {
223 dffcemux = ffcemux;
224 dffcepol = ffcepol;
225 argD = port(ffcemux, ffcepol ? \B : \A);
226 dffD.replace(port(ffcemux, \Y), argD);
227 }
228 else
229 dffcemux = nullptr;
230 endcode