From c710df181c2e9931ce464ea60568c864b7195e8b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 16 Aug 2019 13:26:36 +0200 Subject: [PATCH] Add pmgen "generate" feature Signed-off-by: Clifford Wolf --- passes/pmgen/pmgen.py | 57 +++++++++++---- passes/pmgen/test_pmgen.cc | 142 ++++++++++++++++++++++++++++++++++++ passes/pmgen/test_pmgen.pmg | 22 ++++++ 3 files changed, 208 insertions(+), 13 deletions(-) diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index c6e9a9cbf..e252c52f5 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -186,6 +186,9 @@ def process_pmgfile(f, filename): block["src"] = "%s:%d" % (filename, linenr) block["pattern"] = (current_pattern, current_subpattern) + block["genargs"] = None + block["gencode"] = None + line = line.split() assert len(line) == 2 assert (line[1] not in state_types[current_pattern]) or (state_types[current_pattern][line[1]] == "Cell*") @@ -236,6 +239,19 @@ def process_pmgfile(f, filename): block["semioptional"] = True continue + if a[0] == "generate": + block["genargs"] = list([int(s) for s in a[1:]]) + block["gencode"] = list() + assert len(block["genargs"]) < 2 + while True: + linenr += 1 + l = f.readline() + assert l != "" + a = l.split() + if a[0] == "endmatch": break + block["gencode"].append(rewrite_cpp(l.rstrip())) + break + assert False if block["optional"]: @@ -310,7 +326,17 @@ with open(outfile, "w") as f: print("struct {}_pm {{".format(prefix), file=f) print(" Module *module;", file=f) print(" SigMap sigmap;", file=f) - print(" std::function on_accept;".format(prefix), file=f) + print(" std::function on_accept;", file=f) + print(" bool generate_mode;", file=f) + print("", file=f) + + print(" uint32_t rngseed;", file=f) + print(" int rng(unsigned int n) {", file=f) + print(" rngseed ^= rngseed << 13;", file=f) + print(" rngseed ^= rngseed >> 17;", file=f) + print(" rngseed ^= rngseed << 5;", file=f) + print(" return rngseed % n;", file=f) + print(" }", file=f) print("", file=f) for index in range(len(blocks)): @@ -415,7 +441,7 @@ with open(outfile, "w") as f: print("", file=f) print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) - print(" module(module), sigmap(module) {", file=f) + print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f) for current_pattern in sorted(patterns.keys()): for s, t in sorted(udata_types[current_pattern].items()): if t.endswith("*"): @@ -469,17 +495,15 @@ with open(outfile, "w") as f: print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) print(" }", file=f) print("", file=f) - print(" void run_{}(std::function on_accept_f) {{".format(current_pattern, current_pattern), file=f) - print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) - print(" }", file=f) - print("", file=f) print(" void run_{}() {{".format(current_pattern), file=f) print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f) print(" }", file=f) print("", file=f) - for p, s in sorted(subpatterns.keys()): - print(" void block_subpattern_{}_{}() {{ block_{}(); }}".format(p, s, subpatterns[(p, s)]), file=f) + if len(subpatterns): + for p, s in sorted(subpatterns.keys()): + print(" void block_subpattern_{}_{}() {{ block_{}(); }}".format(p, s, subpatterns[(p, s)]), file=f) + print("", file=f) current_pattern = None current_subpattern = None @@ -611,8 +635,8 @@ with open(outfile, "w") as f: print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f) print(" const vector &cells = index_{}[key];".format(index), file=f) - if block["semioptional"]: - print(" bool found_semioptional_match = false;", file=f) + if block["semioptional"] or block["genargs"] is not None: + print(" bool found_any_match = false;", file=f) print("", file=f) print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) @@ -620,8 +644,8 @@ with open(outfile, "w") as f: print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) for expr in block["filter"]: print(" if (!({})) continue;".format(expr), file=f) - if block["semioptional"]: - print(" found_semioptional_match = true;", file=f) + if block["semioptional"] or block["genargs"] is not None: + print(" found_any_match = true;", file=f) print(" block_{}();".format(index+1), file=f) print(" if (rollback) {", file=f) print(" if (rollback != {}) {{".format(index+1), file=f) @@ -639,10 +663,17 @@ with open(outfile, "w") as f: print(" block_{}();".format(index+1), file=f) if block["semioptional"]: - print(" if (!found_semioptional_match) block_{}();".format(index+1), file=f) + print(" if (!found_any_match) block_{}();".format(index+1), file=f) print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) + if block["genargs"] is not None: + print(" if (generate_mode && !found_any_match) {", file=f) + if len(block["genargs"]) == 1: + print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f) + for line in block["gencode"]: + print(" " + line, file=f) + print(" }", file=f) else: assert False diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc index 3bff9ae12..48d58b263 100644 --- a/passes/pmgen/test_pmgen.cc +++ b/passes/pmgen/test_pmgen.cc @@ -23,7 +23,12 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +// for peepopt_pm +bool did_something; + #include "passes/pmgen/test_pmgen_pm.h" +#include "passes/pmgen/ice40_dsp_pm.h" +#include "passes/pmgen/peepopt_pm.h" void reduce_chain(test_pmgen_pm &pm) { @@ -94,6 +99,100 @@ void reduce_tree(test_pmgen_pm &pm) log(" -> %s (%s)\n", log_id(c), log_id(c->type)); } +#define GENERATE_PATTERN(pmclass, pattern) \ + generate_pattern([](pmclass &pm, std::function f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) + +void pmtest_addports(Module *module) +{ + pool driven_bits, used_bits; + SigMap sigmap(module); + int icnt = 0, ocnt = 0; + + for (auto cell : module->cells()) + for (auto conn : cell->connections()) + { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + used_bits.insert(bit); + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + driven_bits.insert(bit); + } + + for (auto wire : vector(module->wires())) + { + SigSpec ibits, obits; + for (auto bit : sigmap(wire)) { + if (!used_bits.count(bit)) + obits.append(bit); + if (!driven_bits.count(bit)) + ibits.append(bit); + } + if (!ibits.empty()) { + Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits)); + w->port_input = true; + module->connect(ibits, w); + } + if (!obits.empty()) { + Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits)); + w->port_output = true; + module->connect(w, obits); + } + } + + module->fixup_ports(); +} + +template +void generate_pattern(std::function)> run, const char *pmclass, const char *pattern, Design *design) +{ + log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); + + int modcnt = 0; + + while (modcnt < 100) + { + int submodcnt = 0, itercnt = 0, cellcnt = 0; + Module *mod = design->addModule(NEW_ID); + + while (submodcnt < 10 && itercnt++ < 1000) + { + pm matcher(mod, mod->cells()); + + matcher.rng(1); + matcher.rngseed += modcnt; + matcher.rng(1); + matcher.rngseed += submodcnt; + matcher.rng(1); + matcher.rngseed += itercnt; + matcher.rng(1); + matcher.rngseed += cellcnt; + matcher.rng(1); + + if (GetSize(mod->cells()) != cellcnt) + { + bool found_match = false; + run(matcher, [&](){ found_match = true; }); + + if (found_match) { + Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d", + pmclass, pattern, modcnt++)); + mod->cloneInto(m); + pmtest_addports(m); + submodcnt++; + } + + cellcnt = GetSize(mod->cells()); + } + + matcher.generate_mode = true; + run(matcher, [](){}); + } + + design->remove(mod); + } +} + struct TestPmgenPass : public Pass { TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { } void help() YS_OVERRIDE @@ -104,11 +203,18 @@ struct TestPmgenPass : public Pass { log("\n"); log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n"); log("\n"); + log("\n"); log(" test_pmgen -reduce_tree [options] [selection]\n"); log("\n"); log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); log("\n"); + + log("\n"); + log(" test_pmgen -generate [options] \n"); + log("\n"); + log("Create modules that match the specified pattern.\n"); + log("\n"); } void execute_reduce_chain(std::vector args, RTLIL::Design *design) @@ -149,6 +255,40 @@ struct TestPmgenPass : public Pass { test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); } + void execute_generate(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + + if (argidx+1 != args.size()) + log_cmd_error("Expected exactly one pattern.\n"); + + string pattern = args[argidx]; + + if (pattern == "reduce") + return GENERATE_PATTERN(test_pmgen_pm, reduce); + + if (pattern == "ice40_dsp") + return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); + + if (pattern == "peepopt-muldiv") + return GENERATE_PATTERN(peepopt_pm, muldiv); + + if (pattern == "peepopt-shiftmul") + return GENERATE_PATTERN(peepopt_pm, shiftmul); + + log_cmd_error("Unkown pattern: %s\n", pattern.c_str()); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { if (GetSize(args) > 1) @@ -157,6 +297,8 @@ struct TestPmgenPass : public Pass { return execute_reduce_chain(args, design); if (args[1] == "-reduce_tree") return execute_reduce_tree(args, design); + if (args[1] == "-generate") + return execute_generate(args, design); } log_cmd_error("Missing or unsupported mode parameter.\n"); } diff --git a/passes/pmgen/test_pmgen.pmg b/passes/pmgen/test_pmgen.pmg index ccb37e553..077d337d6 100644 --- a/passes/pmgen/test_pmgen.pmg +++ b/passes/pmgen/test_pmgen.pmg @@ -13,6 +13,22 @@ endcode match first select first->type.in($_AND_, $_OR_, $_XOR_) filter !non_first_cells.count(first) +generate + SigSpec A = module->addWire(NEW_ID); + SigSpec B = module->addWire(NEW_ID); + SigSpec Y = module->addWire(NEW_ID); + switch (rng(3)) + { + case 0: + module->addAndGate(NEW_ID, A, B, Y); + break; + case 1: + module->addOrGate(NEW_ID, A, B, Y); + break; + case 2: + module->addXorGate(NEW_ID, A, B, Y); + break; + } endmatch code @@ -64,6 +80,12 @@ match next select next->type.in($_AND_, $_OR_, $_XOR_) index next->type === chain.back().first->type index port(next, \Y) === port(chain.back().first, chain.back().second) +generate 50 + SigSpec A = module->addWire(NEW_ID); + SigSpec B = module->addWire(NEW_ID); + SigSpec Y = port(chain.back().first, chain.back().second); + Cell *c = module->addAndGate(NEW_ID, A, B, Y); + c->type = chain.back().first->type; endmatch code -- 2.30.2