# Open-source Stand-Alone Versatile Tensor Accelerator

Anthony Faure-Gignoux, Kevin Delmas, Adrien Gauffriau, Claire Pagetti

► To cite this version:

Anthony Faure-Gignoux, Kevin Delmas, Adrien Gauffriau, Claire Pagetti. Open-source Stand-Alone Versatile Tensor Accelerator. 44th Digital Avionics Systems Conference (DASC), Sep 2025, Montreal, Canada. hal-05269864

HAL Id: hal-05269864

https://hal.science/hal-05269864v1

Submitted on 23 Sep 2025

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
# Open-source Stand-Alone Versatile Tensor Accelerator.

Anthony Faure-Gignoux¹

Kevin Delmas²

Adrien Gauffriau¹

Claire Pagetti²

¹*Airbus*, France

²*ONERA*, France

September 23, 2025

## Abstract

Machine Learning (ML) applications demand significant computational resources, posing challenges for safety-critical domains like aeronautics. The Versatile Tensor Accelerator (VTA) is a promising FPGA-based solution, but its adoption was hindered by its dependency on the TVM compiler and by other code non-compliant with certification requirements. This paper presents an open-source, stand-alone Python compiler pipeline for the VTA, developed from scratch and designed with certification requirements, modularity, and extensibility in mind. The compiler's effectiveness is demonstrated by compiling and executing LeNet-5 Convolutional Neural Network (CNN) using the VTA simulators, and preliminary results indicate a strong potential for scaling its capabilities to larger CNN architectures. All contributions are publicly available.

## 1 Introduction

Machine Learning (ML) applications are increasingly demanding significant computational resources. This is particularly challenging in domains constrained by hardware limitations, such as aeronautics. Multi-core CPUs often struggle to meet these demands efficiently. Therefore, dedicated hardware accelerators, offering highly parallel computing resources, are a way forward.

FPGAs are widely used in aeronautics due to their reconfigurability and potential for tailored, high-performance designs. Therefore, FPGA-based accelerators are a promising solution for executing ML in aeronautics. In this context, the Versatile Tensor Accelerator (VTA) [1] emerges as a compelling open-source solution. Designed specifically for the efficient execution of matrix multiplication operations, its architecture is inherently flexible and configurable, allowing it to be tailored to various target FPGA devices. Furthermore, the use of a VTA-inspired accelerator by the aeronautical company Daedalean for running its Convolutional Neural Networks (CNNs) [2] highlights the platform's potential as an industrial-grade solution. Finally, the VTA incorporates both a High-Level Synthesis (HLS) [3] description, for FPGA implementation on an UltraScale+, and a CHISEL [4] description, for cycle-accurate simulation. A second simulator in C++ provides a functional simulation of the VTA behaviour.

However, the practical adoption of VTA faces several substantial challenges, as it must adhere to the established avionics guidelines for hardware (DO-254 [5]) and software (DO-178C [6]). The VTA was highly dependent on the TVM compiler [7], which is not compliant with aeronautics regulations [8]. Indeed, the TVM compiler performs numerous transformations, making it complex to ensure traceability; it also prevents fine-grained user control over the compilation chain. Lastly, the TVM project chose to deprecate the VTA.

Consequently, we provide an alternative open-source compilation chain for VTA and a live GitHub repository of associated tools (e.g., simulators), all developed in consideration of the applicable certification documents. An in-depth investigation of the VTA was necessary to accurately understand its architecture, especially the memory allocation done by the TVM compiler (Section 2). This investigation enabled us to develop from scratch a compilation chain for the VTA. First, we delve into matrix multiplication compilation, which is key to executing CNNs on the VTA (Section 3). Second, we highlight the link between matrix multiplications and CNN execution; then, we extend the compiler to CNN compilation (Section 4). This compiler aims to meet certification requirements. It provides a simpler and more transparent toolchain,
enabling users to trace the various transformations from the CNNs to the VTA matrices. It also offers a
static implementation strategy enabling a more predictable execution time. Additionally, the modular design
of the compiler allows using and testing different implementation strategies. Finally, we compiled the LeNet-
5 CNN with our compiler and applied it to the VTA simulators to highlight its efficiency (Section 5). All our
work is open-source and available via GitHub [9]. This work enhances VTA’s applicability for safety-critical
systems by offering a verifiable and independent compilation pathway.

2 Background: the Versatile Tensor Accelerator

This section reviews the existing VTA, detailing its established architecture, functional behaviour, and
memory management principles, as originally implemented within the TVM compiler framework.

**2.1 The VTA architecture**

**Hybrid architecture:** A hybrid architecture consists of general-purpose CPUs and accelerators, which are highly specialised hardware designed to process large volumes of data efficiently. The VTA is an accelerator intended for use within such hybrid architectures under the control of a CPU, as shown in Figure 1. Practically, the CPU sends a start signal containing the memory address of the instructions. The VTA loads the instructions from the DRAM. Within the instructions, it reads the DRAM addresses of the data. The VTA locally copies the data and then performs its operations on it. The result is written back to the DRAM. Finally, the VTA sends a completion signal to the CPU. It can then manipulate the data from the DRAM and initiate a new VTA execution.

<figure><img src="image_2.png" /><figcaption>Figure 1: Hybrid architecture</figcaption></figure>

**VTA architecture:** The VTA contains a local SRAM memory segmented into four buffers: input (INP), weight (WGT), accumulator (ACC), and output (OUT). INP, WGT, and OUT data are encoded as signed 8-bit integers, whereas ACC uses signed 32-bit integers. The VTA manipulates data structures rather than individual data elements. INP, ACC, and OUT are vectors with *block size* elements, whereas WGT is a square matrix of *block size* × *block size* elements. The *block size* value is a VTA hardware configuration parameter, and its default value is 16, i.e., an INP vector contains 16 elements. The SRAM uses logical addresses to reference these data structures.
The VTA is also composed of four modules. The Fetch module dispatches the instructions to the three other modules that operate in parallel. The Compute module is further subdivided into two submodules: TensorGemm, responsible for vector-matrix multiplications, and TensorAlu, which handles element-wise operations (e.g., ReLU - Rectified Linear Unit).

TensorGemm performs multiplications between INP vectors and WGT matrices. The resulting products are then accumulated in ACC vectors. TensorAlu applies element-wise operations to the ACC vectors. Finally, the OUT vectors are written to the DRAM. It is important to note that OUT vectors are truncated ACC vectors.

## 2.2 DRAM data mapping

**Logical addresses:** DRAM is a large global storage accessible by both the CPU and the VTA. Usually, the memory is segmented into regions, with each region allocated to a specific application. In our case, a region of memory within the DRAM is assigned to the VTA to store its data and instructions. The memory address of this region is offset.

The DRAM memory system uses both physical and logical addresses. The logical addresses serve as an abstraction of the physical hardware addresses. The VTA manipulates logical addresses computed from the physical addresses as defined in Definition 1.

**Definition 1 (Physical and logical address relation)** Let phy_addr be the physical DRAM address, log_addr be the logical VTA address, offset be the memory offset of the DRAM region allocated to the VTA, precision be the data representation in Bytes (e.g., 1 Byte for an INP and 4 Bytes for an ACC), nb_elem be the number of elements in the structure (e.g., block size for the vectors and block size × block size for the matrices). The relation between phy_addr and log_addr is as follows:

$$log_addr = \lfloor \frac{phy_addr - offset}{precision \times nb_elem} \rfloor$$

This mechanism facilitates direct referencing of a vector or a matrix as opposed to its individual elements. For example, the two consecutive logical addresses inp_addr and inp_addr + 1 correspond to the INP vectors n and n + 1. In this paper, the addresses, whether physical or logical, are denoted by "@" followed by a hexadecimal value.

**DRAM allocation:** The TVM compiler is based on a memory allocation function that oversees the management of DRAM memory in 4 KiB pages. The TVM compiler allocates contiguous physical addresses and provides the corresponding logical addresses. Each memory allocation begins on a new page, even if the previous page is only partially filled. The TVM compiler opts for distinct allocation of the various data types, allocating first the INP vectors, then the WGT matrices, and so on.

<figure><img src="image_3.png" /><figcaption>Figure 2: DRAM allocation example</figcaption></figure>

Figure 2 illustrates an example of memory allocation with the memory offset set to offset = 0. Initially, the pointer is on Page 0 (phy_addr = @0000). The TVM compiler allocates 256 Bytes. It first advances the pointer to the start of the next available page, Page 1 (phy_addr = @1000). Then it allocates the contiguous physical addresses @1000 to @10FF. The pointer is now positioned at phy_addr = @1100. Next, the TVM compiler allocates 4352 Bytes, exceeding the capacity of a single 4 KiB page. The pointer is advanced to
Page 2 (*phy_addr* = @2000), and the requested bytes are allocated using the physical addresses @2000 to @30FF. The pointer is consequently positioned at @3100.

The DRAM allocation mechanism reserves contiguous regions for specific data structures. For instance, the second allocated region shown in Figure 2 is designated for 17 WGT matrices. Each matrix has a size of 256 Bytes. The logical address of each WGT matrix can be deduced from Definition 1. The logical address of the first WGT matrix is: *log_addr* = @2000 / 256 = @0020.

## 2.3 Instructions

The VTA uses a Complex Instruction Set Computer (CISC) architecture. The host CPU generates 128-bit instructions. Instructions operate using logical addresses. There are three distinct types of instructions: (i) LOAD / STORE, (ii) GEMM, and (iii) ALU. All instructions share two common fields: a 3-bit OPCODE and a 4-bit DEPT_FLAG. The OPCODE specifies the type of instruction, while the DEPT_FLAG, corresponding to the dependency flags, manages resources shared among the modules. The VTA is designed primarily for accelerating matrix multiplications; consequently, its GeMM instructions, executed by the TensorGemm module to perform these fundamental computations, are of particular significance.

**Focus on GeMM instructions:** Figure 3 shows a GeMM instruction used by the TensorGemm module. A GeMM (as well as an ALU) relies on a set of UOPs (micro-operations). These UOPs provide the initial SRAM logical addresses for ACC, INP, and WGT used by the GeMM instruction, as shown in Figure 4.

<figure><img src="image_4.png" /><figcaption>Figure 3: 128-bit GeMM instruction</figcaption></figure>

<figure><img src="image_5.png" /><figcaption>Figure 4: 32-bit UOP</figcaption></figure>

The GeMM instruction, whose pseudo-code is given in Algorithm 1, consists of three nested loops: (i) The outer loop (Line 1), defined by *LP*<sub>*O*</sub>, denoted *LP_OUT* in Figure 3; (ii) The inner loop (Line 2), defined by *LP*<sub>*I*</sub> (*LP_IN*); (iii) The UOP loop (Line 3), defined by the number of UOPs to read, from *UOP*<sub>*B*</sub> (*UOP_BEGIN*) until *UOP*<sub>*E*</sub> (*UOP_END*);

The initial INP, WGT, and ACC addresses are provided by the UOPs (Line 4). These addresses are then incremented through loop iterations and instruction factors (Lines 5, 7, and 8). For instance, the current INP vector depends on *INP*<sub>*O*</sub> (*INP IDX OUT*) and *INP*<sub>*I*</sub> (*INP IDX IN*) as shown in Line 7. Line 9 performs the computation *C* = *A* × *W*<sup>*T*</sup> + *X*. Since the TVM compiler always stores the weight matrix in its transposed form (i.e., *W* = *B*<sup>*T*</sup>), the resulting operation is *C* = *A* × *B* + *X*.
<caption>**Algorithm 1** Pseudo-code of GeMM instruction</caption>

**Input:** uop_buf, i_buf, w_buf, acc_buf
1: **for** $i_{out} \leftarrow 0$ until $LP_O$ **do**
2:   **for** $i_{in} \leftarrow 0$ until $LP_I$ **do**
3:     **for** $i_{uop} \leftarrow$UOP$_B$ until UOP$_E$ **do**
4:       $(i_{acc}, i_{inp}, i_{wgt}) = \text{uop\_buf}[i_{uop}]$
5:       $x = i_{out} \times \text{ACC}_O + i_{in} \times \text{ACC}_I + i_{acc}$
6:       $X = \text{acc\_buf}[x]$
7:       $A = i_{buf}[i_{out} \times \text{INP}_O + i_{in} \times \text{INP}_I + i_{inp}]$
8:       $W = w_{buf}[i_{out} \times \text{WGT}_O + i_{in} \times \text{WGT}_I + i_{wgt}]$
9:       $\text{acc\_buf}[x] = A \times W^T + X$
10:    **end for**
11:  **end for**
12: **end for**

A compiler must generate adequate instructions and data memory accesses to properly configure Algorithm 1 to perform the intended matrix operation. In the initial VTA/TVM repository, such a compiler was intertwined with the TVM compiler [10]. Our purpose is to define an independent and stand-alone compiler. Our approach is detailed in the next section.

# 3 Stand-alone VTA compiler

In this paper, we propose an open-source and fully-automated Python compiler pipeline from a matrix operation description down to the generation of the associated binary data and instructions, available on GitHub [9].

Our compiler adopts certain principles originating from the TVM ecosystem for VTA, namely its DRAM allocation strategy (see Section 2.2) and instruction sequence ordering (including reset and termination). Nevertheless, it was developed from scratch, guided by key objectives that significantly differentiate it from the original TVM approach. Unlike the tightly integrated and complex transformations within TVM, our pipeline offers a more transparent path from high-level matrix operations to VTA-specific binaries. This transparency, which is key for traceability, is achieved through a sequence of well-defined transformation steps. Each step generates distinct intermediate outputs, making the overall transformation flow more comprehensible and verifiable. The modular architecture also offers significant flexibility and extensibility, simplifying the exploration and evaluation of compilation choices or implementation strategies without necessitating an overhaul of the entire pipeline. All of these contribute to meeting aeronautics certification requirements.

## 3.1 Pipeline

The pipeline, shown in Figure 5, is divided into two parts: the data definition, which compiles the data; and the operations definition, which generates the instructions and UOPs. They are linked through the DRAM allocation, ensuring the correct correspondence between the data and the operations. Both parts are further subdivided into two transformation stages.

The VTA compiler takes as input a matrix operation and the associated matrices. These are both hardware-independent, also referred to as hardware-agnostic. The first stage makes the matrices and operations hardware-dependent. Specifically for matrix multiplication, the transformation process involves converting the data into INP vectors and WGT matrices of a size compatible with the VTA (see Section 2.1), along with converting the operation into VTA instructions and UOPs. The second stage involves encoding all preceding results into binary formats compatible with the VTA. The compiler produces up to six binary files: `input.bin` for the INP vectors, `weight.bin` for the WGT matrices, `expected_out.bin` for the reference result, `accumulator.bin` for the ACC vectors, `instructions.bin` and `uop.bin` for instructions.
<figure><img src="image_6.png" /><figcaption>Figure 5: VTA compiler pipeline</figcaption></figure>
## 3.2 Data definition

The data definition part is composed of three main functions: padding, splitting and binarisation. Figure 5 gives a simplified illustration of the data transformation process, with the *block size* equal to 2 (see Section 2.1).

**Padding:** The padding function (*matrix padding*) takes as input the initial hardware-agnostic matrix and returns a matrix, which may include additional columns and rows filled with zeros on the right and at the bottom. The purpose is to ensure that the data conform to the VTA data structure constraints described in Section 2.1. Therefore, the width and height of weight matrices must be rounded up to the nearest multiple of *block size* (e.g., in this example, *block size* is 2). However, INP and ACC are manipulated as vectors, so only the width is constrained to be the nearest higher multiple of the *block size*. In practice, padding INP and ACC along the height (generally) simplifies instruction generation. Hence, this approach is adopted throughout the subsequent paper.

In the example, let us suppose the hardware-agnostic matrix of size 3×3. The padding function pads the matrix so that both its width and height are multiples of 2, resulting in a 4×4 matrix. The grey boxes represent the added padding.

**Splitting:** The function *matrix*_ splitting splits the padded matrix into a list of smaller matrices, called blocks, and returns the number of blocks that make up a row. Each block is as wide as the VTA hardware *block size*. All the blocks, except for the last row, must be square. The blocks are stored in a list, ordered by row.

In the example given in Figure 5, the padded matrix is split into four 2×2 blocks. The resulting list of blocks is ($A_0, A_1, A_2, A_3$).

From the VTA's perspective, WGT matrices are considered *block size* × *block size* matrices, where each matrix has a single logical address. Other matrices, such as INP matrices, are treated as sets of *block size* vectors (where each row of the matrix constitutes a vector). Each such vector has its own logical address. Consequently, an INP matrix corresponds to *block size* logical addresses, one for each of its *block size* vectors.

**Binarisation:** Finally, the blocks are encoded into a binary file. The encoding follows the order in which the blocks are provided in the list, i.e., from left to right and from top to bottom. In the case of the weight matrix, the data within the blocks are transposed (see Section 2.3); however, the order of the blocks remains unchanged. Each initial matrix is encoded in a separate binary file, i.e., there is an INP file, a WGT file, and so forth.

In Figure 5, the matrix represents an INP. Each block is composed of *block size* vectors. Hence, each logical address refers to a row of these blocks (e.g., @00 is the first row of $A_0$ and @01 is the second row of $A_0$).

## 3.3 Operations definition

The definition of operations depends on hardware-agnostic matrix operations, the data layout specified by the data definition, and the DRAM allocation (see Section 2.2). We choose to use the same DRAM allocation as the TVM compiler to serve as a reference.

The operations are generated using a template in which only the instruction fields and the UOPs are modified. First, a pair of instructions is used to reset the VTA before starting the operations. This ensures that no residual data remain that could affect the execution. Second, the data are loaded, i.e., the INP, WGT, and ACC. The loading capability is constrained by the size of the buffers within the SRAM; therefore, the default VTA configuration supports loading up to 2048 INP vectors, 1024 WGT matrices, and 2048 ACC vectors. Third, the matrix multiplication is performed using the GeMM instruction and the associated UOPs (which must be loaded). A single GeMM instruction can perform a complete matrix multiplication provided the operand matrices fit into the SRAM. Fourth, the element-wise operations are applied using the TensorAlu. As with the GeMM, the corresponding UOPs are loaded, and the ALU instructions are executed. Multiple ALU instructions can be performed sequentially. Fifth, the resulting OUT vectors are stored back into the DRAM to be accessible by both the VTA and the CPU. Finally, a termination sequence is executed to properly finalise the VTA execution and prepare it for the next operation.

If the data do not fit into the buffers, steps 2 to 5 must be repeated as necessary, i.e., several GeMM instructions must be executed.
**Focus on the GeMM instructions:** A single GeMM instruction is capable of performing a block matrix multiplication. Figure 6 illustrates such operation $C = A \times B + X$, where each block represents a *block size × block size* matrix. Definition 2 provides the relationship between the blocks.

<figure><img src="image_7.png" /><figcaption>Figure 6: Block matrix multiplication</figcaption></figure>

**Definition 2 (Block matrix multiplication)** Let A be a $\alpha \times \lambda$ block matrix, let $A_{idx_A}$ be its blocks with $idx_A < \lambda \times \alpha$ the memory index. Let B be a $\lambda \times \beta$ block matrix, let $B_{idx_B}$ be its blocks with $idx_B < \beta \times \lambda$. Let X, respectively C, be two $\alpha \times \beta$ block matrices, let $X_{idx}$, respectively $C_{idx}$, be their blocks with $idx < \beta \times \alpha$. $C = A \times B + X$ is equivalent to the following block matrix multiplication, $\forall i < \alpha, j < \beta$:

$$C_{i \times \beta + j} = \sum_{k=0}^{\lambda-1} (A_{i \times \lambda + k} \times B_{k \times \beta + j}) + X_{i \times \beta + j}$$

Note that matrix A is the one converted into INP vectors, matrix B into WGT matrices, and matrix X into ACC vectors, which are loaded into the ACC buffer prior to the TensorGemm execution. Matrix C is the resulting matrix, corresponding to the ACC vectors after the TensorGemm execution.

Assuming that $\alpha \times \lambda \le 2048$, $\lambda \times \beta \le 1024$ and $\alpha \times \beta \le 2048$, and that all blocks are square with a size of *block_size*, Definition 2 is implemented using a single GeMM instruction shown in Figure 7. Otherwise, multiple GeMM instructions must be generated.

<figure><img src="image_8.png" /><figcaption>Figure 7: GeMM instruction implementation</figcaption></figure>

In this implementation, the inner loop (Algorithm 1, Line 2) performs the block multiplication, i.e., $A_{i \times \lambda + k} \times B_{k \times \beta + j} + X_{i \times \beta + j}$. The outer loop (Algorithm 1, Line 1) performs the sum over the index k. The UOP loop (Algorithm 1, Line 3) iterates over the $\alpha \times \beta$ blocks of C. At each UOP loop iteration, a UOP is decoded (Algorithm 1, Line 4). The first UOP decoded is the one at the address UOP_BEGIN (here an arbitrary value $\epsilon$) in the UOP buffer, after which the address is incremented by one. Each UOP points to the first ACC vector of a block. Figure 8 shows the implementation of the UOPs.

## 3.4 Simple execution example

In this example, we want to multiply the 16×16 matrix A with the 16×16 matrix B before performing a Rectified Linear Unit (ReLU) on the product.
<figure><img src="image_9.png" /><figcaption>Figure 8: UOP implementation $\forall i < \alpha, j < \beta$</figcaption></figure>

**Data definition:** First, $A$ and $B$ are padded if necessary. Here, $A$ and $B$ have a width and height equal to *block size*, thus no padding is needed. The matrices are then split. Both matrices consist of one block, respectively $A_0$ and $B_0$. As explained in Section 3.2, $B_0$ is transposed. Finally, the binary data are allocated as described in Section 2.2. The allocation order is as follows: the INP $((A_0))$, the WGT $((B_0^T))$, the OUT, and the UOPs. Their respective logical addresses in the DRAM are: @0100, @0020, @0300, and @1000.

**Operation definitions:** First, the VTA is reset; this requires a UOP located at address @0 in the UOP buffer.

Second, the INP and WGT are loaded into their respective buffers. $A_0$ consists of 16 INP vectors located from @0 to @F in the INP buffer. $B_0^T$ consists of one WGT matrix located at @0 in the WGT buffer.

Third, the matrix multiplication implementation follows that of Figure 7 and Figure 8, with $\alpha = \lambda = \beta = 1$ and $\text{block\_size} = 16$. Therefore, there is a single UOP associated with the operation with all its fields set to 0, which is loaded at address @1 in the UOP buffer (i.e., $\epsilon = 1$). The parameters used by Algorithm 1 to perform $A \times B$ are $LP\_OUT = 1$, $LP\_IN = 16$, $UOP\_BEGIN = 1$ and $UOP\_END = 2$.

Fourth, the TensorAlu submodule performs a ReLU, which is an element-wise maximum operation between each ACC vector and 0. The ALU implementation for a ReLU is similar to the GeMM implementation. Similarly to GeMM, this requires a UOP with all fields set to 0.

Fifth, the OUT vectors produced by the VTA, and located from address @0 to @F in the OUT buffer, are written to the DRAM at address @0300. Sixth, the VTA execution is terminated.

**Execution:** Figure 9 illustrates the execution of the GeMM operation. At each inner loop iteration (Algorithm 1, Line 2), the TensorGemm multiplies an INP vector by the WGT matrix, resulting in an ACC vector.

<figure><img src="image_10.png" /><figcaption>Figure 9: Matrix multiplication within the VTA SRAM</figcaption></figure>

The product results in 16 ACC vectors, which are then processed by the TensorAlu. The TensorAlu applies the ReLU operation on each vector and overwrites the results in place. For instance, after the ReLU operation, the second and last values of ACC @0 become 0 while the others remain unchanged.

Once both the GeMM and ALU operations are completed, the OUT vectors are generated by converting the ACC vectors into signed 8-bit integers. The Compute module then releases the OUT buffer, allowing the Store module to write the result to the DRAM. Finally, the termination sequence is executed prior to the next execution.
The preceding example has demonstrated how the VTA executes a matrix multiplication (GeMM) followed by an element-wise activation function (ReLU). This specific sequence represents the basic building block of most layers found in CNNs. Building upon this, Section 4 will now explore how to effectively execute CNNs on the VTA.

# 4 Execution of Convolutional Neural Networks

There exists a significant gap between CNNs and traditional matrix operations. CNNs are typically described in terms of tensors [11], which are multidimensional data structures. Moreover, CNNs are composed of a sequence of operations applied to these tensors. In this section, we outline key high-level principles of CNNs and discuss the challenges inherent in their implementation, which we will subsequently illustrate using LeNet-5 [12] on the VTA. It should be noted that this paper does not explore the theoretical foundations of neural networks. For further details, the book [13] and the course [14] provide comprehensive insights.

## 4.1 Principles / Reminder

In this paper, we consider two main categories of tensor operations [1]: dense linear operations (e.g., convolution or fully connected) and non-linear operations, which include element-wise transformations (e.g., activation functions) and region-based operations (e.g., pooling). We define a *layer* as comprising a single dense linear operation, followed by subsequent non-linear operations. For example, LeNet-5 is composed of five such layers. Its first layer consists of a convolution, followed by an activation function (e.g., sigmoid or ReLU), and then a pooling operation (e.g., average or max pooling).

**Relationship between tensor and matrix domain:** The operations in CNNs are typically described using 4D tensors, as shown at the top of Figure 10, which represent collections of 3D tensors. These tensors are commonly represented in the NCHW format [15], where the dimensions are given in the following order: first, the batch size ($b$ or $n_f$); second, the number of channels ($n_c$, $f_c$, or $m_c$); third, the height of the tensor ($n_h$, $f_h$, or $m_h$); and fourth, the width of the tensor ($n_w$, $f_w$, or $m_w$).

Input and output tensors consist of 3D tensors, processed independently. A batch size of 1 ($b = 1$) is used for our experiments. Weight tensors are composed of 3D filters, each filter corresponding to one output channel.

<figure><img src="image_11.png" /><figcaption>Figure 10: im2row/ker2col transformation principle</figcaption></figure>

Dense linear operations (e.g., convolution or fully connected) involve multiplying tensors together. These operations can be transformed into matrix multiplications [16] executable by the VTA (see Section 3). One such transformation method is im2row transformation [17], as illustrated in Figure 10. Definition 3
establishes the principles of the transformation functions. Once the transformations are done, the input and weight matrices are multiplied using the TensorGemm module. Subsequently, non-linear operations can be applied to the resulting output matrices using the TensorAlu module.

**Definition 3 (im2row, ker2col and mat2tensor principles)** Let $T_A$ be an input tensor. Let $T_B$ be a weight tensor with dimensions ($n_f, f_c, f_h, f_w$). Let $T_C$ be an output tensor such that $T_C = T_A \otimes T_B$, with dimensions (1, $m_c$, $m_h$, $m_w$). Let $A$ be a $\alpha \times \lambda$ input matrix. Let $B$ be a $\lambda \times \beta$ weight matrix. Let $C$ be a $\alpha \times \beta$ matrix such that $C = A \times B$. Let im2row be the function that converts an input tensor into an input matrix, ker2col be the function that converts a weight tensor into a weight matrix, mat2tensor be the transformation function that converts an output matrix into an output tensor. Then, if $A = im2row(T_A)$ and $B = ker2col(T_B)$, we have: $T_C = mat2tensor(C)$.

## 4.2 Implementation of CNNs using our VTA compiler

Our VTA compiler pipeline implements a single layer that is first converted into the matrix domain. Figure 11 shows the extended pipeline, which includes the first compilation stage responsible for the hardware-agnostic conversion of tensors into matrices.

<figure><img src="image_12.png" /><figcaption>Figure 11: Compilation of one layer for the VTA</figcaption></figure>

**Layer chaining:** CNNs are composed of multiple layers. In the tensor domain, these layers are executed sequentially without specific post-processing between them. However, once converted into matrices through the *im2row/ker2col* methods, post-processing may be required between each layer. This post-processing typically includes reshaping the matrix to match the input format expected by the next layer.

Layer chaining is not yet automated, mainly due to the matrix reshaping and the global DRAM allocation strategy. The current approach to chain layers is to compile all the layers independently to generate data and instructions. Then, the data are allocated in the DRAM and the instructions are adapted to match this allocation strategy. Finally, the matrix reshaping is configured to get the output of a layer from the DRAM and provide the input for the next layer within the DRAM. The matrix reshaping is performed between two VTA executions.

We chose to implement a naive solution to perform this reshaping. It consists of the two main following stages: (i) Convert the output matrix back into a tensor using *mat2tensor*; (ii) Convert the tensor into the next input matrix using *im2row*. These steps must be extended to fit the VTA implementation. Therefore, the first stage involves the binary decoding of the output in order to reconstruct the resulting blocks from the block matrix multiplication (see Definition 2). These blocks are then merged (or unsplit) to form a complete matrix, and the padding is removed. The resulting matrix is then converted using *mat2tensor*. The second stage consists of reapplying all the transformation steps of the extended pipeline: *im2row*, *padding*, *splitting*, and *binarisation*.

Figure 12 illustrates the layer chaining on LeNet-5.
<figure><img src="image_13.png" /><figcaption>Figure 12: Layer chaining on LeNet-5</figcaption></figure>

## 4.3 Application to LeNet-5

LeNet-5 [12] is a well-known neural network designed for handwritten digit recognition, specifically for the MNIST [18] dataset. Its architecture consists of five sequential layers: the first two layers combine convolution, ReLU activation, and average pooling; the third layer comprises convolution and ReLU; the fourth layer is fully connected with ReLU; and the final layer is a fully connected output stage producing ten classes. LeNet-5 is applied to the VTA using the extended pipeline (depicted in Figure 11). Each layer is compiled and tested independently. Then, the instructions and reshaping process are manually configured to combine the five layers. The reshaping process is performed twice: once between the first and second layers, and again between the second and third layers. The other layers result in a format compatible with the next one, thanks to the fully-connected layers.

**First layer:** The input of LeNet-5 is an image in black-and-white with a resolution of 32×32 pixels. It results in an input tensor (1, 1, 32, 32). The *im2row* transformation results in a 784×25 input matrix. This matrix is padded and split to result in a block matrix with $\alpha = 49$ and $\lambda = 2$, where each block is 16×16. Then, it is encoded into binaries and executed on the VTA. The output is subsequently decoded into a hardware-agnostic matrix of size 196×6, and then converted into an output tensor of shape (1, 6, 14, 14).

**Other layers:** All the layers are compiled prior to executing LeNet-5 in the same way as layer 1. All of these binaries, along with those related to the subsequent layers, are allocated in DRAM and must be taken into account when defining the logical addresses within the instructions. Consequently, only the conversion of the previous output tensor into binaries (i.e., the second stage of reshaping) is performed between two VTA executions, directly on the host machine.

# 5 Simulation and results

The VTA/TVM project from [10] provides two simulators: a functional simulator and a cycle-accurate simulator. However, these simulators were not easily executable, as the functional simulator was embedded within the compilation pipeline, while the cycle-accurate simulator did not accept the binary files resulting from the compilation. To address this, we extracted and modified both simulators to make them more accessible, ensuring that they both accept raw binaries as input.

We have compiled and simulated the LeNet-5 model on both VTA simulators. The PyTorch model [15] served as the reference for the simulation.

## 5.1 Functional simulator

The functional simulator, written in C++, provides fast results strictly equivalent to those produced by the VTA hardware implementation. Only limited execution details can be observed with this simulator: the total size of data exchanged with DRAM, the total number of loops, and the execution output.

**LeNet-5 simulation:** This simulator returns the bit-accurate result almost instantaneously, thereby proving the correctness of the compilation. It also reports that the execution requires 2942 GeMM loops to perform all the matrix multiplications required for LeNet-5.
## 5.2 Cycle-accurate simulator

The cycle-accurate simulator adheres to the hardware constraints as it is based on CHISEL (Constructing Hardware In a Scala Embedded Language) [4], a Hardware Description Language (HDL). Furthermore, the CHISEL language makes the simulator easy to modify, allowing for the customisation of the execution report to highlight or adapt specific details.

We limited the cycle-accurate simulation to the Compute module, as it constitutes the core of the execution and was the primary focus of our analysis.

**LeNet-5 simulation:** This simulation takes significantly longer, approximately 4 hours. Like the functional simulator, it produces the bit-accurate result. Additionally, it provides cycle-level details, including the current INP vector and WGT matrix being used, as well as the ACC vector produced. The simulation indicates that the VTA takes 2972 cycles to execute these TensorGemm operations, including decoding the GeMM instruction and checking buffer availability. Therefore, the VTA is able to almost complete an entire GeMM loop in each cycle. In this case, with *block size* = 16, a GeMM loop consists of 256 Multiply-Accumulate (MAC) operations. Considering a modern SIMD CPU capable of performing 16 MACs per cycle [19], at least 47552 total cycles would be required (approximately 16 times more cycles per loop compared to the VTA). In total, 6358 cycles are needed to execute LeNet-5 (without considering Load and Store operations). Considering an FPGA with a clock speed of 650 MHz, LeNet-5 is executed in 9.8 microseconds. The considered CPU must have a frequency of approximately 10 GHz to achieve the same execution time. This frequency is significantly beyond the typical operating range of current commercial CPUs.

# 6 Related work

## 6.1 Hardware accelerators

Hardware accelerators are essential for executing modern Machine Learning algorithms, such as CNNs. They aim to efficiently execute dense linear algebra operations [20,21], the most computationally critical parts of CNNs. A wide variety of hardware accelerators exists, including Tensor Processing Units (TPUs) [22], Neural Processing Units (NPUs) [23], Graphics Processing Units (GPUs) [24], and FPGA-based accelerators [1]. Most feature parallel architectures, which are well-suited for executing matrix-based operations.

When selecting a hardware accelerator, two major factors must be considered: performance and flexibility. TPUs generally offer the highest performance, whereas FPGA-based accelerators provide the greatest flexibility [25]. For safety-critical applications, additional considerations should be taken into account, such as the availability of detailed internal architectural information.

We selected the VTA (Versatile Tensor Accelerator) [1] for this study. Its open-source description using CHISEL, an RTL-like description language, provides fine-grained hardware details that are key to hardware analysis and formal verification in safety-critical applications. Leveraging the Scala programming environment, CHISEL facilitates the setup of test benches and hardware simulations. This environment also provides CHISEL with efficient simulation-based verification capabilities [26]. Moreover, it offers formal verification features [27], valuable for safety-critical analyses.

## 6.2 Compiling tensors into matrices

Executing tensor-based NN operations on matrix accelerators like VTA requires transforming tensors into suitable matrix representations. Compilers like TVM offer various techniques for this purpose [7]. Two common approaches are tensorisation and explicit matrix conversion methods like *im2col/im2row*.

Tensorisation [7] maps high-level tensor operations directly onto VTA's architecture for execution. While potentially efficient, this often involves complex sequences of transformations within the compiler flow [28].

Alternatively, transformations like *im2col* [29] (image-to-column) and *im2row* [17] (image-to-row) explicitly restructure input tensors (e.g., from convolutional layers) into large matrices suitable for standard GeMM operations. These methods are conceptually similar, differing mainly in the output matrix layout (transpose relationship). A known drawback is the significant memory overhead due to data replication within the generated matrix. However, their transformation logic is often considered more direct compared
to multi-step tensorisation pipelines. Research efforts focus on optimising these methods to mitigate the
memory overhead [30].

Other techniques, such as channel merging and kernel interleaving [31], target specific hardware (e.g., Multi-Bit-Width units) to potentially avoid explicit reshaping between some layers, though possibly at the cost of less standard data layouts.

In our extended pipeline, we selected *im2row* partly because its resulting matrix layout appears well-suited to the vector processing architecture of VTA's TensorAlu module, facilitating efficient mapping of computations.

## 6.3 Certification aspects

Applying ML accelerators like VTA in safety-critical domains, such as avionics, requires stringent certification regarding predictability, traceability, and verifiable semantic preservation. These certification requirements are anticipated based on the EASA (European Union Aviation Safety Agency) concept paper [32], which will define the regulatory framework for ML in critical avionics. The joint international working group, EUROCAE WG-114 and SAE G-34, gathering industry, academia, and regulatory authorities (including EASA), is developing the ED-324/ARP6983 standard. This standard is expected to be recognised as a Means of Compliance (MOC) with the upcoming regulatory framework, meaning its application will ensure compliance.

The ED-324/ARP6983 standard promotes a design assurance process based on a W-shaped development lifecycle. The first 'V' is dedicated to the design and validation. The second 'V' focuses on the implementation and verification on the target hardware. A primary purpose of the standard is to capitalise extensively on existing and well-established avionics guidelines, such as DO-178C [6] for software development and DO-254 [5] for hardware development. Adherence to DO-254 and DO-178C is therefore a key consideration in the development of the VTA compiler.

# 7 Conclusion

This paper addressed significant challenges hindering the adoption of the VTA in computationally intensive fields, particularly safety-critical systems such as aeronautics. To tackle these issues, we developed a fully automated Python compiler pipeline, transforming hardware-agnostic matrix operations into VTA-compatible binary data and instructions. We detailed the processes of data padding, splitting, and binarisation, along with the generation of VTA instructions, including the critical GeMM operations for matrix multiplication. Furthermore, we outlined the principles for executing CNNs on the VTA by converting tensor operations into matrix multiplications using methods such as *im2row/ker2col*, applying this methodology to the LeNet-5 network. We also provided a simulation framework to investigate different compilation strategies.

Future work can effectively build upon the compiler and simulation framework presented. First, this framework provides the tools to investigate, simulate, and compare different compilation strategies and transformation techniques for the VTA. For instance, it can evaluate advanced methods, such as the one proposed in [31] for directly chaining multiple network layers, assessing their performance and correctness implications. Second, once compilation strategies are clearly identified and validated through this framework, the insights gained will enable further automatising the compiler pipeline for streamlined and direct implementation of NNs on the VTA. Finally, complementing these compilation-focused efforts, a crucial perspective involves the detailed analysis and formal verification of the VTA architecture itself. This could leverage the VTA's hardware description (e.g., in CHISEL) to provide stronger guarantees, paramount for safety-critical applications.

## Acknowledgment

This work has benefited from the AI cluster ANITI2 and from the PHYLOG 2 project funded by the French government through the France Relance program, based on the funding from and by the European Union through the NextGenerationEU program.
## References

[1] T. Moreau, T. Chen, L. Vega, J. Roesch, E. Yan, L. Zheng, J. Fromm, Z. Jiang, L. Ceze, C. Guestrin, and A. Krishnamurthy, "A Hardware-Software Blueprint for Flexible Deep Learning Specialization," *IEEE Micro*, vol. 39, no. 5, pp. 8-16, 2019.

[2] M. Haandbaek et al., "Safety-critical systems: A case for modern verification tools and accelerators," in *Proceedings of the 2023 Conference on Autonomous Flight Systems*, 2023.

[3] P. Coussy, D. D. Gajski, M. Meredith, and A. Takach, "An introduction to High-Level Synthesis," *IEEE Des. Test Comput.*, vol. 26, no. 4, pp. 8-17, 2009.

[4] J. Bachrach, H. Vo, B. C. Richards, Y. Lee, A. Waterman, R. Avizienis, and et al., "Chisel: constructing hardware in a Scala embedded language," in *The 49th Annual Design Automation Conference 2012, DAC*, 2012, pp. 1216-1225.

[5] RTCA, Inc., "DO-254: Design Assurance Guidance for Airborne Electronic Hardware," April 2000.

[6] —, "DO-178C: Software Considerations in Airborne Systems and Equipment Certification," December 2011.

[7] T. Chen, T. Moreau, Z. Jiang, L. Zheng, E. Q. Yan, H. Shen, and et al., "TVM: An Automated End-to-End Optimizing Compiler for Deep Learning," in *13th USENIX Symposium on Operating Systems Design and Implementation*, 2018, pp. 578-594.

[8] I. De Albuquerque Silva, T. Carle, A. Gauffriau, and C. Pagetti, "ACETONE: Predictable Programming Framework for ML Applications in Safety-Critical Systems," in *36th European Conference on Real-Time Systems*, ser. ECRTS, 2022.

[9] "GitHub: standalone-vta." [Online]. Available: https://github.com/onera/standalone-vta

[10] "GitHub: Apache TVM v.0.18.0." [Online]. Available: https://github.com/apache/tvm/releases/tag/v0.18.0.rc0

[11] H. Guo, *What Are Tensors Exactly?* WorldScientific, 2021.

[12] Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner, "Gradient-based learning applied to document recognition," *Proc. IEEE*, vol. 86, no. 11, pp. 2278-2324, 1998.

[13] I. Goodfellow, Y. Bengio, and A. Courville, *Deep Learning*. MIT Press, 2016, http://www.deeplearningbook.org.

[14] B. M. N. Smets, "Mathematics of neural networks (lecture notes graduate course)," *CoRR*, vol. abs/2403.04807, 2024.

[15] A. Paszke, S. Gross, F. Massa, A. Lerer, J. Bradbury, G. Chanan, and et al., "PyTorch: An Imperative Style, High-Performance Deep Learning Library," in *Advances in Neural Information Processing Systems 2019*, 2019, pp. 8024-8035.

[16] W. Ma and J. Lu, "An Equivalence of Fully Connected Layer and Convolutional Layer," *CoRR*, vol. abs/1712.01252, 2017.

[17] P. Wang, X. Wang, R. Luo, D. Wang, M. Luo, S. Qiao, and Y. Zhou, "An efficient im2row-based fast convolution algorithm for ARM cortex-m mcus," *IEEE Access*, vol. 9, pp. 124384-124395, 2021.

[18] E. M. Kussul and T. Baidyk, "Improved method of handwritten digit recognition tested on MNIST database," *Image Vis. Comput.*, vol. 22, no. 12, pp. 971-981, 2004.

[19] A. Fog, "The microarchitecture of intel, AMD and VIA CPUs: An optimization guide for assembly programmers and compiler makers," Tech. Rep., 2024.
[20] M. Capra, B. Bussolino, A. Marchisio, G. Masera, M. Martina, and M. Shafique, "Hardware and Software Optimizations for Accelerating Deep Neural Networks: Survey of current trends, challenges, and the road ahead," *IEEE Access*, vol. 8, pp. 225 134–225 180, 2020.

[21] Y. Hu, Y. Liu, and Z. Liu, "A survey on convolutional neural network accelerators: GPU, FPGA and ASIC," in *2022 14th International Conference on Computer Research and Development (ICCRD)*, 2022, pp. 100–107.

[22] X. He, S. Pal, A. Amarnath, S. Feng, D. Park, A. Rovinski, H. Ye, K. Chen, R. G. Dreslinski, and T. N. Mudge, "Sparse-tpu: adapting systolic arrays for sparse matrices," in *ICS '20: 2020 International Conference on Supercomputing, Barcelona Spain, June, 2020*, 2020, pp. 19:1–19:12.

[23] A. Parashar, M. Rhu, A. Mukkara, A. Puglielli, R. Venkatesan, B. Khailany, J. S. Emer, S. W. Keckler, and W. J. Dally, "SCNN: an accelerator for compressed-sparse convolutional neural networks," *CoRR*, vol. abs/1708.04485, 2017.

[24] Z. Luo, H. Liu, and X. Wu, "Artificial neural network computation on graphic process unit," in *IEEE International Joint Conference on Neural Networks, IJCNN 2005, Montreal, QC, Canada, July 31 - August 4, 2005*, 2005, pp. 622–626.

[25] A. P. Munanday, N. Sazali, W. S. W. Harun, K. Kadirgama, and A. S. Jamaludin, "Analysis of convolutional neural networks for facial expression recognition on GPU, TPU and CPU," *Journal of Advanced Research in Applied Sciences and Engineering Technology*, vol. 31, no. 3, pp. 50–67, 2023.

[26] A. Dobis, K. Laeufer, H. J. Damsgaard, T. Petersen, K. J. H. Rasmussen, E. Tolotto, and et al., "Verification of chisel hardware designs with ChiselVerify," *Microprocessors and Microsystems*, vol. 96, p. 1047–1049, 2023.

[27] K. Laeufer, J. Bachrach, and K. Sen, "Open-source formal verification for Chisel," in *Proceedings of the Fourth Workshop on Open-Source EDA Technology (WOSET)*, 2021.

[28] "Apache TVM Documentation." [Online]. Available: https://tvm.apache.org/docs/

[29] H. Wang and C. Ma, "An optimization of im2col, an important method of CNNs, based on continuous address access," in *2021 IEEE International Conference on Consumer Electronics and Computer Engineering (ICCECE)*, 2021, pp. 314–320.

[30] I. D. A. Silva, T. Carle, A. Gauffriau, and C. Pagetti, "Extending a predictable machine learning framework with efficient gemm-based convolution routines," *Real Time Syst.*, vol. 59, no. 3, pp. 408–437, 2023.

[31] M. Beyer, S. Gesper, A. Guntoro, G. Payá-Vayá, and H. Blume, "Exploiting subword permutations to maximize CNN compute performance and efficiency," in *34th IEEE International Conference on Application-specific Systems, Architectures and Processors 2023*, 2023, pp. 61–68.

[32] European Union Aviation Safety Agency, "EASA Artificial Intelligence (AI) Concept Paper Issue 2: Guidance for Level 1 & 2 machine learning applications," 2024.