2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 struct OptLutInsPass
: public Pass
{
27 OptLutInsPass() : Pass("opt_lut_ins", "discard unused LUT inputs") { }
28 void help() YS_OVERRIDE
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
32 log(" opt_lut_ins [options] [selection]\n");
34 log("This pass removes unused inputs from LUT cells (that is, inputs that can not\n");
35 log("influence the output signal given this LUT's value). While such LUTs cannot\n");
36 log("be directly emitted by ABC, they can be a result of various post-ABC\n");
37 log("transformations, such as mapping wide LUTs (not all sub-LUTs will use the\n");
38 log("full set of inputs) or optimizations such as xilinx_dffopt.\n");
40 log(" -tech <technology>\n");
41 log(" Instead of generic $lut cells, operate on LUT cells specific\n");
42 log(" to the given technology. Valid values are: xilinx, ecp5, gowin.\n");
45 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
47 log_header(design
, "Executing OPT_LUT_INS pass (discard unused LUT inputs).\n");
51 for (argidx
= 1; argidx
< args
.size(); argidx
++)
53 if (args
[argidx
] == "-tech" && argidx
+1 < args
.size()) {
54 techname
= args
[++argidx
];
59 extra_args(args
, argidx
, design
);
61 if (techname
!= "" && techname
!= "xilinx" && techname
!= "ecp5" && techname
!= "gowin")
62 log_cmd_error("Unsupported technology: '%s'\n", techname
.c_str());
64 for (auto module
: design
->selected_modules())
66 log("Optimizing LUTs in %s.\n", log_id(module
));
68 std::vector
<Cell
*> remove_cells
;
70 for (auto cell
: module
->selected_cells())
72 if (cell
->get_bool_attribute(ID::keep
))
75 std::vector
<SigBit
> inputs
;
76 std::vector
<SigBit
> output
;
77 bool ignore_const
= false;
79 if (cell
->type
!= ID($lut
))
81 inputs
= cell
->getPort(ID::A
).bits();
82 output
= cell
->getPort(ID::Y
);
83 lut
= cell
->getParam(ID(LUT
));
84 } else if (techname
== "xilinx" || techname
== "gowin") {
85 if (cell
->type
== ID(LUT1
)) {
87 cell
->getPort(ID(I0
)),
89 } else if (cell
->type
== ID(LUT2
)) {
91 cell
->getPort(ID(I0
)),
92 cell
->getPort(ID(I1
)),
94 } else if (cell
->type
== ID(LUT3
)) {
96 cell
->getPort(ID(I0
)),
97 cell
->getPort(ID(I1
)),
98 cell
->getPort(ID(I2
)),
100 } else if (cell
->type
== ID(LUT4
)) {
102 cell
->getPort(ID(I0
)),
103 cell
->getPort(ID(I1
)),
104 cell
->getPort(ID(I2
)),
105 cell
->getPort(ID(I3
)),
107 } else if (cell
->type
== ID(LUT5
)) {
109 cell
->getPort(ID(I0
)),
110 cell
->getPort(ID(I1
)),
111 cell
->getPort(ID(I2
)),
112 cell
->getPort(ID(I3
)),
113 cell
->getPort(ID(I4
)),
115 } else if (cell
->type
== ID(LUT6
)) {
117 cell
->getPort(ID(I0
)),
118 cell
->getPort(ID(I1
)),
119 cell
->getPort(ID(I2
)),
120 cell
->getPort(ID(I3
)),
121 cell
->getPort(ID(I4
)),
122 cell
->getPort(ID(I5
)),
128 lut
= cell
->getParam(ID(INIT
));
129 if (techname
== "xilinx")
130 output
= cell
->getPort(ID(O
));
132 output
= cell
->getPort(ID(F
));
133 } else if (techname
== "ecp5") {
134 if (cell
->type
== ID(LUT4
)) {
136 cell
->getPort(ID::A
),
137 cell
->getPort(ID::B
),
138 cell
->getPort(ID(C
)),
139 cell
->getPort(ID(D
)),
141 lut
= cell
->getParam(ID(INIT
));
142 output
= cell
->getPort(ID(Z
));
149 std::vector
<int> swizzle
;
150 std::vector
<SigBit
> new_inputs
;
152 for (int i
= 0; i
< GetSize(inputs
); i
++) {
153 SigBit input
= inputs
[i
];
155 if (input
.data
== State::S1
)
156 swizzle
.push_back(-2);
158 swizzle
.push_back(-1);
159 // For ECP5, smaller LUTs are
160 // implemented as LUT4s with
161 // extra const inputs. Do not
162 // consider that to be a reason
167 bool redundant
= true;
168 for (int j
= 0; j
< GetSize(lut
); j
++) {
169 if (lut
[j
] != lut
[j
^ 1 << i
])
173 swizzle
.push_back(-1);
176 swizzle
.push_back(GetSize(new_inputs
));
177 new_inputs
.push_back(input
);
183 log(" Optimizing lut %s (%d -> %d)\n", log_id(cell
), GetSize(inputs
), GetSize(new_inputs
));
184 if (techname
== "ecp5") {
185 // Pad the LUT to 4 inputs, adding consts from the front.
186 int extra
= 4 - GetSize(new_inputs
);
187 log_assert(extra
>= 0);
189 for (int i
= 0; i
< extra
; i
++)
190 new_inputs
.insert(new_inputs
.begin(), State::S0
);
191 for (auto &swz
: swizzle
)
196 Const
new_lut(0, 1 << GetSize(new_inputs
));
197 for (int i
= 0; i
< GetSize(new_lut
); i
++) {
199 for (int j
= 0; j
< GetSize(inputs
); j
++) {
201 if (swizzle
[j
] == -2) {
203 } else if (swizzle
[j
] == -1) {
206 val
= (i
>> swizzle
[j
]) & 1;
210 new_lut
[i
] = lut
[lidx
];
212 // For ecp5, do not replace with a const driver — the nextpnr
213 // packer requires a complete set of LUTs for wide LUT muxes.
214 if (new_inputs
.empty() && techname
!= "ecp5") {
216 remove_cells
.push_back(cell
);
217 module
->connect(output
, new_lut
[0]);
219 if (techname
== "") {
220 cell
->setParam(ID(LUT
), new_lut
);
221 cell
->setParam(ID(WIDTH
), GetSize(new_inputs
));
222 cell
->setPort(ID::A
, new_inputs
);
223 } else if (techname
== "ecp5") {
224 log_assert(GetSize(new_inputs
) == 4);
225 cell
->setParam(ID(INIT
), new_lut
);
226 cell
->setPort(ID::A
, new_inputs
[0]);
227 cell
->setPort(ID::B
, new_inputs
[1]);
228 cell
->setPort(ID(C
), new_inputs
[2]);
229 cell
->setPort(ID(D
), new_inputs
[3]);
232 cell
->setParam(ID(INIT
), new_lut
);
233 if (techname
== "xilinx")
234 log_assert(GetSize(new_inputs
) <= 6);
236 log_assert(GetSize(new_inputs
) <= 4);
237 if (GetSize(new_inputs
) == 1)
238 cell
->type
= ID(LUT1
);
239 else if (GetSize(new_inputs
) == 2)
240 cell
->type
= ID(LUT2
);
241 else if (GetSize(new_inputs
) == 3)
242 cell
->type
= ID(LUT3
);
243 else if (GetSize(new_inputs
) == 4)
244 cell
->type
= ID(LUT4
);
245 else if (GetSize(new_inputs
) == 5)
246 cell
->type
= ID(LUT5
);
247 else if (GetSize(new_inputs
) == 6)
248 cell
->type
= ID(LUT6
);
251 cell
->unsetPort(ID(I0
));
252 cell
->unsetPort(ID(I1
));
253 cell
->unsetPort(ID(I2
));
254 cell
->unsetPort(ID(I3
));
255 cell
->unsetPort(ID(I4
));
256 cell
->unsetPort(ID(I5
));
257 cell
->setPort(ID(I0
), new_inputs
[0]);
258 if (GetSize(new_inputs
) >= 2)
259 cell
->setPort(ID(I1
), new_inputs
[1]);
260 if (GetSize(new_inputs
) >= 3)
261 cell
->setPort(ID(I2
), new_inputs
[2]);
262 if (GetSize(new_inputs
) >= 4)
263 cell
->setPort(ID(I3
), new_inputs
[3]);
264 if (GetSize(new_inputs
) >= 5)
265 cell
->setPort(ID(I4
), new_inputs
[4]);
266 if (GetSize(new_inputs
) >= 6)
267 cell
->setPort(ID(I5
), new_inputs
[5]);
271 for (auto cell
: remove_cells
)
272 module
->remove(cell
);
277 PRIVATE_NAMESPACE_END