Setting up the environment
Setting up the the computer for HLS development is unfortunately a rather tedious task, and will probably take a few hours. It’s recommended to start this with no less than 30-40 GB free disk space, some of which are reclaimed at the end of the process by removing installation files.
There is however nothing about this procedure that requires any special knowledge except for installing software on your computer. Once finished, the sample project can be easily modified into whatever functionality is desired.
For the setting involving PCIe and a PC computer, it’s warmly recommended to install and run the development tools on a computer other than the one into which the PCIe board is installed. This computer will require frequent reboots. It’s also recommended to run Linux on this computer, if you’re comfortable with that OS.
The overall procedure consists of the following steps:
- Choosing and acquiring the FPGA board (people who read this usually have…)
- Downloading and installing Xilinx’ Vivado HLx
- Downloading the Xillybus demo bundle for the targeted FPGA (Xillinux if Zedboard is targeted).
- Building the demo bundle FPGA project using Vivado, following step-by-step instructions
- Downloading and Installing the driver for Linux or Windows on the host computer (except for Zedboard).
- Running a simple test to confirm that all went well so far
- Downloading the sample project for HLS
- Compiling the sample project
- Modifying the demo bundle to integrate with the function that was synthesized by HLS
- Rebuilding the FPGA project (now with the synthesized function)
- Verify that it works
Choosing the FPGA board
The board should be based upon an FPGA which is supported by Vivado: Xilinx Series-7 FPGAs and later (including the Ultrascale series). The FPGA device family should also be supported by Xillybus, as listed here.
Those not familiar with FPGA devices and their boards should probably choose one of the Xilinx boards listed (series-7 and later), so that the Xillybus bundle works out of the box, and FPGA-related troubleshooting is avoided.
For an embedded solution, the Zedboard, Zybo or MicroZed are recommended, with Xillinux running on the Zynq device’s ARM processor.
Those who don't have access to any of the (paid license) subscription editions of Vivado may consider choosing an FPGA target which is covered by the no-fee WebPack edition of Vivado.
Download and install the tools
Note that Vivado HLS is available in the no-fee WebPack edition since 2015.4, so it's recommended to use this revision or later.
If the targeted FPGA is covered by the WebPack Edition, it's usually the better choice, even if there's a licensing option of the "full" edition offered at no cost (mainly to avoid issues with licensing guards).
- If you’ve purchased a Xilinx evaluation board, it may arrive with a free licensing voucher for some tools, locked to the specific FPGA device. This is best sorted out before ordering a development board.
- It’s possible to download a free the 30-day fully functional evaluation license. It works exactly like the purchased one.
- Xilinx has a University Program, supplying academic institutions with hardware and software alike.
Setting up Xillybus
The purpose of this step is to set up the communication channel between the logic and the host.
PCIe-based: Download the respective demo FPGA bundle and the driver for your operating system, and follow Getting started with the FPGA demo bundle for Xilinx, section 3. Then install the driver on the host according to Getting started with Xillybus on a Linux host or Getting started with Xillybus on a Windows host, whichever applies.
Targeting the Zedboard: Download the boot image creation kit and SD card image from Xillinux' page and follow the instructions in the Getting Started Guide for Zynq-7000 EPP up to section 4 (inclusive). Resizing the file system on the SD card is usually a good idea, but is optional. So is allowing remote SSH connections. There is no need to install any driver on Xillinux — it’s already part of the system.
Note: Even though the instructions for implementing the demo bundles offer a freedom between Verilog and VHDL, the verilog subdirectory should be used for working with HLS. The instructions below depend on choosing Verilog.
Testing Xillybus’ bundle standalone
An important milestone is to boot up the host and verify that the Xillybus device files appear on it. The respective Getting Started guide details the steps for achieving this. Making this standalone check is a critical point to verify that things have been done properly so far. It also helps gaining a general understanding of the interface with HLS.
Once the system is up, it’s recommended to run the quick and simple test in section 3.3 of the Getting started with Xillybus on a Linux host guide. Windows users may install Linux-like utilities for this purpose, as described in the guide for Windows.
Modify the Xillydemo file
This step requires some simple editing in one of the files in the Xillybus bundle. There are several such bundles out there (one for each device family), but they all have a certain part that should be removed and replaced with other code. This is a simple step, and yet it’s recommended to do it with accuracy in mind.
This is the only time HDL code is touched. The purpose of this code replacement is to change the functionality of the logic from a plain loopback for the “Hello world” test, to interfacing with the wrapper module of the synthesized code.
The change is in a Verilog file. For general knowledge, this language looks a bit like C, but the meaning is slightly different. What looks more or less like function calls are instantiations. It’s a bit like creating an object in C++, but what happens is more like buying a chip and wiring its pins to other chips on the board. What looks like C variables are wires, that behave like copper wires connected between two electronic devices. That’s more or less the idea.
Now to the change to make: Find the following segment in verilog/src/xillydemo.v
// 32-bit loopback fifo_32x512 fifo_32 ( .clk(bus_clk), .srst(!user_w_write_32_open && !user_r_read_32_open), .din(user_w_write_32_data), .wr_en(user_w_write_32_wren), .rd_en(user_r_read_32_rden), .dout(user_r_read_32_data), .full(user_w_write_32_full), .empty(user_r_read_32_empty) ); assign user_r_read_32_eof = 0; // 8-bit loopback fifo_8x2048 fifo_8 ( .clk(bus_clk), .srst(!user_w_write_8_open && !user_r_read_8_open), .din(user_w_write_8_data), .wr_en(user_w_write_8_wren), .rd_en(user_r_read_8_rden), .dout(user_r_read_8_data), .full(user_w_write_8_full), .empty(user_r_read_8_empty) ); assign user_r_read_8_eof = 0;
and replace it with
// Wires related to HLS_wrapper wire [31:0] in_r_dout; wire in_r_read; wire hls_fifo_rd_en; reg in_r_empty_n; wire [31:0] out_r_din; wire out_r_full; wire out_r_write; wire [7:0] debug_out_din; wire debug_out_full; wire debug_out_write; fifo_32x512 fifo_to_function ( .clk(bus_clk), .srst(!user_w_write_32_open), .din(user_w_write_32_data), .wr_en(user_w_write_32_wren), .rd_en(hls_fifo_rd_en), .dout(in_r_dout), .full(user_w_write_32_full), .empty(hls_fifo_empty) ); assign hls_fifo_rd_en = !hls_fifo_empty && (in_r_read || !in_r_empty_n); always @(posedge bus_clk) if (!user_w_write_32_open) in_r_empty_n <= 0; else if (hls_fifo_rd_en) in_r_empty_n <= 1; else if (in_r_read) in_r_empty_n <= 0; fifo_32x512 fifo_from_function ( .clk(bus_clk), .srst(!user_r_read_32_open), .din(out_r_din), .wr_en(out_r_write), .rd_en(user_r_read_32_rden), .dout(user_r_read_32_data), .full(out_r_full), .empty(user_r_read_32_empty) ); assign user_r_read_32_eof = 0; fifo_8x2048 fifo_8 ( .clk(bus_clk), .srst(!user_r_read_8_open), .din(debug_out_din), .wr_en(debug_out_write), .rd_en(user_r_read_8_rden), .dout(user_r_read_8_data), .full(debug_out_full), .empty(user_r_read_8_empty) ); assign user_r_read_8_eof = 0; assign user_w_write_8_full = 1; // Not used, hence always full xillybus_wrapper HLS_wrapper ( .ap_clk(bus_clk), .ap_rst(!user_w_write_32_open || !user_r_read_32_open), .debug_ready(!debug_out_full || !user_r_read_8_open), .debug_out(debug_out_din), .debug_out_ap_vld(debug_out_write), .in_r_dout(in_r_dout), .in_r_empty_n(in_r_empty_n), .in_r_read(in_r_read), .out_r_din(out_r_din), .out_r_full_n(!out_r_full), .out_r_write(out_r_write) );
That's all. But hey, don't try to implement the project yet... The integration with the HLS project is explained in the next part.
There are three lines marked in red above. These should be deleted if the no debug messages are generated in the code. In case of doubt, leave them there — the Xilinx tools will complain if they should be removed.
Download the sample code for HLS
Download a sample project bundle for Vivado HLS and unzip it into a path close to where the Xillybus demo bundle was unzipped (for convenience). This project contains three source files:
- main.c — The synthesized and wrapper functions, which form a basis for developing the application HLS code
- xilly_debug.c and xilly_debug.h — A little package of debug functions.
The project bundle is ready for use. For a beginning, changes should be made only to main.c, or possibly adding source files like in any C project. A brief outline of the project’s settings is given in part VII.