FONT SIZE : AAA
Introducing Vivado HLS
In this section, we will start by defining what Vivado HLS does and the steps involved, before considering its role in the design flow for Zynq. Later, Chapter 15 will cover use of the tool on a practical level, along with further discussions of algorithm and interface synthesis, and the processes involved in creating solutions and evaluating them.
What Does Vivado HLS Do?
In short, Vivado HLS transforms a C, C++ or SystemC design into an RTL implementation, which can then be synthesised and implemented onto the programmable logic of a Xilinx FPGA or Zynq device [33]. This represents the high-level synthesis step depicted in Figure 14.2 on page 258.
It is important to reiterate that all C-based designs in the context of HLS are for imple mentation in programmable logic; i.e. as distinct from software code intended to run on a processor (whether Zynq’s ARM processor, or a soft processor such as MicroBlaze).
In performing HLS, the two primary aspects of the design are analysed:
• The interface of the design, i.e. its top-level connections, and
• The functionality of the design, i.e. the algorithm(s) that it implements.
In Vivado HLS design, the functionality is synthesised from the input code via the process of Algorithm Synthesis. The interface is created using one of two alternatives: it can either be (i) manually specified, or (ii) inferred from the code (Interface Synthesis). A simple conceptual diagram is provided in Figure 14.4 (note that this depicts only a subset of interface types).
In the specific case of the SystemC input language, interfaces must be manually specified, with two exceptions which will be mentioned later [33]

Algorithm Synthesis
Algorithm Synthesis is concerned with the functionality of the design. The desired behaviour is interpreted from the C, C++, or SystemC code that forms the input to the process (the input to the HLS process is a function written in the chosen programming language). Operations are inferred, and these are translated into a set of RTL statements, which are usually executed over several clock cycles.
As will be discussed later, the designer can exert control over the algorithm synthesis process via Vivado HLS directives, resulting in variations on the RTL output from HLS being produced. For example, Solution 1 might require 500 slices to implement and 20 clock cycles to execute, whereas Solution 2 might require 1200 slices and 10 clock cycles. The designer is able to experiment and thus achieve a favourable result in terms of their priority implementation metric(s).
Interfaces I: Interface Synthesis
As its name suggests, Interface Synthesis refers to the interface of the HLS design, and this includes both the ports and the protocols used. The details of all ports (in terms of their types, dimensions, and directions) are inferred from the top-level function arguments and return values of the source C/C++ file; protocols are inferred from the behaviour of the ports. For example, the simplest interface would be a simple 1-bit wire, while for more complex interfaces, a bus or RAM interface may be used. Naturally the synthesised interface facilitates communicate with other modules in the system.
Interfaces that can be inferred from interface synthesis include: wires, registers, one-way and two-way handshakes, FIFOs, memories, and buses [33]. Further options are available relating to interface synthesis, specifically to permit ports to be inferred from global variables, and to include a global clock enable. Interface synthesis will be discussed in detail in Chapter 15.
Interfaces II: Manual Specification
Although C and C++ designs are fully supported for interface synthesis, SystemC designs are not, and as such, the interfaces of SystemC designs must be manually specified and their behaviour fully described. This corresponds with the hardware-specific features of the SystemC language, and an example will be provided in Chapter 15 which illustrates the similarity between SystemC-based interface specification, and the equivalent in VHDL.
Notably there are two exceptions to the general rule stated above: memory and bus interface types can both be inferred by interface synthesis of SystemC code.
Manual interface specification is also supported for C and C++ designs and may be used if desired; this means that there is the option to explicitly define interfaces, rather than have the interface synthesis process infer them.
Vivado HLS Design Flow
In the previous section, our discussion was limited to the primary processes and outputs, i.e. the execution of HLS algorithms and the production of RTL code. However, the full design flow for HLS comprises further stages, including elements of verification in particular. The full design flow is shown in Figure 14.5, and then summarised.

Inputs to the HLS Process
The primary input to the HLS process is a C/C++/SystemC function, along with a Cbased testbench which has been developed to exercise the function and verify correct operation. This will involve a ‘golden reference’ against which to test the outputs produced by the function intended for synthesis; the golden reference may take the form of a prepared set of output values, or it may form part of the testbench itself.
Functional Verification
Firstly, it is necessary to verify the functional integrity of the C/C++/SystemC code that forms the input to HLS, before beginning the process of synthesising it into RTL code. This can be achieved by writing a testbench in the same high-level language, and checking the results produced against some form of ‘golden reference’; for instance, this might be a prepared set of output test vectors which are known to be correct.
High-Level Synthesis
The next step is to undertake the HLS process itself, which involves analysis and processing of the C-based code, together with user-supplied directives and constraints, to create an RTL description of the circuit. Once the HLS process is complete, a set of output files is produced, including design files in the desired RTL language. Various other log and report files, testbenches, scripts, etc. are also created.
C/RTL Cosimulation
Once HLS has been performed and the equivalent RTL model produced, it can be checked against the original C/C++/SystemC code via the process of C/RTL cosimulation in Vivado HLS. This process re-uses the original, C-based testbench to supply inputs to the RTL version generated by HLS, and check the outputs it produces against expected values. Importantly, this saves the effort of generating a new RTL testbench. The SystemC output is particularly useful here, as it provides a mechanism for verifying the design in environments where an HDL simulator is not available. A good example covering both C functional verification and C/RTL cosimulation is available in [32].
Evaluation of Implementation
Along with verifying the integrity of the design, it is also necessary to evaluate the RTL output in terms of its implementation and performance. For example, the numbers of resources it requires in the PL, the latency of the design, maximum supported clock frequency, and so on. We will outline these metrics in Section 14.4.4, and discuss them in
further detail in Chapter 15. For now, it is sufficient to note that, as the designer, we can influence the implementation via the constraints and directives applied to the HLS process.
Design Iterations
Noting the above, as part of the design flow, the implementation of the RTL is evaluated and, as necessary, the constraints and directives are refined; each revision corresponds to a new ‘solution’ in Vivado HLS terminology (more to follow on solutions in Section 14.4.6). It is also possible that evaluation of the design will prompt more fundamental review and refinement of the original algorithm, as designed in C code and input to the HLS process. Figure 14.5 shows the steps undertaken from C design, to the creation of outputs for RTL synthesis. Note that multiple HLS iterations may be undertaken using modified directives and constraints, in order to find a ‘best’ solution; this corresponds to the feedback path shown on the right hand side of the diagram. Should the designer be prompted to change the input C code, a more significant step backwards in the design process is involved, and this is indicated by the arrow at the left hand side of the diagram. Any changes to the C code require functional re-verification, before the subsequent HLS, C/RTL verification, and implementation evaluation processes are again performed and iterated as needed.
RTL Export
Once the design has been validated, and the implementation iterated to the point of achieving the intended design goals, it will be intended for integration into a larger system. This can be achieved directly using the RTL files automatically created by the HLS process (i.e. VHDL or Verilog code), however it may be more convenient to use the facilities of Vivado HLS for packaging IP. Packaging the outputs produced by Vivado HLS means that HLS designs can be easily introduced into other Xilinx tools, namely IP Integrator within Vivado IDE, XPS (for the ISE design flow), and System Generator.
SystemC outputs from the HLS process are produced to enable verification of the hardware produced, but are not themselves synthesisable.
C Functional Verification and C/RTL Cosimulation
Given the importance of verification, it is useful to further detail the C functional verification and C/RTL cosimulation processes. These are described graphically in Figure 14.6.
Depicted on the left hand side, a C-based testbench has been designed to create and supply input test vectors to the functional C module. The same test vectors are passed
through a ‘known good’ golden reference design, or alternatively read from a prepared file, to give golden reference output test vectors. These are compared with the outputs from the C module, and the testbench reports a pass if the two set of results match, or failure otherwise. The testbench may also be designed to report the total number of errors, or to provide other automated feedback on the results.
As part of the Vivado HLS C/RTL cosimulation process, an equivalent testbench configuration is automatically created by Vivado HLS (shown on the right of Figure 14.6). The testbench verifies the RTL version of the original C module, i.e. the primary output of HLS, against the golden reference, and reports success or failure as before.

All of the files required for C/RTL cosimulation are created automatically by Vivado HLS, which removes the need for manual RTL testbench creation. The generated testbench includes the necessary translations of data passing between the C-based testbench and the RTL module being tested.
Vivado HLS is also capable of creating a bit-true, cycle accurate System-C model of the generated hardware, and this can be co-simulated in circumstances where an RTL simulation is not available.
Verification is clearly an important aspect of the design process, and the availability of this tool support for RTL-level testing enables increased productivity. In particular, the designer does not need to spend time creating an equivalent testbench for RTL simulation, and the potential for introducing errors by doing so are eliminated. However, it is important to note that RTL simulation is a functional simulation, which does not model realistic timing or bus protocol behaviours. Therefore, it cannot completely verify the correct operation of the module in non-ideal conditions.
Implementation Metrics and Considerations
At this stage, it is useful to define the implementation metrics and related considerations which form part of the design process. We do so here in a simple and informal style; these issues will be returned to and expanded upon later, in Chapter 15.
• Resources / area — How many resources are needed to implement my design, and how does this compare to the amount available on my target FPGA / Zynq device?
• Throughput — At what rate can I pass data through the design? Does this meet the
needs of my application?
• Clock frequency — What is the maximum clock frequency that I can run my design at? Is this compatible with the rest of my system?
• Latency — How many clock cycles does it take for my design to produce an output? Is this delay acceptable in the context of the system in general?
• Power consumption — How much power does my design consume when it is operating? Is this part of a system sensitive to power consumption?
• I/O requirements — How complex are the interfaces of my design? Are they compatible with other components of the system?
Any or all of the above factors may be constrained in some way, often with certain factors being prioritised over others. This normally depends on the requirements of the application. For example, a system targeted at a low cost application might prioritise resource minimisation, in order to utilise a smaller device; whereas, on the other hand, a system requiring to adapt quickly to changing inputs may seek to minimise latency and maximise throughput, at the expense of greater resource utilisation.
Any or all of the above factors may be constrained in some way, often with certain factors being prioritised over others. This normally depends on the requirements of the application. For example, a system targeted at a low cost application might prioritise resource minimisation, in order to utilise a smaller device; whereas, on the other hand, a system requiring to adapt quickly to changing inputs may seek to minimise latency and maximise throughput, at the expense of greater resource utilisation.
Overview of the High-Level Synthesis Process
Although we have discussed the design flow in general terms, it is useful to consider the process of HLS is more detail. This section will therefore summarise the steps involved in the HLS of C/C++/SystemC design files to achieve an RTL equivalent. For the purpose of providing practical examples, C will be used as the design language.
Recall from Section 14.4.1 that the HLS process performs (i) algorithm synthesis and (ii) interface synthesis (if the interface is not explicitly specified). Here we focus on the former.
Aside from the design files themselves, other inputs to this process are the specification of a particular target device, and the directives and constraints supplied by the designer. As will be discussed in Section 14.4.6, these directly influence the implementation produced by HLS. For the purposes of our current review, we will consider that the target device is fixed, and the constraints and directives applied are constant.
Algorithm synthesis comprises three primary stages, which occur in the following order:
1. Extraction of data path and control;
2. Scheduling and binding; and
3. Optimisations
Each of these will now be briefly explained in turn.
Extraction of Datapath and Control
The first stage of HLS is to analyse the C/C++/SystemC code and interpret the required functionality. This may, for instance, include: logical and arithmetic operations; conditional statements and branching; array operations; and loops.
The implementation will have a datapath component, and normally there will also be a control component. For clarification, here ‘datapath’ processing refers to operations performed on the data samples, whereas ‘control’ is the circuitry required to co-ordinate dataflow processing. The nature of the algorithm fundamentally defines both the datapath and control components but, as we will see in Chapter 15, the designer can take steps during HLS to minimise the complexity of the control component in particular.
Scheduling and Binding
HLS is comprised of two main processes: scheduling and binding. These are undertaken on an iterative basis, as shown in Figure 14.7, as one affects the other. The operations performed in the two processes are summarised below.
• Scheduling is the translation of the RTL statements interpreted from the C code into a set of operations, each with an associated duration in terms of clock cycles. The decisions made at this stage are affected by the clock frequency and uncertainty, the target device technology, and any directives applied by the user.
• Binding is the process of associating the scheduled operations with the physical resources of the target device. The functional and timing characteristics of these resources may affect scheduling, and therefore binding information is fed back into the scheduling process. For instance, the use of DSP48x resources implies a shorter critical path than an equivalent operator built from logic slices.For example, if the synthesised algorithm requires that a set of arithmetic operations are performed, the HLS process must decide how to schedule the operations (how many clock

cycles to allocate to their completion), and how to bind the operations (i.e. how to map them to the computational resources on the PL), bearing in mind the target clock frequency and uncertainty. Recall that the hardware architecture is not conveyed or specified by the C source code, but rather different architectural variations can be generated from the source code by applying directives.
The resulting implementation has a set of characteristics, principally in terms of (i) latency, (ii) throughput, and (iii) the resources used.
To illustrate, let us assume that our C algorithm involves calculating the average of an array input, consisting of ten numbers. The implied operations are:
• 9 addition operations to find the total; followed by
• A multiplication by 0.1 to calculate the average.
There are a few different options in terms of scheduling and binding these operations. One possibility is to operate serially over several clock cycles, using a single adder and a single multiplier. Alternatively, the critical path may permit multiple operations to take place within one clock cycle at the targeted frequency, resulting in an implementation with lower latency and higher throughput.
Three variations are depicted in Figure 14.8. Consider in particular the differences in implementation characteristics between them.
1. The first implementation uses the fewest resources (1 adder and 1 multiplier, both constructed from logic fabric), and has a latency of 11 clock cycles. This design has
a low throughput — one 11th of the clock rate — because a new operation cannot
start until the last one has finished (we assume that pipelining is not used here — to
be explained later in Chapter 15).
2. Based on the target technology, the HLS process determines that 3 addition operations can be scheduled per clock cycle,while meeting the timing constraints. This results in an implementation using more resources on the device, but with a shorter atency and higher throughput.
3. Finally, it is determined that, if DSP48x slices are used in place of fabric resources, all operations can take place within one clock cycle. This corresponds to the most costly implementation, requiring 9 DSP48x slices in total (one each for the first 8 additions, with the last addition and multiplication combined into a single DSP48x slice), but it has a much reduced latency (1 clock cycle), and a throughput equal to the clock rate. This style of implementation would of course only be applicable if

timing constraints were met — otherwise Vivado HLS may insert pipelining registers to meet timing
By default, the HLS process will optimise area, i.e. it will adopt the first strategy outlined above, which consumes the fewest resources. The disadvantages of this implementation are its long latency and low throughput, which may not meet the requirements of the application. However, the designer can exert influence by constraining and directing the HLS processes of scheduling and binding, and thus optimising in a different way.
Optimisations
As mentioned above, the designer has mechanisms available to drive the high-level synthesis process towards his or her implementation goals. There are two methods which can be used to dictate the behaviour of the HLS process, and hence influence the results:
• Constraints — The designer places a limit on some aspect of the design. For instance, the minimum clock period may be specified. This makes it easy to ensure that the implementation meets the requirements of the system into which it will be integrated. Similarly, the designer may choose to constrain resource utilisation or other criteria, with the aim of optimising the design for the application in hand.
• Directives — The designer can exert more specific influence over aspects of the RTL implementation via directives. There are various types of directive available which map to certain features of the code, enabling the designer to dictate, for example, how the HLS engine treats loops or arrays identified in the C code, or the latency of particular operations. This can yield significant changes to the RTL output. Therefore, with knowledge of the available directives, the designer can optimise according to application requirements.
A Note on the RTL Output
The user has the option to specify the RTL language for the generated output files, and can choose from VHDL, Verilog, and SystemC. It is, of course, notable that SystemC is also one of the available input languages for HLS, and therefore it might initially seem curious that it is also listed as an output type. However, the SystemC file produced as an output of HLS is an RTL description of the hardware, i.e. a lower-level representation than the input to HLS. In the same way as for the other HLS output languages (VHDL and Verilog), the implementation is based on the chosen target device. This output can be particularly useful in verifying the design where an RTL simulator is not available.
Solutions: Exploring the Design Space
A Vivado HLS project is comprised of a set of design files, a set of testbench files, and project settings, The project can have multiple solutions — this is an important term because it relates to the theme of “exploring the design space”, i.e. generating a selection of possible implementations which can be compared, and the most suitable version chosen.
It is important to recognise that each solution is a different implementation of the same C/C++/SystemC source code. The differences in the synthesised RTL solution are determined by four factors:
• The target technology and part (e.g. Virtex-7, Kintex-7, Zynq-7000.)
• The target clock frequency
• The implementation constraints applied
• User defined synthesis directives
For a given application, the first two of these (target technology and part) are likely to remain constant, and the designer exerts influence over the generated solutions by varying the implementation constraints and synthesis directives, as discussed in the previous section. These will be defined in more detail as they relate to interface and algorithm synthesis in Chapter 15. Once created, each solution contains information about the target, the applied directives and constraints, and the results obtained.
As will be discussed in detail in the next chapter, the results obtained for a set of solutions can differ according to resource cost, throughput, and latency. These can be explored, and further refined, according to the requirements of the task.
Vivado HLS Library Support
It is worth noting that Vivado HLS includes support for arithmetic and mathematical functions, as well as linear algebra, video processing, DSP and others. Full details of library support is available in [33].
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Active Active
RoHS: -
Manufacturer:Xilinx
Product Categories:
Lifecycle:Obsolete -
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAS
Lifecycle:Obsolete -
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAs
Lifecycle:Active Active
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories:
Lifecycle:Any -
RoHS: -
Support