5f7bf2189b8bfe1953c9a16642494f77079bc795
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
29 #include "passes/pmgen/test_pmgen_pm.h"
30 #include "passes/pmgen/ice40_dsp_pm.h"
31 #include "passes/pmgen/peepopt_pm.h"
33 void reduce_chain(test_pmgen_pm
&pm
)
35 auto &st
= pm
.st_reduce
;
36 auto &ud
= pm
.ud_reduce
;
38 if (ud
.longest_chain
.empty())
41 log("Found chain of length %d (%s):\n", GetSize(ud
.longest_chain
), log_id(st
.first
->type
));
44 SigSpec Y
= ud
.longest_chain
.front().first
->getPort(ID(Y
));
45 auto last_cell
= ud
.longest_chain
.back().first
;
47 for (auto it
: ud
.longest_chain
) {
49 if (cell
== last_cell
) {
50 A
.append(cell
->getPort(ID(A
)));
51 A
.append(cell
->getPort(ID(B
)));
53 A
.append(cell
->getPort(it
.second
== ID(A
) ? ID(B
) : ID(A
)));
55 log(" %s\n", log_id(cell
));
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
);
70 log(" -> %s (%s)\n", log_id(c
), log_id(c
->type
));
73 void reduce_tree(test_pmgen_pm
&pm
)
75 auto &st
= pm
.st_reduce
;
76 auto &ud
= pm
.ud_reduce
;
78 if (ud
.longest_chain
.empty())
81 SigSpec A
= ud
.leaves
;
82 SigSpec Y
= st
.first
->getPort(ID(Y
));
83 pm
.autoremove(st
.first
);
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
));
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
);
99 log(" -> %s (%s)\n", log_id(c
), log_id(c
->type
));
102 #define GENERATE_PATTERN(pmclass, pattern) \
103 generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
105 void pmtest_addports(Module
*module
)
107 pool
<SigBit
> driven_bits
, used_bits
;
108 SigMap
sigmap(module
);
109 int icnt
= 0, ocnt
= 0;
111 for (auto cell
: module
->cells())
112 for (auto conn
: cell
->connections())
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
);
122 for (auto wire
: vector
<Wire
*>(module
->wires()))
124 SigSpec ibits
, obits
;
125 for (auto bit
: sigmap(wire
)) {
126 if (!used_bits
.count(bit
))
128 if (!driven_bits
.count(bit
))
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
);
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
);
143 module
->fixup_ports();
147 void generate_pattern(std::function
<void(pm
&,std::function
<void()>)> run
, const char *pmclass
, const char *pattern
, Design
*design
)
149 log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern
, pmclass
);
156 int submodcnt
= 0, itercnt
= 0, cellcnt
= 0;
157 Module
*mod
= design
->addModule(NEW_ID
);
159 while (modcnt
< 100 && submodcnt
< maxsubcnt
&& itercnt
++ < 1000)
161 pm
matcher(mod
, mod
->cells());
164 matcher
.rngseed
+= modcnt
;
166 matcher
.rngseed
+= submodcnt
;
168 matcher
.rngseed
+= itercnt
;
170 matcher
.rngseed
+= cellcnt
;
173 if (GetSize(mod
->cells()) != cellcnt
)
175 bool found_match
= false;
176 run(matcher
, [&](){ found_match
= true; });
179 Module
*m
= design
->addModule(stringf("\\pmtest_%s_%s_%05d",
180 pmclass
, pattern
, modcnt
++));
186 cellcnt
= GetSize(mod
->cells());
189 matcher
.generate_mode
= true;
190 run(matcher
, [](){});
198 struct TestPmgenPass
: public Pass
{
199 TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
200 void help() YS_OVERRIDE
202 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
204 log(" test_pmgen -reduce_chain [options] [selection]\n");
206 log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n");
210 log(" test_pmgen -reduce_tree [options] [selection]\n");
212 log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
216 log(" test_pmgen -generate [options] <pattern_name>\n");
218 log("Create modules that match the specified pattern.\n");
222 void execute_reduce_chain(std::vector
<std::string
> args
, RTLIL::Design
*design
)
224 log_header(design
, "Executing TEST_PMGEN pass (-reduce_chain).\n");
227 for (argidx
= 2; argidx
< args
.size(); argidx
++)
229 // if (args[argidx] == "-singleton") {
230 // singleton_mode = true;
235 extra_args(args
, argidx
, design
);
237 for (auto module
: design
->selected_modules())
238 while (test_pmgen_pm(module
, module
->selected_cells()).run_reduce(reduce_chain
)) {}
241 void execute_reduce_tree(std::vector
<std::string
> args
, RTLIL::Design
*design
)
243 log_header(design
, "Executing TEST_PMGEN pass (-reduce_tree).\n");
246 for (argidx
= 2; argidx
< args
.size(); argidx
++)
248 // if (args[argidx] == "-singleton") {
249 // singleton_mode = true;
254 extra_args(args
, argidx
, design
);
256 for (auto module
: design
->selected_modules())
257 test_pmgen_pm(module
, module
->selected_cells()).run_reduce(reduce_tree
);
260 void execute_generate(std::vector
<std::string
> args
, RTLIL::Design
*design
)
262 log_header(design
, "Executing TEST_PMGEN pass (-generate).\n");
265 for (argidx
= 2; argidx
< args
.size(); argidx
++)
267 // if (args[argidx] == "-singleton") {
268 // singleton_mode = true;
274 if (argidx
+1 != args
.size())
275 log_cmd_error("Expected exactly one pattern.\n");
277 string pattern
= args
[argidx
];
279 if (pattern
== "reduce")
280 return GENERATE_PATTERN(test_pmgen_pm
, reduce
);
282 if (pattern
== "ice40_dsp")
283 return GENERATE_PATTERN(ice40_dsp_pm
, ice40_dsp
);
285 if (pattern
== "peepopt-muldiv")
286 return GENERATE_PATTERN(peepopt_pm
, muldiv
);
288 if (pattern
== "peepopt-shiftmul")
289 return GENERATE_PATTERN(peepopt_pm
, shiftmul
);
291 log_cmd_error("Unkown pattern: %s\n", pattern
.c_str());
294 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
296 if (GetSize(args
) > 1)
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
);
305 log_cmd_error("Missing or unsupported mode parameter.\n");
309 PRIVATE_NAMESPACE_END