|
Packit |
534379 |
# OPAE Python Bindings
|
|
Packit |
534379 |
|
|
Packit |
534379 |
OPAE (Open Programmable Acceleration Engine) now includes Python bindings for
|
|
Packit |
534379 |
interacting with FPGA resources. The OPAE Python API is built on top of the
|
|
Packit |
534379 |
OPAE C++ Core API and its object model. Because of this, developing OPAE
|
|
Packit |
534379 |
applications in Python is very similar to developing OPAE applications in C++
|
|
Packit |
534379 |
which significantly reduces the learning curve required to adapt to the Python API.
|
|
Packit |
534379 |
While the object model remains the same, some static factory functions in the
|
|
Packit |
534379 |
OPAE C++ Core API have been moved to module level methods in the OPAE Python API
|
|
Packit |
534379 |
with the exception of the properties class. The goal of the OPAE Python API is
|
|
Packit |
534379 |
to enable fast prototyping, test automation, infrastructure managment, and an
|
|
Packit |
534379 |
easy to use framework for FPGA resource interactions that don't rely on software
|
|
Packit |
534379 |
algorithms with a high runtime complexity.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Currently, the only Python package that is part of OPAE is `opae.fpga`
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Implementation
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The OPAE Python API is implemented by creating a Python extension using `pybind11
|
|
Packit |
534379 |
<http://pybind11.readthedocs.io/en/stable>`_.
|
|
Packit |
534379 |
This extension is created by using the pybind11 API which relies mostly on
|
|
Packit |
534379 |
macros and compile time introspection to define the module initialization point
|
|
Packit |
534379 |
as well as type converters between OPAE C++ Core types and OPAE Python types.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Benefits
|
|
Packit |
534379 |
The major benefits of using pybind11 for developing the OPAE Python API
|
|
Packit |
534379 |
include, but are not limited to, the following features of pybind11:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
* Uses C++ 11 standard library although it can use C++ 14 or C++17.
|
|
Packit |
534379 |
* Automatic conversions of shared_ptr types
|
|
Packit |
534379 |
* Built-in support for numpy and Eigen numerical libraries
|
|
Packit |
534379 |
* Interoperable with the Python C API
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Runtime Requirements
|
|
Packit |
534379 |
Because opae.fpga is built on top of the opae-cxx-core API, it does require
|
|
Packit |
534379 |
that the runtime libraries for both opae-cxx-core and opae-c be installed on
|
|
Packit |
534379 |
the system (as well as any other libraries they depend on). Those libraries can
|
|
Packit |
534379 |
be installed using the opae-libs package (from either RPM or DEB format -
|
|
Packit |
534379 |
depending on your Linux distribution).
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Installation
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Python Wheels
|
|
Packit |
534379 |
The preferred method of installation is to use a binary wheel package for your
|
|
Packit |
534379 |
version of Python.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The following table lists example names for different Python versions and
|
|
Packit |
534379 |
platforms.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
| Python Version | Python ABI | Linux Platform | Package Name |
|
|
Packit |
534379 |
|----------------|-----------------|----------------|--------------|
|
|
Packit |
534379 |
| 2.7 | CPython w/ UCS4 | x86_64 | opae.fpga.<release>-cp27-cp27mu-linux_x86_64.whl |
|
|
Packit |
534379 |
| 3.4 | CPython w/ UCS4 | x86_64 | opae.fpga.<release>-cp34-cp34mu-linux_x86_64.whl |
|
|
Packit |
534379 |
| 3.6 | CPython w/ UCS4 | x86_64 | opae.fpga.<release>-cp36-cp36mu-linux_x86_64.whl |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
opae.fpga is currently not available in the Python Package Index but once it
|
|
Packit |
534379 |
does become available, one should be able to install using pip by simply typing
|
|
Packit |
534379 |
the following:
|
|
Packit |
534379 |
```shell
|
|
Packit |
534379 |
> pip install --user opae.fpga
|
|
Packit |
534379 |
```
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Installing From Source
|
|
Packit |
534379 |
In addition to the runtime libraries mentioned above, installing from source
|
|
Packit |
534379 |
does require that the OPAE header files be installed as well as those header
|
|
Packit |
534379 |
files for pybind11. The former can be installed with the opae-devel package and
|
|
Packit |
534379 |
the latter can be installed by installing pybind11 Python module.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
### Example Installation
|
|
Packit |
534379 |
The following example shows how to build from source by installing the
|
|
Packit |
534379 |
prerequisites before running the setup.py file.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
```shell
|
|
Packit |
534379 |
>sudo yum install opae-libs-<release>.x86_64.rpm
|
|
Packit |
534379 |
>sudo yum install opae-devel-<release>.x86_64.rpm
|
|
Packit |
534379 |
>pip install --user pybind11
|
|
Packit |
534379 |
>pip install --user opae.fpga-<release>.tar.gz
|
|
Packit |
534379 |
```
|
|
Packit |
534379 |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
_NOTE_: The `pip` examples above use the `--user` flag to avoid requiring root
|
|
Packit |
534379 |
permissions. Those packages will be installed in the user's `site-packages`
|
|
Packit |
534379 |
directory found in the user's `.local` directory.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
## Example Scripts
|
|
Packit |
534379 |
The following example is an implementation of the sample, hello_fpga.c, which
|
|
Packit |
534379 |
is designed to configure the NLB0 diagnostic accelerator for a simple loopback.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
```Python
|
|
Packit |
534379 |
import time
|
|
Packit |
534379 |
from opae import fpga
|
|
Packit |
534379 |
|
|
Packit |
534379 |
NLB0 = "d8424dc4-a4a3-c413-f89e-433683f9040b"
|
|
Packit |
534379 |
CTL = 0x138
|
|
Packit |
534379 |
CFG = 0x140
|
|
Packit |
534379 |
NUM_LINES = 0x130
|
|
Packit |
534379 |
SRC_ADDR = 0x0120
|
|
Packit |
534379 |
DST_ADDR = 0x0128
|
|
Packit |
534379 |
DSM_ADDR = 0x0110
|
|
Packit |
534379 |
DSM_STATUS = 0x40
|
|
Packit |
534379 |
|
|
Packit |
534379 |
def cl_align(addr):
|
|
Packit |
534379 |
return addr >> 6
|
|
Packit |
534379 |
|
|
Packit |
534379 |
tokens = fpga.enumerate(type=fpga.ACCELERATOR, guid=NLB0)
|
|
Packit |
534379 |
assert tokens, "Could not enumerate accelerator: {}".format(NlB0)
|
|
Packit |
534379 |
|
|
Packit |
534379 |
with fpga.open(tokens[0], fpga.OPEN_SHARED) as handle:
|
|
Packit |
534379 |
src = fpga.allocate_shared_buffer(handle, 4096)
|
|
Packit |
534379 |
dst = fpga.allocate_shared_buffer(handle, 4096)
|
|
Packit |
534379 |
dsm = fpga.allocate_shared_buffer(handle, 4096)
|
|
Packit |
534379 |
handle.write_csr32(CTL, 0)
|
|
Packit |
534379 |
handle.write_csr32(CTL, 1)
|
|
Packit |
534379 |
handle.write_csr64(DSM_ADDR, dsm.io_address())
|
|
Packit |
534379 |
handle.write_csr64(SRC_ADDR, cl_align(src.io_address())) # cacheline-aligned
|
|
Packit |
534379 |
handle.write_csr64(DST_ADDR, cl_align(dst.io_address())) # cacheline-aligned
|
|
Packit |
534379 |
handle.write_csr32(CFG, 0x42000)
|
|
Packit |
534379 |
handle.write_csr32(NUM_LINES, 4096/64)
|
|
Packit |
534379 |
handle.write_csr32(CTL, 3)
|
|
Packit |
534379 |
while dsm[DSM_STATUS] & 0x1 == 0:
|
|
Packit |
534379 |
time.sleep(0.001)
|
|
Packit |
534379 |
handle.write_csr32(CTL, 7)
|
|
Packit |
534379 |
|
|
Packit |
534379 |
```
|
|
Packit |
534379 |
|
|
Packit |
534379 |
This example shows how one might reprogram (Partial Reconfiguration) an
|
|
Packit |
534379 |
accelerator on a given bus, 0x5e, using a bitstream file, m0.gbs.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
```Python
|
|
Packit |
534379 |
from opae import fpga
|
|
Packit |
534379 |
|
|
Packit |
534379 |
BUS = 0x5e
|
|
Packit |
534379 |
GBS = 'm0.gbs'
|
|
Packit |
534379 |
tokens = fpga.enumerate(type=fpga.DEVICE, bus=BUS)
|
|
Packit |
534379 |
assert tokens, "Could not enumerate device on bus: {}".format(BUS)
|
|
Packit |
534379 |
with open(GBS, 'rb') as fd, fpga.open(tokens[0]) as device:
|
|
Packit |
534379 |
device.reconfigure(0, fd)
|
|
Packit |
534379 |
```
|
|
Packit |
534379 |
|