IP IntegrationΒΆ

Apart from directly writing Allo kernels in Python, we also support integrating existing C++ HLS kernels into Allo. This feature is useful when you have a existing optimized C++ HLS code that wants to be integrated into Allo. The following example shows how to integrate a simple vector addition kernel written in C++ into Allo.

Suppose the C++ kernel is implemented in the vadd.cpp file:

void vadd(int A[32], int B[32], int C[32]) {
    for (int i = 0; i < 32; ++i) {
        C[i] = A[i] + B[i];
    }
}

In Allo, we can create an IP module to wrap the C++ kernel. Basically, we need to provide the top-level function name and the implementation file. Allo will automatically parse the C++ kernel signature, compile the kernel, and generate the corresponding Python wrapper based on the provided files. Multi-dimensional arrays and pointers are supported in this C++ function definition. The last argument link_hls of the IPModule determines whether the C++ compiler should link the Vitis HLS libraries (e.g., ap_int), which is only available when your machine has installed Vitis HLS.

vadd = allo.IPModule(top="vadd", impl=["vadd.cpp"], link_hls=False)

After creating the IP module, we can use it in Allo as a normal Python function. For example, we can directly call the vadd function to perform vector addition. The inputs and outputs will be automatically wrapped and unwrapped as NumPy arrays, which greatly simplies the burden of complex C-Python interface management. This is also very useful when you want to debug the HLS kernels with the Python data.

np_A = np.random.randint(0, 100, (32,)).astype(np.int32)
np_B = np.random.randint(0, 100, (32,)).astype(np.int32)
np_C = np.zeros((32,), dtype=np.int32)
vadd(np_A, np_B, np_C)
np.testing.assert_allclose(np_A + np_B, np_C, atol=1e-6)

Moreover, the IP module can also be called in a normal Allo kernel. In the following example, we wrap the vadd function into an Allo kernel and use it to perform vector addition. The Allo kernel can then be further customized and compiled with the external C++ HLS kernel.

def kernel(A: int32[32], B: int32[32]) -> int32[32]:
    C: int32[32] = 0
    vadd(A, B, C)
    return C

s = allo.customize(kernel)
print(s.module)
mod = s.build()
np_A = np.random.randint(0, 100, (32,)).astype(np.int32)
np_B = np.random.randint(0, 100, (32,)).astype(np.int32)
allo_C = mod(np_A, np_B)
np.testing.assert_allclose(np_A + np_B, allo_C, atol=1e-6)

Similar to other Allo kernels, we can also change the build target to invoke the HLS compiler to generate the hardware design with the external C++ kernel. Make sure you have installed Vitis environment before running the following code.

mod = s.build(target="vitis_hls", mode="csyn", project="vadd.prj")
mod()