3.1. System Overview
This accelerator uses a Xilinx 7 series FPGA as its target platform. It interacts with a host computer at high speed via a PCIe interface and utilizes DDR3 memory as an off-chip data cache. A complete CNN forward-inference accelerator is built within the FPGA for the quantized YOLOv5n network; the current prototype is therefore a host–FPGA collaborative detector rather than a fully standalone device-only system.
As shown in
Figure 2, the overall system architecture consists of three core parts: a PCIe communication subsystem, a DDR3 storage subsystem, and an NPU (Neural Processing Unit) computing subsystem. The top-level module, top.v, is responsible for coordinating the interconnection and clock management of these three subsystems. The system uses the clk_wiz_0 clock management IP core, which multiplies/divides the external input clock pl_clk to generate the NPU operating clock npu_clk and the 200 MHz reference clock clk_200m required by the DDR3 (Micron, Boise, ID, USA) controller. The inverted locked signal of the clock management module is used as the global reset signal npu_rst for the NPU subsystem, ensuring that the system only starts normal operation after the clock stabilizes.
The PCIe communication subsystem is encapsulated in a wrapper module, integrating an IP core, an XDMA engine, and an AXI interconnect. The XDMA engine provides the NPU subsystem with two sets of read channels and two sets of write channels. Each channel includes a command interface and a data interface. The read channel has a 128-bit data width, while the write channels m_0 and m_1 are 128 bits and 64 bits respectively. Furthermore, the host computer configures the NPU’s internal registers via the AXI-Lite interface.
The DDR3 storage subsystem uses a Xilinx MIG IP core connected to 32-bit DDR3 SDRAM. DDR3 is used to store input image data, convolution weight parameters, intermediate feature maps, and detector-head outputs. All data is pre-loaded into DDR3 by the host computer via the PCIe/XDMA channel. During inference, the NPU reads the required data layer by layer via DMA, completes the calculation, and writes the results back. The DDR3 address space is strictly partitioned according to function. The weight storage area starts from the low address and consists of 60 equally spaced partitions, each 1 MB. These partitions sequentially store the weights of the 56 convolutional layers (conv2 to conv57), the weights of the three detector output layers, and the weights of conv1, totaling approximately 60 MB. The input image area has a base address of 0 × 10,000,000 and stores approximately 1.6 MB of quantized image data (640 × 640 × 4 bytes) after preprocessing by the host computer. The source and destination addresses of different layers are explicitly specified by the ‘addr’ field in the instruction, systematically avoiding address conflicts. After FPGA forward inference, the host computer reads the outputs back via DMA and performs sigmoid, coordinate decoding, and NMS post-processing.
The NPU computing subsystem is the core of the entire system and is implemented by the ‘npu’ module. The NPU internally includes a register controller, data-stream exchange, and seven functional operator units: a 3 × 3 convolution operator, a 1 × 1 convolution operator, an element-wise addition operator, a channel concatenation operator, an SPPF operator, an upsampling operator, and a Focus operator. These seven operators cover the major operator types required by the quantized YOLOv5n forward path before host-side post-processing. Communication between the PS and PL is established through two bus protocols. The AXI4-Lite slave interface provides a register configuration channel: for each network layer, the PS writes the source address, target address, weight address, feature-map size, number of channels, quantization parameters (scale and zero-point), and stride configuration to the register controller (reg_ctrl), and then issues a start command. The AXI4-Stream interface, in conjunction with the DMA engine, provides a high-bandwidth data channel between DDR memory and on-chip cache.
The system workflow is divided into five stages:
(1) Initialization stage: the host computer loads the image data to be detected and the network weight parameters into the specified address space of the DDR3 memory via PCIe/XDMA.
(2) Instruction writing stage: The host computer writes the inference instruction sequence to the register controller one by one via the AXI-Lite interface. The instructions are stored in the internal SPRAM.
(3) Inference execution stage: The host computer writes to the register to trigger the NPU to start inference. The register controller fetches instructions in sequence, parses parameters and configures the corresponding operators, and then issues a start signal.
(4) Layer-by-layer inference stage: After receiving the start signal, each operator reads the input data and weights from DDR3 via DMA, completes the calculation, and writes it back to DDR3. Upon completion, the operator generates an end signal to notify the register controller to fetch the next instruction.
(5) Result feedback stage: After the last instruction is executed, the calculated end signal triggers a user interrupt via cross-clock-domain synchronization. The host reads the detector-head outputs and performs sigmoid, box decoding, and NMS post-processing. Accordingly, the system boundary of this paper is defined as FPGA acceleration of the quantized YOLOv5n forward path plus host-side post-processing, rather than a fully independent hardware-only detection pipeline.
3.2. Hardware Operator Design
The NPU module instantiates seven operator modules and one register controller, as shown in
Table 1.
3.2.1. Design and Implementation of the 3 × 3 Convolution Operator (Conv33)
The 3 × 3 convolution is the most basic and computationally intensive operation in object-detection networks. The conv33 operator in this design implements the standard 3 × 3 convolution operation, supporting stride = 1 and stride = 2 strides. It integrates INT8 multiplication–accumulation, bias addition, quantization scaling, and ReLU activation. Furthermore, the 3 × 3 convolution architecture is a common architecture for many subsequent operators, consisting of a top-level module, a control module, input and output data buffering modules, a weight management module, a computation module, and a post-processing module. The design principles of each module will be described below.
Figure 3 shows the overall data flow and internal modules.
(1) Input and Output Data Buffer Module: The main purpose of this module is to accelerate the entire convolutional neural network computation process and achieve efficient data transfer. The time required for the FPGA to retrieve data from DDR is much longer than the time required to retrieve data from on-chip RAM. If data has to be transferred from DDR for each computation, the overall computational utilization will be very low. However, on-chip RAM resources are generally insufficient to store all the data required for neural network computation. Therefore, the process of transferring data from DDR needs to be optimized. The ping-pong buffer strategy has been specifically introduced in
Section 3.2.2. In this design, a ping-pong buffer for data_in is set to use a ping-pong operation for the process of retrieving data from DDR. Each time data is retrieved, the address jump changes to W × C, and one row of data is retrieved at a time. Each point has C bytes of data. After each row of data is written, the ping/pong select signal is reversed, so that the two ping-pong buffers alternately write data and are read by the subsequent modules. In this way, when the subsequent computation module performs computation, the data to be computed next is supplemented into RAM. The same applies to the output buffer module. When a row of data is computed by the computation module, it will be read out and written to DDR. The entire process is shown in
Figure 4.
(2) Input Data Control Module: This module is responsible for organizing the input feature map data. Convolutional neural networks do not simply perform convolutional multiplications; they also involve zero-padding and stride adjustments. The next-level computational units are only responsible for computation, so the data needs to be organized into a format that can be directly used by the lower-level modules. Specifically, five RAMs are simulated for data storage, each containing one row of data. The state transitions are described in the state machine shown in
Figure 5 below.
S0: Idle state. idle when no start signal is detected; jumps to S1 upon detection of a start signal.
S1: Padding operation is performed, adding a ring of zeros to the outermost layer. Therefore, the first calculation can begin when there are two rows of data in RAM, entering state S2.
S2: Data is sent to the next-level module for calculation. When the calculation is complete, it jumps to state S3.
S3: The padding operation is no longer considered. Therefore, if there are three or more rows of data in RAM, it can enter state S4; otherwise, it waits for data to be read in state S3.
S4: Stride operation is considered. If the calculation of the entire frame is complete (i.e., when calculating the last row), if stride = 2, it jumps back to state S0 when the number of calculated rows is half the number of rows in the original image. If stride = 1, it jumps to state S5. If the calculation has not reached the last row, it jumps back to state S3 to wait for the next three rows of data.
S5: Similar to the first row, it enters the calculation of the last two rows. After the calculation is complete, it jumps back to state S0.
Simultaneously, the utilization of the five on-chip RAMs also needs to be considered. Since RAM continuously retrieves data from higher-level modules, the on-chip multiplexing technique described in
Section 3.2.4 is required. For example, RAM0 stores the first row of data, RAM1 stores the second row, and RAM2 stores the third row. A 3 × 3 convolution calculation can then be performed. After the calculation is complete, the subsequent stage only needs to supplement the fourth row of data from RAM3. Then, RAM1, RAM2, and RAM3 can complete the next calculation with a stride of 1, and so on. When the stride is 2, skipping a RAM is equivalent to skipping a row.
The design of the five state machines and RAM enablement described above completes the classification of the input data for the entire convolution calculation. Whether it is a padding operation or an operation with a stride of 1 or 2, the correct feature map data to be calculated can be passed to the next-level calculation module.
(3) The weight management module: ‘conv33_weight’ is responsible for reading 3 × 3 convolution kernel weights from DDR3 and providing them to the computation core in an appropriate format. Similar to the caching module, it employs a ping-pong caching strategy: while the current set of weights is being used by the computation core, the next set is prefetched, thus overlapping the weight loading and computation pipelines and eliminating loading latency. The controller tracks the available weight cache quantity using the ‘weight_cnt’ counter and actively sends a ‘weight_req’ request signal when the cache is insufficient.
(4) The computation module: ‘conv33_calc’ is the most crucial module of the ‘conv33’ operator, implementing highly parallel multiplication and accumulation operations for 3 × 3 convolutions. Following the input data module and weight management module, the input data module takes in three rows of data. The ‘Conv3 × 3’ convolution calculates the convolution of 9 feature map data points with the weights and then sums them, requiring 9 feature map data points. In FPGA design, using registers to time signals can generate signals delayed by one clock cycle. Therefore, by timer processing the incoming feature map data with one row and two rows respectively, we can obtain data, data_1, and data_2. The method for generating the 9 positions of the convolution is shown in
Figure 6.
For weight storage, two sets of ping-pong weight memories are used, each consisting of a 16 × 8 array of 72-bit registers. Each 72-bit storage unit stores a complete 3 × 3 convolution kernel (9 8-bit weight values, totaling 72 bits) corresponding to one input channel and one output channel; 16 corresponds to 16 input channel parallelisms, and 8 corresponds to 8 output channel parallelisms. When writing weights, the bytes at the same position in the 9 weight ports are reassembled and packaged into 72 bits and written to the corresponding storage location.
Having obtained the feature map data and weight data, the parallel computation design is the focus of this section. This module receives 9 sets of 128-bit weight inputs (corresponding to the 9 positions of the 3 × 3 convolution kernel) and 3 sets of 128-bit input data (which, after the above processing, can also be considered as data for the 9 positions of the convolution kernel). Each set of 128-bit data contains 16 8-bit channel values. The calculation separates the 16 channels.
Section 3.2.3 introduces the DMP-based reuse of DSP resources. The calculation involves concatenating two 8-bit weights with eight zeros padded in between, and then performing calculations with the feature map data. A single calculation yields the equivalent of instantiating two multipliers. As shown in
Figure 7, the high-parallelism convolution multiplication calculation instantiates 16 × 4 × 9 = 576 multiplication units. One clock cycle can calculate 9 × 16 × 8 convolution results, where 9 refers to the 9 points of a 3 × 3 convolution, 16 refers to the depth of the weights and features, and 8 refers to the 8 different convolution kernels. For accumulation operations, the outputs of the 576 multipliers are reduced through a multi-stage pipelined addition tree. First, the products at the same convolution kernel position (3 positions in the same row) are summed in three paths to obtain the row partial sum. Then, the three-row partial sums are summed again to obtain the single-channel convolution result. Next, the convolution results of the 16 input channels are accumulated through a four-stage pipeline, finally obtaining the 24-bit convolution accumulation values for each of the 8 output channels. The entire multiply–accumulate pipeline experiences a delay of approximately 12–14 clock cycles. The data valid signal ‘data_valid’ and the end signal ‘data_last’ are synchronized and delayed through a chain of shift registers of equal length to ensure precise alignment between the control signals and the data.
(5) The post-processing module ‘conv33_add’ performs three operations, including bias addition, quantization scaling, and ReLU activation, converting the 24-bit convolutional sum into an 8-bit quantized output. This module also employs a ping-pong buffer strategy to manage bias data and uses eight SPRAMs to implement partial sum accumulation across input channels. The specific processing flow is as follows: (a) accumulate the convolution result of the current input channel group with the preceding partial sum stored in the SPRAM; (b) after the last input channel group is completed, multiply the accumulated result by a 16-bit scaling factor ‘scale’; (c) add a 32-bit bias value; (d) truncate negative values to zero to simulate ReLU; (e) add the output zero; and (f) truncate the high-order bits and round them to an 8-bit unsigned output, while performing overflow saturation processing. This series of operations realizes the complete transformation process from convolution accumulation to quantization output in INT8 quantization inference.
The accelerator employs a cache–compute–cache dataflow strategy: feature maps and weights of each layer are stored in DDR, the DMA engine transfers them into on-chip ping-pong buffers for local streaming computation, and the results are written back to DDR as inputs for subsequent layers. Although this introduces DDR round trips between layers, it provides three key advantages: (a) each operator only needs on-chip caching for the current block, significantly reducing BRAM consumption; (b) operators are completely decoupled, allowing flexible layer scheduling, including residual branching and multi-scale feature fusion; and (c) any intermediate feature map can be accessed by multiple downstream layers through its DDR address. Intra-layer, data flows through a 128-bit AXI-Stream channel, precisely matching the 16-element INT8 parallelism of the computation core. This cache–compute–cache organization is one of the main architectural distinctions of the proposed design.
3.2.2. 1 × 1 Point Convolution Module
The 1 × 1 convolutions (also known as pointwise convolutions) are widely used in lightweight networks for linear transformations and feature fusion along the channel dimension. Compared to 3 × 3 convolutions, 1 × 1 convolutions do not require sliding window operations in the spatial dimension, but they do require handling a large number of inter-channel cross-calculations. The conv11 operator in this design has a similar module hierarchy to conv33 in architecture: including a control module (conv11_ctrl), input data management, weight management, a computational core (conv11_calc), a post-processing module (conv11_add), and an output buffer, but it has been optimized for the characteristics of 1 × 1 convolutions in terms of parallelism and data flow organization.
The key differences between the conv11 operator and conv33 are: (1) the output parallelism is increased from 8 channels to 16 channels, that is, the calculation results of 16 output channels can be generated simultaneously in each clock cycle; (2) the input data ports are reduced from 3 groups to 1 group of 128 bits (16 INT8 pixels); (3) the weight ports are expanded from 9 groups to 16 groups of 128 bits, corresponding to a complete 1 × 1 convolution kernel for 16 output channels; and (4) a new en_relu control signal is added to support optional ReLU activation instead of the fixed ReLU of conv33, to adapt to some unnecessary ReLU activations in the YOLOv5 network. The 1 × 1 convolutional layer is to be activated.
The implementation of the computational core ‘conv11_calc’ fully utilizes the computational characteristics of 1 × 1 convolution. Since the kernel size is 1 × 1, no window sliding or row buffering is needed; each clock cycle directly performs multiplication and accumulation operations on the pixel values of the 16 input channels and the 16 × 16 weight matrix. Weight storage uses a ping-pong buffer, with each group consisting of a 16 × 16 array of 8-bit registers. The multiplication array consists of 16 × 8 = 128 ‘conv_mul_dsp’ units, which, after applying DMP to each DSP48, cover 16 × 16 = 256 multiplication operations.
3.2.3. Design and Implementation of the Element-Wise Addition Operator
The element-wise addition operator is used to implement residual connections and is a key component of the C3 module in the YOLOv5 network. Residual connections add shallow and deep features element-wise, helping to alleviate the vanishing gradient problem in deep networks and enhancing feature reuse capabilities. In INT8 quantization scenarios, the two addends typically have different quantization parameters; therefore, element-wise addition is not a simple integer addition but requires a dequantization–addition–requantization operation.
The add_top module receives two sets of input data and their corresponding quantization parameters, as well as output quantization parameters, and outputs the requantized addition result. The module internally includes a control module, input buffer, computation core, and output buffer.
The computation core add_calc’s processing pipeline is as follows: First stage (PIPE_1): subtract the zeros from the two input data from each of the 16 channels to achieve dequantization from INT8 to the unsigned offset; if the input value is less than zero, it is truncated to 0 to prevent unsigned overflow. The second stage (PIPE_2): multiplies the dequantized values by their respective scaling factors, aligning and scaling the two data streams to a unified intermediate domain. The third stage (PIPE_3): adds the scaled values channel by channel, obtaining a 25-bit sum. The fourth stage (PIPE_4): multiplies the sum by the output scaling factor, completing the final weighting operation. The fifth stage (PIPE_5): extracts the high-order bits of the multiplication result and rounds them to 8 bits, while performing saturation processing.
The entire pipeline has a latency of 12 clock cycles, with 16 channels processing in full parallel. Each clock cycle can complete the element-wise addition of 128 bits (16 bytes) of data. The two sets of input data are loaded from DDR3 via DMA read channels, and the output results are written back to DDR3 via DMA write channels.
3.2.4. Design and Implementation of the Channel Concatenation Operator
The channel concatenation operator is used to concatenate two feature maps along the channel dimension. It is a core operation of the Feature Pyramid Network (FPN) and Path Aggregation Network (PAN) structures in YOLOv5 networks. In FPN/PAN, feature maps of different scales need to be concatenated along the channel dimension before subsequent convolutional processing to achieve multi-scale feature fusion.
The architecture of the cat module is similar to that of the add module, receiving two sets of input data, but their processing methods differ: the cat operator concatenates sequentially rather than adding simultaneously. The parameters received by the module include two sets of input addresses, output address, feature map spatial dimension, number of input channels, and quantization parameters.
The processing flow of the computational core cat_calc is highly similar to that of add_calc in the quantization recalibration stage, but the data organization method is different. cat_calc distinguishes whether the current input data comes from the first or second path using two valid signals. In the first-stage pipeline, the corresponding zero point is selected for subtraction based on the current data source; simultaneously, the scaling factor is dynamically switched according to the source. Because the two feature maps have different quantization parameters, the ‘cat’ operator recalibrates both data streams to the same quantization domain before concatenation, ensuring that the concatenated feature maps have consistent quantization parameters.
Subsequent scaling and saturation truncation processing is consistent with ‘add_calc’: first multiply by the scaling factor corresponding to the channel, then multiply by the output scaling factor, and finally extract the high-order bits and round them to 8 bits for output. The controller organizes data transmission in the order of reading all channels of the first channel first, and then all channels of the second channel, thus naturally achieving the channel-dimensional concatenation effect at the output. The entire pipeline has a latency of 11 clock cycles and processes 16 channels in parallel.
3.2.5. Design and Implementation of Spatial Pyramid Pooling—Fast (SPPF)
SPPF is a key module at the end of the YOLOv5 network backbone. Its function is to extract spatial features of different receptive field ranges through multi-scale max pooling operations and concatenate them to enhance the network’s ability to perceive targets at different scales. Compared to the original SPP module, which uses multiple pooling kernels of different sizes, SPPF achieves the same receptive field by concatenating three 5 × 5 max pooling operations, significantly reducing computational complexity while maintaining functional equivalence.
The sppf_top module includes a control module, input data management, a computational core, and an output buffer. Module interface parameters include source address, destination address, column–channel product, number of columns, number of rows, and number of channels. Both input and output data are 128 bits wide, corresponding to parallel processing of 16 INT8 channels.
The design of the computational core is the focus of this module. This module receives five sets of 128-bit input data, corresponding to five rows of data in the row direction of the sliding window. In the column direction, a five-stage shift register chain stores the data of the current column and the previous four columns, thus constructing a complete 5 × 5 receptive field. For each channel, the module performs a maximum value operation on 25 data points within the 5 × 5 window.
The maximum value calculation employs a two-stage comparison strategy to shorten the critical path. Level 1: In the 5 rows of data, each row undergoes 5 independent comparisons. The maximum value and its conditional encoding for each element are found by comparing it with the other 4 elements. Then, a case statement is used to select the maximum value for each row. Level 2: The maximum values of the 5 rows are then compared again using 5 comparisons to find the global maximum value within a 5 × 5 window. This two-level hierarchical comparison strategy decomposes the 25 comparisons into a 5 × 5 + 5 structure, effectively reducing the combinational logic depth and increasing the operating frequency. The entire pipeline latency is approximately 5–9 clock cycles, with 16 channels processed in full parallel.
3.2.6. Design and Implementation of the Upsample Operator
The upsample operator in the FPN/PAN structure of the YOLOv5 network is used to upscale low-resolution deep feature maps to the same spatial resolution as shallow feature maps for subsequent channel concatenation. This design employs nearest neighbor interpolation to achieve 2× upsampling, which involves copying each pixel of the input feature map twice in both the horizontal and vertical directions, ensuring that the width and height of the output feature map are twice that of the input.
The upsample module uses a three-sub-module architecture: an input control module reads input data from DDR3, an output control module writes the upsampled results back to DDR3, and two ping-pong buffer modules handle temporary data storage and 2× copying. Module interface parameters include the number of rows, number of channels, data length, and source/destination addresses.
The ping-pong double buffering mechanism is a key design feature of this operator. Two upsample_buf instances work alternately: while buf_ping is receiving a new row of input data, buf_pang is reading the previously stored data twice (achieving 2× copying in the vertical direction); after buf_ping has finished outputting its data, the two instances switch roles. Horizontally, each buffer sends each 128-bit data twice during output, achieving 2× copying in the horizontal direction. This ping-pong approach ensures complete pipelined processing between data loading and output, avoiding waiting delays. The output control module is also responsible for generating the ‘calc_end’ signal, indicating that upsampling processing of all rows is complete.
3.2.7. Design and Implementation of the Focus Slicing Operator
The Focus operator is the first layer in the YOLOv5 network, its function being to reconstruct the input image from spatial to channel dimensions. Specifically, Focus samples the input image at 2 × 2 grid intervals, generating four sub-images (corresponding to even rows and even columns, even rows and odd columns, odd rows and even columns, and odd rows and odd columns, respectively), and then concatenates them along the channel dimension. For a 640 × 640 × 3 RGB input image, the Focus operation yields a 320 × 320 × 12 feature map, halving the spatial resolution while increasing the number of channels by four times. This operation, without loss of information, transforms spatial redundancy into channel-dimensional feature richness, providing a denser input representation for subsequent convolutional layers.
As shown in
Figure 8, the input image data is 640 × 640 × 3, with each pixel data occupying 8 bits. The data interface of the module is uniformly 128-bit wide. The interlaced operation can be regarded as a 4 × 4 matrix. The entire image is repeatedly extracting pixels at the corresponding positions of this 4 × 4 matrix. If designed according to normal input, each repetition unit is 4 rows of pixels in 3 channels, corresponding to 3 × 4 × 8 = 96 bits, which does not match the 128-bit width of the input interface. Direct processing will lead to a cumbersome design process. To simplify the calculation, this paper adds a 0-pixel channel, resulting in a 4 × 4 × 8 = 128-bit input. This means each input corresponds to one of the four channels for four pixels. Taking the input data [23:0] and data [87:64] from the odd-numbered rows yields the data for the red pixels; data [55:32] and data [119:96] from the odd-numbered rows yields the data for the yellow pixels; data [23:0] and data [87:64] from the even-numbered rows yields the data for the blue pixels; and data [55:32] and data [119:96] from the even-numbered rows yields the data for the green pixels. By adding a channel filled with all zeros, the focus extraction for all corresponding pixels can be easily completed.
The architecture of the focus module follows the general architecture design presented in this paper, also employing a three-module architecture: input control, output control, and ping-pong buffer (buf_ping/pang). The ping-pong caching mechanism is similar to upsampling but functions in reverse: during data writing, ‘focus_buf’ interleaves the data of consecutive rows according to a 2 × 2 grid sampling pattern—routing even-numbered rows to the ping and pang caches; during data reading, each cache separates and reassembles the stored data according to even and odd columns, and finally outputs the concatenated data along the channel dimension. The input controller reads the raw image data from DDR3 line by line, and the output controller writes the results back to DDR3 according to the reassembled row order and channel arrangement. The entire process is purely data transfer, without any arithmetic operations, so the computational complexity of the Focus operator is extremely low, and its main overhead lies in the data transfer bandwidth of DDR3.