ICL

The core of the FPGA interface is implemented across three files:

  • args_fpga.py - defines the interfaces to be used by drivers

  • fpga_icl.py - provides infrastructure for higher-level abstractions of FPGA functions to be implemented

  • args_map.py - decodes the ARGS map into register names & addresses

UML Class diagram, surrounding text describes the key points

args_fpga

ArgsFpgaIface defines a common interface used by drivers. The ICL code will use this interface to communicate with the FPGA.

ArgsFpgaDriver defines the common functions expected of any FPGA driver. Some examples are shown on the diagram: ArgsXrt, ArgsSimulator. These derived classes will implement the ‘heavy lifting’ of actually talking to the FPGA.

fpga_icl

Users are expected to implement classes derived from FpgaPersonality and FpgaPeripheral to implement their desired functionality. The term “personality” refers to a FPGA firmware image with a distinct functionality. Peripherals may be shared between multiple personalities.

FpgaPersonality brings all the pieces together. Given at least one ArgsFpgaInterface and exactly one ArgsMap, it will create FpgaPeripheral objects for each peripheral. FpgaPeripheral also provides shortcuts to access certain members of its default interface.

FpgaPeripheral collects the ‘fields’ (registers) of a peripheral together. Derived classes can provide additional configuration and abstraction functions.

IclField is a data class that should be returned by any methods or attributes that are added to FpgaPeripheral or FpgaPersonality for use in the control system. It supports all the usual python operators. It also inherits from typing.Generic, to allow the type of its value to be specified in a type hint. This could be used for static type checking, or at run-time. Note that I have not yet been able to link the type hint to the type_ attribute (if you know how to do this, please let me know!).

# setting type hints
def my_icl_name() -> IclField[str]:
    return IclField(value="Andrew")

def show_name(name: IclField[str]):
    print("My name is", name.value)

show_name(my_icl_name())

# inspecting type hints at run time
from typing import get_args, get_type_hint

return_class = get_origin(get_type_hints(my_int_af)["return"])
assert return_class is IclField  # True

return_value_type = get_args(get_type_hints(my_icl_name)["return"])[0]
assert return_value_type is str  # True

IclFpgaField is a data class used for FPGA registers. It adds read & write interfaces to IclField. The required instances of this class should be created automatically.

# increment a register value
demo_fpga.packetiser.control_vector += 1

# compare register value
if demo_fpga.packetiser.control_vector > 0:
    pass

args_map

ArgsMap takes a build timestamp and a search directory, and looks there for a specially-named python file (e.g. fpgamap_21080211.py). For sensible results, provide the build timestamp read from the FPGA via the relevant ArgsFpgaDriver.

Drivers

Common Interface

All drivers inherit from ArgsFpgaDriverIface, which specifies a common interface:

  • read

  • write

  • read_memory

  • write_memory

See the docstrings in the code for usage details.

Information about the FPGA card hardware, if present, is available via .info - this will be either None (by default) or an instance of XrtInfo (if instantiated by the driver).

ArgsSimulator

A simulation of an FPGA, for development/testing when FPGA hardware is not available.

ArgsXrt

Uses Xilinx’s PyXRT to communicate with a Xilinx Alveo FPGA card registers & memories.

Status Monitoring

XrtInfo

Provides extra information about the Alveo FPGA card, including parameters for health and status monitoring. Access to most information is via array index syntax (UUID is via a property), returned data is in a range of formats.

Other

RegisterLoader

Used to load a text file of register values into the FPGA. These files are usually generated by other software, for testing/verification. The file uses 32-bit hexadecimal values, and multiple values can be specified for large registers.

[<peripheral>.<ignored>.<field>][<offset>]
0x000000a1
0x000000a2
0x000000a3
0x000000a4
[<peripheral>.<ignored>.<field>][<offset>]
0x000000b1

e.g. to set the secondcornerturn peripheral’s beams_enabled register to 1:

[secondcornerturn.config.beams_enabled][0]
0x00000001