AXI Interface Generation

In order to run programs on FPGAs, fud is capable of utilizing Calyx to generate a fairly complex AXI interface that can be daunting to deal with if confronting for the first time. The following is an overview of how the generation occurs and how the fud-generated AXI interface behaves as of 2022-9-11.

In general, when fud is asked to create an .xclbin file a kernel.xml, main.sv, and toplevel.v are created as intermediate files required for our Xilinx tools to properly work.

main.sv contains the SystemVerilog implementation of the Calyx program we are interested in executing on an FPGA. toplevel.v wraps our SystemVerilog implementation and contains the AXI interface for each memory marked @external in a Calyx program. Our toplevel.v and kernel.xml is what our Xilinx tools interface with. Our toplevel adheres to the Xilinx kernel interface requirements. kernel.xml defines register maps and ports of our toplevel module used by our Xilinx tools.

For more information on the generation of the files mentioned above see how the Xilinx Toolchain works

Toplevel

Our toplevel is generated through files in src/backend/xilinx/.

AXI memory controller

Here, the toplevel component of a Calyx program is queried and memories marked @external are turned into AXI buses. To note, separate AXI interfaces are created for each memory (meaning, there is no shared bus between memories). Each memory has its own (single port) BRAM which writes data taken from an mi_axi_RDATA wire where i is the index of the memory. Eventually the BRAMs are read and fed into the computation kernel of main.sv, which outputs results directly into the relevant memories as defined in the original Calyx program. Addresses, data widths, and sizes are determined from cell declarations.

There is always the possiblity that something is hardcoded as a remnant of previous versions of our AXI generation. If something is hardcoded where it shouldn't be please open an issue.

AXI memory controllers are constructed as (full) AXI4 managers that lack a small amount of functionality. For example, xPROT signals are not currently supported. Additionally, things like bursting are not currently supported, but should be easy to implement due to the existing infrastructure and generation tools.

A list of current signals that are hardcoded follows:

  • xLEN is set to 0, corresponding to a burst length of 1.
  • xBURST is set to 01, corresponding to INCR type of bursts.
  • xSIZE is set to the width of the data we are using in bytes.
  • xPROT is not generated, and is therefore not supported.
  • xLOCK is not generated, defaulting to 0 (normal accesses).
  • xCACHE is not generated, making accesses non-modifiable, non-bufferable.
  • xQOS is not generated. See QoS signaling.
  • xREGION is not generated. See Multiple region signaling.
  • No low power signals are generated.

Subordinate AXI control controller

In addition to our manager memory-controllers, a subordinate interface, connected to our control module is also generated. This module is responsible for signaling our computational kernel to start working, as well as calculating the correct base addresses to use for our memory controllers. Things like addresses and data widths are hard coded at the moment. It is suspected that this hardcoding is okay for the types of programs we generate. But more work needs to be done to see if our control structure works for arbitrary programs or needs to be changed to allow this.