Computing stuff tied to the physical world

The language(s) of FPGAs

First off: this is not going to be an introduction to VHDL or Verilog, the two languages normally used to define the configuration of an FPGA. There are books for that, it’s a huge field, and yours truly isn’t really versed enough in either of them… not yet, anyway.

Let’s simply explore this whole domain a bit. Enough to get a feel for what’s involved.

At the most basic level, you might expect a structural definition of the entire circuit, i.e. reems and reems of “take a logic gate of type X, and attach its pins to … etc.” – but as you can imagine, this would quickly lead to a lot of defining code.

We could introduce hierarchy, and build more sophisticated blocks out of smaller ones. Which would probably go a long way to simplify things.

Now let’s take VHDL, which stands for “VHSIC Hardware Description Language”, where VHSIC stands for “Very High Speed Integrated Circuit”. An example from Wikipedia:

library IEEE;
use IEEE.std_logic_1164.all;

entity ANDGATE is
  port ( 
    I1 : in std_logic;
    I2 : in std_logic;
    O  : out std_logic);
end entity ANDGATE;

architecture RTL of ANDGATE is
begin
  O <= I1 and I2;
end architecture RTL;

There are two parts: the “entity” describes the outside view, while the “architecture” describes the internal design. This is a (rather verbose) way of defining an AND gate.

Except that we’re not…

We’re calling something an ANDGATE, but we’ve defined its design in terms of logical operations. We could also have used a case statement, or series of if/then/else clauses – something like “if 1 and 1 then 1, else 0”. It doesn’t matter – either way works, and they will all lead to the same implementation in the end.

See the Wikipedia page on VHDL for more examples. There are some surprises in there, such as defining partial outcomes to create state, i.e. latched data.

Despite the superficial resemblance, with its syntax, keywords, and indentation, VHDL is NOT your usual programming language. It’s more a sort of non-procedural description, in other words: “this is how it should behave, you (the IDE, or actually the “synthesiser” – more on that in a moment) have to figure out how to turn it into a real logic configuration”.

VHDL includes a simple array-like notation to describe many signals at once. It’s trivial to define an 8-bit data bus, for example. Or to wire many multi-signal units together.

So the gist of it all is: you define a bunch of entities (usually in terms of lots of other entities), and then “wire them up” (which is merely the simplest possible architecture).

In the case of MultiComp, all the hard work has been done for you. All the VHDL is already included in the project (for all the possible CPU and peripheral variations, in fact). All you need to do is hook things up and tweak a few incompatible details (a 6809 addresses external memory differently than a Z80, for example). Here’s MultiComp’s “big picture”:

MulticompBreadboardBare

It’s a bit like placing a bunch of matching puzzle pieces inside the cutouts.

The ONE BIG WARNING SIGN here is that all the definition code you insert runs in parallel. When you write “connect A to B” and “connect C to D”, you’re not creating a sequential mechanism. These things are wires, they’ll “run” instantly, at the same time, and totally independently of each other.

Sounds trivial, right? Not so fast. When you create a chain of logic gates, i.e. outputs to inputs, then you are in fact creating a sequential dependency. Each of these connections does sort of “run in parallel”, yet the actual events do have a certain propagation delay!

But it’s all happening at a different level. You could define the end of the chain first, and then the others. It would not matter – it’s not the fact that a description comes earlier in the VHDL source file which defines its place in the bigger scheme of things. Or its timing.

Ok, say you’ve written everything down and your design is ready, now what?

There are two issues: first off, how do you know whether the design works? We need some way to debug it. This is where simulation comes in. The Altera or Xilinx IDE you’re using will have a simulator in it, which lets you run the whole design and look at any signals you like, freeze time, etc – quite similar to running software.

The simulator is like a debugger for FPGAs. But it has one major drawback: it’s immensely inefficient. Think of all the steps it has to go through to process one step in a system made up of thousands of logic cells. It may run a million times slower than the real thing!

Luckily there are other, higher level, simulation options. Part of this comes from the fact that designs are written as higher-level constructs. If we have an “adder” circuit in there, then we can simply perform an add in the simulator, if that’s not the part being debugged.

The other issue is actually generating a definition which can be loaded into the FPGA. This process is called “synthesising”, and the result (which may take some time to produce) is called a “bit stream”. Because that’s exactly what it is: a stream of bits, shifted into the FPGA’s “upper” level of memory cells, the part which controls all the connections made.

Turning VHDL into a bit stream is (unfortunately) a black box, containing closely-guarded secrets by all the vendors of FPGA chips. There is (apart from one exception so far) no other way than to run whatever proprietary tools the vendors have made available.

And then there’s one last little surprise …

We can send a bit stream to the FPGA, and lo and behold – it’ll start acting like the “thing” we defined in VHDL (and/or Verilog). Magic! – soft cores, interfaces, whatever – anything! But the moment power is turned off, the FPGA loses its identity. This is not very practical.

For that reason, an extra mechanism is included in every FPGA, whereby an attached special kind of flash memory can be read out on power up (or when the FPGA is “reset”, not to be confused with a reset of any soft cores it might be running).

So the last step is to store the bit stream in flash. This is much slower than direct loading into the FPGA, so it’s usually not done in the midst of active development – only later on.

That’s the essence of FPGAs. There are many, many variations, sizes, speed grades, and vendors. The “EP2C5” used in MultiComp is one of the smallest (and yet, look how much it can already do!). It’s Altera‘s “Cylone II”, there are also newer III, IV, and V generations. More pins, faster, more capable (through special hard-coded features), it never ends. On the Xilinx side, there are the Spartan-3 chips (bit like the EP2), the Spartan-6’s, and more.

Here is a brief overview of these “low-end” FPGAs, copied from specs in the datasheets. In order of appearance, you’ll find the Cyclone II, Cyclone IV, Spartan-3, and Spartan-6:

Fpga sizes

If you look around on WaveShare and eBay, you’ll see that there are several boards in the $15..100 range. Development boards in particular, are convenient because they include various types of RAM and peripherals. For more professional development boards, some of which are nevertheless quite reasonably priced, see Terasic (Altera) and Digilent (Xilinx).

For a very informative book on the topic, see “The Design Warrior’s Guide to FPGAs”, by Clive Maxfield, ISBN 9780080477138. An excellent 500-page intro into this whole subject.

Sooo… if you ever grow out of the performance levels of a ┬ÁC, you’ll know where to look!