| # Modules | |
| ## Interface | |
| This document contains all the information needed to configure modules for | |
| your _**f4pga**_ project as well as some info about the API used to write | |
| modules. | |
| ### Configuration interface: | |
| Modules are configured through an internal API by _**f4pga**_. | |
| The basic requirement for a module script is to expose a class with `Module` | |
| interface. | |
| _**f4pga**_ reads its configuration from two different sources: | |
| **platform's flow definition**, which is a file that usually comes bundled with f4pga | |
| and **project's flow configuration**, which is a set of configuration options provided by the user | |
| through a JSON file or CLI interface. | |
| Those sources contain snippets of _module configurations_. | |
| A _module configuration_ is a structure with the following fields: | |
| * `takes` - a dictionary that contains keys which are names of the dependencies used by the module. | |
| The values are paths to those dependencies. | |
| They can be either singular strings or lists of strings. | |
| * `produces` - a dictionary that contains keys which are names of the dependencies produced by the module. | |
| The values are requested filenames for the files generated by the module. | |
| They can be either singular strings or lists of strings. | |
| * `values` - a dictionary that contains other values used to configure the module. | |
| The keys are value's names and the values can have any type. | |
| ### Platform-level configuration | |
| In case of **platform's flow definition**, a `values` dictionary can be defined | |
| globally and the values defined there will be passed to every module's config. | |
| Those values can be overridden per-module through `module_options` dictionary. | |
| Parameters used during module's construction can also be defined in `module_options` | |
| as `params` (those are not a part of _module configuration_, instead they are used | |
| during the actual construction of a module instance, before it declares any of its | |
| input/outputs etc.. This is typically used to achieve some parametrization over module's | |
| I/O). | |
| Defining dictionaries for `takes` and `produces` is currently disallowed within | |
| **platform's flow definition**. | |
| For examples of **platform's flow definition** described here, please have a look at | |
| `f4pga/platforms/` directory. It contains **platform flow definitions** that come bundled | |
| with f4pga. | |
| ### Project-level configuration | |
| This section describes **project's flow configuration**. | |
| Similarly to **platform's flow definition**, `values` dict can be provided. | |
| The values provided there will overwrite the values from | |
| **platform's flow definition** in case of a collision. | |
| Unlike **platform's flow definition**, **project's flow configuration** may contain | |
| `dependencies` dict. This dictionary would be used to map symbolic dependency | |
| names to actual paths. Most dependencies can have their paths resolved implicitly | |
| without the need to provide explicit paths, which is a mechanism that is described | |
| in a later section of this document. However some dependencies must be provided | |
| explicitly, eg. paths to project's Verilog source files. It should be noted that | |
| depending on the flow definition and the dependency in question, the path does not | |
| necessarily have to point to an already existing file. If the dependency is a | |
| product of a module within the flow, the path assigned to it will be used | |
| by the module to build that dependency. This is also used to in case of _on-demand_ | |
| dependencies, which won't be produced unless the user explicitly provides a path | |
| for them. | |
| **project's flow configuration** cannot specify `params` for modules and does not | |
| use `module_options` dictionary. Neither it can instantiate any extra stages. | |
| Any entry with a couple _exceptions*_ is treated as a platform name. | |
| Enabling support for a given platform within a **project's flow configuration** file | |
| requires having an entry for that platform. | |
| Each of those entries may contain `dependencies`, `values` fields which will | |
| overload the `dependecies` and `values` defined in a global scope of | |
| **project's flow configuration**. Any other field under those platform entries | |
| is treated as a _stage-specific-configuration_. The key is a name of a stage within | |
| a flow for the specified platform and the values are dicts which may contain | |
| `dependencies` and `values` fields that overload `dependencies` and `values` | |
| respectively, locally for the stage. Additionally a `default_target` field can be | |
| provided to specify a default target to built when the user does not specify it through | |
| a CLI interface. | |
| The aforementioned _*exceptions_ are: | |
| * `dependencies` - dependencies shared by all platforms. | |
| * `values` - values shared by all platforms | |
| * `default_platform` - default platform to chose in case it doesn't get specified | |
| by the user | |
| Those apply only to flow configuration file. | |
| ### Internal environmental variables | |
| It's very useful to be able to refer to some data within | |
| **platform's flow definition** and **project's flow configuration** to | |
| either avoid redundant definitions or to store and access results of certain operations. | |
| _**f4pga**_ allows doing that by using a special syntax for accessing internal | |
| environmental variables. | |
| The syntax is `${variable_name}`. Any string value within | |
| **platform's flow definition** and **project's flow configuration** that contains | |
| such patterns will have them replaced with the values of the variables referenced | |
| if those values are strings. Eg.: | |
| With the following values defined: | |
| ```json | |
| { | |
| "a_value": "1234", | |
| "another_value": "a_value: ${a_value}" | |
| } | |
| ``` | |
| `another_value` will resolve to: | |
| ```json | |
| "a_value: 1234" | |
| ``` | |
| If the value is a list however, the result would be a list with all entries being | |
| the original string with the reference to a variable replaced by following | |
| items of the original list. Eg.: | |
| With the following values defined | |
| ```json | |
| { | |
| "list_of_values": ["a", "b", "c"], | |
| "some_string": "item: ${list_of_values}" | |
| } | |
| ``` | |
| `some_string` will resolve to | |
| ```json | |
| ["item: a", "item: b", "item: c"] | |
| ``` | |
| Be careful when using this kind of resolution, as it's computational and memory | |
| complexity grows exponentially in regards to the number of list variables being | |
| referenced, which is a rather obvious fact, but it's still worth mentioning. | |
| The variables that can be referenced within a definition/configuration fall into 3 | |
| categories: | |
| * **value references** - anything declared as a `value` can be accessed by it's | |
| name | |
| * **dependency references** - any dependency path can be referenced using the name | |
| of the dependency prefaced with a ':' prefix. Eg.: `${:eblif}` will resolve | |
| to the path of `eblif` dependency. Make sure that the dependency can be | |
| actually resolved when you are using this kind of reference. For example | |
| you can't use the a reference to `eblif` dependency in a module which does not | |
| rely on it. An exception is the producer module which can in fact reference it's | |
| own outputs but these references cannot be used during the _mapping_ stage | |
| (more on that later). | |
| * **built-in references** - there are a couple of built-in variables which are very | |
| handy: | |
| * `shareDir` - path to f4pga's _share_ directory. | |
| * `binDir` - path to f4pga's _bin_ directory. | |
| * `prjxray_db` - Project X-Ray database path. | |
| * `python3` - path to Python 3 interpreter. | |
| * `noisyWarnings` - (this one should probably get removed) | |
| ### `Module` class | |
| Each module is represented as a class derived from `Module` class. | |
| The class should implement the following methods: | |
| * `execute(self, ctx: ModuleContext)` - executes the module in _exec_ mode | |
| * `map_io(self, ctx: ModuleContext) -> 'dict[str, ]'` - executes the module in | |
| _mapping_ mode | |
| * `__init__(self, params: 'dict[str, ]')` - initializer. The `params` | |
| is a dict with optional parameter for the module. | |
| Each module script should expose the class by defining it's name/type alias as | |
| `ModuleClass`. f4pga tries to access a `ModuleClass` attribute within a package | |
| when instantiating a module. | |
| ### Module's execution modes | |
| A module has essentially two execution modes: | |
| * _mapping_ mode | |
| * _exec_ mode | |
| #### _mapping_ mode | |
| In _mapping_ mode the module is provided with an incomplete configuration which | |
| includes: | |
| * `takes` namespace: this maps names of input dependencies to the paths of these | |
| dependencies | |
| * `values` namespace: this maps names of variables to the values of those | |
| variables. | |
| The module has to provide a dictionary that will provide every output dependency | |
| that's not _on-demand_ a default path. This is basically a promise that when | |
| executed in _exec_ mode, the module will produce files for this paths. | |
| Typically such paths would be derived from a path of one of it's input dependencies. | |
| This mechanism allows the user to avoid specifying an explicit path for each | |
| intermediate target. | |
| It should be noted that variables referring to the output dependencies | |
| can't be accessed at this stage for the obvious reason as their values are yet | |
| to be evaluated. | |
| #### _exec_ mode | |
| In _exec_ mode the module does the actual work. | |
| The configuration passed into this mode is full and it includes: | |
| * `takes` namespace: this maps names of input dependencies to the paths of these | |
| dependencies | |
| * `values` namespace: this maps names of variables to the values of those | |
| variables. | |
| * `produces` namespace: this maps names of output dependencies to explicit paths. | |
| This should not be used directly really, but it's useful for | |
| `ModuleContext.is_output_explicit` method. | |
| * `outputs` namespace: this maps names of output dependencies to their paths. | |
| When the module finishes executing in _exec_ mode, all of the dependencies | |
| described in `outputs` should be present. | |
| ### Module initialization/instantiation | |
| In the `__init__` method of module's class, the following fields should be | |
| set: | |
| * `takes` - a list of symbolic dependency names for dependencies used by the module | |
| * `produces` - a list of symbolic dependencies names for dependencies produced | |
| by the module. | |
| * `values` - a list of names given to the variables used withing the module | |
| * `prod_meta` - A dictionary which maps product names to descriptions of these | |
| products. Those entries are optional and can be skipped. | |
| #### Qualifiers/decorators | |
| By default the presence of all the dependencies and values is mandatory | |
| (In case of `produces` that means that the module always has to produce the listed | |
| dependencies). This can be changed by "decorating" a name in one of the following | |
| ways: | |
| * '`?`' _suffix_ | |
| * In `takes` - the dependency is not necessary for the module to execute | |
| * In `produces` - the dependency may be produced, but it is not guaranteed. | |
| * In `values` the value is not required for the module to execute. | |
| Referring to it through `ModuleContext.values.value_name` won't raise an | |
| exception if the value is not present, instead `None` will be returned. | |
| * '`!`' _suffix_ | |
| * In `produces` - the dependency is going to be produced only if the user | |
| provides an explicit path for it. | |
| Currently it's impossible to combine both '`!`' and '`?`' together. This limitation | |
| does not have any reason behind it other than the way the qualifier system | |
| is implemented at the moment. It might be removed in the future. | |
| ## Common modules | |
| ```{toctree} | |
| fasm | |
| generic_script_wrapper | |
| io_rename | |
| mkdirs | |
| pack | |
| place | |
| place_constraints | |
| route | |
| synth | |
| ``` |