Disclaimer:  I take no responsibility for the information on this page.  Although by default I  retain
an exclusive copyright on this material, by using any of this, you agree to assume all liability and
consequences that may arise.  In other words, if you don't like it, or you suffer harm from using it,
don't blame me.  If you don't agree to this, then leave now by clicking here or stay to find out some
valuable information.
 

Where to Start...

So you've decided that you want to use an FPGA with VHDL code.  When I first started out, I thought it
was going to be a piece of cake.  After all, what could be more simple?  Write everything behaviorally, use
classical programming skills, burn a chip and turn in your project to your supervisor.  Of course, this works
for all of about five minutes...then you realize what a pain things are.

FPGAs are about the closest thing you can get to a totally integrated digital system without using full
custom IC design.  But you have to treat the process with respect.  By that I mean you have to write well-
behaved VHDL code, and fully understand the processes that are happening within the software.  If not,
you get a very expensive keychain ornament after you're done.

I'm going to assume a few things here, including:

Ok, now that that business is finished, let's talk VHDL...
 

Well-Behaved VHDL Code for Synthesis

What exactly is this kind of VHDL code?  Well, you can basically partition VHDL into two different
styles:  code for synthesis and code for simulation.  Simulation code implies that, as long as your code
is syntactically correct with respect to the VHDL standard, it will behave within a simulator like QHSIM
as you intend it to.  You can add delays, wait statements, nest if-then-else and case statements, play with
events and do basically whatever else you want.

Unfortunately, you are constrained quite a bit when it comes to writing synthesis code.  Code for
synthesis implies that you are coding VHDL to be put on some logic device, such as a CPLD or an
FPGA.  That means that you often can't insert "wait for" statements, or depend on both edges of an
event as a trigger, or do a lot of other things that you could do if you were coding for simulation only.
Even where certain code styles are allowed, you won't necessarily be able to synthesize a particular
design in a compact way.  Things can get out of control really quickly, so the best way is to know some
of the most common pitfalls of coding.  If you get in the habit of coding for synthesis, you can make your
life easier when designing, and increase the chances for portability to other devices.
 

What are the "Synthesis Tools" Anyway?

Synthesis tools are programs that prepare VHDL code that you've written for implementation
in an FPGA.  They take either behavioral or structural VHDL code, transform the code into FPGA
primitives or "standard native components" specific to the device, and ultimately yield a fuse file which
can be used in an FPGA burner.  Along the way, there are several stops, including compilation into a
preliminary format (EDIF in the case of Actmap), optimization for area or speed, specification of
constraints such as pre-assigned pin placements and delay targets, and final extraction into a fuse file
or into a "back-annotated" delay file.  The diagram below shows the hierarchy and what each
component of the synthesis tools does:

The beauty of synthesis tools is that they isolate the digital designer from a lot of the very intricate
details specific to the part being used, and even from traditional design techniques.  Minimization of
logic, state machine creation and even arithmetic function creation don't have to be done using the
"classical" digital design methods.  For example, my EE552 project partner and I implemented a
binary-to-dual-seven-segment converter with a range of 0 to 99 in 65 modules!  (And a logic module
in an Actel FPGA is three 2:1 MUXes and an OR gate).  Try doing that using traditional techniques,
and you'll see that pen-and-paper succumb to the almighty synthesis tool.  That doesn't mean that
you don't have to think anymore, however.  The issues within digital design using FPGAs and
synthesis tools with VHDL are different, but just as critical.  You can't just code anything and
expect the tools to behave properly, because there are a lot of constraints.
 

What Are Some Of The Common Pitfalls?

By no means is this a comprehensive list.  I may have missed a few things or not run into some of the
problems that you're running into.  If you see any significant gaps, mail me and I'll get around to
changing it.  A lot of this is cribbed directly from Actel's documentation for Actmap (thanks to Eric
Masson for the reference), but also from my experience and resultant headaches.

1.  Non-modular code - if you do anything in VHDL, write in a modular style.  This means that you use
some of the built-in features of the language, such as processes, packages, and components.  Breaking
your code down into smaller fragments makes it easier to analyze, understand, and debug.  Some more
specific things that I suggest are:

2.  Multiple timing events - This is a big one.  I personally can't stress it enough.  You cannot depend
on multiple events in time as conditions.  Specifically: 3.  Specified delays - If you intend on synthesizing a design, you can't insert specific delays within
your code.  That's because delays aren't deterministic in FPGAs.  In Actel's Designer, you can specify
delay targets (i.e. foobar < 50ns delay), but you can't rely on them to even be met, and you can only do
this after you've compiled your VHDL code.  This includes: If you need to synthesize a specific delay, use a divide-by circuit based on the system clock
frequency.  For example, I needed a 0.5Hz system signal from a system clock frequency of 4.194MHz.
so I set up a 23 bit counter count(22 downto 0), incremented it based on the incoming clock signal, and
tapped the most significant bit off of the counter (i.e. signal <= count(22)).

Note the specific clock frequency of 4.194MHz.  Why that particular one?  Well, it isn't just because
it was available hardware, but also because I can divide-by-2 a total of 23 times and I get a number
very close to 0.500 Hz.  In general, if you need something like this done, the rule of thumb is that the
base-2 logarithm of the clock frequency should come out very close to a whole number.  This
way, you can divide it simply by using a counter, and you don't even need a preload function or direction
control.  Also, just let the count overflow...you don't really need to care about the carry out.
e.g.    if (clear='0') then
        count <= "00000000"; -- zero the count on a clear signal
     elsif (clock'event and clock='1') then
        count <= count + "00000001";  -- increment on system clock event
        output <= count(7);  -- assign output to last bit which will
     end if;                 -- change every time overflow occurs

Yet another alternative (and you have to be really hard-up to get to this point IMHO) is to use an implied
comparator and derive the number of clock pulses it takes to reach a certain time, then trigger when it's
equal to a set value.
e.g.    constant triggertime : std_logic_vector(9 downto 0) := "0101011010";
     ...
     counter : process(reset,clock)
     begin
        if (clear='1') then count <= "000000000";
        elsif (clock'event and clock='1') then
           count <= count + "0000000001";
        end if;
     end process blek;
     ...
     outassign : process(count)
     begin
        if (count=triggertime) then
           output <= not(output); -- invert the previous output value
           clear <= '0';          -- on each iteration and clear counter
        else
           clear <= '1';
        end if;
     end process outassign;
This will chew up more silicon than the previous counter, so it's ultimately up to the designer what s/he
wants to do.

4.  "Open-ended" and nested conditional statements - Suppose you have a 16-bit wide signal.  You
need to do an address decoder for a device on a bus, so you type:
    if (address = "0000111100001111") then
       data_bus_signal <= "0001";    --(or the equivalent as a CASE statement)
   end case;
Now, this is all fine and dandy, but when you try to compile it, you have an enormous number of modules
used up in the FPGA.  What you don't see is an implied handling of all of the other cases of the "address"
signal.  It's as if you had typed:
   if (address = "0000000000000000") then data_bus_signal <=
    elsif (address = "0000000000000001") then data_bus_signal <= "0000";
    ...
    elsif (address = "1111111111111111") then data_bus_signal <= "0000";
  end case;
Now, this would take you months to type out.  It also takes Actmap a relatively long time, and in the
process chews up a lot of silicon area.  A better way to do this is to make a closed-ended conditional
statement so that you prevent the synthesis of unnecessary logic.  You would retype the above statement
as:
    if (address = "0000111100001111") then data_bus_signal <= "0001";
       elsif (address /= "0000111100001111") then data_bus_signal <= "0000";
    end if;

By specifying "elsif" as opposed to "else" (or "when others" instead of excluding "when others" in a "case"
statement), you prevent the synthesis tool from adding unnecessary logic.  It's like blinders for horses.
When you race them, they need them to keep focused and not go all over the place when you want to
go straight ahead.  I do want to mention two caveats to this:

Ultimately, the best thing to do is to experiment with your particular design and see what happens.

One short note one nested conditional statements (e.g. if blah then if blah then if blah then ...).  Unless
you have a specific need for such structures (or a conceptual failing, and I usually fall in the latter
category), you can cause your code to become excessively large.  Try and split it up as per #1 above,
or use multiple processes and pass signals between them.

5.  Structural VHDL code from Designer and Actgen - one would think that structural code is the
ubiquitous solution to synthesis problems.  It isn't.  Actmap likes to choke on this type of code regularly
so don't use it.  For one thing, if you follow all the rest of the rules for well-behaved VHDL synthesis
code, Actmap will run the macro generator internally and produce the equivalent code.  I personally
avoided using Actgen, but if you need to, you can search the Actel site "Guru" for "How do I add an
ACTgen macro to my VHDL design?"  It's pretty intense, so be careful if you want to use it.

6.  VHDL '92/'93 constructs - don't use these.  They aren't well supported in synthesis tools from
what I've seen.  They're more for simulation purposes.  It's hard to go wrong with VHDL '87 it
seems (although it can be inconvenient), plus you're allowing yourself better migration to other tools
for synthesis and simulation later on if you need that.

7.  Loop statements - most traditional firmware programmers know that statements like "while" and
"loop" are dangerous.  They cause compiled code to almost literally explode in size.   The same
things happen in the VHDL world, only worse - they usually won't synthesisze.  Don't use them.
I believe the one exception to this is if you use a for with the loop statement in a certain way, though
I'm not sure.  Corrections are always welcome :).

8.  "Unusual" data types - there are a few data constructs that cause major havoc within the
synthesis environment.  If you're lucky enough to have it compile, you probably won't be saving
yourself a lot of space by using it.  Some of the ones to watch for include:

I guess the most important lesson of this point is to use signals and constants which are defined in
std_logic or std_logic_vector format, and become comfortable in dealing with numbers that are in
binary format.  Special thanks to Eric Masson  for some of these specific references (You've saved a lot of
people a lot of time Eric... :) ).

9.  Using the "inout" signal direction between internal components - if you try to use the
"inout" to specify your signal direction on components inside your top level, the design won't work
properly.  Just use multiple signal assignments from the same signal and "multiplex" the feedback.
If, for some reason, you absolutely have to use inout signals in your design, you're going to have to
route them to the outside of the chip, then hardwire them back to another I/O pad.  If this seems
inefficient, it is.  Avoid it at all costs.

10.  Using simulator tools to compile code through revision - this is generally a bad idea.
Why?  Well, you eventually want to compile this for synthesis.  Even assuming you took most of the
above points to heart, you may still encounter some weird stuff  that doesn't compile.  You'd never
find this out until after you've written all your code that compiles nicely for the simulator.  By first
compiling with the synthesis tool, you can see whether or not your design has the general form for
synthesis.  Once you're certain that your code compiles for synthesis, you can be almost positive
that the synthesis tool will deal with it.  Not always, but most of the time.

What I mean by "not always" is that CAD/CAE tools have a tendency to differ in the way they
handle libraries from the synthesis tools.  Each synthesis tool vendor has their own way of handling
basic mathematical functions, data types, and other elements of the language, just as each design
and simulation tool vendor.  No matter what you use, always include the following library statements
within your code:
    library ieee;  --always put this in, it's the same either way
    use ieee.std_logic_1164.all;  --allows use of std_logic types

In the particular case of Mentor Graphics and Actmap, you need to do the following:

What I usually do is include all of the statements above, and comment the one out that I'm not
using, because I still need to test out the basic functionality of the design with the simulation tools.
Eventually you'll want simulate the same design using back annotated delays to make sure that
nothing bad happens when you burn the FPGA.  By the way - if you don't use the libraries that
correspond to the programs above, you'll get all sorts of weird errors.
 
Jeez, after all that writing I feel like I gave birth...and that's probably not all of it.  Eventually I'd
like this section to grow, so any additions and changes are more than welcome.   Of course, this
would be for nothing if you didn't know the procedure that you go through to get the design
implemented.

Click here to continue...

Copyright 1997 Mike Daskalopoulos and Ishfaqur Rahman.  All rights reserved.
Read this legal notice before using any information contained in this document.