Stage 4: Writing the FPGA design in VHDL
So we’ve finally made it to the finale in our series on designing with FPGA’s. Following on from our previous article where we implemented the software functions we need in order to be able to reprogram our FPGA easily, we can now get into the nitty-gritty of programming the FPGA to do what we want.
Firmware with a difference
As mentioned briefly in our first article, FPGA’s are not like your common microcontroller. A microcontroller has a processor core that executes instructions sequentially that are stored in on board memory. They’re really good at logically complex sequential operations but are much harder to constrain time wise. Unless you’re using interrupts/hand-crafted assembler then you can probably argue that they’re also non-deterministic, meaning that you don’t know when exactly something is going to be performed. This is due to the other workload the microcontroller has to work through first.
The FPGA on the other hand is an array of logic which you can specify via an HDL to become the logical function you need. Unlike Microcontrollers, FPGA’s excel at more simplistic, high speed parallel tasks. They’re also much more deterministic and are fantastic at doing tightly constrained real time operations and calculations. FPGA’s are consistently used to implement non-standard protocols, tightly controlled DSP calculations and tasks that require parallelizable functions to be performed. They do however struggle with algorithmically complex functions, requiring a lot of logic resource in order to do so.
Writing the VHDL required to get an FPGA working is a very different beast to writing the C or assembler for a microcontroller. When you write VHDL you constantly have to think about how all the logic you’re defining will work with other parts of your design on a real time, concurrent basis. It’s a very different mindset from writing any other language. You also want to be as far removed from device primitive instantiations as much as possible so that you can make good use of the modularity VHDL can provide (although sometimes you can’t get around them).
Debugging/Verifying VHDL is also very different. In C you can run simulators or debug on the platform by stepping through your code with a debugging tool. In VHDL you rely on using test benches and bus functional models to simulate and verify the majority of the functionality of your design. Only very rarely would you resort to using the equivalent debugging tool which is an IP block that captures the states of certain pre-specified signals for download via a programmer/debugger tool. A typical industry setup for designing FPGA’s usually has two or three verification engineers to each design engineer, demonstrating how much more verification work goes into an FPGA than that which would happen on a typical microcontroller.
Starting Somewhere
There are a lot of different tasks when it comes to designing an FPGA with VHDL. Some of the most frequent are:
- Doing the design in VHDL
- Writing informal test benches for the design in VHDL
- Making the verification solution (which is different from an informal test bench!) in a scripted language
- Checking timing/using static timing analysis
- Checking for clock domain crossing/meta-stability/synchronisation etc…
The list of things to do very much depends on how complex your design is. If you’re making a design which is “low speed” (usually below some tens of megahertz) then you can usually get away with not doing as many timing checks. If you’re only ever using one clock domain (read as just using one clock to run the whole design) then you can avoid clock domain crossing checks. You can also get away with only doing informal test benches if what you are doing if very simple or is not going into a product that needs to be reliable (if they even exist). The list of things to do is very much tailored to the requirements.
In our case, we just want to do some extremely simple stuff. This means we can actually skip test benches, timing checks and other checks all together. All we plan on doing is writing some really simple VHDL in order to show the basics of FPGA design. At some point in the near future, we will write another series on “high speed” FPGA design and verification because that is a whole topic in itself.
Get the tools
We mentioned in previous articles that there are a few main vendors in the FPGA market, with Xilinx and Altera being the biggest. Each of these vendors provides their own software tools in order to design and synthesise FPGA logic. Because we’re focusing on a Xilinx part, we’re going to be using the Xilinx tool set in order to do our design.
Xilinx has two main tools that you can use to design FPGA’s: ISE and Vivado. Vivado is aimed at their much newer line of FPGA’s, more specifically their “7 Series” and above e.g. Artix 7, Kintex 7 and Virtex 7. ISE is aimed at all FPGA’s historically before this, including our humble Spartan 3A. This means that we need to use Xilinx ISE in order to create our design. At the time of writing this (and for probably most of the future now as ISE is no longer in development), the version of ISE I’m going to use is the 64 bit version of 14.7.
ISE has pretty much most of the functionality you will need in order to develop a basic FPGA. The IDE has an built in text editor, GUI windows for the FPGA workflow and also a way to launch iSim, their basic FPGA simulation tool. If we were to set up this design to be built from an automated platform or other synthesizer tools/simulators were to be used then the tool-chain becomes trickier to set up. As we quickly mentioned before though, we’re all good in this instance. ISE can be downloaded straight from the Xilinx website here.
If you chose to go down a different route of programming your FPGA in your design (e.g. on-board SPI flash) then you would also need some programming hardware. Xilinx provides its Platform Cable to aid in the JTAG programming process you would need to perform. In our instance, we covered in the previous article about programming the FPGA that we are instead using a different method to do this. As a side note: I personally never understand why programming cables cost so much and are proprietary to each vendor. This goes for all FPGA vendors and MCU vendors alike.
What’s the design?
It’s always a good idea to know what sort of design you want to make before you begin doing anything. Here at Circuithinking, we plan our systems to ensure that we go into designs prepared and with a target goal and architecture in mind. Preparation for designs is key to making something that is modular and coherent. Not preparing properly in this way can lead into really nasty uninterpretable code. Although we won’t follow the process in this article, we’ll still use a cut-down plan as the framework for when we start coding.
Because the design has been made with breadboard connectivity in mind, we want something simple we can connect up on a breadboard. We also want something that, for the purposes of exhibition, is visual. For those reasons, we’ll go with an LED design. The idea will be to have LED’s dimming in a sequence using pulse width modulation. We can use 8 LED’s with the same driver stamped out for each LED, but with a time offset built into the design so that it will look as if the LED’s are scrolling through brightness one after another. This is one of the best things about VHDL, FPGA’s and I suppose code in general: modularity. If you’ve done it properly once, you can copy and paste to do it many times again.
In deciding an architecture for the code it’s always best to try and group together repeated functions. In our case, the LED driver that suits one LED will work for all so we need just the one LED driver block. We also need some top-level