-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
GHA
committed
Sep 9, 2024
0 parents
commit c56a984
Showing
259 changed files
with
24,671 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Sphinx build info version 1 | ||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. | ||
config: 018e93181f9d5503ad98b5d544ba9bf1 | ||
tags: 645f666f9bcd5a90fca523b33c5a78b7 |
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Command-line Interface | ||
|
||
## Building design | ||
|
||
To run Topwrap, use: | ||
|
||
``` | ||
python -m topwrap build --design project.yml | ||
``` | ||
|
||
Where `project.yml` should be your file with description of the top module. | ||
|
||
You can specify a directory to be scanned for additional sources: | ||
|
||
``` | ||
python -m topwrap build --sources src --design project.yml | ||
``` | ||
|
||
To implement the design for a specific FPGA chip, provide the part name: | ||
|
||
``` | ||
python -m topwrap build --sources src --design project.yml --part 'xc7z020clg400-3' | ||
``` | ||
|
||
(connect-topwrap-to-pm)= | ||
|
||
## Connect Topwrap to Pipeline Manager | ||
|
||
If you want to use Pipeline Manager as a UI for creating block design, you need to: | ||
|
||
1. Build and run Pipeline Manager server application. | ||
|
||
``` | ||
python -m topwrap kpm_build_server | ||
python -m topwrap kpm_run_server | ||
``` | ||
|
||
2. Run Topwrap's client application, that will connect to a running Pipeline Manager server app. | ||
|
||
``` | ||
python -m topwrap kpm_client [-h ip_addr] [-p port] [-d FILE] FILES | ||
``` | ||
|
||
Topwrap will then try to connect to the server running on `ip_addr:port` and send a specification generated from `FILES`, which should be IP core description yamls. | ||
|
||
If `-h` or `-p` options are not specified, ip address `127.0.0.1` and port `9000` will be chosen by default. | ||
|
||
If `-d` option is specified, kpm will start with specified design file loaded. | ||
|
||
(generating-ip-yamls)= | ||
|
||
## Generating IP core description YAMLs | ||
|
||
You can also use Topwrap to generate ip core description yamls from HDL sources, | ||
that can be later used in your `project.yml`: | ||
|
||
``` | ||
python -m topwrap parse HDL_FILES | ||
``` | ||
|
||
In HDL source files, ports that belong to the same interface (e.g. wishbone or AXI), | ||
have often a common prefix, which corresponds to the interface name. If such naming | ||
convention is followed in the HDL sources, Topwrap can also divide ports into user-specified | ||
interfaces, or automatically deduce interfaces names when generating yaml file: | ||
|
||
``` | ||
python -m topwrap parse --iface wishbone --iface s_axi HDL_FILES | ||
|
||
python -m topwrap parse --iface-deduce HDL_FILES | ||
``` | ||
|
||
To get help, use: | ||
|
||
``` | ||
python -m topwrap [build|kpm_client|parse] --help | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
(description-files)= | ||
|
||
# Description files | ||
|
||
(design-description)= | ||
|
||
## Design Description | ||
|
||
To create a complete, fully synthesizable design, a proper design file is needed. | ||
It's used to specify interconnects, IP cores, set their parameters' values, describe hierarchies for the project, | ||
connect the IPs and hierarchies, and pick external ports (those which will be connected to physical I/O). | ||
|
||
You can see example design files in `examples` directory. The structure is as below: | ||
|
||
```yaml | ||
ips: | ||
# specify relations between IPs instance names in the | ||
# design yaml and IP cores description yamls | ||
{ip_instance_name}: | ||
file: {path_to_yaml_file_of_the_ip} | ||
... | ||
|
||
design: | ||
name: {design_name} # optional name of the toplevel | ||
hierarchies: | ||
# see "Hierarchies" page for a detailed description of the format | ||
... | ||
parameters: # specify IPs parameter values to be overridden | ||
{ip_instance_name}: | ||
{param_name} : {param_value} | ||
... | ||
|
||
ports: | ||
# specify incoming ports connections of an IP named `ip1_name` | ||
{ip1_name}: | ||
{port1_name} : [{ip2_name}, {port2_name}] | ||
... | ||
# specify incoming ports connections of a hierarchy named `hier_name` | ||
{hier_name}: | ||
{port1_name} : [{ip_name}, {port2_name}] | ||
... | ||
# specify external ports connections | ||
{ip_instance_name}: | ||
{port_name} : ext_port_name | ||
... | ||
|
||
interfaces: | ||
# specify incoming interfaces connections of `ip1_name` IP | ||
{ip1_name}: | ||
{iface1_name} : [{ip2_name}, {iface2_name}] | ||
... | ||
# specify incoming interfaces connections of `hier_name` hierarchy | ||
{hier_name}: | ||
{iface1_name} : [{ip_name}, {iface2_name}] | ||
... | ||
# specify external interfaces connections | ||
{ip_instance_name}: | ||
{iface_name} : ext_iface_name | ||
... | ||
|
||
interconnects: | ||
# see "Interconnect generation" page for a detailed description of the format | ||
... | ||
|
||
external: # specify names of external ports and interfaces of the top module | ||
ports: | ||
out: | ||
- {ext_port_name} | ||
inout: | ||
- [{ip_name/hierarchy_name, port_name}] | ||
interfaces: | ||
in: | ||
- {ext_iface_name} | ||
# note that `inout:` is invalid in the interfaces section | ||
``` | ||
|
||
`inout` ports are handled differently than `in` and `out` ports. When any IP has an inout port or when a hierarchy has an inout port specified in its `external.ports.inout` section, it must be included in `external.ports.inout` section of the parent design by specifying the name of the IP/hierarchy and port name that contains it. Name of the external port will be identical to the one in the IP core. In case of duplicate names a suffix `$n` is added (where `n` is a natural number) to the name of the second and subsequent duplicate names. `inout` ports cannot be connected to each other. | ||
|
||
The design description yaml format allows creating hierarchical designs. In order to create a hierarchy, it suffices to add its name as a key in the `design` section and describe the hierarchy design "recursively" by using the same keys and values (`ports`, `parameters` etc.) as in the top-level design (see above). Hierarchies can be nested recursively, which means that you can create a hierarchy inside another one. | ||
|
||
Note that IPs and hierarchies names cannot be duplicated on the same hierarchy level. For example, the `design` section cannot contain two identical keys, but it's correct to have `ip_name` key in this section and `ip_name` in the `design` section of some hierarchy. | ||
|
||
(ip-description)= | ||
|
||
## IP description files | ||
|
||
Every IP wrapped by Topwrap needs a description file in YAML format. | ||
|
||
The ports of an IP should be placed in global `signals` node, followed by the direction of `in`, `out` or `inout`. | ||
Here's an example description of ports of Clock Crossing IP: | ||
|
||
```yaml | ||
# file: clock_crossing.yaml | ||
signals: | ||
in: | ||
- clkA | ||
- A | ||
- clkB | ||
out: | ||
- B | ||
``` | ||
|
||
The previous example is enough to make use of any IP. However, in order to benefit from connecting whole interfaces at once, ports must belong to a named interface like in this example: | ||
|
||
```yaml | ||
#file: axis_width_converter.yaml | ||
interfaces: | ||
s_axis: | ||
type: AXIStream | ||
mode: slave | ||
signals: | ||
in: | ||
TDATA: [s_axis_tdata, 63, 0] | ||
TKEEP: [s_axis_tkeep, 7, 0] | ||
TVALID: s_axis_tvalid | ||
TLAST: s_axis_tlast | ||
TID: [s_axis_tid, 7, 0] | ||
TDEST: [s_axis_tdest, 7, 0] | ||
TUSER: s_axis_tuser | ||
out: | ||
TREADY: s_axis_tready | ||
|
||
m_axis: | ||
type: AXIStream | ||
mode: master | ||
signals: | ||
in: | ||
TREADY: m_axis_tready | ||
out: | ||
TDATA: [m_axis_tdata, 31, 0] | ||
TKEEP: [m_axis_tkeep, 3, 0] | ||
TVALID: m_axis_tvalid | ||
TLAST: m_axis_tlast | ||
TID: [m_axis_tid, 7, 0] | ||
TDEST: [m_axis_tdest, 7, 0] | ||
TUSER: m_axis_tuser | ||
signals: # These ports don't belong to any interface | ||
in: | ||
- clk | ||
- rst | ||
``` | ||
|
||
Names `s_axis` and `m_axis` will be used to group the selected ports. | ||
Each signal in an interface has a name which must match with the signal it's supposed to be connected to, for example `TDATA: port_name` will be connected to `TDATA: other_port_name`. | ||
|
||
Note that you don't have to write IP core description yamls by hand. You can use Topwrap's `parse` command (see {ref}`Generating IP core description YAMLs <generating-ip-yamls>`) in order to generate yamls from HDL source files and then adjust the yaml to your needs. | ||
|
||
### Port widths | ||
|
||
The width of every port defaults to `1`. | ||
You can specify the width using this notation: | ||
|
||
```yaml | ||
interfaces: | ||
s_axis: | ||
type: AXIStream | ||
mode: slave | ||
signals: | ||
in: | ||
TDATA: [s_axis_tdata, 63, 0] # 64 bits | ||
... | ||
TVALID: s_axis_tvalid # defaults to 1 bit | ||
|
||
signals: | ||
in: | ||
- [gpio_io_i, 31, 0] # 32 bits | ||
``` | ||
|
||
### Parameterization | ||
|
||
Port widths don't have to be hardcoded - you can use parameters to describe an IP core in a generic way. | ||
Values specified in IP core yamls can be overridden in a design description file (see {ref}`Design Description <design-description>`). | ||
|
||
```yaml | ||
parameters: | ||
DATA_WIDTH: 8 | ||
KEEP_WIDTH: (DATA_WIDTH+7)/8 | ||
ID_WIDTH: 8 | ||
DEST_WIDTH: 8 | ||
USER_WIDTH: 1 | ||
|
||
interfaces: | ||
s_axis: | ||
type: AXI4Stream | ||
mode: slave | ||
signals: | ||
in: | ||
TDATA: [s_axis_tdata, DATA_WIDTH-1, 0] | ||
TKEEP: [s_axis_tkeep, KEEP_WIDTH-1, 0] | ||
... | ||
TID: [s_axis_tid, ID_WIDTH-1, 0] | ||
TDEST: [s_axis_tdest, DEST_WIDTH-1, 0] | ||
TUSER: [s_axis_tuser, USER_WIDTH-1, 0] | ||
``` | ||
|
||
Parameters values can be integers or math expressions, which are evaluated using `numexpr.evaluate()`. | ||
|
||
(port-slicing)= | ||
|
||
### Port slicing | ||
|
||
You can also slice a port, to use some bits of the port as a signal that belongs to an interface. | ||
The example below means: | ||
|
||
`Port m_axi_bid of the IP core is 36 bits wide. Use bits 23..12 as the BID signal of AXI master named m_axi_1` | ||
|
||
```yaml | ||
m_axi_1: | ||
type: AXI | ||
mode: master | ||
signals: | ||
in: | ||
BID: [m_axi_bid, 35, 0, 23, 12] | ||
``` | ||
|
||
(interface-description-files)= | ||
|
||
## Interface Description files | ||
|
||
Topwrap can use predefined interfaces described in YAML files that come packaged with the tool. | ||
Currently supported interfaces are AXI4, AXI3, AXI Stream, AXI Lite and Wishbone. | ||
|
||
You can see an example file below: | ||
|
||
```yaml | ||
name: AXI4Stream | ||
port_prefix: AXIS | ||
signals: | ||
# convention assumes the AXI Stream transmitter (master) perspective | ||
required: | ||
out: | ||
TVALID: tvalid | ||
TDATA: tdata | ||
TLAST: tlast | ||
in: | ||
TREADY: tready | ||
optional: | ||
out: | ||
TID: tid | ||
TDEST: tdest | ||
TKEEP: tkeep | ||
TSTRB: tstrb | ||
TUSER: tuser | ||
TWAKEUP: twakeup | ||
``` | ||
|
||
The name of an interface has to be unique. | ||
We also specify a prefix which will be used as a shortened identifier. | ||
Signals are either required or optional. | ||
Their direction is described from the the perspective of master (i.e. directionality of signals in the slave is flipped) - note that clock and reset are not included as these are usually inputs in both master and slave so they're not supported in interface specification. | ||
These distinctions are used when an option to check if all mandatory signals are present is enabled and when parsing an IP core with `topwrap parse` (not all required signals must necessarily be present but it's taken into account). | ||
Every signal is a key-value pair, where the key is a generic signal name (usually from interface specification) and value is a regex that is used to pair the generic name with a concrete signal name in the RTL source when using `topwrap parse`. | ||
This pairing is performed on signal names that are transformed to lowercase and have a common prefix of an interface they belong to removed. | ||
If a regexp occurs in such transformed signal name anywhere, that name is paired with the generic name. | ||
Since this occurs on names that have all characters in lowercase, regex must be written in lowercase as well. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Config | ||
|
||
A {class}`~topwrap.config.Config` object stores configuration values. | ||
A global `topwrap.config.config` object is used throughout the codebase to access topwrap's configuration. | ||
This is created by {class}`~topwrap.config.ConfigManager` that reads config files defined in {attr}`topwrap.config.ConfigManager.DEFAULT_SEARCH_PATHS`, with files most local to the project taking precedence. | ||
|
||
```{eval-rst} | ||
.. autoclass:: topwrap.config.Config | ||
:members: | ||
|
||
.. automethod:: __init__ | ||
``` | ||
|
||
```{eval-rst} | ||
.. autoclass:: topwrap.config.ConfigManager | ||
:members: | ||
|
||
.. automethod:: __init__ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# ElaboratableWrapper class | ||
|
||
{class}`~topwrap.elaboratable_wrapper.ElaboratableWrapper` encapsulates an Amaranth's Elaboratable and exposes an interface compatible with other wrappers which allows making connections with them. | ||
Supplied elaboratable must contain a `signature` property and a conforming interface as specified by [Amaranth docs](https://amaranth-lang.org/rfcs/0002-interfaces.html). | ||
Ports' directionality, their names and widths are inferred from it. | ||
|
||
```{eval-rst} | ||
.. autoclass:: topwrap.elaboratable_wrapper.ElaboratableWrapper | ||
:members: | ||
|
||
.. automethod:: __init__ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Examples | ||
|
||
:::{note} | ||
Basic usage of examples is explained in the {ref}`getting-started` section. | ||
::: | ||
|
||
Examples provided with this project should cover from very simple designs to complex fully synthesizable cores. | ||
They should be sorted by increasing complexity and number of used features, e.g: | ||
- 101: minimal base design | ||
- 102: introduce user to parameters | ||
- 103: introduce user to slicing | ||
- 104: introduce user to interfaces | ||
- 105: etc. | ||
|
||
Developers are encouraged to create/add new examples in the same spirit. | ||
Simple examples are used to teach how to use this tool and demonstrate its features. | ||
Real-world use cases are also welcome to prove that the implementation is mature enough to handle practical designs. |
Oops, something went wrong.