In my previous column in which we introduced FPGA hardware — in particular, the programmable fabric that is the hallmark of an FPGA — we discussed how a lot of folks on the microcontroller (MCU) side of the design fence don’t really understand what these devices are or what they do.
Much of the same thing applies to the hardware description languages (HDLs) used by FPGA designers. The MCU folks have heard of these languages — like Verilog and VHDL — and they understand that the FPGA designers use these languages to capture their design intent, but that’s pretty much as far as it goes. So, let’s try to shed a little light on this subject.
MCU vs. FPGA High-Level Design Flows
Let’s assume that you are writing a program to run on your MCU. In this case, you will typically capture your program source in a software language like C/C++. Next, you will run this program through a compiler to generate a corresponding machine code (executable or object) file. Eventually, you will load this program into the MCU’s memory and run it.
Well, looking at things from a high level, the FPGA design flow is somewhat similar. One thing we should note is that the FPGA contains special cells called configuration cells (these might be based on Flash, SRAM, or even antifuse technologies, depending on the FPGA). These cells are used to configure the look-up tables (LUTs), registers, and interconnect that form the FPGA’s programmable fabric.
So, first we capture the design intent using a HDL like Verilog or VHDL. Although not shown above, we might use a special software tool called a simulator to verify that the design works as planned.
Next, we use a synthesis tool that understands the FPGA architecture in question and generates the 0s and 1s required to program the configuration cells to implement the logical functions and interconnections necessary to realize our design.
Finally, we load the configuration file into the FPGA, at which point the little rascal is ready to rock and roll.
Sequential vs. Parallel
One of the things MCU folks find difficult to wrap their heads around is the fact that the HDLs we use to design FPGAs support the concept of concurrency, but what does this mean?
Well, in the MCU world — assuming a single thread and a single processor core — everything happens sequentially, one instruction after another. By comparison, in the FPGA world, multiple things can be happening at the same time — for example, one input could transition from 0 to 1 at the same time another input transitions from 1 to 0 — so languages like Verilog and VHDL allow us to describe this concurrency.
S/W Functions vs. H/W Blocks
This is somewhat related to the previous point. Suppose we have a software program that has six functions. The main body of the program may call each function in turn, but only one function can be active at any particular time.
Now, suppose that we were to take the actions (logical and mathematical operations) performed by one of our software functions, and replicate them as a functional block in an FPGA.
Let’s further suppose that we do the same for the other software functions. The point is that each of these blocks can be running simultaneously in the FPGA.
In an earlier column, Using FPGAs to Accelerate C/C++ (Pipelining), we talked about how we could take the individual operations forming a software function and pipeline them in the FPGA to dramatically increase the throughput. Well, we can do the same thing with entire functions.
The bottom line is that MCUs are great for certain tasks and not so great for others. Similarly, there are some tasks for which FPGAs can offer significant advantages. Although my columns have provided only a high-level introduction, hopefully they will prompt you to at least consider using FPGAs in your future projects.