Design Article
Guide to VHDL for embedded software developers: Part 2 - More essential commands
Peter Wilson
7/19/2011 10:35 PM EDT
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.
Functions
In this part in the series, the basic approach of defining functions will be described. The simple form of a function is to define a header with the input and output variables as shown below:
Packages
Packages are a common single way of disseminating type and function information in the VHDL design community. The basic definition of a package is as follows:
As can be seen, the package consists of two parts, the header and the body. The header is the place where the types and functions are declared, and the package body is where the declarations themselves take place.
The resulting package declaration would then use the function in the body and the function header in the package header thus:
While procedures, functions and packages are useful in including behavioral constr ucts generally, with VHDL being used in a hardware design context, often there is a need to encapsulate design blocks as a separate component that can be included in a design, usually higher in the system hierarchy.
The method for doing this in VHDL is called a COMPONENT. Caution needs to be exercised with components as the method of including components changed radically between VHDL 1987 and VHDL 1993, as such care needs to be taken to ensure that the cor rect language definitions are used consistently.
Components are a way of incorporating an existing VHDL entity and architecture into a new design without including the previously created model. The first step is to declare the component ñ in a similar way that functions need to be declared. For example, if an entity is called and4, and it has 4 inputs (a, b, c, d of type bit) and 1 output (q of type bit), then the component declaration would be of the for m shown below:
Procedures are similar to functions, except that they have more flexibility in the parameters, in that the direction can be in, out or inout. This is useful in comparison to functions where there is generally only a single output (although it may be an array) and avoids the need to create a record structure to manage the return value.
Although procedures are useful, they should be used only for small specific functions. Components should be used to par tition the design, not procedures, and this is especially true in FPGA design, as the injudicious use of procedures can lead to bloated and inefficient implementations, although the VHDL description can be very compact. A simple procedure to execute a full adder could be of the form:
Next: Page 2
In hierarchical designs, functions are a simple way of encapsulating behavior in a model that can be reused in multiple architectures. Functions can be defined locally to an architecture or more commonly in a package.
Functions
In this part in the series, the basic approach of defining functions will be described. The simple form of a function is to define a header with the input and output variables as shown below:
function name (input declarations) return output_type is
... variable declarations
begin
... function body
end
For example, a simple function that takes two input numbers and multiplies them together could be defined as follows:function mult (a,b : integer) return integer is
begin
return a * b;
end;
Packages
Packages are a common single way of disseminating type and function information in the VHDL design community. The basic definition of a package is as follows:
package name is
...package header contents
end package;
package body name is
... package body contents
end package body;
As can be seen, the package consists of two parts, the header and the body. The header is the place where the types and functions are declared, and the package body is where the declarations themselves take place.
For example, a function could be described in the package body and the function is declared in the package header. Take a simple example of a function used to car ry out a simple logic function:
and10 = and(a,b,c,d,e,f,g,h,i,j)
The VHDL function would be something like the following:function and10 (a,b,c,d,e,f,g,h,i,j : bit) return bit is
begin
return a and b and c and d and e and f
and g and h
and i and j;
end;
The resulting package declaration would then use the function in the body and the function header in the package header thus:
package new_functions is
function and10 (a,b,c,d,e,f,g,h,i,j : bit) return bit;
end;
package body new_functions is
function and10 (a,b,c,d,e,f,g,h,i,j : bit) return
bit is
begin
return a and b and c and d and e \
and f and g and h and i and j;
end;
end;
ComponentsWhile procedures, functions and packages are useful in including behavioral constr ucts generally, with VHDL being used in a hardware design context, often there is a need to encapsulate design blocks as a separate component that can be included in a design, usually higher in the system hierarchy.
The method for doing this in VHDL is called a COMPONENT. Caution needs to be exercised with components as the method of including components changed radically between VHDL 1987 and VHDL 1993, as such care needs to be taken to ensure that the cor rect language definitions are used consistently.
Components are a way of incorporating an existing VHDL entity and architecture into a new design without including the previously created model. The first step is to declare the component ñ in a similar way that functions need to be declared. For example, if an entity is called and4, and it has 4 inputs (a, b, c, d of type bit) and 1 output (q of type bit), then the component declaration would be of the for m shown below:
component and4
port ( a, b, c, d : in bit; q : out bit );
end component;
Then this component can be instantiated in a netlist for m in the VHDL model architecture:d1 : and4 port map ( a, b, c, d, q );
Note that in this case, there is no explicit mapping between port names and the signals in the current level of VHDL, the pins are mapped in the same order as defined in the component declaration. If each pin is to be defined independent of the order of the pins, then the explicit port map definition needs to be used:d1: and4 port map ( a => a, b => b, c => c, d => d, q => q);
The final thing to note is that this is called the default binding. The binding is the link between the compiled architecture in the current library and the component being used. It is possible, for example, to use different architectures for different instantiated components using the following statement for a single specific device:for d1 : and4 use entity work.and4(behaviour) port map
(a,b,c,d,q);
or the following to specify a specific device for all the instantiated components:for all : and4 use entity work.and4(behaviour) port
map (a,b,c,d,q);
ProceduresProcedures are similar to functions, except that they have more flexibility in the parameters, in that the direction can be in, out or inout. This is useful in comparison to functions where there is generally only a single output (although it may be an array) and avoids the need to create a record structure to manage the return value.
Although procedures are useful, they should be used only for small specific functions. Components should be used to par tition the design, not procedures, and this is especially true in FPGA design, as the injudicious use of procedures can lead to bloated and inefficient implementations, although the VHDL description can be very compact. A simple procedure to execute a full adder could be of the form:
procedure full_adder (a,b : in bit; sum, carry : out bit)
is
begin
sum := a xor b;
carry := a and b;
end;
Notice that the syntax is the same as that for variables (NOT signals), and that multiple outputs are defined without the need for a return statement.
Next: Page 2
Navigate to related information



YEE_HAA
7/22/2011 12:29 AM EDT
?
Sign in to Reply