Skip to main content
The Vivado backend targets the discontinued Vivado HLS compiler. For new designs, consider using the Vitis backend instead.

Overview

The Vivado backend enables deployment of neural networks on AMD/Xilinx FPGAs using the Vivado HLS compiler. It generates High-Level Synthesis (HLS) IP cores that can be integrated into Vivado designs.

When to Use Vivado Backend

  • Working with legacy projects using Vivado HLS
  • Targeting older AMD/Xilinx FPGA development flows
  • Maintaining existing Vivado HLS-based designs
New hls4ml developments may not be backported to the Vivado backend. Consider migrating to Vitis for access to latest features.

Installation and Setup

Prerequisites

  • Vivado HLS installation (ensure vivado_hls is on PATH)
  • AMD/Xilinx FPGA development tools
  • Python 3.8 or higher
  • hls4ml library installed

Environment Setup

# Verify Vivado HLS is available
command -v vivado_hls

# Source Vivado settings (adjust path for your installation)
source /tools/Xilinx/Vivado/<version>/settings64.sh

Configuration

Basic Configuration

Create a model configuration for the Vivado backend:
import hls4ml

config = hls4ml.utils.config_from_keras_model(
    model, 
    granularity='name',
    backend='Vivado'
)

# Convert model
hls_model = hls4ml.converters.convert_from_keras_model(
    model,
    hls_config=config,
    output_dir='my_vivado_project',
    part='xcvu13p-flga2577-2-e',
    clock_period=5,
    io_type='io_parallel'
)

Configuration Options

The Vivado backend supports the following configuration parameters:
part
string
default:"xcvu13p-flga2577-2-e"
FPGA part number to target
clock_period
int
default:"5"
Clock period in nanoseconds
clock_uncertainty
string
default:"12.5%"
Clock uncertainty percentage for timing analysis
io_type
string
default:"io_parallel"
I/O implementation type:
  • io_parallel: Processes all inputs/outputs simultaneously
  • io_stream: Streams data through the design
namespace
string
default:"None"
Optional C++ namespace for generated code
write_weights_txt
bool
default:"true"
Write weights to .txt files for faster compilation
write_tar
bool
default:"false"
Compress output directory into .tar.gz file

Layer-Specific Configuration

Strategy Selection

Vivado backend supports multiple implementation strategies:
config['Model']['Strategy'] = 'Resource'  # or 'Latency'

# Per-layer configuration
config['LayerName']['ReuseFactor'] = 16
config['LayerName']['Strategy'] = 'Resource'
Available Strategies:
  • Latency: Fully unrolled implementation (low latency, high resource usage)
  • Resource: Serialized implementation with configurable reuse factor
  • Resource_Unrolled: Combination of resource sharing with partial unrolling
  • Distributed_Arithmetic: Uses lookup tables for dense layers (must have ReuseFactor=1)

Convolution Layers

# Conv2D configuration
config['conv2d_layer']['ConvImplementation'] = 'LineBuffer'  # or 'Encoded'
config['conv2d_layer']['ParallelizationFactor'] = 4
config['conv2d_layer']['ReuseFactor'] = 8

RNN Layers

# LSTM/GRU configuration
config['lstm_layer']['ReuseFactor'] = 1
config['lstm_layer']['RecurrentReuseFactor'] = 1
config['lstm_layer']['static'] = True  # Static vs dynamic implementation
config['lstm_layer']['table_size'] = 1024

Build Process

Synthesis Commands

# Compile and synthesize the model
hls_model.compile()

# Build with various options
report = hls_model.build(
    reset=False,      # Reset project before build
    csim=True,        # Run C simulation
    synth=True,       # Run HLS synthesis
    cosim=False,      # Run co-simulation
    validation=False, # Run validation
    export=False,     # Export IP
    vsynth=False      # Run Vivado synthesis
)

Build Options

OptionDescriptionDefault
resetReset project before buildingFalse
csimRun C simulation testbenchTrue
synthRun HLS synthesisTrue
cosimRun RTL co-simulationFalse
validationRun validation testsFalse
exportExport as IP for VivadoFalse
vsynthRun Vivado synthesisFalse
fifo_optOptimize FIFO depthsFalse

TCL Script Execution

The build process generates and executes a build_prj.tcl script:
cd my_vivado_project
vivado_hls -f build_prj.tcl "csim=1 synth=1 cosim=0"

Example Project Structure

After conversion, the project structure looks like:
my_vivado_project/
├── firmware/
│   ├── myproject.cpp          # Top-level HLS implementation
│   ├── myproject.h            # Header file
│   ├── parameters.h           # Network parameters
│   ├── weights/               # Weight data files
│   └── nnet_utils/            # HLS utility functions
├── tb_data/
│   ├── tb_input_features.dat  # Test input data
│   └── tb_output_predictions.dat  # Expected outputs
├── myproject_test.cpp         # C++ testbench
├── build_prj.tcl              # Vivado HLS build script
└── myproject_prj/             # HLS project (after build)
    ├── solution1/
    │   ├── syn/
    │   │   └── report/        # Synthesis reports
    │   └── impl/              # Implementation results
    └── vivado_hls.log

Performance Optimization

Reuse Factor Tuning

The reuse factor controls resource/latency tradeoff:
# Lower reuse factor = more parallel, higher resources
config['dense_1']['ReuseFactor'] = 1  # Fully parallel

# Higher reuse factor = more serial, lower resources
config['dense_1']['ReuseFactor'] = 64  # Highly serialized

Precision Configuration

from hls4ml.model.types import FixedPrecisionType

# Set precision for layer outputs
config['dense_1']['Precision'] = 'ap_fixed<16,6>'

# Set accumulator precision
config['dense_1']['accum_t'] = FixedPrecisionType(24, 12)

Pipeline Optimization

For streaming designs:
config['Model']['IOType'] = 'io_stream'
config['Model']['Strategy'] = 'Latency'

# Optimize FIFO depths
report = hls_model.build(fifo_opt=True)

Performance Characteristics

Resource Usage

  • LUTs: Depends on precision, strategy, and reuse factor
  • DSPs: Used for multiplications (resource strategy shares DSPs)
  • BRAM: Stores weights and intermediate data
  • FFs: Flip-flops for pipelining

Latency Considerations

io_parallel:
  • Latency = Sum of layer latencies
  • Initiation interval (II) = Total latency for pipelined designs
io_stream:
  • Pipelined dataflow between layers
  • Throughput limited by slowest layer
  • Lower latency for streaming applications

Clock Frequency

Typical achievable frequencies:
  • Conservative: 100-150 MHz (clock_period=10-6.67ns)
  • Moderate: 150-200 MHz (clock_period=6.67-5ns)
  • Aggressive: 200-250 MHz (clock_period=5-4ns)

Advanced Features

Distributed Arithmetic

For dense layers, enable distributed arithmetic implementation:
config['dense_1']['Strategy'] = 'Distributed_Arithmetic'
config['dense_1']['ReuseFactor'] = 1  # Required

Quantization-Aware Training

Integrate with QKeras for quantization:
from qkeras import QDense, quantized_bits

# Create quantized model
model = Sequential([
    QDense(64, kernel_quantizer=quantized_bits(8,0,alpha=1)),
    # ...
])

# Convert to hls4ml
hls_model = hls4ml.converters.convert_from_keras_model(model)

Custom Layers

Implement custom layer templates:
from hls4ml.model.layers import Layer
from hls4ml.model.optimizer import layer_optimizer

@layer_optimizer(CustomLayer)
def init_custom_layer(self, layer):
    # Configure custom layer
    layer.set_attr('custom_param', value)

Troubleshooting

Ensure vivado_hls is in your PATH:
export PATH=/tools/Xilinx/Vivado/<version>/bin:$PATH
Or source the settings script:
source /tools/Xilinx/Vivado/<version>/settings64.sh
  • Increase clock period
  • Increase reuse factors
  • Reduce precision
  • Enable pipelining pragmas
  • Use lower clock uncertainty
  • Increase reuse factors
  • Use Resource strategy instead of Latency
  • Reduce precision
  • Enable weight compression
  • Use io_stream for large models
  • Check that all layer types are supported
  • Verify precision specifications are valid
  • Ensure weight dimensions match layer configuration
  • Check for unsupported activation functions

Migration to Vitis

To migrate from Vivado to Vitis backend:
# Change backend specification
hls_model = hls4ml.converters.convert_from_keras_model(
    model,
    hls_config=config,
    backend='Vitis',  # Changed from 'Vivado'
    output_dir='my_vitis_project'
)
Most configurations are compatible, but review Vitis-specific validation passes and adjust as needed.

Vitis Backend

Modern alternative using Vitis HLS

Configuration Guide

Detailed configuration options

Optimization Tips

Performance tuning strategies

API Reference

Python API documentation

Build docs developers (and LLMs) love