Topic hub

High-level synthesis

What high-level synthesis tools such as Vitis HLS, Altera HLS, oneAPI, Bambu and Dynamatic do with C and C++, how pragmas shape the hardware, and where HLS wins or loses.

Updated 13 Nov 2026 · HLS, Vitis HLS, oneAPI, initiation interval, pipelining, dataflow, pragmas, Bambu

Overview

High-level synthesis (HLS) compiles a function written in C, C++ or SYCL into register-transfer level hardware. The tool decides which operations happen in which clock cycle (scheduling), which physical units carry them out (binding) and how arrays map to memories. You steer it with pragmas and with the shape of the code. This hub is for engineers who have heard that HLS lets software people build FPGAs and want to know how much of that is true.

The honest answer is that HLS moves the work rather than removing it. You stop writing state machines and pipelines by hand, and you start reasoning about loop trip counts, memory ports and initiation intervals. For dataflow-heavy kernels such as filters, matrix operations, image pipelines and packet processing, that trade is often a good one. For control-dominated logic, bit-level protocols and anything that must hit a precise cycle budget, hand-written RTL still wins.

Key ideas

Scheduling, binding and the initiation interval

A loop in C is sequential. In hardware, the HLS tool unrolls it, pipelines it, or both. Pipelining a loop means starting a new iteration before the previous one finishes, and the number of cycles between starts is the initiation interval (II). An II of 1 means one iteration per clock, which is what you want for a streaming filter. The tool fails to reach II=1 when an iteration depends on the previous one (a loop-carried dependency), when two iterations fight over a single memory port, or when a floating-point operation cannot be pipelined fast enough. Reading the schedule report and understanding why the II slipped is most of the daily work.

Binding decides how many multipliers, adders and memories to instantiate. Unrolling a loop by eight creates eight copies of its body and eight times the demand for memory ports. Partitioning an array across several block RAMs supplies those ports. These two pragmas, unroll and array partition, account for most of the area and throughput control an HLS user has.

C or C++kernel + pragmasC testbenchgolden vectorsHLS compilerschedule, bindallocate memoriesC simulationseconds, no timingRTLVerilog or VHDLCo-simulationRTL vs C resultsVivado orQuartussame testbenchreports: II, latency, area, then edit pragmas
An HLS flow. C simulation and co-simulation check the same source at two levels before the RTL enters the normal implementation flow.

Interfaces and dataflow

The function’s arguments become hardware ports. A pointer argument can become an AXI master that reads from DDR, an AXI-Stream port fed by another kernel, or a block RAM interface. Choosing the interface pragma is choosing the system architecture. The dataflow pragma takes several functions in sequence and turns them into concurrent blocks joined by FIFOs, so that a producer and consumer overlap. This is how image pipelines and network functions reach full throughput. The rule that each intermediate buffer has one producer and one consumer is strict, and violating it is the most common dataflow error.

Which tool

AMD Vitis HLS is the most widely used. It accepts C++ with arbitrary-precision types and emits RTL packaged as Vivado IP, and it is the engine behind Vitis acceleration kernels. Altera’s path has been through the Intel HLS Compiler and, more recently, oneAPI with SYCL for FPGA, which at the time of writing is being re-homed under the Altera name after the spin-out. Bambu, from Politecnico di Milano, is an open-source HLS tool that targets any vendor through emitted Verilog and is useful for research and for devices without a vendor HLS. Dynamatic, from EPFL, synthesises dynamically scheduled circuits in which handshakes replace a fixed schedule, which helps irregular loops that static HLS handles badly. Microchip’s SmartHLS targets PolarFire. Siemens Catapult and Cadence Stratus serve ASIC teams and are rarely seen in FPGA projects.

Where to start

HLS makes more sense once you have written and debugged RTL by hand, so start with:

An intermediate lesson building a streaming FIR filter in Vitis HLS and comparing it against hand RTL is coming.

Tools and vendors

Tool Input Target Licence Notes
Vitis HLS C, C++ AMD devices Free with Vivado Mature, large pragma set, good reports
Altera HLS Compiler and oneAPI C++, SYCL Altera devices Free tiers available oneAPI covers both kernels and host code
SmartHLS C, C++ Microchip PolarFire Free with Libero Based on LegUp
Bambu (PandA) C, C++ Any, via Verilog Open source Research-grade, actively maintained
Dynamatic C, C++ Any, via VHDL Open source Dynamic scheduling, handshake circuits
Catapult, Stratus C++, SystemC ASIC and FPGA Commercial Mostly ASIC teams

See /vendors/amd/ and /vendors/altera/ for installation notes.

Common mistakes

  • Treating HLS as a C compiler and expecting unmodified software to perform. Pointers, recursion, dynamic allocation and system calls are not hardware.
  • Reading only the estimated clock in the HLS report. The real number comes from place and route.
  • Unrolling loops without partitioning the arrays they read, which leaves the tool starved for memory ports.
  • Using floating point where fixed point would do, and paying for it in area and II.
  • Ignoring the interface pragma and accepting the default, then wondering why the block has a 32-bit memory-mapped port instead of a stream.
  • Skipping co-simulation. C simulation proves the algorithm, not the hardware.

Going deeper

Recent papers

  • A State Augmented Approach to Paralle Modeling in High-Level Synthesis

    N. Kovacs, H. Zheng · arXiv cs.AR · digest

    HLS can only schedule the concurrency its input makes legal, and a plain sequential C++ model of a feedback-coupled design such as a processor hides the state boundaries the tool needs. The authors model the design as synchronous sequential processes that start together and synchronise on completion, keeping persistent state and feedback explicit in C++ while HLS schedules the operations inside each process. A five-stage RV32I core written this way reaches 1.221 cycles per instruction at 220 MHz on a Kintex UltraScale+, against 4.000 for a naive HLS version and 1.575 at 242 MHz for the hand-written Ibex core. An area-tuned variant cuts LUTs by 65 per cent at the cost of 9.7 per cent more cycles. The result depends on the designer taking back control of architecture, which is the opposite of what HLS marketing promises.