Try new LUT delays
[yosys.git] / techlibs / ice40 / ice40_opt.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "passes/techmap/simplemap.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 static SigBit get_bit_or_zero(const SigSpec &sig)
30 {
31 if (GetSize(sig) == 0)
32 return State::S0;
33 return sig[0];
34 }
35
36 static void run_ice40_opts(Module *module)
37 {
38 pool<SigBit> optimized_co;
39 vector<Cell*> sb_lut_cells;
40 SigMap sigmap(module);
41
42 for (auto cell : module->selected_cells())
43 {
44 if (cell->type == "\\SB_LUT4")
45 {
46 sb_lut_cells.push_back(cell);
47 continue;
48 }
49
50 if (cell->type == "\\SB_CARRY")
51 {
52 SigSpec non_const_inputs, replacement_output;
53 int count_zeros = 0, count_ones = 0;
54
55 SigBit inbit[3] = {
56 get_bit_or_zero(cell->getPort("\\I0")),
57 get_bit_or_zero(cell->getPort("\\I1")),
58 get_bit_or_zero(cell->getPort("\\CI"))
59 };
60 for (int i = 0; i < 3; i++)
61 if (inbit[i].wire == nullptr) {
62 if (inbit[i] == State::S1)
63 count_ones++;
64 else
65 count_zeros++;
66 } else
67 non_const_inputs.append(inbit[i]);
68
69 if (count_zeros >= 2)
70 replacement_output = State::S0;
71 else if (count_ones >= 2)
72 replacement_output = State::S1;
73 else if (GetSize(non_const_inputs) == 1)
74 replacement_output = non_const_inputs;
75
76 if (GetSize(replacement_output)) {
77 optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
78 module->connect(cell->getPort("\\CO")[0], replacement_output);
79 module->design->scratchpad_set_bool("opt.did_something", true);
80 log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
81 log_id(module), log_id(cell), log_signal(replacement_output));
82 module->remove(cell);
83 }
84 continue;
85 }
86 }
87
88 for (auto cell : sb_lut_cells)
89 {
90 SigSpec inbits;
91
92 inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
93 inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
94 inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
95 inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
96 sigmap.apply(inbits);
97
98 if (optimized_co.count(inbits[0])) goto remap_lut;
99 if (optimized_co.count(inbits[1])) goto remap_lut;
100 if (optimized_co.count(inbits[2])) goto remap_lut;
101 if (optimized_co.count(inbits[3])) goto remap_lut;
102
103 if (!sigmap(inbits).is_fully_const())
104 continue;
105
106 remap_lut:
107 module->design->scratchpad_set_bool("opt.did_something", true);
108 log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell));
109
110 cell->type ="$lut";
111 cell->setParam("\\WIDTH", 4);
112 cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
113 cell->unsetParam("\\LUT_INIT");
114
115 cell->setPort("\\A", SigSpec({
116 get_bit_or_zero(cell->getPort("\\I3")),
117 get_bit_or_zero(cell->getPort("\\I2")),
118 get_bit_or_zero(cell->getPort("\\I1")),
119 get_bit_or_zero(cell->getPort("\\I0"))
120 }));
121 cell->setPort("\\Y", cell->getPort("\\O")[0]);
122 cell->unsetPort("\\I0");
123 cell->unsetPort("\\I1");
124 cell->unsetPort("\\I2");
125 cell->unsetPort("\\I3");
126 cell->unsetPort("\\O");
127
128 cell->check();
129 simplemap_lut(module, cell);
130 module->remove(cell);
131 }
132 }
133
134 struct Ice40OptPass : public Pass {
135 Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { }
136 void help() YS_OVERRIDE
137 {
138 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
139 log("\n");
140 log(" ice40_opt [options] [selection]\n");
141 log("\n");
142 log("This command executes the following script:\n");
143 log("\n");
144 log(" do\n");
145 log(" <ice40 specific optimizations>\n");
146 log(" opt_expr -mux_undef -undriven [-full]\n");
147 log(" opt_merge\n");
148 log(" opt_rmdff\n");
149 log(" opt_clean\n");
150 log(" while <changed design>\n");
151 log("\n");
152 }
153 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
154 {
155 string opt_expr_args = "-mux_undef -undriven";
156
157 log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
158 log_push();
159
160 size_t argidx;
161 for (argidx = 1; argidx < args.size(); argidx++) {
162 if (args[argidx] == "-full") {
163 opt_expr_args += " -full";
164 continue;
165 }
166 break;
167 }
168 extra_args(args, argidx, design);
169
170 while (1)
171 {
172 design->scratchpad_unset("opt.did_something");
173
174 log_header(design, "Running ICE40 specific optimizations.\n");
175 for (auto module : design->selected_modules())
176 run_ice40_opts(module);
177
178 Pass::call(design, "opt_expr " + opt_expr_args);
179 Pass::call(design, "opt_merge");
180 Pass::call(design, "opt_rmdff");
181 Pass::call(design, "opt_clean");
182
183 if (design->scratchpad_get_bool("opt.did_something") == false)
184 break;
185
186 log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
187 }
188
189 design->optimize();
190 design->sort();
191 design->check();
192
193 log_header(design, "Finished OPT passes. (There is nothing left to do.)\n");
194 log_pop();
195 }
196 } Ice40OptPass;
197
198 PRIVATE_NAMESPACE_END