5f7bf2189b8bfe1953c9a16642494f77079bc795
[yosys.git] / passes / pmgen / test_pmgen.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
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 // for peepopt_pm
27 bool did_something;
28
29 #include "passes/pmgen/test_pmgen_pm.h"
30 #include "passes/pmgen/ice40_dsp_pm.h"
31 #include "passes/pmgen/peepopt_pm.h"
32
33 void reduce_chain(test_pmgen_pm &pm)
34 {
35 auto &st = pm.st_reduce;
36 auto &ud = pm.ud_reduce;
37
38 if (ud.longest_chain.empty())
39 return;
40
41 log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
42
43 SigSpec A;
44 SigSpec Y = ud.longest_chain.front().first->getPort(ID(Y));
45 auto last_cell = ud.longest_chain.back().first;
46
47 for (auto it : ud.longest_chain) {
48 auto cell = it.first;
49 if (cell == last_cell) {
50 A.append(cell->getPort(ID(A)));
51 A.append(cell->getPort(ID(B)));
52 } else {
53 A.append(cell->getPort(it.second == ID(A) ? ID(B) : ID(A)));
54 }
55 log(" %s\n", log_id(cell));
56 pm.autoremove(cell);
57 }
58
59 Cell *c;
60
61 if (last_cell->type == ID($_AND_))
62 c = pm.module->addReduceAnd(NEW_ID, A, Y);
63 else if (last_cell->type == ID($_OR_))
64 c = pm.module->addReduceOr(NEW_ID, A, Y);
65 else if (last_cell->type == ID($_XOR_))
66 c = pm.module->addReduceXor(NEW_ID, A, Y);
67 else
68 log_abort();
69
70 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
71 }
72
73 void reduce_tree(test_pmgen_pm &pm)
74 {
75 auto &st = pm.st_reduce;
76 auto &ud = pm.ud_reduce;
77
78 if (ud.longest_chain.empty())
79 return;
80
81 SigSpec A = ud.leaves;
82 SigSpec Y = st.first->getPort(ID(Y));
83 pm.autoremove(st.first);
84
85 log("Found %s tree with %d leaves for %s (%s).\n", log_id(st.first->type),
86 GetSize(A), log_signal(Y), log_id(st.first));
87
88 Cell *c;
89
90 if (st.first->type == ID($_AND_))
91 c = pm.module->addReduceAnd(NEW_ID, A, Y);
92 else if (st.first->type == ID($_OR_))
93 c = pm.module->addReduceOr(NEW_ID, A, Y);
94 else if (st.first->type == ID($_XOR_))
95 c = pm.module->addReduceXor(NEW_ID, A, Y);
96 else
97 log_abort();
98
99 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
100 }
101
102 #define GENERATE_PATTERN(pmclass, pattern) \
103 generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
104
105 void pmtest_addports(Module *module)
106 {
107 pool<SigBit> driven_bits, used_bits;
108 SigMap sigmap(module);
109 int icnt = 0, ocnt = 0;
110
111 for (auto cell : module->cells())
112 for (auto conn : cell->connections())
113 {
114 if (cell->input(conn.first))
115 for (auto bit : sigmap(conn.second))
116 used_bits.insert(bit);
117 if (cell->output(conn.first))
118 for (auto bit : sigmap(conn.second))
119 driven_bits.insert(bit);
120 }
121
122 for (auto wire : vector<Wire*>(module->wires()))
123 {
124 SigSpec ibits, obits;
125 for (auto bit : sigmap(wire)) {
126 if (!used_bits.count(bit))
127 obits.append(bit);
128 if (!driven_bits.count(bit))
129 ibits.append(bit);
130 }
131 if (!ibits.empty()) {
132 Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
133 w->port_input = true;
134 module->connect(ibits, w);
135 }
136 if (!obits.empty()) {
137 Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
138 w->port_output = true;
139 module->connect(w, obits);
140 }
141 }
142
143 module->fixup_ports();
144 }
145
146 template <class pm>
147 void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
148 {
149 log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
150
151 int modcnt = 0;
152 int maxsubcnt = 4;
153
154 while (modcnt < 100)
155 {
156 int submodcnt = 0, itercnt = 0, cellcnt = 0;
157 Module *mod = design->addModule(NEW_ID);
158
159 while (modcnt < 100 && submodcnt < maxsubcnt && itercnt++ < 1000)
160 {
161 pm matcher(mod, mod->cells());
162
163 matcher.rng(1);
164 matcher.rngseed += modcnt;
165 matcher.rng(1);
166 matcher.rngseed += submodcnt;
167 matcher.rng(1);
168 matcher.rngseed += itercnt;
169 matcher.rng(1);
170 matcher.rngseed += cellcnt;
171 matcher.rng(1);
172
173 if (GetSize(mod->cells()) != cellcnt)
174 {
175 bool found_match = false;
176 run(matcher, [&](){ found_match = true; });
177
178 if (found_match) {
179 Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
180 pmclass, pattern, modcnt++));
181 mod->cloneInto(m);
182 pmtest_addports(m);
183 submodcnt++;
184 }
185
186 cellcnt = GetSize(mod->cells());
187 }
188
189 matcher.generate_mode = true;
190 run(matcher, [](){});
191 }
192
193 design->remove(mod);
194 maxsubcnt *= 2;
195 }
196 }
197
198 struct TestPmgenPass : public Pass {
199 TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
200 void help() YS_OVERRIDE
201 {
202 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
203 log("\n");
204 log(" test_pmgen -reduce_chain [options] [selection]\n");
205 log("\n");
206 log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n");
207 log("\n");
208
209 log("\n");
210 log(" test_pmgen -reduce_tree [options] [selection]\n");
211 log("\n");
212 log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
213 log("\n");
214
215 log("\n");
216 log(" test_pmgen -generate [options] <pattern_name>\n");
217 log("\n");
218 log("Create modules that match the specified pattern.\n");
219 log("\n");
220 }
221
222 void execute_reduce_chain(std::vector<std::string> args, RTLIL::Design *design)
223 {
224 log_header(design, "Executing TEST_PMGEN pass (-reduce_chain).\n");
225
226 size_t argidx;
227 for (argidx = 2; argidx < args.size(); argidx++)
228 {
229 // if (args[argidx] == "-singleton") {
230 // singleton_mode = true;
231 // continue;
232 // }
233 break;
234 }
235 extra_args(args, argidx, design);
236
237 for (auto module : design->selected_modules())
238 while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {}
239 }
240
241 void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design)
242 {
243 log_header(design, "Executing TEST_PMGEN pass (-reduce_tree).\n");
244
245 size_t argidx;
246 for (argidx = 2; argidx < args.size(); argidx++)
247 {
248 // if (args[argidx] == "-singleton") {
249 // singleton_mode = true;
250 // continue;
251 // }
252 break;
253 }
254 extra_args(args, argidx, design);
255
256 for (auto module : design->selected_modules())
257 test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
258 }
259
260 void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
261 {
262 log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
263
264 size_t argidx;
265 for (argidx = 2; argidx < args.size(); argidx++)
266 {
267 // if (args[argidx] == "-singleton") {
268 // singleton_mode = true;
269 // continue;
270 // }
271 break;
272 }
273
274 if (argidx+1 != args.size())
275 log_cmd_error("Expected exactly one pattern.\n");
276
277 string pattern = args[argidx];
278
279 if (pattern == "reduce")
280 return GENERATE_PATTERN(test_pmgen_pm, reduce);
281
282 if (pattern == "ice40_dsp")
283 return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
284
285 if (pattern == "peepopt-muldiv")
286 return GENERATE_PATTERN(peepopt_pm, muldiv);
287
288 if (pattern == "peepopt-shiftmul")
289 return GENERATE_PATTERN(peepopt_pm, shiftmul);
290
291 log_cmd_error("Unkown pattern: %s\n", pattern.c_str());
292 }
293
294 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
295 {
296 if (GetSize(args) > 1)
297 {
298 if (args[1] == "-reduce_chain")
299 return execute_reduce_chain(args, design);
300 if (args[1] == "-reduce_tree")
301 return execute_reduce_tree(args, design);
302 if (args[1] == "-generate")
303 return execute_generate(args, design);
304 }
305 log_cmd_error("Missing or unsupported mode parameter.\n");
306 }
307 } TestPmgenPass;
308
309 PRIVATE_NAMESPACE_END