
## 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.
- Build the design, and upload it to your device.
- Operate the cores from the host machine.

Manta’s cores are small, configurable blocks that each provide some functionality. More information on each core can be found on their respective documentation pages. Manta supports an arbitrary amount of unique cores, limited only by the available resources of your device.

## Usage in Traditional Verilog-Based Workflows

Although modern HDLs are rising in popularity, most existing FPGA designs use a Verilog-based workflow. This consists of synthesizing a number of Verilog files into a single design. Manta can easily be used in such a workflow, as described below:

- The cores and interface used to communicate with them is specified in a configuration file, written in YAML. This file is typically named `manta.yaml` .
- A Verilog file containing the cores specified in the configuration file is generated. This is most often done at the command line with the `manta gen` command (for example, `manta gen manta.yaml manta.v`) but can also be done with the `generate_verilog`method of the `Manta` Python class. This file contains the definition of a Verilog module named `manta`, which includes all the cores specified in the configuration file.
- This `manta` module is instantiated in your design, and the signals to each core are connected to your logic. Connections are also made to the signals of the interface specified in the configuration file. The `manta inst` command can also be used to generate a Verilog instantiation that can be copy-pasted into your source.
- After the design is built and uploaded to the FPGA, the cores are operated from the host machine. Each core exposes a Python API containing methods that can be invoked from a Python script. These are described in great detail in the documentation for each core.

!!! success "VHDL works too!"

    If your FPGA design is VHDL-based, fret not! Most synthesis tools support mixed-language projects, and will happily ingest both a Verilog-based Manta module inside of a VHDL-based design. Just take care to ensure that interfaces match between the VHDL and Verilog modules.

### Example

A minimal example of a `manta.yaml` file may be observed below:

```yaml
cores:
  my_io_core:
    type: io

    inputs:
      my_input_signal: 6

    outputs:
      my_output_signal: 12

uart:
  port: "auto"
  baudrate: 3e6
  clock_freq: 100e6
```

This includes a single IO core in the `manta` module, which communicates with the host machine over a 3Mbaud UART link. Instantiating this core in your design might look like the following, as generated by `manta inst`:

```verilog
manta manta_inst (
    .clk(clk),
    .rst(rst),
    .rx(rx),
    .tx(tx),
    .my_input_signal(my_input_signal),
    .my_output_signal(my_output_signal));
```

!!! note "Reset is active high!"

    The Manta instance will reset while `rst` is held high. If you want to share reset logic with an active low reset signal (for example, `rst_n`), be sure to invert it first.

More examples of Verilog-based designs can be found in the [examples/verilog](https://github.com/fischermoseley/manta/tree/main/examples/verilog) folder of the repo.

## Usage in Amaranth Designs

Since Manta itself is written in [Amaranth](https://github.com/amaranth-lang/amaranth), it’s very easy to use Manta in an Amaranth design. In this flow, the RTL build and generation are offloaded to Amaranth’s build system, such that you need only to configure and operate the core, which is done from Python.

Configuration is done by creating a Manta object in Python, adding cores to it, and adding it to your design as an Amaranth submodule:

```python
from amaranth import *
from manta import *

class ExampleDesign(Elaborateable):
	def __init__(self):
		self.manta = Manta()
		self.manta.interface = UARTInterface("auto", 2e6, 12e6)
		self.manta.cores.my_io_core = IOCore(inputs=[], outputs=[])


	def elaborate(self, platform):
		m = Module()
		m.submodules.manta = self.manta

		return m

	def operate(self):
		self.manta.cores.my_io_core.set_probe("foo", 2)
		self.manta.cores.my_io_core.get_probe(bar)
```

Using this `ExampleDesign` in the configure-build-operate flow might look like the following:

```python
>>> from amaranth_boards.icestick import ICEStickPlatform
>>> design = ExampleDesign()
>>> ICEStickPlatform.build(design, do_program=True)
>>> design.operate()
>>> design.manta.my_io_core.get_probe(bar)
```

Here, Amaranth’s board definitions and build system are being used to build and program an iCEstick development board. More examples of Amaranth-based designs can be found in the [examples/amaranth](https://github.com/fischermoseley/manta/tree/main/examples/amaranth) folder of the repo.

!!! warning "Usage with older versions of Amaranth"

    Unfortunately, Manta has a hard dependency on Amaranth 0.5 (due to [this](https://github.com/amaranth-lang/amaranth/issues/1011) bugfix), and it may not work correctly in projects built upon older versions of Amaranth. If this is the case for your project, you may need to generate a standalone Verilog module from the Verilog-based flow, and then include in your project as an [Instance](https://amaranth-lang.org/docs/amaranth/latest/guide.html#instances). Alternatively, you may upgrade your project’s version of Amaranth by following the [migration guides](https://amaranth-lang.org/docs/amaranth/latest/changes.html#migrating-from-version-0-4).

### Adding Manta as an Instance Variable

It’s worth noting that this usage represents a slight departure from typical Amaranth style. Typically, submodules would be defined and added to a `Module` in the `elaborate` method. Here, the Manta module is instead defined as an instance variable in the `__init__` function, and then later added as a submodule in the `elaborate` method.

This is necessary as the `Manta` object contains both HDL needed for build and methods for operating the cores. Saving the `Manta` instance in the class and re-using it later removes the need to define and configure separate instances when elaborating and operating the cores.

Lastly, including `manta` as an instance variable also allows it to be directly accessed from an interpreter, as shown above. This allows for a more interactive debugging session, as the definition of the `operate` method doesn’t have to change when you wish to use Manta’s cores differently.
