TL;DR
If you want to deploy some logic to a FPGA and talk to that logic over PCIE, it’s harder than it has any right to be, but it can be done by gluing together Xilinx’s XDMA core and the logic using AXI. We’ll use memory mapped I/O (MMIO) to actually transfer data from the host to the FPGA.
Disclaimer
Since so much of the tooling around FPGAs is proprietary (and thus brittle as hell) so it’s worth mentioning that I got this to work using 2021.1 Xilinx tools and on an Artix 7 (PicoEVB with XC7A50T-CSG325-1).
Acronyms
One of the most annoying things about working with FPGAs is the immense number of acronyms that documentation expects you to be familiar with. Hopefully this alleviates some of your frutration with that.
- FPGA: Field Programmable Gate Array; the device which we’re programming.
- CPU: Central Processing Unit; the processor on the host device.
- I/O: Input/Output; self-explanatory.
- PCIE: Peripheral Component Interconnect (Express); the communication interface we’re using to communicate with the host device (i.e., the CPU and operating system and memory).
- AXI: Advanced eXtensible Interface; the communication interface that the components will use to communicate amongst themselves, on the FPGA itself.
- DMA: Direct Memory Access; a system that lets individual components access memory directly, independently of the CPU.
- MMIO: Memory-Mapped I/O; uses the same address space to address both memory and I/O devices. The memory and registers of the I/O devices are mapped to (associated with) address values (in the address range assigned by the DMA controller).
- IP: Intellectual Property; wacky name for a module/chunk of logic.
- RTL: Register-Transfer Level; circuits designed in terms signals and registers.
- HLS: High-Level Synthesis; a technique for translating procedural code (e.g., C++) to RTL designs.
The Kernel
As the kernel we’ll use something simple, in particular something we can use Vitis HLS to synthesize for us:
void kernel(int* out, int in){
*out = 2*in;
}