Hackster - io-Hardware-as-Code Part II Hello FPGA
Hackster - io-Hardware-as-Code Part II Hello FPGA
hackster.io/sthibault/hardware-as-code-part-ii-hello-fpga-1f898a
Scott Thibault
Hardware components
× 1
UPduino
PlatformIO IDE
Story
1/7
Welcome back! In this installment, we’re going to get our development environment set
up and generate our first custom hardware design. If you found yourself here without
seeing Part I, head on over to Hardware-as-Code Part I and read the introduction to what
series is all about. If you haven't gotten the hardware yet, see the link in the Things
section.
Software installation
First, let’s install the required software. We need to install three packages:
PlatformIO can be used from the command line or within the Visual Studio Code
environment. The following are instructions for both options.
To install the Upduino HLS toolchain, we need to use the PlatformIO CLI. To open a CLI
window, click the PlatformIO icon (ant) on the left and then select PlatformIO Core CLI
under the Miscellaneous heading as shown below.
This will open a new terminal windows where you can enter pio commands. Install the
HLS toolchain by entering the following two commands:
2/7
Install PlatformIO:
Radiant install
If you purchased the target hardware mentioned in part I
(https://tinyvision.ai/products/upduino-v3-0?variant=39608867618919), then you will
need to install the Radiant Programmer to download hardware designs into the board. If
you do not have the board, then you do not need this package and can skip ahead to the
project creation section.
You do not need to download the complete Radiant package which is quite large. We just
need the programmer, so look for this download option towards the bottom of the
download page:
Project creation
With these tools in hand, let’s create a first project. If you want to save time, simply clone
the Hardware-as-Code Examples git repository (https://github.com/sathibault/hac-
examples.git) and open the hello-fpga folder.
If you don’t have git installed, or don’t want to clone the project, these are the detailed
steps to create your own project:
[env:fpga]
platform = upduino_hls
3/7
NOTE: If you did not install the Radiant programmer because you don’t have the board,
you will need to edit the project’s platform.ini file to add the line: upload_command
= none . This will prevent the tool chain from complaining about not finding the
programmer software.
Hello FPGA
Let’s walk through the source code of this first example:
Line 3: Include the Core Fusion FPGA programming framework header. Often
times, programming a co-processor like an FPGA or GPU requires a lot of boilerplate
code. We've designed the Core Fusion framework to minimize the effort necessary to get
started, but still provide lower-level APIs for more advanced design.
Line 12: Create an instance of the C++ type that represents the FPGA board.
This not only tells the compiler what board to compile for, but provides an interface to
communicate with the board.
Line 15: Turn the calc function into a custom FPGA function. The call to
fpga_func is what indicates to the compiler that we want to implement the calc
function in hardware. It also synthesizes and returns a wrapper function that will
communicate with the FPGA to call the hardware version whenever we invoke the
wrapper. The first two arguments tell it how to communicate with the FPGA, i.e. via the
board's serial input/output.
Line 18: Initialize the board. This must appear after the creation of any hardware
functionality; for now that means after the call to fpga_func .
Line 23: Call the FPGA function! When we call fun , the wrapper function returned
by fpga_func , it sends the input argument i to the FPGA function over the board's
serial input and then waits for the FPGA function to return the result over the board's
serial output.
Line 27: Do necessary cleanup. This terminates any connections to the board and
performs some other necessary internal housekeeping when we are done with the board.
So, what exactly did that do anyway? If you look at the output, it appears to have built an
executable named program.exe . That looks like software, not hardware! That’s because
the default build rule will build only the software version of your program. All the
4/7
“hardware-as-code” we write is also valid software and can be run on our computer. In
fact, that’s one of the major advantages of this approach, that we can easily verify the
functional behavior of our code without building any hardware at all!
Okay, let's run it. From the command prompt enter (if you’re using Visual Studio Code,
open a command prompt by clicking the PlatformIO icon (ant) on the left and then
selecting Platform Core CLI under Miscellaneous):
> .\program
calc(0) = -15
calc(1) = -8
calc(2) = -1
calc(3) = 6
calc(4) = 13
When run without any options, instead of using the FPGA, the software will simply call
the original calc function compiled for the CPU. In this way, we can quickly develop
and test our function before generating the hardware implementation.
Inspecting the output, you can see that the calc function seems to be doing what we'd
expect, so we can go ahead and implement this in hardware.
First, plug the board into a USB port on your computer. Generate the hardware
implementation and upload it to the FPGA by clicking the right-arrow icon (next to build
icon) at the bottom of the IDE, or if you are using the command line, enter the command:
pio run --target upload
NOTE: if you don't have the board, you can go through the build process without
uploading to a board with the command: pio run --target bitstream
This process will take a couple minutes and you will see a lot of output fly by, but when it
completes, you will have a hardware implementation of the calc function on the FPGA.
The board needs to be reset after programming, so unplug it from the USB port and
plug it back in to reset the USB interface.
After re-plugging the board into the USB port, you will need to open the device manager
to see what serial port it is using. See the example below:
Under Ports (COM & LPT), you will see a "USB Serial Port" with the name of the COM
port it is using next to it. This is the UPduino board (TIP: The COM port number will not
change if you always plug the board into the same USB port).
You may now run the program again, this time using the FPGA by providing the
appropriate COM port name as an argument (COM5 in my case):
5/7
> .\program --dev COM5
calc(0) = -15
calc(1) = -8
calc(2) = -1
calc(3) = 6
calc(4) = 13
You should get the same output as before, but this time it's from the FPGA!
We've just created our first special-purpose hardware implementation from a C function.
Since it's a standard C function, it is quick and easy to test/debug on the computer using
any standard software development tools. It's also super small and ultra efficient! This
post is already long, so we won't look into the details just yet, but the generated hardware
is basically want you'd expect: 1 multiplier connected to 1 adder.
Next steps
Although every function we implement in hardware is standard a C function, not any C
function can be translated to hardware. In the next few installments, we'll work through
the features that are available to us and how to use them effectively. We'll also get into
some details of performance: What are the strengths and weaknesses of the generated
hardware? How does it compare with the software/CPU approach?
Connect
Please follow me to stay up-to-date as I release new installments. There is also a Discord
server (public chat platform) for any comments, questions, or discussion you might have
at https://discord.gg/3sA7FHayGH
Code
Hardware-as-Code Examples
sathibault / hac-examples
00
Hardware-as-Code Examples — Read More
Download as zip
Credits
6/7
Scott Thibault
3 projects • 5 followers
Doctorate in programming languages + experience in FPGA, design automation,
embedded systems, and machine learning.
Contact
7/7