3.6.6 SmartHLS Migration Guide

Learn how existing Vitis HLS / Vivado HLS designs can be easily migrated to SmartHLS.

3.6.6.1 SmartHLS Migration Guide

This section describes how existing Vitis HLS / Vivado HLS designs can be easily migrated to SmartHLS. When migrating an existing C++ design from Vitis HLS / Vivado HLS, the pragmas and libraries used in the source code should be changed to the equivalent ones in SmartHLS. Changes to the C++ source code may also be necessary.

3.6.6.2 General Porting

Vitis HLS / Vivado HLSSmartHLS
set_top <FUNC> (in synthesis Tcl file)On the first line of <FUNC> , add #pragma HLS function top
#include <ap_int.h>

#include <hls/ap_int.hpp>

using hls::ap_uint;

using hls::ap_int;

#include <ap_fixed.h>
#include <hls/ap_fixpt.hpp>
using hls::ap_fixpt;
using hls::ap_ufixpt;
#define ap_fixed  ap_fixpt
#define ap_ufixed ap_ufixpt
#include <hls_stream.h>

#include <hls/streaming.hpp>

#define stream FIFO

hls::stream constructor

Vitis/Vivado HLS’s stream constructor optionally takes a string name as argument, while SmartHLS’s FIFO constructor optionally takes depth and type.

  • Remove the FIFO name argument from constructor call if it exists.
  • Vitis/Vivado HLS’s stream has infinite depth in software simulation, that means stream's capacity will grow dynamically at simulation time. In SmartHLS, capacity of a FIFO has to be statically given for both hardware synthesis and simulation. Due to the nature of the simulation engine, capacity of a SmartHLS's FIFO may need to be much bigger in software simulation than what's actually needed in hardware implementation. Users can determine the FIFO's depth for simulation based on the application code and testbench.
Example of External FIFO Porting
Vitis/Vivado HLS
hls::stream<int> data;
SmartHLS
#define SIM_FIFO_DEPTH 1e4
hls::stream<int> data(SIM_FIFO_DEPTH);
Example of Internal FIFO porting
Vitis/Vivado HLS
hls::stream<int> data;
#pragma HLS stream variable = data depth = 2
SmartHLS
#define SIM_FIFO_DEPTH 1e4
#ifndef __SYNTHESIS__
hls::stream<int> data(SIM_FIFO_DEPTH);
#else
hls::stream<int> data(2);
#endif
<AP_INT_VAR>.to_int()<AP_INT_VAR>.to_uint64(), or

<AP_INT_VAR>.to_int64()

Vitis/Vivado HLS's ap_int has a rich list of C-type conversion functions (e.g. to_short(), to_int(), to_long()). Since SmartHLS currently only has to_uint64() and to_int64() available, users may need to add extra explicit casting to fit their needs.

<AP_INT_VAR>.range(7,0).to_int()

(ap_uint<...><AP_INT_VAR>.range(7,0)).to_int64()

In SmartHLS, the return value of <AP_INT_VAR>.range() cannot be used to directly invoke to_int64()/to_uint64().

stringstream >> ap_fixpt<W, IW, Q_M, O_M>
std::stringstream istr(line)
ap_fixpt<W, IW, Q_M, O_M> = args;
double args_temp;
istr >> args_temp;
args = args_temp;
#include <assert.h>
#ifdef __SYNTHESIS__
#define NDEBUG
#endif
#include <assert.h>

3.6.6.3 Pragmas

Vitis HLS / Vivado HLSSmartHLS
aggregate, data_packSee the Struct Variable/Argument Packing pragmas.
allocation

A global constraint of operation resources can be set via set_resource_constraint; constraining the operation resource within a function, a loop or a block of code is not yet available.

Functions that are not inlined (automatically by SmartHLS tool or specified via the Inline Function pragma) always have a single RTL module instance in hardware, and it is shared by all callers. Replication of a function instance in hardware can be achieved by the Replicate Function and Inline Function pragmas. In the case of multi-threading, each thread of a function creates an instance of the corresponding RTL module.

array_partition
Porting for a globally or locally declared variable
Vitis/Vivado HLS
#pragma HLS array_partition variable=<VAR> <TYPE> dim=<DIM>
SmartHLS
Move the pragma to right before the <VAR>variable declaration, and transform it to this form:
#pragma HLS memory partition variable(<VAR>) type(<TYPE>) dim(<DIM>)
For more information, see the Partition Memory pragma.
Porting for a top-level function argument
Vitis/Vivado HLS
#pragma HLS array_partition variable=<VAR> <TYPE> dim=<DIM>
SmartHLS
Move the pragma to the beginning of the function body, and transform it to this form:
#pragma HLS memory partition argument(<VAR>) type(<TYPE>) dim(<DIM>)
For more information, see the Partition Top-Level Interface pragma.
Porting complete memory partitioning in multiple but not all dimensions in an array
SmartHLS supports complete memory partitioning in either 1 or all dimensions, while Vitis/Vivado HLS can apply complete memory partitioning in more than 1 discrete dimensions. To port such case, users may need to reshape the array. Below is an example.
Vitis/Vivado HLS
ap_uint<12>    buffer[DIM_X][DIM_Y][DIM_Z];
#pragma HLS_ARRAY_PARTITION variable=buffer complete dim=1
#pragma HLS_ARRAY_PARTITION variable=buffer complete dim=2

// Access macro of 'buffer'
#define BUFFER(x,y,z)  (buffer[x][y][z])
SmartHLS
#pragma HLS memory partition variable(buffer) type(complete) dim(1)
ap_uint<12>    buffer[DIM_X*DIM_Y][DIM_Z];

// Access macro of 'buffer'
#define BUFFER(x,y,z)  (buffer[(x)*DIM_Y+(y)][z])
dataflowData Flow Parallelism and Multi-threading can be used to implement a task-level (dataflow) pipeline.
dependenceSee the Loop Dependency pragma.

If inside a loop, the pragma should be moved outside the loop.

disaggregateSee the struct_fields option of the Partition Top-Level Interface pragma.
expression_balanceSee LATENCY_REDUCTION Tcl settings to control the expression balance optimization.
function_instantiateThe equivalent optimization can be achieved with the Inline Function pragma or C++ template functions.
inlineSee the Inline Function pragma.
Vitis/Vivado HLS
#pragma HLS inline
SmartHLS
#pragma HLS function inline
inline offSee the Noinline Function pragma.
Vitis/Vivado HLS
#pragma HLS inline off
SmartHLS
#pragma HLS function noinline
interfaceSee Top-Level RTL Interface for details about supported interfaces and corresponding pragmas.
loop_tripcount
See the Bound Loop pragma.
Vitis/Vivado HLS
#pragma HLS loop_tripcount min=<MIN> max=<MAX> avg=<AVG>
SmartHLS
Move the pragma to the outside of the loop and transform it to the following form. Ignore avg=<AVG>.
#pragma HLS loop bounds lower(<MIN>) upper(<MAX>)
pipeline, pipeline II=<II>

See Pipeline Function and Pipeline Loop pragmas.

If inside a loop, the pragma should be lifted outside the loop.

If inside a function, add the pragma to the beginning of the function definition block.
Pipeline pragma without II
Vitis/Vivado HLS
#pragma HLS pipeline
SmartHLS
#pragma HLS loop pipeline                // Inside a loop, lift it outside the loop
#pragma HLS function pipeline            // Inside a function
Pipeline pragma with II
Vitis/Vivado HLS
#pragma HLS pipeline II=<II>
SmartHLS
#pragma HLS loop pipeline II(<II>)      // Inside a loop, lift it outside the loop
#pragma HLS function pipeline II(<II>)  // Inside a function
pipeline offRemove since pipelining is not applied by default.
stableSee the stable option of the Scalar Argument Interface pragma.
streamStreaming interface is implemented via the hls::FIFO Argument.
topSee the Set Top-Level Function pragma.
unrollSee the Unroll Loop pragma, and lift it outside the loop.

The SmartHLS tool currently does not support the following Vitis/Vivado HLS pragmas:

  • array_map
  • array_reshape
  • bind_op
  • bind_storage
  • disaggregate
  • latency
  • loop_flatten
  • loop_merge
  • occurrence
  • protocol
  • reset
  • shared

3.6.6.4 Libraries

Arbitrary Precision Data Types
Similar to Vitis/Vivado HLS, SmartHLS provides C++ Arbitrary Precision Integer Library and C++ Arbitrary Precision Fixed Point Library. Like Vitis/Vivado HLS, conversion between primitive array data type pointers and the equivalent ap_int/ap_uint array pointers through simple pointer casting is supported in SmartHLS.

For example, the following SmartHLS code is valid and safe in both hardware synthesis and software simulation.

#include <stdint.h>
#include <hls/ap_int.hpp>
using hls::ap_uint;
 
uint8_t d_u8[8];
ap_uint<8>  *p_u8  = (ap_uint<8> *)d_u8;
 
uint16_t d_u16[8];
ap_uint<16> *p_u16 = (ap_uint<16> *)d_u16;
 
uint32_t d_u32[8];
ap_uint<32> *p_u32 = (ap_uint<32> *)d_u32;
 
uint64_t d_u64[8];
ap_uint<64> *p_u64 = (ap_uint<64> *)d_u64;
Streaming Library
Similar to the hls::stream template class in Vitis/Vivado HLS, SmartHLS provides a hls::FIFO template class in the Streaming Library.
Math Library
While SmartHLS supports a subset of functions in the Math Library (math.h), SmartHLS also has a Fixed Point Math Library that is optimized for hardware implementation with customizable arbitrary precisions. This library is in active development.
Vision Library
Like Vitis/Vivado HLS, SmartHLS has a vision library designed to simplify the development of video processing solutions on Microchip FPGA devices. The library provides pre-optimized HLS C++ library functions for fast algorithm prototyping of video applications. Using this library, OpenCV-based designs can be ported onto FPGAs with a faster time to market.
Other Libraries
Other libraries such as FFT, FIR, DDS, and SRL libraries are not yet supported by SmartHLS. We are actively developing libraries, such as the computer vision IPs. If you are interested in having support of certain IPs, please email us at SmartHLS@microchip.com. Your feedback is valuable to us and will help to prioritize our production plan.