A guide to VHDL for embedded software developers: Part 1 – Essential commands

Editor’s Note: In this series of articles based on his book – Design Recipes for FPGAs – Peter Wilson provides a basic quick overview of VHDL (VHSIC hardware description language) followed by examples of its use in describing – in HDL code form – functions familiar to most embedded software developers such as arithmetic logic units (ALUs) and finite state machines (FSMs). It is not intended as a comprehensive VHDL reference. For that, he recommends “Digital System Design with VHDL,” by Mark Zwolinski; ”VHDL: Analysis and modeling of digital systems,” by Zainalabedin Navabi or “Designer’s Guide to VHDL” by Peter Ashenden.

This series of articles is designed to give concise and useful summary information on important language constructs and usage in VHDL – helpful and easy to use, but not necessarily complete.

It will introduce the key concepts in VHDL and the important syntax required for most VHDL designs, particularly with reference to Field Programmable Gate Arrays (FPGAs).

In most cases, the decision to use VHDL over other languages such as Verilog or SystemC, will have less to do with designer choice, and more to do with software availability and company decisions. Over the last decade or so, a ‘war of words’ has raged between the VHDL and Verilog communities about which is the best language, and in most cases it is completely pointless as the issue is more about design than syntax.

There are numerous differences in the detail between VHDL and Verilog, but the fundamental philosophical difference historically has been the design context of the two languages.

Verilog has come from a ‘bottom-up’ tradition and has been heavily used by the IC industry for cell-based design, whereas the VHDL language has been developed much more from a ‘topdown’ perspective.

Of course, these are generalizations and largely out of date in a modern context, but the result is clearly seen in the basic syntax and methods of the two languages. Without descending into a minute dissection of the differences between Verilog and VHDL one important advantage of VHDL is the ability to use multiple levels of model with different architectures.

This is not unique to VHDL, and in fact Verilog does have the concept of different behavior in a single ‘module’; however, it is explicitly defined in VHDL and is extremely useful in putting together practical multi-level designs in VHDL.

The division of a model into its interface part (the ‘entity’ in VHDL) and the behavior part (the ‘architecture’ in VHDL) is an incredibly practical approach for modeling multiple behavior for a single interface and makes model exchange and multiple implementations straightforward.

The remainder of the first part in this series will describe the key parts of VHDL, starting with the definition of a basic model structure using entities and architectures, discuss the important variable types, review the methods of encapsulating concur rent, sequential and hierarchical behavior and finally introduce the important fundamental data types required in VHDL.

Entity: model interface
Entity definition. The entity defines how a design element described in VHDL connects to other VHDL models and also defines the name of the model. The entity also allows the definition of any parameters that are to be passed into the model using hierarchy. The basic template for an entity is as follows:

entity is
....
entity ;

If the entity has the name ‘test’, then the entity template could be either:

entity test is
end entity test;

OR:

entity test is
end test;

Ports. The method of connecting entities together is using PORTS. These are defined in the entity using the following method:

port
(
...list of port declarations...
);

The port declaration defines the type of connection and direction where appropriate. For example, the port declaration for an input bit called in1 would be as follows:

in1 : in bit;

And if the model had two inputs (in1 and in2 ) of type bit and a single output (out1 ) of type bit, then the declaration of the ports would be as follows:

port (
   in1, in2 : in bit;
   out1 : out bit
);

As the connection points between entities are effectively the same as those inter-process connections, they are effectively signals and can be used as such within the VHDL of the model.

Generics. If the model has a parameter, then this is defined using generics. The general declaration of generics is shown below:

generic (
...list of generic declarations...
);

In the case of generics, the declaration is similar to that of a constant with the for m as shown below:

param1 : integer := 4;

Taking an example of a model that had two generics (gain (integer) and time_delay (time)) , they could be defined in the entity as follows:

generic (
   gain : integer := 4;
   time_delay : time = 10 ns
);

Constants. It is also possible to include model specific constants in the entity using the standard declaration of constants method previously described, for example:

constant : rpullup : real := 1000.0;

Entity examples. To illustrate a complete entity, we can bring together the ports and generics examples previously and construct the complete entity for this example:

entity test is
   port (
      in1, in2 : in bit;
      out1 : out bit
   );
   generic (
      gain : integer := 4;
      time_delay : time := 10 ns
   );
   constant : rpullup : real := 1000.0;
end entity test;

Architecture: model behavior
While the entity describes the interface and parameter aspects of the model, the architecture defines the behavior.

Basic definition of an architecture. There are several types of VHDL architecture and VHDL allows different architectures to be defined for the same entity. This is ideal for developing behavioral, Register Transfer Level RTL and gate Level architectures that can be incor porated into designs and tested using the same test benches.The basic approach for declaring an architecture could be as follows:

architecture behaviour of test is
..architecture declarations
Begin
...architecture contents
end architecture behaviour;

OR

architecture behaviour of test is
..architecture declarations
begin
...architecture contents
end behaviour;

Architecture declaration section
After the declaration of the architecture name and before the begin statement, any local signals or variables can be declared. For example, if there were two internal signals to the architecture called sig1 and sig2, they could be declared in the declaration section of the model as follows:

architecture behaviour of test is

signal sig1, sig2 : bit;

begin

Then the signals can be used in the architecture statement section.

Architecture statement section
VHDL architectures can have a variety of structures to achieve different types of functionality. Simple combinatorial expressions use signal assignments to set new signal values as shown below:

out1 <= in1 and in2 after 10 ns;

Note that for practical design, the use of the ‘after 10 ns’ is not synthesizable. In practice, the only way to ensure correct synthesizable design is to either make the design delay insensitive or synchronous.

The design of combinatorial VHDL will result is additional delays due to the technology library gate delays, potentially resulting in glitches or hazards.

An example of a multiple gate combinatorial architecture using internal signal declarations is given below:

architecture behavioural of test is

signal int1, int2 : bit;

begin

int1 <= in1 and in2;
int2 <= in3 or in4;
out1 <= int1 xor int2;


end architecture behavioural;

Process: the basic functional unit in VHDL
The process in VHDL is the mechanism by which sequential statements can be executed in the correct sequence, and with more than one process, concurrently.Each process consists of a sensitivity list, declarations and statements. The basic process syntax is given below:

process sensitivity_list is
  ... declaration part
begin
  ... statement part
end process;

The sensitivity list allows a process to be activated when a specific signal changes value, for example a typical usage would be to have a global clock and reset signal to control the activity of the process, for example:

process (clk, rst) is
begin
  ... process statements
end process;

In this example, the process would only be activated when either clk or rst changed value. Another way of encapsulating the same behavior is to use a wait statement in the process so that the process is automatically activated once, and then waits for activity on either signal before running the process again. The same process could then be written as follows:

process
begin
   ... process statements
   wait on clk, rst;
end process;

In fact, the location of the wait statement is not impor tant, as the VHDL simulation cycle executes each process once during initialization, and so the wait statement could be at the start or the end of the process and the behavior would be the same in both cases.

In the declaration section of the process, signals and variables can be defined locally as described previously, for example a typical process may look like the following:

process (a) is
  signal na : bit;
begin
  na <= not a;
end process;

With the local signal na and the process activated by changes on the signal a that is externally declared (with respect to the process).

Basic variable types and operators
Constants. When a value needs to be static throughout a simulation, the type of element to use is a constant. This is often used to initialize parameters or to set fixed register values for comparison.

A constant can be declared for any defined type in VHDL with examples as follows:

constant a : integer := 1;
constant b : real := 0.123;
constant c : std_logic := ‘0’;

Signals. Signals are the link between processes and sequential elements within the processes. They are effectively ‘wires’ in the design and connect all the design elements together.

When simulating signals, the simulator will in tur n look at updating the signal values and also checking the sensitivity lists in processes to see whether any changes have occur red that will mean that processes become active.

Signals can be assigned immediately or with a time delay, so that an event is scheduled for sometime in the future (after the specified delay).

It is also important to recognize that signals are not the same as a set of sequential program code (such as in C), but are effectively concurrent signals that will not be able to be considered stable until the next time the process is activated.

Examples of signal declaration and assignment are shown below:

signal sig1 : integer := 0;
signal sig2 : integer := 1;
sig1 <= 14;
sig1 <= sig2;
sig1 <= sig2 after 10 ns;

Variables. While signals are the external connections between processes, variables are the internal values within a process. They are only used in a sequential manner, unlike the concur rent nature of signals within and between processes. Variables are used within processes and are declared and used as follows:

variable var1 : integer := 0;
variable var2 : integer := 1;
var1 := var2;

Notice that there is no concept of a delay in the variable assignment – if you need to schedule an event, it is necessary to use a signal.

Boolean operators. VHDL has a set of standard Boolean operators built in, which are self-explanatory. The list of operators are and, or, nand, not, nor, xor. These operators can be applied to BIT, BOOLEAN or logic types with examples as follows:

out1 <= in1 and in2;
out2 <= in3 or in4;
out5 <= not in5;

Arithmetic operators. There are a set of arithmetic operators built into VHDL which again are self-explanatory and these are described and examples provided in Table 1, below.


Table 1: Basic arithmetic operators

Comparison operators. VHDL has a set of standard comparison operators built in, which are self-explanatory. The list of operators are =,/=,<,<=,> ,and >= . These operators can be applied to a variety of types as follows:

in1 < 1
in1 /= in2
in2 >= 0.4

Shifting functions. VHDL has a set of six built in logical shift functions which are summarized in Table 2 below :

Table 2: Basic logical shift functions

Concatenation. The concatenation function XE ‘VHDL:concatenation’ in VHDL is denoted by the & symbol and is used as follows:

A <= ‘1111’;
B <= ‘000’;
out1 <= A & B & ‘1’; -- out1 = ‘11110001’;

Decisions and loops
If-then-else. The basic syntax for a simple if statement is as follows:

if (condition) then
     ... statements
end if;

The condition is a Boolean expression, of the for m a b or a b. Note that the comparison operator for equality is a single , not to be confused with the double used in some programming languages. For example, if two signals are equal, then set an output high would be written in VHDL as:

if ( a = b ) then
   out1 <= ‘1’;
end if;

If the decision needs to have both the if and else options, then the statement is extended as follows:

if (condition) then
   ... statements
else
   ... statements
end if;

So in the previous example, we could add the else statements as follows:

if ( a = b ) then
    out1 <= ‘1’;
else
    out1 <= ‘0’;
end if;

And finally, multiple if conditions can be implemented using the general form:

if (condition1) then
   ... statements
elsif (condition2)
   ... statements
... more elsif conditions & statements
else
   ... statements
end if; 

With an example:

if (a > 10) then
    out1 <= ‘1’;
elsif (a > 5) then
    out1 <= ‘0’;
else
    out1 <= ‘1’;
end if;

Case. As we have seen with the IF statement, it is relatively simple to define multiple conditions, but it becomes a little cumbersome, and so the case statement offers a simple approach to branching, without having to use Boolean conditions in every case.

This is especially useful for defining state diagrams or for specific transitions between states using enumerated types. An example of a case statement is:

case testvariable is
   when 1 =>
     out1 <= ‘1’;
   when 2 =>
     out2 <= ‘1’;
   when 3 =>
     out3 <= ‘1’;
end case;

This can be extended to a range of values, not just a single value :

case test is
   when 0 to 4 => out1 <= ‘1’;

It is also possible to use Boolean conditions and equations. In the case of the default option (i.e. when none of the conditions have been met), then the term when others can be used:

case test is
    when 0 => out1 <= ‘1’;
    when others => out1 <= ‘0’;
end case;

For. The most basic loop in VHDL is the FOR loop. This is a loop that executes a fixed number of times. The basic syntax for the FOR loop is shown below:

for loopvar in start to finish loop
    ... loop statements
end loop;

It is also possible to execute a loop that counts down rather than up, and the general form of this loop is:

for loopvar in start downto finish loop
    ... loop statements
end loop;

A typical example of a for loop would be to pack an array with values bit by bit, for example:

signal a : std_logic_vector(7 downto 0);
for i in 0 to 7 loop
    a(i) <= ‘1’;
end loop;

While and loop. Both the while and loop loops have an in-determinant number of loops, compared to the fixed number of loops in a FOR loop and as such are usually not able to be synthesized. For FPGA design, they are not feasible as they will usually cause an error when the VHDL model is compiled by the synthesis software.

Exit. The exit command allows a FOR loop to be exited completely. This can be useful when a condition is reached and the remainder of the loop is no longer required. The syntax for the exit command is shown below:

for i in 0 to 7 loop
   if ( i = 4 ) then
       exit;
   endif;
endloop;

Next. The next command allows a FOR loop iteration to be exited, this is slightly different to the exit command in that the cur rent iteration is exited, but the overall loop continues onto the next iteration.

This can be useful when a condition is reached and the remainder of the iteration is no longer required. An example for the next command is shown below:

for i in 0 to 7 loop
   if ( i = 4 ) then
      next;
   endif;
endloop;

To read Part 2 , go to: More essential VHDL commands.
To read Part 3, go to:  Building ALU logic and FSMs.
To read more by Peter Wilson, go to: A simple VGA interface

Used with permission from Newnes, a division of Elsevier. Copyright 2007, from “Design Recipies for FPGAs,” by Peter Wilson. For more information about this title and other similar books, please visit www.elsevierdirect.com.

Dr. Peter Wilson has worked for many years as a senior design engineer in the electronics industry with Ferranti plc and as an EDA technical specialist with Analogy Inc. before joining the Department of Electronics and Computer Science at the University of Southampton, U.K., where he is senior lecturer in Electronics. He is also a consultant in various aspects of embedded systems design, including design and modeling with VHDL, Verilog, Verilog-AMS and VHDL-AMS.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.