Tuesday, May 14, 2013

Getting started with FPGAs

FPGAs are pretty awesome. But what are they, and how do you use one? Search no further than here!
A Cyclone III FPGA chip on an Altera DE0 dev
board, up close.

An FPGA is kind of like a CPU, but more awesome. Just like you can reprogram a CPU to do different things, you can reprogram an FPGA to be different things. In other words, you are given a whole bunch of logic gates and the complete freedom to hook them up however you want. Think about that for a moment.

That's the awesomeness of FPGAs.

You can make audio processors, password crackers, Bitcoin miners, and even parallelizable GPUs and CPUs - all on an FPGA.

The question is, how?

Just like a CPU is programmed with a number of different special languages, an FPGA is also programmed with a kind of special language - a Hardware Description Language, or HDL for short. Unlike a procedural language like Python, C or Java, an HDL tells the FPGA how to hook up its logic gates.

This means that, more often than not, a bunch of things are happening at the same exact time, and that, primarily, is what FPGAs are good at. When learning to program FPGAs, you will be learning to think in parallel, and that is a powerful thing. FEEL THE POWER!!!

There are two main HDLs out there: Verilog, and VHDL. Because Verilog is the first language I learned, and it is less verbose than VHDL, I'll talk about that. First, look at the commented code below.

module FPGA_TOP(
    input        CLOCK,   // from the hardware clock generator
    output [7:0] GPIO_LED // blinky lights!

reg [7:0] count;  // 8 bits

// ### LOGIC ###
/* Continuous assignment; the wire GPIO_LED is driven by
 * count, no matter what else is happening.
assign GPIO_LED = count;

/* The stuff in this always block happens on the rising clock edge.
 * Thus the funny <= assignment operator below; above was 
 * a continuous assignment. Here, it's an edge-triggered 
 * assignment. Why? BECAUSE THIS IS NOT C. Above, we were driving a
 * wire. Here, we are clocking data into a register.
always @(posedge CLOCK) begin
    count <= count+1;
end  // always @(posedge CLOCK)


What do you think this does? It counts in binary using the 8 LEDs on the dev board. Some things to notice about this code:

  • It begins with module MODULE_NAME(...); and ends with endmodule.
  • You must declare the size of your regs and wires, or they will be one bit wide. (You can do some pretty wacky stuff, like making a 39-bit CPU, similar to what NASA did 50 years ago!)
  • Use begin to begin blocks, and end to end them. Makes sense, no?
  • The Verilog code, translated into circuits.
    Logisim is great.

OK. The first thing you might want to do is translate this into C or Python. DON'T. Behaviorally, this is NOT C, OR ANYTHING LIKE IT. Instead, translate this code into circuits. This is what the Verilog compiler does. We are coding circuits, not programs. Look at the diagram at the right, and convince yourself that it is the same as the Verilog.
An uncontrolled counter. Does
not work.
 Logisim didn't like
it either, and refused to
simulate it.
Note the CLOCK signal in the diagram and in the Verilog. Things only change on the rising edge of CLOCK; even if the CLOCK stays high, there will only be one change until the clock goes low and goes high a second time. That is why we use always @(posedge CLOCK) in our Verilog. We could have put the code in an always @(*) instead without waiting for the CLOCK edge, but then the count would increment over and over again very fast and without control. In the diagram, this would be the same as removing the count register and connecting the input and output of the +1 block together.

So, registers are like locks in a canal; they hold data still until ready to be changed.

How did you like your first taste of Verilog? Please leave a comment if you are interested in more; I'll write more about it.

No comments:

Post a Comment