Merge pull request #1412 from YosysHQ/eddie/equiv_opt_async2sync
[yosys.git] / passes / pmgen / xilinx_dsp_CREG.pmg
1 pattern xilinx_dsp_packC
2
3 udata <std::function<SigSpec(const SigSpec&)>> unextend
4 state <SigBit> clock
5 state <SigSpec> sigC sigP
6 state <bool> ffCcepol ffCrstpol
7 state <Cell*> ffC ffCcemux ffCrstmux
8
9 // subpattern
10 state <SigSpec> argQ argD
11 state <bool> ffcepol ffrstpol
12 state <int> ffoffset
13 udata <SigSpec> dffD dffQ
14 udata <SigBit> dffclock
15 udata <Cell*> dff dffcemux dffrstmux
16 udata <bool> dffcepol dffrstpol
17
18 match dsp
19 select dsp->type.in(\DSP48E1)
20 select param(dsp, \CREG, 1).as_int() == 0
21 select nusers(port(dsp, \C, SigSpec())) > 1
22 endmatch
23
24 code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC sigP clock
25 unextend = [](const SigSpec &sig) {
26 int i;
27 for (i = GetSize(sig)-1; i > 0; i--)
28 if (sig[i] != sig[i-1])
29 break;
30 // Do not remove non-const sign bit
31 if (sig[i].wire)
32 ++i;
33 return sig.extract(0, i);
34 };
35 sigC = unextend(port(dsp, \C, SigSpec()));
36
37 SigSpec P = port(dsp, \P);
38 if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
39 // Only care about those bits that are used
40 int i;
41 for (i = 0; i < GetSize(P); i++) {
42 if (nusers(P[i]) <= 1)
43 break;
44 sigP.append(P[i]);
45 }
46 log_assert(nusers(P.extract_end(i)) <= 1);
47 }
48 else
49 sigP = P;
50
51 if (sigC == sigP)
52 reject;
53
54 clock = port(dsp, \CLK, SigBit());
55
56 argQ = sigC;
57 subpattern(in_dffe);
58 if (dff) {
59 ffC = dff;
60 clock = dffclock;
61 if (dffrstmux) {
62 ffCrstmux = dffrstmux;
63 ffCrstpol = dffrstpol;
64 }
65 if (dffcemux) {
66 ffCcemux = dffcemux;
67 ffCcepol = dffcepol;
68 }
69 sigC = dffD;
70 }
71 endcode
72
73 code
74 if (ffC)
75 accept;
76 endcode
77
78 // #######################
79
80 subpattern in_dffe
81 arg argD argQ clock
82
83 code
84 dff = nullptr;
85 for (auto c : argQ.chunks()) {
86 if (!c.wire)
87 reject;
88 if (c.wire->get_bool_attribute(\keep))
89 reject;
90 Const init = c.wire->attributes.at(\init, State::Sx);
91 if (!init.is_fully_undef() && !init.is_fully_zero())
92 reject;
93 }
94 endcode
95
96 match ff
97 select ff->type.in($dff)
98 // DSP48E1 does not support clock inversion
99 select param(ff, \CLK_POLARITY).as_bool()
100
101 slice offset GetSize(port(ff, \D))
102 index <SigBit> port(ff, \Q)[offset] === argQ[0]
103
104 // Check that the rest of argQ is present
105 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
106 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
107
108 set ffoffset offset
109 endmatch
110
111 code argQ argD
112 {
113 if (clock != SigBit() && port(ff, \CLK) != clock)
114 reject;
115
116 SigSpec Q = port(ff, \Q);
117 dff = ff;
118 dffclock = port(ff, \CLK);
119 dffD = argQ;
120 argD = port(ff, \D);
121 argQ = Q;
122 dffD.replace(argQ, argD);
123 // Only search for ffrstmux if dffD only
124 // has two (ff, ffrstmux) users
125 if (nusers(dffD) > 2)
126 argD = SigSpec();
127 }
128 endcode
129
130 match ffrstmux
131 if !argD.empty()
132 select ffrstmux->type.in($mux)
133 index <SigSpec> port(ffrstmux, \Y) === argD
134
135 choice <IdString> BA {\B, \A}
136 // DSP48E1 only supports reset to zero
137 select port(ffrstmux, BA).is_fully_zero()
138
139 define <bool> pol (BA == \B)
140 set ffrstpol pol
141 semioptional
142 endmatch
143
144 code argD
145 if (ffrstmux) {
146 dffrstmux = ffrstmux;
147 dffrstpol = ffrstpol;
148 argD = port(ffrstmux, ffrstpol ? \A : \B);
149 dffD.replace(port(ffrstmux, \Y), argD);
150
151 // Only search for ffcemux if argQ has at
152 // least 3 users (ff, <upstream>, ffrstmux) and
153 // dffD only has two (ff, ffrstmux)
154 if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
155 argD = SigSpec();
156 }
157 else
158 dffrstmux = nullptr;
159 endcode
160
161 match ffcemux
162 if !argD.empty()
163 select ffcemux->type.in($mux)
164 index <SigSpec> port(ffcemux, \Y) === argD
165 choice <IdString> AB {\A, \B}
166 index <SigSpec> port(ffcemux, AB) === argQ
167 define <bool> pol (AB == \A)
168 set ffcepol pol
169 semioptional
170 endmatch
171
172 code argD
173 if (ffcemux) {
174 dffcemux = ffcemux;
175 dffcepol = ffcepol;
176 argD = port(ffcemux, ffcepol ? \B : \A);
177 dffD.replace(port(ffcemux, \Y), argD);
178 }
179 else
180 dffcemux = nullptr;
181 endcode