mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-24 16:34:38 +00:00 
			
		
		
		
	- Techlib pmgens are now in relevant techlibs/*. - `peepopt` pmgens are now in passes/opt. - `test_pmgen` is still in passes/pmgen. - Update `Makefile.inc` and `.gitignore` file(s) to match new `*_pm.h` location, as well as the `#include`s. - Change default `%_pm.h` make target to `techlibs/%_pm.h` and move it to the top level Makefile. - Update pmgen target to use `$(notdir $*)` (where `$*` is the part of the file name that matched the '%' in the target) instead of `$(subst _pm.h,,$(notdir $@))`.
		
			
				
	
	
		
			384 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Pattern Matcher Generator
 | |
| =========================
 | |
| 
 | |
| The program `pmgen.py` reads a `.pmg` (Pattern Matcher Generator) file and
 | |
| writes a header-only C++ library that implements that pattern matcher.
 | |
| 
 | |
| The "patterns" in this context are subgraphs in a Yosys RTLIL netlist.
 | |
| 
 | |
| The algorithm used in the generated pattern matcher is a simple recursive
 | |
| search with backtracking. It is left to the author of the `.pmg` file to
 | |
| determine an efficient cell order for the search that allows for maximum
 | |
| use of indices and early backtracking.
 | |
| 
 | |
| 
 | |
| API of Generated Matcher
 | |
| ========================
 | |
| 
 | |
| When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
 | |
| a class `foobar_pm`. That class is instantiated with an RTLIL module and a
 | |
| list of cells from that module:
 | |
| 
 | |
|     foobar_pm pm(module, module->selected_cells());
 | |
| 
 | |
| The caller must make sure that none of the cells in the 2nd argument are
 | |
| deleted for as long as the pattern matcher instance is used.
 | |
| 
 | |
| At any time it is possible to disable cells, preventing them from showing
 | |
| up in any future matches:
 | |
| 
 | |
|     pm.blacklist(some_cell);
 | |
| 
 | |
| The `.run_<pattern_name>(callback_function)` method searches for all matches
 | |
| for the pattern`<pattern_name>` and calls the callback function for each found
 | |
| match:
 | |
| 
 | |
|     pm.run_foobar([&](){
 | |
|         log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
 | |
|         log("          with 'bar' cell: %s\n", log_id(pm.st.bar));
 | |
|     });
 | |
| 
 | |
| The `.pmg` file declares matcher state variables that are accessible via the
 | |
| `.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
 | |
| of type `foobar_pm::state_<pattern_name>_t`.)
 | |
| 
 | |
| 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`.
 | |
| 
 | |
| There are three versions of the `run_<pattern_name>()` method: Without callback,
 | |
| callback without arguments, and callback with reference to `pm`. All versions
 | |
| of the `run_<pattern_name>()` method return the number of found matches.
 | |
| 
 | |
| 
 | |
| The .pmg File Format
 | |
| ====================
 | |
| 
 | |
| The `.pmg` file format is a simple line-based file format. For the most part
 | |
| lines consist of whitespace-separated tokens.
 | |
| 
 | |
| Lines in `.pmg` files starting with `//` are comments.
 | |
| 
 | |
| Declaring a pattern
 | |
| -------------------
 | |
| 
 | |
| A `.pmg` file contains one or more patterns. Each pattern starts with a line
 | |
| with the `pattern` keyword followed by the name of the pattern.
 | |
| 
 | |
| Declaring state variables
 | |
| -------------------------
 | |
| 
 | |
| One or more state variables can be declared using the `state` statement,
 | |
| followed by a C++ type in angle brackets, followed by a whitespace separated
 | |
| list of variable names. For example:
 | |
| 
 | |
|     state <bool> flag1 flag2 happy big
 | |
|     state <SigSpec> sigA sigB sigY
 | |
| 
 | |
| State variables are automatically managed by the generated backtracking algorithm
 | |
| and saved and restored as needed.
 | |
| 
 | |
| They are automatically initialized to the default constructed value of their type
 | |
| when `.run_<pattern_name>(callback_function)` is called.
 | |
| 
 | |
| Declaring udata variables
 | |
| -------------------------
 | |
| 
 | |
| Udata (user-data) variables can be used for example to configure the matcher or
 | |
| the callback function used to perform actions on found matches.
 | |
| 
 | |
| There is no automatic management of udata variables. For this reason it is
 | |
| recommended that the user-supplied matcher code treats them as read-only
 | |
| variables.
 | |
| 
 | |
| They are declared like state variables, just using the `udata` statement:
 | |
| 
 | |
|     udata <int> min_data_width max_data_width
 | |
|     udata <IdString> data_port_name
 | |
| 
 | |
| They are automatically initialized to the default constructed value of their type
 | |
| when the pattern matcher object is constructed.
 | |
| 
 | |
| Embedded C++ code
 | |
| -----------------
 | |
| 
 | |
| Many statements in a `.pmg` file contain C++ code. However, there are some
 | |
| slight additions to regular C++/Yosys/RTLIL code that make it a bit easier to
 | |
| write matchers:
 | |
| 
 | |
| - Identifiers starting with a dollar sign or backslash are automatically
 | |
|   converted to special IdString variables that are initialized when the
 | |
|   matcher object is constructed.
 | |
| 
 | |
| - The `port(<cell>, <portname>)` function is a handy alias for
 | |
|   `sigmap(<cell>->getPort(<portname>))`.
 | |
| 
 | |
| - Similarly `param(<cell>, <paramname>)` looks up a parameter on a cell.
 | |
| 
 | |
| - The function `nusers(<sigspec>)` returns the number of different cells
 | |
|   connected to any of the given signal bits, plus one if any of the signal
 | |
|   bits is also a primary input or primary output.
 | |
| 
 | |
| - In `code..endcode` blocks there exist `accept`, `reject`, `branch`,
 | |
|   `finish`, and `subpattern` statements.
 | |
| 
 | |
| - In `index` statements there is a special `===` operator for the index
 | |
|   lookup.
 | |
| 
 | |
| Matching cells
 | |
| --------------
 | |
| 
 | |
| Cells are matched using `match..endmatch` blocks. For example:
 | |
| 
 | |
|     match mul
 | |
|         if ff
 | |
|         select mul->type == $mul
 | |
|         select nusers(port(mul, \Y) == 2
 | |
|         index <SigSpec> port(mul, \Y) === port(ff, \D)
 | |
|         filter some_weird_function(mul) < other_weird_function(ff)
 | |
|         optional
 | |
|     endmatch
 | |
| 
 | |
| A `match` block starts with `match <statevar>` and implicitly generates
 | |
| a state variable `<statevar>` of type `RTLIL::Cell*`.
 | |
| 
 | |
| All statements in the match block are optional. (An empty match block
 | |
| would simply match each and every cell in the module.)
 | |
| 
 | |
| The `if <expression>` statement makes the match block conditional. If
 | |
| `<expression>` evaluates to `false` then the match block will be ignored
 | |
| and the corresponding state variable is set to `nullptr`. In our example
 | |
| we only try to match the `mul` cell if the `ff` state variable points
 | |
| to a cell. (Presumably `ff` is provided by a prior `match` block.)
 | |
| 
 | |
| The `select` lines are evaluated once for each cell when the matcher is
 | |
| initialized. A `match` block will only consider cells for which all `select`
 | |
| expressions evaluated to `true`. Note that the state variable corresponding to
 | |
| the match (in the example `mul`) is the only state variable that may be used
 | |
| in `select` lines.
 | |
| 
 | |
| Index lines are using the `index <type> expr1 === expr2` syntax.  `expr1` is
 | |
| evaluated during matcher initialization and the same restrictions apply as for
 | |
| `select` expressions. `expr2` is evaluated when the match is calulated. It is a
 | |
| function of any state variables assigned to by previous blocks. Both expression
 | |
| are converted to the given type and compared for equality. Only cells for which
 | |
| all `index` statements in the block pass are considered by the match.
 | |
| 
 | |
| Note that `select` and `index` are fast operations. Thus `select` and `index`
 | |
| should be used whenever possible to create efficient matchers.
 | |
| 
 | |
| Finally, `filter <expression>` narrows down the remaining list of cells. For
 | |
| performance reasons `filter` statements should only be used for things that
 | |
| can't be done using `select` and `index`.
 | |
| 
 | |
| The `optional` statement marks optional matches. That is, the matcher will also
 | |
| explore the case where `mul` is set to `nullptr`. Without the `optional`
 | |
| statement a match may only be assigned nullptr when one of the `if` expressions
 | |
| evaluates to `false`.
 | |
| 
 | |
| The `semioptional` statement marks matches that must match if at least one
 | |
| matching cell exists, but if no matching cell exists it is set to `nullptr`.
 | |
| 
 | |
| Slices and choices
 | |
| ------------------
 | |
| 
 | |
| Cell matches can contain "slices" and "choices". Slices can be used to
 | |
| create matches for different sections of a cell. For example:
 | |
| 
 | |
|     state <int> pmux_slice
 | |
| 
 | |
|     match pmux
 | |
|         select pmux->type == $pmux
 | |
|         slice idx GetSize(port(pmux, \S))
 | |
|         index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
 | |
|         set pmux_slice idx
 | |
|     endmatch
 | |
| 
 | |
| The first argument to `slice` is the local variable name used to identify the
 | |
| slice. The second argument is the number of slices that should be created for
 | |
| this cell. The `set` statement can be used to copy that index into a state
 | |
| variable so that later matches and/or code blocks can refer to it.
 | |
| 
 | |
| A similar mechanism is "choices", where a list of options is given as
 | |
| second argument, and the matcher will iterate over those options:
 | |
| 
 | |
|     state <SigSpec> foo bar
 | |
|     state <IdString> eq_ab eq_ba
 | |
| 
 | |
|     match eq
 | |
|         select eq->type == $eq
 | |
|         choice <IdString> AB {\A, \B}
 | |
|         define <IdString> BA (AB == \A ? \B : \A)
 | |
|         index <SigSpec> port(eq, AB) === foo
 | |
|         index <SigSpec> port(eq, BA) === bar
 | |
|         set eq_ab AB
 | |
|         set eq_ba BA
 | |
|     endmatch
 | |
| 
 | |
| Notice how `define` can be used to define additional local variables similar
 | |
| to the loop variables defined by `slice` and `choice`.
 | |
| 
 | |
| Additional code
 | |
| ---------------
 | |
| 
 | |
| Interleaved with `match..endmatch` blocks there may be `code..endcode` blocks.
 | |
| Such a block starts with the keyword `code` followed by a list of state variables
 | |
| that the block may modify. For example:
 | |
| 
 | |
|     code addAB sigS
 | |
|         if (addA) {
 | |
|             addAB = addA;
 | |
|             sigS = port(addA, \B);
 | |
|         }
 | |
|         if (addB) {
 | |
|             addAB = addB;
 | |
|             sigS = port(addB, \A);
 | |
|         }
 | |
|     endcode
 | |
| 
 | |
| The special keyword `reject` can be used to reject the current state and
 | |
| backtrack. For example:
 | |
| 
 | |
|     code
 | |
|         if (ffA && ffB) {
 | |
|             if (port(ffA, \CLK) != port(ffB, \CLK))
 | |
|                 reject;
 | |
|             if (param(ffA, \CLK_POLARITY) != param(ffB, \CLK_POLARITY))
 | |
|                 reject;
 | |
|         }
 | |
|     endcode
 | |
| 
 | |
| Similarly, the special keyword `accept` can be used to accept the current
 | |
| state. (`accept` will not backtrack. This means it continues with the current
 | |
| branch and may accept a larger match later.)
 | |
| 
 | |
| The special keyword `branch` can be used to explore different cases. Note that
 | |
| each code block has an implicit `branch` at the end. So most use-cases of the
 | |
| `branch` keyword need to end the block with `reject` to avoid the implicit
 | |
| branch at the end. For example:
 | |
| 
 | |
|     state <int> mode
 | |
| 
 | |
|     code mode
 | |
|         for (mode = 0; mode < 8; mode++)
 | |
|             branch;
 | |
|         reject;
 | |
|     endcode
 | |
| 
 | |
| But in some cases it is more natural to utilize the implicit branch statement:
 | |
| 
 | |
|     state <IdString> portAB
 | |
| 
 | |
|     code portAB
 | |
|         portAB = \A;
 | |
|         branch;
 | |
|         portAB = \B;
 | |
|     endcode
 | |
| 
 | |
| There is an implicit `code..endcode` block at the end of each (sub)pattern
 | |
| that just rejects.
 | |
| 
 | |
| A `code..finally..endcode` block executes the code after `finally` during
 | |
| back-tracking. This is useful for maintaining user data state or printing
 | |
| debug messages. For example:
 | |
| 
 | |
|     udata <vector<Cell*>> stack
 | |
| 
 | |
|     code
 | |
|         stack.push_back(addAB);
 | |
|         ...
 | |
|     finally
 | |
|         stack.pop_back();
 | |
|     endcode
 | |
| 
 | |
| `accept` and `finish` statements can be used inside the `finally` section,
 | |
| but not `reject`, `branch`, or `subpattern`.
 | |
| 
 | |
| Declaring a subpattern
 | |
| ----------------------
 | |
| 
 | |
| A subpattern starts with a line containing the `subpattern` keyword followed
 | |
| by the name of the subpattern. Subpatterns can be called from a `code` block
 | |
| using a `subpattern(<subpattern_name>);` C statement.
 | |
| 
 | |
| Arguments may be passed to subpattern via state variables. The `subpattern`
 | |
| line must be followed by a `arg <arg1> <arg2> ...` line that lists the
 | |
| state variables used to pass arguments.
 | |
| 
 | |
|     state <IdString> foobar_type
 | |
|     state <bool> foobar_state
 | |
| 
 | |
|     code foobar_type foobar_state
 | |
|         foobar_state = false;
 | |
|         foobar_type = $add;
 | |
|         subpattern(foo);
 | |
|         foobar_type = $sub;
 | |
|         subpattern(bar);
 | |
|     endcode
 | |
| 
 | |
|     subpattern foo
 | |
|     arg foobar_type foobar_state
 | |
| 
 | |
|     match addsub
 | |
|         index <IdString> addsub->type === foobar_type
 | |
|         ...
 | |
|     endmatch
 | |
| 
 | |
|     code
 | |
|         if (foobar_state) {
 | |
|             subpattern(tail);
 | |
|         } else {
 | |
|             foobar_state = true;
 | |
|             subpattern(bar);
 | |
|         }
 | |
|     endcode
 | |
| 
 | |
|     subpattern bar
 | |
|     arg foobar_type foobar_state
 | |
| 
 | |
|     match addsub
 | |
|         index <IdString> addsub->type === foobar_type
 | |
|         ...
 | |
|     endmatch
 | |
| 
 | |
|     code
 | |
|         if (foobar_state) {
 | |
|             subpattern(tail);
 | |
|         } else {
 | |
|             foobar_state = true;
 | |
|             subpattern(foo);
 | |
|         }
 | |
|     endcode
 | |
| 
 | |
|     subpattern tail
 | |
|     ...
 | |
| 
 | |
| Subpatterns can be called recursively.
 | |
| 
 | |
| If a `subpattern` statement is preceded by a `fallthrough` statement, this is
 | |
| equivalent to calling the subpattern at the end of the preceding block.
 | |
| 
 | |
| Generate Blocks
 | |
| ---------------
 | |
| 
 | |
| Match blocks may contain an optional `generate` section that is used for automatic
 | |
| test-case generation. For example:
 | |
| 
 | |
|     match mul
 | |
|         ...
 | |
|     generate 10 0
 | |
|         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 first argument to `generate` is the chance of this generate block being
 | |
| executed when the match block did not match anything, in percent.
 | |
| 
 | |
| The second argument to `generate` is the chance of this generate block being
 | |
| executed when the match block did match something, in percent.
 | |
| 
 | |
| The special statement `finish` can be used within generate blocks to terminate
 | |
| the current pattern matcher run.
 |