docs: autogenerate Python API docs, update IO core docs
This commit is contained in:
parent
4adda3639a
commit
2c124200da
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
Regardless of if you use Manta in a traditional Verilog-based workflow or natively in an Amaranth design, the general concept of operation is as follows:
|
||||
## Overview
|
||||
Regardless of if you use it in a traditional Verilog-based workflow or natively in an Amaranth design, using Manta consists of the following steps:
|
||||
|
||||
- Specify and configure the cores you wish to include in your FPGA design.
|
||||
- Generate RTL for these cores, and include this RTL in your design.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
|
||||
## Overview
|
||||
Registers are a fundamental building block of digital hardware, and the IO core provides a simple way of interacting with them from the host machine. It allows you to define a set of inputs and outputs of arbitrary width, and then set values to the outputs and read values from the inputs.
|
||||
Registers are a fundamental building block of digital hardware, and the IO core provides a simple way of interacting with them from the host machine. It allows you to define inputs and outputs of arbitrary width, and then write values to the outputs and read values from the inputs.
|
||||
|
||||
This is a very, very simple task - and while configuration is straightforward, there are a few caveats. More on both topics below:
|
||||
This is a very, very simple task - however it's surprisingly useful in practice. Both the [Use Cases](../use_cases) page and the repository's [examples](https://github.com/fischermoseley/manta/tree/main/examples) folder contain examples of the IO Core for your reference.
|
||||
|
||||
!!! warning "It's not instantaneous!"
|
||||
|
||||
If you're trying to read or write values in your design with cycle-accurate timing, this will not do that for you. The time taken by Python to evaluate an expression is not constant, nor is the amount of time it takes for your OS to put bytes on the wire. If you need cycle-accurate timing, the [Logic Analyzer Core](./logic_analyzer_core.md) and it's [Playback feature](./logic_analyzer_core.md#playback) may be helpful.
|
||||
|
||||
## Configuration
|
||||
|
||||
Just like the rest of the cores, the IO core is configured via an entry in a project's configuration file. This is easiest to show by example:
|
||||
As explained in the [getting started](../getting_started) page, the IO Core must be configured and included in the FPGA design before it can be operated. Configuration is performed differently depending on if you're using a traditional Verilog-based workflow, or if you're building an Amaranth-native design.
|
||||
|
||||
### Verilog-Based Workflows
|
||||
|
||||
Cores are configured with an entry in a project's configuration file when using a Verilog-based workflow, and the IO Core is no different. This is best shown by example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
|
@ -25,67 +33,31 @@ my_io_core:
|
|||
fozzy: 1
|
||||
gonzo: 3
|
||||
|
||||
user_clock: True
|
||||
```
|
||||
Inside this configuration, the following parameters may be configured:
|
||||
Inside this configuration, the following parameters may be set:
|
||||
|
||||
- `name` _(required)_: The name of the IO core. This name is used to reference the core when working with the API, and can be whatever you'd like.
|
||||
- `type` _(required)_: This denotes that this is an IO core. All cores contain a `type` field, which must be set to `io` to be recognized as an IO core.
|
||||
- `inputs` _(optional)_: This lists all inputs from from the FPGA fabric to the host machine. Signals in this list may be read by the host, but ___cannot___ be written to. Technically specifying input probes is totally optional - it's perfectly fine to have an IO core with only output probes.
|
||||
- `outputs` _(optional)_: This lists all outputs from the host machine to the FPGA fabric. Signals in this list are usually written to by the host, but they can also be read from. Doing so returns the value last written to the register. Just like the `inputs` parameter, this list is technically optional, and it's perfectly valid to have an IO core with input probes only.
|
||||
- `initial_value` _(optional)_: This sets an initial value for an output probe to take after the FPGA powers on. This is done with an `initial` statement in Manta's Verilog, and is independent of the input clock or resets elsewhere in the FPGA. This parameter is optional, and if it isn't provided the probe will initialize to zero.
|
||||
- `user_clock` _(optional)_: If set to True, an extra input port will be added to the `manta` module for an clock input to run the IO core on. This lets the IO Core handle clock domain crossing through its internal buffers. If set to False, Manta will run the IO core from its internal clock (the one provided through `manta`'s `clk` port). More information on this is available in the [diagram](#how-it-works) below. This parameter is optional, and defaults to False.
|
||||
- `inputs` _(optional)_: This lists all inputs from from the FPGA fabric to the host machine. Signals in this list may be read by the host, but ___cannot___ be written to. Specifying input probes is optional - it's perfectly valid to have an IO core with only output probes.
|
||||
- `outputs` _(optional)_: This lists all outputs from the host machine to the FPGA fabric. Signals in this list are usually written to by the host, but they can also be read from. Doing so returns the value last written to the register. Specifying output probes is optional - it's perfectly valid to have an IO core with only input probes.
|
||||
- `initial_value` _(optional)_: This sets an initial value for an output probe to take after the FPGA powers on. This is done with an `initial` statement in Manta's Verilog, and is independent of the input clock or resets elsewhere in the FPGA. This parameter is optional, and defaults to zero.
|
||||
<!-- - `user_clock` _(optional)_: If set to True, an extra input port will be added to the `manta` module for an clock input to run the IO core on. This lets the IO Core handle clock domain crossing through its internal buffers. If set to False, Manta will run the IO core from its internal clock (the one provided through `manta`'s `clk` port). This parameter is optional, and defaults to False. More information is available in the [architecture](../architecture#io-core) page. -->
|
||||
|
||||
!!! warning "Name things carefully!"
|
||||
|
||||
The names of the core and its probes are referenced in the autogenerated Verilog. This means that while the names can be arbitrary, they must be unique within your project and not contain any characters that your synthesis engine won't appreciate.
|
||||
|
||||
### Amaranth-Native Designs
|
||||
|
||||
## Python API
|
||||
Since Amaranth modules are Python objects, the configuration of the IO Core is given by the arguments given during initialization. See the documentation for the `IOCore` [class constructor](#manta.IOCore) below, as well as the Amaranth [examples](https://github.com/fischermoseley/manta/tree/main/examples/amaranth) in the repo.
|
||||
|
||||
The IO core functionality is stored in the `Manta.IOCore` class in [src/manta/io_core/\_\_init\_\_.py](https://github.com/fischermoseley/manta/blob/main/src/manta/io_core.py), and it may be controlled with the two functions:
|
||||
## Operation
|
||||
|
||||
---
|
||||
Regardless of the technique you used to configure your IO Core, it is operated using the [`set_probe()`](#manta.IOCore.set_probe) and [`get_probe()`](#manta.IOCore.get_probe) methods. Documentation for these methods is available below.
|
||||
|
||||
`Manta.IOCore.set_probe(name, data)`
|
||||
|
||||
- [`string`] _name_: The probe to write to. Must not be an output port, and must match the name provided in the config file.
|
||||
- [`int`, `bool`] _data_: The value to write to an output probe. May be signed or unsigned, but will raise an exception if the value is too large for the width of the port.
|
||||
- _returns_: None
|
||||
|
||||
This method is blocking. When called it will dispatch a request to the FPGA, and halt execution until the request has been sent.
|
||||
|
||||
---
|
||||
|
||||
`Manta.IOCore.get_probe(name)`
|
||||
|
||||
- [`string`] _name_: The probe to read from. May be either an input or an output port, and must match the name provided in the config file.
|
||||
- _returns_: The value of an input or output probe. In the case of an output probe, the value returned will be the last value written to the probe.
|
||||
|
||||
This method is blocking. When called it will dispatch a request to the FPGA, and halt execution until the request has been sent and a response has been received.
|
||||
|
||||
---
|
||||
These methods are members of the `IOCore` class, so if you're using Manta in a Verilog-based workflow, you'll first need to obtain a `Manta` object that contains an `IOCore` member. This is done with `Manta.from_config()`, as shown in the Verilog [examples](https://github.com/fischermoseley/manta/tree/main/examples/verilog).
|
||||
|
||||
|
||||
### Example
|
||||
## Python API Documentation
|
||||
|
||||
A small example is shown below, using the [example configuration](#configuration) above. More extensive examples can also be found in the repository's [examples/](https://github.com/fischermoseley/manta/tree/main/examples) folder.
|
||||
|
||||
```python
|
||||
>>> import Manta
|
||||
>>> m = Manta
|
||||
>>> m.my_io_core.set_probe("fozzy", True)
|
||||
>>> m.my_io_core.get_probe("fozzy")
|
||||
True
|
||||
>>> m.my_io_core.set_probe("gonzo", 4)
|
||||
>>> m.my_io_core.get_probe("scooter")
|
||||
5
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
While the IO core performs a very, very simple task, it carries a few caveats.
|
||||
|
||||
- First, __it's not instantaneous__. Manta has designed to be as fast as possible, but setting and querying registers relies on passing messages between the host and FPGA, which is slow relative to FPGA clock speeds! If you're trying to set values in your design with cycle-accurate timing, this will not do that for you. However, the [Logic Analyzer's playback feature](./logic_analyzer_core.md#playback) might be helpful.
|
||||
|
||||
- Second, __the API methods are blocking__, and will wait for a response from the FPGA before resuming program execution. Depending on your application, you might want to run your IO Core operations in a separate thread, but you can also decrease the execution time by using a faster interface between the host and FPGA. This means using a higher UART baudrate, or using Ethernet.
|
||||
::: manta.IOCore
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from time import sleep
|
|||
|
||||
from amaranth import *
|
||||
from amaranth.lib import io
|
||||
|
||||
from manta import *
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from time import sleep
|
|||
|
||||
from amaranth import *
|
||||
from amaranth.lib import io
|
||||
|
||||
from manta import *
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from amaranth import *
|
||||
from amaranth.lib import io
|
||||
|
||||
from manta import *
|
||||
|
||||
|
||||
|
|
|
|||
37
mkdocs.yml
37
mkdocs.yml
|
|
@ -21,21 +21,21 @@ theme:
|
|||
palette:
|
||||
- media: "(prefers-color-scheme)"
|
||||
toggle:
|
||||
icon: material/link
|
||||
icon: material/brightness-7
|
||||
name: Switch to light mode
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
primary: blue
|
||||
accent: custom
|
||||
toggle:
|
||||
icon: material/toggle-switch
|
||||
icon: material/brightness-4
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: black
|
||||
accent: custom
|
||||
toggle:
|
||||
icon: material/toggle-switch-off
|
||||
icon: material/brightness-auto
|
||||
name: Switch to system preference
|
||||
|
||||
extra_css:
|
||||
|
|
@ -66,18 +66,43 @@ extra:
|
|||
version:
|
||||
provider: mike
|
||||
|
||||
plugins:
|
||||
- mkdocstrings:
|
||||
handlers:
|
||||
python:
|
||||
options:
|
||||
heading_level: 3
|
||||
show_bases: false
|
||||
show_root_heading: true
|
||||
show_source: false
|
||||
separate_signature: true
|
||||
show_signature_annotations: true
|
||||
modernize_annotations: true
|
||||
signature_crossrefs: true
|
||||
docstring_section_style: list
|
||||
show_symbol_type_toc: true
|
||||
show_symbol_type_heading: true
|
||||
|
||||
docstring_options:
|
||||
ignore_init_summary: false
|
||||
|
||||
# filters: ["!^_"]
|
||||
unwrap_annotated: true
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Installation: installation.md
|
||||
- Getting Started: getting_started.md
|
||||
- Similar Tools: similar_tools.md
|
||||
- Use Cases: use_cases.md
|
||||
- Architecture: architecture.md
|
||||
- Usage:
|
||||
- Similar Tools: similar_tools.md
|
||||
- Cores:
|
||||
- IO Core: io_core.md
|
||||
- Logic Analyzer Core: logic_analyzer_core.md
|
||||
- Memory Core: memory_core.md
|
||||
|
||||
- Interfaces:
|
||||
- UART Interface: uart_interface.md
|
||||
- Ethernet Interface: ethernet_interface.md
|
||||
- For Developers:
|
||||
- Repository Structure: repository_structure.md
|
||||
- Roadmap: https://github.com/fischermoseley/manta/milestones
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ dev = [
|
|||
"codecov",
|
||||
"ruff",
|
||||
"mkdocs-material",
|
||||
"mkdocstrings[python]",
|
||||
"mike",
|
||||
"amaranth_boards@git+https://github.com/amaranth-lang/amaranth-boards"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,17 +7,32 @@ from manta.utils import *
|
|||
|
||||
class IOCore(MantaCore):
|
||||
"""
|
||||
A module for setting and getting the values of registers of arbitrary size
|
||||
on a FPGA.
|
||||
A synthesizable module for setting and getting the values of registers of
|
||||
arbitrary size.
|
||||
|
||||
Provides methods for generating synthesizable logic for the FPGA, as well
|
||||
as methods for reading and writing the value of a register.
|
||||
|
||||
More information available in the online documentation at:
|
||||
https://fischermoseley.github.io/manta/io_core/
|
||||
"""
|
||||
|
||||
def __init__(self, inputs=[], outputs=[]):
|
||||
"""
|
||||
Create an IO Core, with the given input and output probes.
|
||||
|
||||
This function is the main mechanism for configuring an IO Core in an
|
||||
Amaranth-native design.
|
||||
|
||||
Args:
|
||||
inputs (Optional[List[amaranth.Signal]]): A list of
|
||||
Amaranth Signals to use as inputs. Defaults to an empty list.
|
||||
This parameter is technically optional as an IO Core must have
|
||||
at least one probe, but it need not be an input.
|
||||
|
||||
outputs (Optional[List[amaranth.Signal]]): A list of
|
||||
Amaranth Signals to use as outputs. Defaults to an empty list.
|
||||
This parameter is technically optional as an IO Core must have
|
||||
at least one probe, but it need not be an output.
|
||||
|
||||
"""
|
||||
self._inputs = inputs
|
||||
self._outputs = outputs
|
||||
|
||||
|
|
@ -196,9 +211,26 @@ class IOCore(MantaCore):
|
|||
|
||||
def set_probe(self, probe, value):
|
||||
"""
|
||||
Set the value of an output probe on the FPGA. The value may be either
|
||||
an unsigned or signed integer, but must fit within the width of the
|
||||
probe.
|
||||
Set the value of an output probe on the FPGA.
|
||||
|
||||
Args:
|
||||
probe (str | amaranth.Signal): The output probe to set the value
|
||||
of. This may be either a string containing the name of the
|
||||
probe, or the Amaranth Signal representing the probe itself.
|
||||
Strings are typically used in Verilog-based workflows, and
|
||||
Amaranth Signals are typically used in Amaranth-native designs.
|
||||
|
||||
value (int): The value to set the probe to. This may be either
|
||||
positive or negative, but must fit within the width of the
|
||||
probe.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ValueError: The probe was not found to be an output of the IO Core,
|
||||
or many probes were found with the same name.
|
||||
|
||||
"""
|
||||
|
||||
# This function accepts either the name of an output probe, or a
|
||||
|
|
@ -240,10 +272,27 @@ class IOCore(MantaCore):
|
|||
|
||||
def get_probe(self, probe):
|
||||
"""
|
||||
Get the present value of a probe on the FPGA, which is returned as an
|
||||
unsigned integer. This function may be called on both input and output
|
||||
probes, but output probes will return the last value written to them
|
||||
(or their initial value, if no value has been written to them yet).
|
||||
Get the value of an input or output probe on the FPGA.
|
||||
|
||||
If called on an output probe, this function will return the last value
|
||||
written to the output probe. If no value has been written to the output
|
||||
probe, then it will return the probe's initial value.
|
||||
|
||||
Args:
|
||||
probe (str | amaranth.Signal): The probe to get the value of. This
|
||||
may be either a string containing the name of the probe, or the
|
||||
Amaranth Signal representing the probe itself. Strings are
|
||||
typically used in Verilog-based workflows, and Amaranth Signals
|
||||
are typically used in Amaranth-native designs.
|
||||
|
||||
Returns:
|
||||
value (int): The value of the probe, interpreted as an unsigned
|
||||
integer.
|
||||
|
||||
Raises:
|
||||
ValueError: The probe was not found in the IO Core, or many probes
|
||||
were found with the same name.
|
||||
|
||||
"""
|
||||
|
||||
# This function accepts either the name of an output probe, or a
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import tempfile
|
|||
|
||||
import yaml
|
||||
from amaranth import *
|
||||
|
||||
from manta import *
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from amaranth import *
|
|||
from amaranth.lib import io
|
||||
from amaranth_boards.icestick import ICEStickPlatform
|
||||
from amaranth_boards.nexys4ddr import Nexys4DDRPlatform
|
||||
|
||||
from manta import *
|
||||
from manta.utils import *
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from random import getrandbits
|
||||
|
||||
from amaranth import *
|
||||
|
||||
from manta import *
|
||||
from manta.utils import *
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from amaranth import *
|
|||
from amaranth.lib import io
|
||||
from amaranth_boards.icestick import ICEStickPlatform
|
||||
from amaranth_boards.nexys4ddr import Nexys4DDRPlatform
|
||||
|
||||
from manta import *
|
||||
from manta.utils import *
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from amaranth import *
|
||||
|
||||
from manta.logic_analyzer import LogicAnalyzerCore
|
||||
from manta.logic_analyzer.trigger_block import Operations
|
||||
from manta.utils import *
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from amaranth import *
|
|||
from amaranth.lib import io
|
||||
from amaranth_boards.icestick import ICEStickPlatform
|
||||
from amaranth_boards.nexys4ddr import Nexys4DDRPlatform
|
||||
|
||||
from manta import *
|
||||
from manta.utils import *
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from math import ceil
|
|||
from random import choice, getrandbits, randint
|
||||
|
||||
import pytest
|
||||
|
||||
from manta.memory_core import MemoryCore
|
||||
from manta.utils import *
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import pytest
|
|||
from amaranth_boards.icestick import ICEStickPlatform
|
||||
from amaranth_boards.nexys4ddr import Nexys4DDRPlatform
|
||||
from amaranth_boards.test.blinky import *
|
||||
|
||||
from manta.utils import *
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue