Philipp Wagner | bbbb327 | 2021-03-15 18:36:51 +0000 | [diff] [blame] | 1 | --- |
| 2 | title: "Ipgen: Generate IP blocks from IP templates" |
| 3 | --- |
| 4 | |
| 5 | Ipgen is a tool to produce IP blocks from IP templates. |
| 6 | |
| 7 | IP templates are highly customizable IP blocks which need to be pre-processed before they can be used in a hardware design. |
| 8 | In the pre-processing ("rendering"), which is performed by the ipgen tool, templates of source files, written in the Mako templating language, are converted into "real" source files. |
| 9 | The templates can be customized through template parameters, which are available within the templates. |
| 10 | |
| 11 | Ipgen is a command-line tool and a library. |
| 12 | Users wishing to instantiate an IP template or query it for template parameters will find the command-line application useful. |
| 13 | For use in higher-level scripting, e.g. within [topgen](topgen_tool.md) using ipgen as Python library is recommended. |
| 14 | |
| 15 | |
| 16 | ## Anatomy of an IP template |
| 17 | |
| 18 | An IP template is a directory with a well-defined directory layout, which mostly mirrors the standard layout of IP blocks. |
| 19 | |
| 20 | An IP template directory has a well-defined structure: |
| 21 | |
| 22 | * The IP template name (`<templatename>`) equals the directory name. |
| 23 | * The directory contains a file `data/<templatename>.tpldesc.hjson` containing all configuration information related to the template. |
| 24 | * The directory also contains zero or more files ending in `.tpl`. |
| 25 | These files are Mako templates and rendered into an file in the same location without the `.tpl` file extension. |
| 26 | |
| 27 | ### The template description file |
| 28 | |
| 29 | Each IP template comes with a description itself. |
| 30 | This description is contained in the `data/<templatename>.tpldesc.hjson` file in the template directory. |
| 31 | The file is written in Hjson. |
| 32 | |
| 33 | It contains a top-level dictionary, the keys of which are documented next. |
| 34 | |
| 35 | #### List of template parameters: `template_param_list` |
| 36 | |
| 37 | Keys within `template_param_list`: |
| 38 | |
| 39 | * `name` (string): Name of the template parameter. |
| 40 | * `desc` (string): Human-readable description of the template parameter. |
| 41 | * `type` (string): Data type of the parameter. Valid values: `int`, `str` |
| 42 | * `default` (string|int): The default value of the parameter. The data type should match the `type` argument. As convenience, strings are converted into integers on demand (if possible). |
| 43 | |
| 44 | #### Example template description file |
| 45 | |
| 46 | An exemplary template description file with two parameters, `src` and `target` is shown below. |
| 47 | |
| 48 | ```hjson |
| 49 | // data/<templatename>.tpldesc.hjson |
| 50 | { |
| 51 | "template_param_list": [ |
| 52 | { |
| 53 | "name": "src", |
| 54 | "desc": "Number of Interrupt Source", |
| 55 | "type": "int", |
| 56 | "default": "32" |
| 57 | }, |
| 58 | { |
| 59 | "name": "target", |
| 60 | "desc": "Number of Interrupt Targets", |
| 61 | "type": "int", |
| 62 | "default": "32" |
| 63 | }, |
| 64 | ], |
| 65 | } |
| 66 | ``` |
| 67 | |
| 68 | ### Source file templates (`.tpl` files) |
| 69 | |
| 70 | Templates are written in the [Mako templating language](https://www.makotemplates.org/). |
| 71 | All template parameters are available in the rendering context. |
| 72 | For example, a template parameter `src` can be used in the template as `{{ src }}`. |
| 73 | |
| 74 | Furthermore, the following functions are available: |
| 75 | |
| 76 | * `instance_vlnv(vlnv)`: Transform a FuseSoC core name, expressed as VLNV string, into an instance-specific name. |
| 77 | The `vendor` is set to `lowrisc`, the `library` is set to `opentitan`, and the `name` is prefixed with the instance name. |
Philipp Wagner | 5d21c9a | 2021-10-04 20:57:03 +0100 | [diff] [blame] | 78 | The optional version segment is retained. |
Philipp Wagner | bbbb327 | 2021-03-15 18:36:51 +0000 | [diff] [blame] | 79 | Use this function on the `name` of all FuseSoC cores which contain sources generated from templates and which export symbols into the global namespace. |
| 80 | |
| 81 | ### Templating FuseSoC core files |
| 82 | |
| 83 | FuseSoC core files can be templated just like any other file. |
| 84 | Especially handy is the `instance_vlnv()` template function, which transforms a placeholder VLNV (a string in the form `vendor:library:name:version`) into a instance-specific one. |
| 85 | |
| 86 | For example, a `rv_plic.core.tpl` file could look like this: |
| 87 | |
| 88 | ```yaml |
| 89 | CAPI=2: |
| 90 | name: ${instance_vlnv("lowrisc:ip:rv_plic")} |
| 91 | ``` |
| 92 | |
| 93 | After processing, the `name` key is set to e.g. `lowrisc:opentitan:top_earlgrey_rv_plic`. |
| 94 | |
| 95 | The following rules should be applied when creating IP templates: |
| 96 | |
| 97 | * Template and use an instance-specific name for all FuseSoC cores which reference templated source files (e.g. SystemVerilog files). |
| 98 | * Template and use an instance-specific name at least the top-level FuseSoC core. |
| 99 | * If a FuseSoC core with an instance-specific name exposes a well-defined public interface (see below) add a `provides: lowrisc:ip_interfaces:<name>` line to the core file to allow other cores to refer to it without knowning the actual core name. |
| 100 | |
| 101 | #### Templating core files to uphold the "same name, same interface" principle |
| 102 | |
| 103 | FuseSoC core files should be written in a way that upholds the principle "same name, same public interface", i.e. if a FuseSoC core has the same name as another one, it must also provide the same public interface. |
| 104 | |
| 105 | Since SystemVerilog does not provide no strong control over which symbols become part of the public API developers must be carefully evaluate their source code. |
| 106 | At least, the public interface is comprised of |
| 107 | - module header(s), e.g. parameter names, ports (names, data types), |
| 108 | - package names, and all identifiers within it, including enum values (but not the values assigned to them), |
| 109 | - defines |
| 110 | |
| 111 | If any of those aspects of a source file are templated, the core name referencing the files must be made instance-specific. |
| 112 | |
| 113 | ## Library usage |
| 114 | |
| 115 | Ipgen can be used as Python library by importing from the `ipgen` package. |
| 116 | Refer to the comments within the source code for usage information. |
| 117 | |
| 118 | The following example shows how to produce an IP block from an IP template. |
| 119 | |
| 120 | ```python |
| 121 | from pathlib import Path |
| 122 | from ipgen import IpConfig, IpTemplate, IpBlockRenderer |
| 123 | |
| 124 | # Load the template |
| 125 | ip_template = IpTemplate.from_template_path(Path('a/ip/template/directory')) |
| 126 | |
| 127 | # Prepare the IP template configuration |
| 128 | params = {} |
| 129 | params['src'] = 17 |
| 130 | ip_config = IpConfig("my_instance", params) |
| 131 | |
| 132 | # Produce an IP block |
| 133 | renderer = IpBlockRenderer(ip_template, ip_config) |
| 134 | renderer.render(Path("path/to/the/output/directory")) |
| 135 | ``` |
| 136 | |
| 137 | The output produced by ipgen is determined by the chosen renderer. |
| 138 | For most use cases the `IpBlockRenderer` is the right choice, as it produces a full IP block directory. |
| 139 | Refer to the `ipgen.renderer` module for more renderers available with ipgen. |
| 140 | |
| 141 | ## Command-line usage |
| 142 | |
| 143 | The ipgen command-line tool lives in `util/ipgen.py`. |
| 144 | The first argument is typically the action to be executed. |
| 145 | |
| 146 | ```console |
| 147 | $ cd $REPO_TOP |
| 148 | $ util/ipgen.py --help |
| 149 | usage: ipgen.py [-h] ACTION ... |
| 150 | |
| 151 | optional arguments: |
| 152 | -h, --help show this help message and exit |
| 153 | |
| 154 | actions: |
| 155 | Use 'ipgen.py ACTION --help' to learn more about the individual actions. |
| 156 | |
| 157 | ACTION |
| 158 | describe Show details about an IP template |
| 159 | generate Generate an IP block from an IP template |
| 160 | ``` |
| 161 | |
| 162 | ## `ipgen generate` |
| 163 | |
| 164 | ```console |
| 165 | $ cd $REPO_TOP |
| 166 | $ util/ipgen.py generate --help |
| 167 | usage: ipgen.py generate [-h] [--verbose] -C TEMPLATE_DIR -o OUTDIR [--force] [--config-file CONFIG_FILE] |
| 168 | |
| 169 | Generate an IP block from an IP template |
| 170 | |
| 171 | optional arguments: |
| 172 | -h, --help show this help message and exit |
| 173 | --verbose More info messages |
| 174 | -C TEMPLATE_DIR, --template-dir TEMPLATE_DIR |
| 175 | IP template directory |
| 176 | -o OUTDIR, --outdir OUTDIR |
| 177 | output directory for the resulting IP block |
| 178 | --force, -f overwrite the output directory, if it exists |
| 179 | --config-file CONFIG_FILE, -c CONFIG_FILE |
| 180 | path to a configuration file |
| 181 | ``` |
| 182 | |
| 183 | ## `ipgen describe` |
| 184 | |
| 185 | ```console |
| 186 | $ cd $REPO_TOP |
| 187 | $ util/ipgen.py generate --help |
| 188 | usage: ipgen.py describe [-h] [--verbose] -C TEMPLATE_DIR |
| 189 | |
| 190 | Show all information available for the IP template. |
| 191 | |
| 192 | optional arguments: |
| 193 | -h, --help show this help message and exit |
| 194 | --verbose More info messages |
| 195 | -C TEMPLATE_DIR, --template-dir TEMPLATE_DIR |
| 196 | IP template directory |
| 197 | ``` |
| 198 | |
| 199 | |
| 200 | ## Limitations |
| 201 | |
| 202 | ### Changing the IP block name is not supported |
| 203 | |
| 204 | Every IP block has a name, which is reflected in many places: in the name of the directory containing the block, in the base name of various files (e.g. the Hjson files in the `data` directory), in the `name` key of the IP description file in `data/<ipname>.hjson`, and many more. |
| 205 | |
| 206 | To "rename" an IP block, the content of multiple files, and multiple file names, have to be adjusted to reflect the name of the IP block, while keeping cross-references intact. |
| 207 | Doing that is possible but a non-trivial amount of work, which is currently not implemented. |
| 208 | This limitation is of lesser importance, as each template may be used only once in every toplevel design (see below). |
| 209 | |
| 210 | What is supported and required for most IP templates is the modification of the FuseSoC core name, which can be achieved by templating relevant `.core` files (see above). |
| 211 | |
| 212 | |
| 213 | ### Each template may be used only once per (top-level) design |
| 214 | |
| 215 | Each template may be used to generate only once IP block for each top-level design. |
| 216 | The generated IP block can still be instantiated multiple times from SystemVerilog, including with different SystemVerilog parameters passed to it. |
| 217 | It is not possible, however, to, for example, use one IP block template to produce two different flash controllers with different template parameters. |
| 218 | |
| 219 | IP templates generally contain code which exports symbols into the global namespace of the design: names of SystemVerilog modules and packages, defines, names of FuseSoC cores, etc. |
| 220 | Such names need to be unique for each design, i.e. we cannot have multiple SystemVerilog modules with the same name in one design. |
| 221 | To produce multiple IP blocks from the same IP template within a top-level design, exported symbols in generated IP blocks must be made "unique" within the design. |
| 222 | Making symbols unique can be either done manually by the author of the template or automatically. |
| 223 | |
| 224 | In the manual approach, the template author writes all global identifiers in templates in a unique way, e.g. `module {prefix}_flash_ctrl` in SystemVerilog code, and with similar approaches wherever the name of the IP block is used (e.g. in cross-references in `top_<toplevelname>.hjson`). |
| 225 | This is easy to implement in ipgen, but harder on the IP template authors, as it is easy to miss identifiers. |
| 226 | |
| 227 | In the automated approach, a tool that understands the source code transforms all identifiers. |
| 228 | C++ name mangling uses a similar approach. |
| 229 | The challenge is, however, to create a tool which can reliably do such source code transformations on a complex language like SystemVerilog. |
| 230 | |
| 231 | Finally, a third approach could be a combination of less frequently used/supported SystemVerilog language features like libraries, configs, and compilation units. |