3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-07 09:55:20 +00:00

Add pmgen finish statement, return number of matches

Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
Clifford Wolf 2019-08-16 14:16:35 +02:00
parent f45dad8220
commit 20910fd7c8
4 changed files with 108 additions and 74 deletions

View file

@ -45,9 +45,9 @@ of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of Similarly the `.pmg` file declares user data variables that become members of
`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback, There are three versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with callback without arguments, and callback with reference to `pm`. All versions
reference to `pm.st_<pattern_name>`. of the `run_<pattern_name>()` method return the number of found matches.
The .pmg File Format The .pmg File Format
@ -118,8 +118,8 @@ write matchers:
connected to any of the given signal bits, plus one if any of the signal connected to any of the given signal bits, plus one if any of the signal
bits is also a primary input or primary output. bits is also a primary input or primary output.
- In `code..endcode` blocks there exist `accept`, `reject`, `branch`, and - In `code..endcode` blocks there exist `accept`, `reject`, `branch`,
`subpattern` statements. `finish`, and `subpattern` statements.
- In `index` statements there is a special `===` operator for the index - In `index` statements there is a special `===` operator for the index
lookup. lookup.
@ -246,13 +246,13 @@ debug messages. For example:
code code
stack.push_back(addAB); stack.push_back(addAB);
... ...
finally finally
stack.pop_back(); stack.pop_back();
endcode endcode
`accept` statements can be used inside the `finally` section, but not `accept` and `finish` statements can be used inside the `finally` section,
`reject`, `branch`, or `subpattern`. but not `reject`, `branch`, or `subpattern`.
Declaring a subpattern Declaring a subpattern
---------------------- ----------------------
@ -265,52 +265,75 @@ Arguments may be passed to subpattern via state variables. The `subpattern`
line must be followed by a `arg <arg1> <arg2> ...` line that lists the line must be followed by a `arg <arg1> <arg2> ...` line that lists the
state variables used to pass arguments. state variables used to pass arguments.
state <IdString> foobar_type state <IdString> foobar_type
state <bool> foobar_state state <bool> foobar_state
code foobar_type foobar_state code foobar_type foobar_state
foobar_state = false; foobar_state = false;
foobar_type = $add; foobar_type = $add;
subpattern(foo); subpattern(foo);
foobar_type = $sub; foobar_type = $sub;
subpattern(bar); subpattern(bar);
endcode endcode
subpattern foo subpattern foo
arg foobar_type foobar_state arg foobar_type foobar_state
match addsub match addsub
index <IdString> addsub->type === foobar_type index <IdString> addsub->type === foobar_type
... ...
endmatch endmatch
code code
if (foobar_state) { if (foobar_state) {
subpattern(tail); subpattern(tail);
} else { } else {
foobar_state = true; foobar_state = true;
subpattern(bar); subpattern(bar);
} }
endcode endcode
subpattern bar subpattern bar
arg foobar_type foobar_state arg foobar_type foobar_state
match addsub match addsub
index <IdString> addsub->type === foobar_type index <IdString> addsub->type === foobar_type
... ...
endmatch endmatch
code code
if (foobar_state) { if (foobar_state) {
subpattern(tail); subpattern(tail);
} else { } else {
foobar_state = true; foobar_state = true;
subpattern(foo); subpattern(foo);
} }
endcode endcode
subpattern tail subpattern tail
... ...
Subpatterns cann be called recursively. Subpatterns cann be called recursively.
Generate Blocks
---------------
Match blocks may contain an optional `generate` section that is used for automatic
test-case generation. For example:
match mul
...
generate 10
SigSpec Y = port(ff, \D);
SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
module->addMul(NEW_ID, A, B, Y, rng(2));
endmatch
The expression `rng(n)` returns a non-negative integer less than `n`.
The argument to `generate` is the chance of this generate block being executed
when the match block did not match anything, in percent.
The special statement `finish` can be used within generate blocks to terminate
the current pattern matcher run.

View file

@ -328,6 +328,7 @@ with open(outfile, "w") as f:
print(" SigMap sigmap;", file=f) print(" SigMap sigmap;", file=f)
print(" std::function<void()> on_accept;", file=f) print(" std::function<void()> on_accept;", file=f)
print(" bool generate_mode;", file=f) print(" bool generate_mode;", file=f)
print(" int accept_cnt;", file=f)
print("", file=f) print("", file=f)
print(" uint32_t rngseed;", file=f) print(" uint32_t rngseed;", file=f)
@ -476,7 +477,8 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
for current_pattern in sorted(patterns.keys()): for current_pattern in sorted(patterns.keys()):
print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" accept_cnt = 0;", file=f)
print(" on_accept = on_accept_f;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)
print(" blacklist_dirty = false;", file=f) print(" blacklist_dirty = false;", file=f)
@ -487,14 +489,15 @@ with open(outfile, "w") as f:
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f) print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
print(" block_{}(1);".format(patterns[current_pattern]), file=f) print(" block_{}(1);".format(patterns[current_pattern]), file=f)
print(" log_assert(rollback_stack.empty());", file=f) print(" log_assert(rollback_stack.empty());", file=f)
print(" return accept_cnt;", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) print(" int run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) print(" return run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}() {{".format(current_pattern), file=f) print(" int run_{}() {{".format(current_pattern), file=f)
print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f) print(" return run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
@ -574,7 +577,8 @@ with open(outfile, "w") as f:
if block["type"] == "code": if block["type"] == "code":
print("", file=f) print("", file=f)
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("#define accept do { accept_cnt++; on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f)
print("#define finish do { rollback = -1; rollback_stack.clean(); goto rollback_label; } while(0)", file=f)
print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
@ -586,6 +590,7 @@ with open(outfile, "w") as f:
print("#undef reject", file=f) print("#undef reject", file=f)
print("#undef accept", file=f) print("#undef accept", file=f)
print("#undef finish", file=f)
print("#undef branch", file=f) print("#undef branch", file=f)
print("#undef subpattern", file=f) print("#undef subpattern", file=f)
@ -594,10 +599,12 @@ with open(outfile, "w") as f:
print(" YS_ATTRIBUTE(unused);", file=f) print(" YS_ATTRIBUTE(unused);", file=f)
if len(block["fcode"]): if len(block["fcode"]):
print("#define accept do { on_accept(); check_blacklist(); } while(0)", file=f) print("#define accept do { accept_cnt++; on_accept(); check_blacklist(); } while(0)", file=f)
print("#define finish do { rollback = -1; rollback_stack.clean(); return; } while(0)", file=f)
for line in block["fcode"]: for line in block["fcode"]:
print(" " + line, file=f) print(" " + line, file=f)
print("#undef accept", file=f) print("#undef accept", file=f)
print("#undef finish", file=f)
if len(restore_st) or len(nonconst_st): if len(restore_st) or len(nonconst_st):
print("", file=f) print("", file=f)
@ -631,29 +638,32 @@ with open(outfile, "w") as f:
print(" index_{}_key_type key;".format(index), file=f) print(" index_{}_key_type key;".format(index), file=f)
for field, entry in enumerate(block["index"]): for field, entry in enumerate(block["index"]):
print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f) print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f)
print(" const vector<Cell*> &cells = index_{}[key];".format(index), file=f) print(" auto cells_ptr = index_{}.find(key);".format(index), file=f)
if block["semioptional"] or block["genargs"] is not None: if block["semioptional"] or block["genargs"] is not None:
print(" bool found_any_match = false;", file=f) print(" bool found_any_match = false;", file=f)
print("", file=f) print("", file=f)
print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
print(" {} = cells[idx];".format(block["cell"]), file=f) print(" const vector<Cell*> &cells = cells_ptr->second;".format(index), file=f)
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f)
print(" {} = cells[idx];".format(block["cell"]), file=f)
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
for expr in block["filter"]: for expr in block["filter"]:
print(" if (!({})) continue;".format(expr), file=f) print(" if (!({})) continue;".format(expr), file=f)
if block["semioptional"] or block["genargs"] is not None: if block["semioptional"] or block["genargs"] is not None:
print(" found_any_match = true;", file=f) print(" found_any_match = true;", file=f)
print(" rollback_stack.push_back(make_pair(cells[idx], recursion));", file=f) print(" rollback_stack.push_back(make_pair(cells[idx], recursion));", file=f)
print(" block_{}(recursion+1);".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), file=f)
print(" if (rollback == 0) {", file=f) print(" if (rollback == 0) {", file=f)
print(" rollback_stack.pop_back();", file=f) print(" rollback_stack.pop_back();", file=f)
print(" } else {", file=f) print(" } else {", file=f)
print(" if (rollback != recursion) {{".format(index+1), file=f) print(" if (rollback != recursion) {{".format(index+1), file=f)
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f)
print(" return;", file=f) print(" return;", file=f)
print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f) print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f) print(" }", file=f)
print(" }", file=f) print(" }", file=f)
@ -669,14 +679,14 @@ with open(outfile, "w") as f:
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f)
if block["genargs"] is not None: if block["genargs"] is not None:
print("#define finish do { rollback = -1; rollback_stack.clean(); return; } while(0)", file=f)
print(" if (generate_mode && !found_any_match) {", file=f) print(" if (generate_mode && !found_any_match) {", file=f)
if len(block["genargs"]) == 1: if len(block["genargs"]) == 1:
print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f) print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f)
for line in block["gencode"]: for line in block["gencode"]:
print(" " + line, file=f) print(" " + line, file=f)
print(" rollback_stack.clear();", file=f)
print(" rollback = -1;", file=f)
print(" }", file=f) print(" }", file=f)
print("#undef finish", file=f)
else: else:
assert False assert False

View file

@ -235,7 +235,7 @@ struct TestPmgenPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain); while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {}
} }
void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design) void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design)

View file

@ -41,7 +41,8 @@ code
finally finally
chain.pop_back(); chain.pop_back();
log_assert(chain.empty()); log_assert(chain.empty());
accept; if (GetSize(longest_chain) > 1)
accept;
endcode endcode
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -80,7 +81,7 @@ match next
select next->type.in($_AND_, $_OR_, $_XOR_) select next->type.in($_AND_, $_OR_, $_XOR_)
index <IdString> next->type === chain.back().first->type index <IdString> next->type === chain.back().first->type
index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second) index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
generate 50 generate 10
SigSpec A = module->addWire(NEW_ID); SigSpec A = module->addWire(NEW_ID);
SigSpec B = module->addWire(NEW_ID); SigSpec B = module->addWire(NEW_ID);
SigSpec Y = port(chain.back().first, chain.back().second); SigSpec Y = port(chain.back().first, chain.back().second);