ice40: reduce ABC9 internal fanout warnings with a param for CI->I3
[yosys.git] / passes / pmgen / generate.h
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 #ifndef PMGEN_GENERATE
21 #define PMGEN_GENERATE
22
23 #define GENERATE_PATTERN(pmclass, pattern) \
24 generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
25
26 void pmtest_addports(Module *module)
27 {
28 pool<SigBit> driven_bits, used_bits;
29 SigMap sigmap(module);
30 int icnt = 0, ocnt = 0;
31
32 for (auto cell : module->cells())
33 for (auto conn : cell->connections())
34 {
35 if (cell->input(conn.first))
36 for (auto bit : sigmap(conn.second))
37 used_bits.insert(bit);
38 if (cell->output(conn.first))
39 for (auto bit : sigmap(conn.second))
40 driven_bits.insert(bit);
41 }
42
43 for (auto wire : vector<Wire*>(module->wires()))
44 {
45 SigSpec ibits, obits;
46 for (auto bit : sigmap(wire)) {
47 if (!used_bits.count(bit))
48 obits.append(bit);
49 if (!driven_bits.count(bit))
50 ibits.append(bit);
51 }
52 if (!ibits.empty()) {
53 Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
54 w->port_input = true;
55 module->connect(ibits, w);
56 }
57 if (!obits.empty()) {
58 Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
59 w->port_output = true;
60 module->connect(w, obits);
61 }
62 }
63
64 module->fixup_ports();
65 }
66
67 template <class pm>
68 void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
69 {
70 log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
71
72 int modcnt = 0;
73 int maxmodcnt = 100;
74 int maxsubcnt = 4;
75 int timeout = 0;
76 vector<Module*> mods;
77
78 while (modcnt < maxmodcnt)
79 {
80 int submodcnt = 0, itercnt = 0, cellcnt = 0;
81 Module *mod = design->addModule(NEW_ID);
82
83 while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
84 {
85 if (timeout++ > 10000)
86 log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
87
88 pm matcher(mod, mod->cells());
89
90 matcher.rng(1);
91 matcher.rngseed += modcnt;
92 matcher.rng(1);
93 matcher.rngseed += submodcnt;
94 matcher.rng(1);
95 matcher.rngseed += itercnt;
96 matcher.rng(1);
97 matcher.rngseed += cellcnt;
98 matcher.rng(1);
99
100 if (GetSize(mod->cells()) != cellcnt)
101 {
102 bool found_match = false;
103 run(matcher, [&](){ found_match = true; });
104 cellcnt = GetSize(mod->cells());
105
106 if (found_match) {
107 Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
108 pmclass, pattern, modcnt++));
109 log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
110 mod->cloneInto(m);
111 pmtest_addports(m);
112 mods.push_back(m);
113 submodcnt++;
114 timeout = 0;
115 }
116 }
117
118 matcher.generate_mode = true;
119 run(matcher, [](){});
120 }
121
122 if (submodcnt && maxsubcnt < (1 << 16))
123 maxsubcnt *= 2;
124
125 design->remove(mod);
126 }
127
128 Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
129 log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
130 for (auto mod : mods) {
131 Cell *c = m->addCell(mod->name, mod->name);
132 for (auto port : mod->ports) {
133 Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
134 c->setPort(port, w);
135 }
136 }
137 pmtest_addports(m);
138 }
139
140 #endif