blob: 41baf9c3bb38d892493770ccc4a2bf32aeac389c [file] [log] [blame] [view]
Philipp Wagnerbbbb3272021-03-15 18:36:51 +00001---
2title: "Ipgen: Generate IP blocks from IP templates"
3---
4
5Ipgen is a tool to produce IP blocks from IP templates.
6
7IP templates are highly customizable IP blocks which need to be pre-processed before they can be used in a hardware design.
8In 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.
9The templates can be customized through template parameters, which are available within the templates.
10
11Ipgen is a command-line tool and a library.
12Users wishing to instantiate an IP template or query it for template parameters will find the command-line application useful.
13For 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
18An IP template is a directory with a well-defined directory layout, which mostly mirrors the standard layout of IP blocks.
19
20An 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
29Each IP template comes with a description itself.
30This description is contained in the `data/<templatename>.tpldesc.hjson` file in the template directory.
31The file is written in Hjson.
32
33It contains a top-level dictionary, the keys of which are documented next.
34
35#### List of template parameters: `template_param_list`
36
37Keys 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
46An 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
70Templates are written in the [Mako templating language](https://www.makotemplates.org/).
71All template parameters are available in the rendering context.
72For example, a template parameter `src` can be used in the template as `{{ src }}`.
73
74Furthermore, 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 Wagner5d21c9a2021-10-04 20:57:03 +010078 The optional version segment is retained.
Philipp Wagnerbbbb3272021-03-15 18:36:51 +000079 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
83FuseSoC core files can be templated just like any other file.
84Especially 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
86For example, a `rv_plic.core.tpl` file could look like this:
87
88```yaml
89CAPI=2:
90name: ${instance_vlnv("lowrisc:ip:rv_plic")}
91```
92
93After processing, the `name` key is set to e.g. `lowrisc:opentitan:top_earlgrey_rv_plic`.
94
95The 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
103FuseSoC 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
105Since SystemVerilog does not provide no strong control over which symbols become part of the public API developers must be carefully evaluate their source code.
106At 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
111If 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
115Ipgen can be used as Python library by importing from the `ipgen` package.
116Refer to the comments within the source code for usage information.
117
118The following example shows how to produce an IP block from an IP template.
119
120```python
121from pathlib import Path
122from ipgen import IpConfig, IpTemplate, IpBlockRenderer
123
124# Load the template
125ip_template = IpTemplate.from_template_path(Path('a/ip/template/directory'))
126
127# Prepare the IP template configuration
128params = {}
129params['src'] = 17
130ip_config = IpConfig("my_instance", params)
131
132# Produce an IP block
133renderer = IpBlockRenderer(ip_template, ip_config)
134renderer.render(Path("path/to/the/output/directory"))
135```
136
137The output produced by ipgen is determined by the chosen renderer.
138For most use cases the `IpBlockRenderer` is the right choice, as it produces a full IP block directory.
139Refer to the `ipgen.renderer` module for more renderers available with ipgen.
140
141## Command-line usage
142
143The ipgen command-line tool lives in `util/ipgen.py`.
144The first argument is typically the action to be executed.
145
146```console
147$ cd $REPO_TOP
148$ util/ipgen.py --help
149usage: ipgen.py [-h] ACTION ...
150
151optional arguments:
152 -h, --help show this help message and exit
153
154actions:
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
167usage: ipgen.py generate [-h] [--verbose] -C TEMPLATE_DIR -o OUTDIR [--force] [--config-file CONFIG_FILE]
168
169Generate an IP block from an IP template
170
171optional 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
188usage: ipgen.py describe [-h] [--verbose] -C TEMPLATE_DIR
189
190Show all information available for the IP template.
191
192optional 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
204Every 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
206To "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.
207Doing that is possible but a non-trivial amount of work, which is currently not implemented.
208This limitation is of lesser importance, as each template may be used only once in every toplevel design (see below).
209
210What 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
215Each template may be used to generate only once IP block for each top-level design.
216The generated IP block can still be instantiated multiple times from SystemVerilog, including with different SystemVerilog parameters passed to it.
217It is not possible, however, to, for example, use one IP block template to produce two different flash controllers with different template parameters.
218
219IP 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.
220Such names need to be unique for each design, i.e. we cannot have multiple SystemVerilog modules with the same name in one design.
221To 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.
222Making symbols unique can be either done manually by the author of the template or automatically.
223
224In 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`).
225This is easy to implement in ipgen, but harder on the IP template authors, as it is easy to miss identifiers.
226
227In the automated approach, a tool that understands the source code transforms all identifiers.
228C++ name mangling uses a similar approach.
229The challenge is, however, to create a tool which can reliably do such source code transformations on a complex language like SystemVerilog.
230
231Finally, a third approach could be a combination of less frequently used/supported SystemVerilog language features like libraries, configs, and compilation units.