Navigating VHDL

Introduction

This chapter provides an introduction to the basic language constructs in VHDL; defining logic blocks, structural, dataflow and behavioral descriptions, concurrent and sequential functionality, design partitioning and more.



Jump to table of Contents.

Return to VHDL Top Document.

Jump to Zen & the Art of VHDL



Hypertext Table of Contents

The following hypertext list is a table of contents for this document. The user can navigate to any section of this document by "Pointing and Clicking" on any of the blue highlighted text. This will automatically direct the user to that particular subsection.



Aliases.

Arrays - Indexed & Slices.

Attributes .

Attribute, definition of.

Attribute Useage.

Pre-Defined Attributes.

Blocks

Component Instantiation.

Constants.

Definitions of VHDL terms.

Entities and Architectures.

Architecture, Defintion of.

Entity, Definition of.

Entities Example

Enumeration Types.

Functions and Procedures.

Generics.

Generic, Definition of.

Iterative Statements.

Literals.

Logical Operators.

Loops and Loop Variables.

Objects.

Packages.

Package, definition of.

Ports.

Processes.

Process, definition of.

Process Example.

Signals.

Statements.

Assignment Statements.

Conditional Statements.

Selection Statements.

Syntax & Semantics.

Variables.

Return to top of document.



Definitions.

Architecture

All entities that can be simulated have an architectural description. The architecture describes the behavior of the entity. A single entity can have multiple architectures. One architecture might be behavioral, while another could be a structural description of the design. Jump to Examples of Architecture.

Attribute.

An attribute is data that is attached to VHDL objects or predefined data about VHDL objects. Examples are the current drive capability of a buffer, or the maximum operating temperature of a device. Jump to section on Attributes.

Bus.

A bus is a group or signals or particular method of communication used in hardware design. In VHDL a bus is a special kind of signal that my have its drivers turned off or tri-stated. Go to VHDL Document #2, see section on Busses.

Component.

A definition of the interface to a sub-module, rather like a "socket", to which an entity may later be bound.

Concurrent Statements.

Statements within an architecture which execute concurrently in simulated time, independently of their order.

Configuration.

Defines the "binding" of each component instance to an entity, and each entity to an architecture. Can be defined using a configuration library unit or from within an architecture.

Design File.

A text file containing source code for one or more design units.

Design Library.

A data structure containing analyzed design units (library units).

Design Unit.

A VHDL module contained in a design file, consisting of the source code for a library unit preceded by any required Library or Use clauses. Analysis of a design unit defines the corresponding library unit in a design library.

Driver.

This is a source of a signal. If a signal is driven by two tri-state buffers, if both buffers are active the signal has two drivers.Go to VHDL Document #2, see sections of Buffers.

Entity.

All designs are expressed in terms of entities. An entity is the basic building block in a design. The uppermost level of the design is the top level entity. If the design is hierarchical, then the top-level description will have lower-level descriptions contained in it. These lower level descriptions will be lower level entities contained in the top level description of the design. A library unit which describes the external interface of a hardware module.Jump to Examples of Entities.

Function.

A group of sequential statements which can be "called" from different places in a model, reading one or more input parameters and returning a single value.

Generic.

A generic is VHDL's term for a parameter that passes information to an entity. For instance, if an entity is a gate level model with a rise time and fall time delay, values for those delays could be passed into the entity with generics. Jump to section on Generics

Library Unit.

An analyzed design unit. The five types of library unit are: entity, architecture, package, package body and configuration.

Overloading.

The definition of multiple functions or procedures with the same name, which operate on different parameter combinations or types.

Package.

A package is a collection of commonly used data types and subprograms used in a design. Think of a package as a toolbox that contains the tools used to build designs.Jump to Examples of Packages.

Package Body.

A secondary unit associated with a package, whose main purpose is to contain the full code for any functions or procedures which have been declared in the associated package.

Primary Unit.

A library unit which can exist in a design library. The primary design units are: entity, package and configuration.

Procedure.

A group of sequential statements which can be "called" from different places in a model. It may have parameters of modes in, out or inout.

Process.

A concurrent statement which contains a collection of sequential statements and which can interact concurrently with other concurrent statements. A process is the basic unit of execution in VHDL. All operations that are performed in the simulation of a VHDL description are broken down into single or multiple processes. Jump to section on Processes.

Resolution.

The determination of the value of a signal when it is simultaneously driven by more than one source.

Scope.

The region of VHDL code within which a declared item (e.g. a constant) may be used.

Secondary Unit.

A library unit which defines a body associated with a primary unit which has already been analyzed into the same design library. The secondary units are architecture (associated with an entity) and package body (associated with a package).

Sequential Statements.

Statements which are executed in the order they are written, as with "conventional" software.
Return to top of document.



Entities & Architectures

The basic building blocks in VHDL are Entities and Architectures. An Entity describes the boundaries of the logic block. Its ports and generics are declared here. An Architecture describes the contents of the logic block in structural, dataflow, and behavioral constructs.

Entities Example #1.
 
 
         entity small_block is                    
 
                 port ( a ,b, c : in bit;        
 
 
                         o1 : out bit;               
 
 
                         o2 : out bit                
 
 
                      );                                    
 
 
         end small_block;                            
 
 
 
         architecture vhdl_example of small_block is 
 
 
                 signal s : bit;                        
 
 
         begin                                           
 
 
                 o1 <= s or c;                           
 
 
                 s <= a and b;                           
 
 
                 o2 <= s xor c;                          
 
 
         end vhdl_example;                           
 
 

Return to top of document.

This VHDL description shows the implementation small_block. The port list is given with a direction ( in this case in or out ), and a type (bit) for each port. The entity's name is small_block. There can be multiple architectures per entity, but always only one architecture is executed. By default, the last defined architecture is implemented.

The architecture describes the contents of small_block. The architecture starts with a declarative region; in this case, the internal signal s is declared. It also has the type ( bit ), just like the ports in the entity.

A signal is another form of an object in VHDL. All objects and expressions in VHDL are strongly typed. That means that all objects are of a defined type and the VHDL compiler issues an error message if there is a type mismatch. For example, you can not assign an integer signal to a bit.

The architecture contents starts after the begin statement. This is called the dataflow environment. Please refer to the previous example Go to Example # 1. All statements in the dataflow environment are executed concurrently, and thus the order of the statements is irrelevant. This is why it is valid to use s before s is assigned anything. Assignment of a value to a signal is done with the <= sign. In the first statement, o1 is assigned the result of s or c. or is a predefined operator.

Return to top of document.


Processes

Processes are sequentially executed statements, as opposed to dataflow environment, where all statements are executed concurrently. In a process, the order of the statement does matter. In fact processes resemble the sequential coding style of high level programming languages. Also, processes offer a variety of powerful statements and constructs that make them very suitable for high level behavioral descriptions.

A process can be called from the dataflow area. Each process is a sequentially executed program, but all processes run concurrently. In a sense, multiple processes resemble multiple programs that can run simultaneously. Processes communicate with each other via signals that are declared in the architecture. Also the port defined in the entity can be used in the processes.

Process Example #1
 
    entity experiment is                          
 
 
         port (                                         
 
 
             source : in bit_vector ( 0 to3) ;
  
 
             ce : in bit;                            
 
 
             wrclk : in bit;                         
 
 
             selector : in _vector( 0 to 1);         
 
 
             result : out bit );                     
 
 
     end experiment;                                 
 
 
 
     architecture vhdl_example of experiment is           signal int_reg : bit_vector( 0 to 3);
 
 
         begin -- dataflow environment         
 
 
               writer : process -- process statement 
 
 
                    -- declarative region ( empty here )    
 
 
                 begin -- sequential environment     
 
 
                            -- sequential clocked statements
 
 
                          wait until wrclk'event and wrclk = '1' ;
 
 
                                  if (ce = '1') then    
                                 int_reg <= source ; 
 
                                  end if ;                         
 
 
                 end process writer;                              
 
 
                                                                        
 
               reader : process ( int_reg, selector) 
 
 
                    -- process statements with sensitivity list. 
 
 
                    -- declarative region ( empty here)          
 
 
                 begin -- sequential ( not-clocked) statements.
 
 
                         case selector is                
 
 
                                  when "00" => 
 
 
                                            result <= int_reg(0);
 
 
                                  when "01" =>  
 
 
                                            result <= int_reg(1);
 
 
                                  when "10" =>  
 
 
                                            result <= int_reg(2);
 
 
                                  when "11" =>  
 
 
                                            result <= int_reg(3);
 
 
                         end case;                           
 
 
                end process reader ;                        
 
 
         end vhdl_example;
 
 
 
This example describes a circuit that can load a source vector
of 4 bits, on the edge of a write clock (wrclk ),
store the value internally in the register ( int_reg
) if a chip enable ( ce ) is active while
it produces on bit of the register constantly ( not synchronized
). The bit is selected by a selector signal of 2 bits.
 
The description consists of two process, one to write the value
into the internal register, and one to read from it. The two processes
communicate via the register value int_reg.
 
The first process ( writer) includes a wait
statement. The wait statement causes the process
to execute only if its condition is true. ( A further explanation
is given later in the chapter.) In this case, the wait
statement waits until a positive edge occurs on the signal wrclk
(when "00" => result <= int_reg(0; expression
wrclk'event and wrclk = '1' ). Each time the edge
occurs, the statements below the wait statements are
executed. In this case, the value of the input signal source
is loaded into the internal signal int_reg only if ce
is '1'. If ce is '0', int_reg retains
it's value. In synthesis terms, this translates into a D-flipflop,
clocked on wrclk, and enabled by ce. 
 
The second process (reader) does not have a waitstatement.
Instead, it has a sensitivity list, with the signal int_reg
and selector there. This construct defines that
the whole process is executed each time either int_reg or
selector changes. If the process is executed,
the output signal result gets updated depending upon
the values of int_regand selector. Note
that this leads to combinatorial behavior, since result only
depends on int_reg and selector, and each time
either of these signals changes, result get updated.
 
A process has an optional name ( in this case writer
and reader ), as sensitivity list OR a wait statement, and
a declarative region where signals, variable, functions, etc.
can be declared which are used only within the process.
The next section of the process is the sequential
environment where all statements are made. Each statement is executed
sequentially, as in a programming language.
 
Not all constructs, or combinations of constructs, in a process
lead to behavior that can be synthesized into logic. More information
about synthesizable VHDL constructs is given later.
 
Return to top of document.

   

Literals.

 
 
Constant values in VHDL are given in literals. Literals
are lexical elements. Below is an overview, with examples given
for each type of literal,
 
           Character Literals: '0' 'X' 'a' '%' #
 
           String Literals: "1110100" "XXX" "words in quotes"
 
        
           Bit String Literals: B"0010_0001" X"5f" O"63_07"
 
           
           Decimal Literals: 27 4.25
 
           Physical Literals 2 nS 5.0 V 15 pF
 
           Identifiers: Words that Identify Something.
 
 
 
Literals are used to define types and as constant values in expressions.
This list provides a brief description of their function in VHDL
which will be more clear after the descriptions of types and expressions.
 
 
 
Bit string literals are a special form of string literals. They
contain an array of the characters '0' and '1', and are preceded
by one of three representation forms. Bis the
bit representation ( 0 or 1 allowed ), X is the hexadecimal
representation ( 0 to F allowed ), and O is the octal representation
( 0 to 7 allowed). X"5F" is exactly the same as B"01011111"
which is again the same as the string literal "01011111".
 
 
 
Identifiers can be enumeration literals. They are case-insensitive,
like all identifiers in VHDL. Their use becomes more clear with
the discussion of "types".
 
Return to top of document.

   

Syntax and Semantics

 

 
 
A type is a set of values. VHDL supports a large set
of types, but we will only concentrate on those that are useful
for synthesis. An example of a typeis the VHDL
predefined type bit. It consists of only two values: the character
literals '0' and '1'. In VHDL syntax, the definition of the bit
type is:
 
           type bit is ('0' , '1');
 
 
 
This type indicates that all objects of type bit can
only contain the values '0' or '1'. The VHDL compiler issues an
error if you try to the value 'a' to an object of this type.
 
In VHDL there are bound and unbound types. A bound type has a
defined number of values, and unbound type does not. As an example
of a bound type is the definition of an 8 bit array ( a vector)
of bits:
 
        type eight_bit_vector is array ( 0 to7 ) of bit;
 
 
 
All objects of type eight_bit_vector should have 8 bit
values. On the other hand, we could define an unbound, general
array of bit type:
 
         type bit_vector is array ( integer range <>)of bit;
 
 
 
The syntax <> tells the compiler to reserve space for this
array, but its range has not yet been defined. Its range could
be dependent upon logical constructs created in another section
of code.
 
The type bit_vector is also a predefined type in VHDL,
and it's definition is the same as the one shown above. Also see
Predefined Types.
 
The size of bit_vector is not yet defined, but it can
be used to define other types that are bounded, or objects of
this type can have "bound" on the type. A type with
a bound is called a subtype. For example, we bound
the bit_vectortype and create a 10 bit vector
of bits with the following statement.
 
          subtype ten_bit_vector is bit_vector ( 0 to9);
 
 
 
For logic synthesis all objects should be bounded to assure that
their value can be implemented in a finite amount of space.
 
Another predefined type is an "integer", which
contains all integer values. Officially, VHDL defines that at
least the range of -2147483647 to +2147483647 should be contained
in an integer. Integers can also be bounded.
 
           subtype small_integer is integer range 0 to255;
 
 
 
defines an integer that only allows the values 0 to 255.
 
Return to top of document.

   

Predefined Types.

 

 
 
VHDL pre-defines a number of types. Listed below are the ones
which are important for logic synthesis.
 
           type bit  is ('0', '1');
           type bit_vector is array (integer range<>) of bit;
           type integer  is range MIN  to MAX;
           subtypepositive  is integer range1  to MAX;
           subtype natural  is integer range 0  to MAX;
           type boolean  is ( TRUE, FALSE );
 
 
 
Additionally the IEEE 1164 Standard for VHDL specifies a 9-valued
logic. The meanings of these different types is given below:
 
           'U' Uninitialized
           'X' Unknown
           '0' Forced Low
           '1' Forced High
           'Z' High Impedance
           'W' Weak Unknown
           'L' Weak Low
           'H' Weak High
           '-' Don't Care
 
 
 
The weak values on a node can always be overwritten by a forcing
value. The high impedance state can always be overwritten by all
other values.. Most of these values are meaningful for simulation
purposes only. Some restrictions apply of you want to use these
values for synthesis of logic. Only the values '0', '1', 'X',
'-', and 'Z' have a useful meaning for synthesis.
 
Some examples of IEEE 1164 statements are
 
type std_logic is ('U', 'X','0', '1','Z', 'W', 'L',
'H', '-');
 
 
 
type std_logic_vector is array (natural range <>)
of std_logic;
 
 
 
subtype std_logic is resolution_func_std_logic;
 
 
 
type std_logic_vector is (natural range <>)
of std_logic;
 
 
 
The identifier resolution_func is a function that defines
which value should be generated in case multiple values are assigned
to an object of the same type. This is called the resolution function
of the type. NOTE: Resolution functions are ignored by logic synthesis,
since simultaneous assignment of multiple values to one object
are not synthesizeable.
 
Return to top of document.


   

Enumeration Types

 

 
 
It is possible to define types yourself. VHDL supports enumerated
types with character literals and with identifiers. As an example
of enumerated type with character values is the std_logic
type.
 
Type declarations for synthesis are done to either define
a type whose objects will represent a single bit value
( like bit, or std_logic ) or to define a type
that will represent the states of a state machine.
 
Return to top of document.

   

Objects

 

 
 
Objects in VHDL: signals, variable, constants, ports, loop
variables, generics; can contain values. Values can be assigned
to objects, and these values can be used elsewhere in the description
by using the object in an expression. All objects except loop
variables have to be declared before they are used. This section
describes the various objects in VHDL and their semantics.
 
Return to top of document.

   

Signals

 
 
Signals represent the wires in a logic circuit. Here are a few
examples of signal declarations.
 
 
         signal binary_5 : bit_vector( 0 to 5 ) := B"00000" ;
 
 
         signal aux : bit ;           
 
 
         signal max_value : integer ; 
 
 
 
Signals can be declared in all declarative regions in VHDL except
for functions and procedures. The declaration assigns a name to
the signal ( binary_5 ) ; a type, with or without
a range restriction ( bit_vector ( 0 to 5 )); and optionally,
 
 an initial (constant) value. Initial values on signals are
usually ignored by logic synthesis. But simulator will recognize
it, for behavioral simulation. For further information on
initial values of signals see section onPredefined Types.
Also Jump to VHDL Document #3, section of General VHDL Language Restrictions.
 
 
Signals can be assigned values using an assignment statement (
i.e. aux <= '0' ; ) . If the signal is an array type,
elements of the signal's array can be accessed and assigned
using indexing or slicing. Jump to Indexed Arrays.
 
 
Assignments to signals are not immediate, but scheduled to be
executed after a delay, (this is the essential difference between
variables and signals). This is discussed in detail later. Jump to Assignment Statements.
 
 
Return to top of document.

   

Constants

 

 
 
Constants cannot be assigned a value after their declaration.
Their only value is the initial constantvalue.
Initialization of a constant is required. An example
of declaring a constant is:
 
   constant ZEEE_8 : std_logic_vector ( 0 to7 ) := "ZZZZZZZZ" ;
 
 
 
This assigns a tri-state value to the vector named "ZEEE_8".
 
Return to top of document.

   

Variables

 

 
 
Variables cannot be declared or used in the dataflow areas or
in packages, but only in processes, functions and procedures.
An example of declaring a variable is
 
   variable temp : integer range 0 to15 := 5 ;
 
 
 
Assignment to a variable are immediate. This effect is
an essential difference between variables and signals. This is
discussed in Assignment Statements.
 
 
The initial assignment to a variable is optional. The
initial assignment to a variablein
a process is usually ignored by logic synthesis. Jump to VHDL Document #3, section on General VHDL Language Restrictions.
 
 
Return to top of document.

   

Ports

 
 
A port is an interface terminal of an entity.
A port represents an ordinary port in a netlist
description. Ports in VHDL are just like other objects; they are
typed and can have an initial value. In addition, a port
has a "direction". This is a property that indicates
the possible information flow through the port. Possible
directions are in, out, inout,and
buffer,where inout and buffer
indicate a bidirectional functionality. A buffer is
the synthesis equivalent of tri-state driver (i.e. 74244), two
signals paths may diverge from a pin in an FPGA, etc. the output
path has a buffer attached to it and this buffer will be tri-stated
or high impedance, while the input signal path is in use. An INOUT
is analogous to a 74HC245, a bidirectional buffer driver chip.
 
   entity adder is
 
        port ( 
 
                   input_vector : in bit_vector ( 0 to 7 );
 
 
                    output_vector : out bit_vector (0 to 7 ) 
 
                   );  
 
 
  end adder;
 
 
 
After declaration, a port can be used in the architecture
of the entity as if it were a normal signal,
 
Return to top of document.

   

Generics

 
 
A generic is a property of an entity. A generic
is useful in coding because you can define the property of the
generic in one place in your code. If you need to make a change
later, i.e. change the width of the bus for instance, you would
only have to change the size assignment for it. If did not use
one, you would have find every single instance of the bus in the
code and edit the change in every line. ( and there's no guarantee
that you change them all correctly either.)
 
A good example of a generic is the definition of the
size of the interface of the entity. Generics
are declared in a generic list.
 
   entity increment is 
 
 
            generic (size : integer := 8 );
 
 
                  port (                          
 
 
                            ivec : in bit_vector ( 0 tosize-1 );
 
 
                            ovec : out bit_vector ( 0 to size-1)
 
 
                           ) ; 
 
 
    end increment ;
 
 
 
The generic 'size' can be used inside the 
entity ( i.e. to define the size of the ports ) and
in the architecture that matches the entity.
In this example, the generic 'size' is defined as an integer with
an initial value 8. The sizes of the input and output ports of
the entity increment are set to be 8 bits unless the value of
the generic is overwritten by a generic map statement
in the component instantiation of the entity. 
 
   inst-1 : increment generic map (SIZE =>16 )
 
        port map ( ivec => invec, ovec => outvec);
 
 
 
Here, a 16 bit incrementer is instantiated, and connected to the
signal invec and outvec. The section
on instantiation explains more about this. Jump to section on Component Instantiation.
 
 
Return to top of document.

   

Loop Variables

 

 
 
A loop variable is a special object in the sense that it does
not have to be declared. The loop variable gets its type and value
from the specified range in the iteration scheme.
 
   for I in 0 to 5 loop 
 
 
      a( I ) <= b( I ) and ena ; 
 
 
    end loop ;
 
 
 
In this code fragment, I becomes an integer with the values 0,1,2,,,,5
respectively, when the loop statements are executed 6 times. A
loop variable can only be used in an expression, and there can
be no assignments to the loop variable. For logic synthesis,
the range specified for the loop variable must be a compile-time
constant, otherwise the construct is not synthesizeable; the warning
message that the process runs on forever will be generated.
 
Return to top of document.

   

Slices and Indexed Arrays.

 

 
 
Objects can be defined as arrays. An array is a set of
elements. To access the individual elements, for instance to assign
a value to the element, or if an element is used in an expression,
VHDL supports the indexed array construct. The type of an index
value of the array is the type of an element of the array.
 
 
    signal an_array : bit_vector ( 0 to 8 ) ;
 
 
    signal msb_bit : bit ;                   
 
 
            .......                                        
 
 
            an_array(5) := '0' ;                           
 
 
            msb_bit <= some_array (0) ;
 
 
 
Also, parts of the array can be selected using the sliced array
construct. For example:
 
   signal an_array : bit_vector ( 0 to 8 ) ;      
 
 
    signal a_vector : bit_vector ( 3 downto 0) ; 
 
 
    signal a_slice  : bit_vector ( 3 to 0 ) ;  
 
 
            ........                                         
 
 
            an_array(1 to 4 ) <= a_vector:         
 
 
            an_array( 8 downto 5 ) <= "0000" ; 
 
 
                    --wrong direction for slice.
 
 
 
In the last statement, the direction of the slice range is downto,
while the index range of a_vector was defined to be ascending
to. In this case, an_array( 8 downto 5 ) would
cause the VHDL compiler to issue an error.
 
Indexed arrays resemble a selection from the array. If the index
is a constant, the VHDL compiler will connect a single "wire"
to the right logic element. VHDL support variable indexing of
arrays, where the index can be a non-constant expression. Indexes
of arrays do not have to be integers. An index could also be an
enumerated type.
 
Return to top of document.


   

Statements

 

 
 
This section briefly discusses the basic statements that can be
used in VHDL descriptions.
 
Conditional Statements
 
 
 
These are if - then ,elsif - then
and else types of statements.
 
   signal a : integer ;                        
 
 
         signal output_signal, x, y, z : bit _vector( 0 to3 ) ;
 
 
                    .......
 
 
           output_signal <= x ;
 
 
         elsif a = 2 then                   
 
 
                 output_signal <= y ;                  
 
 
         elsif a = 3 then                   
   
 
                 output_signal <= z ;                  
 
 
         else                                      
 
 
                 output_signal <= "0000" ;   
 
 
         end if ;                                  
 
 
 
This code fragment describes a multiplexer function, implemented
with an if-then-else statement. This statement can only be used
in a sequential environment, such as a process. procedure, or
a function. See sections on Multiplexers in Zen & the Art of VHDL.
and also Tips & Tricks documents
 
The same functionality in a dataflow environment is accomplished
with the use of the conditional signal assignment statement:
 
   signal a : integer ;
 
 
   signal output_signal x, y, z : bit_vector ( 0 to3 );
 
 
            .....                                                    
 
 
            output_signal <= x when a = 1 else   
 
 
                   y when a = 2 else
 
 
                   z when a = 3 else 
 
 
                          "0000" ; 
 
 
 
Return to top of document.

   

Selection Statements.

 

 
 
If many conditional clauses have to be performed on the same selection
signal a case statement is a better solution than the
if-then-else construct.
 
 
    signal output_signal x, y, z : bit_vector ( 0 to3 );
 
 
                    ......                                            
 
 
         case selection is
 
 
                 when "0010" => 
 
 
                            output_signal <= x;
 
 
                 when "0100" =>
 
 
                            output_signal <= y;
 
 
                 when "1000" =>
 
 
                            output_signal <= z; 
 
 
                 when "1010" | "1100" | "0110"=> 
 
 
                            output_signal <= x and y and z ;
 
 
                 when others =>                      
 
 
                            output_signal <= "0000"
 
 
         end case ;
 
 
 
The |  ( logical OR ) sign indicates that this particular case
has to be entered if any of the given choices is true Each
case can contain a sequence of statements.
 
The case statement can only be used in a sequential environment.
In the dataflow environment, the selected signal assignment
statement has the equivalent behavior:
 
   signal output_signal , my_selection, x, y, z : bit_vector( 0 to 3 ) ;
 
 
                    .....
 
 
         with my_selection select            
 
 
             output_signal <= x when "0010" ,
 
 
                                 y when "0100" ,
 
 
                                 z when "1000" ,
 
 
                     x and y and z when "1010" | "1100"| "0110" 
 
 
                   "0000" when others ;
 
 
 
Return to top of document.

   

Iterative Statements

 

 
 
In many cases, especially with operations on arrays, many statements
look alike, but differ only on minor points. In that case, you
might consider using a loop statement.
 
   signal result, input_signal : bit_vector ( 0 to5 ) ;
 
 
         signal ena : bit ;
 
 
                    .....                
 
 
         for i in 0 to 5 loop  
 
 
                 result( i ) <= ena and input_signal( i ) ;
 
 
         end loop ;
 
 
 
In this code fragment, each bit of an input signal is "anded"
with a single bit enable signal, to produce an output array signal.
The loop variable i does not have to be declared.
It holds an integer value since the loop range is an
integer range. For useful examples of iterative statements and
"for loops" jump to Process Examples, in Zen & the Art of VHDL.
 
The loopstatement can only be used inside sequential
environments. It's equivalent statement in the dataflow environment
is the "generate" statement:
 
   signal result, input_signal : bit_vector ( 0 to5 ) ;
 
 
         signal ena : bit ;
 
 
            .....
 
 
                    G1 : for i in 0 to 5 generate  
 
 
                         result( i ) <= ena and input_signal( i ) ;
 
 
                    end generate ;
 
 
Note that the generate statement is preceded by a label
( G1). A label is required in the generate statement
but is optional in the loop statement.
 
Return to top of document.

   

Assignment Statements.

 

 
 
Assignments can be done to signals, port,and
variables in VHDL. Assignments to signals, and
ports are done with the <= operator.
 
   signal o, a, b : std_logic_vector ( 0 to 5) ;
 
 
                    .....
 
 
            o <= a xor b ; 
 
 
 
In this code fragment "o" gets assigned the value of
the vector-XOR (bit by bit) of vectors "a" and "b".
The type of the object on the left hand side of the assignment
should always match the type of the value on the right hand side
of the assignment.. Signal assignments can be used both
in dataflow and sequential environments. For information on std_logic_vector
jump to section on Packages 
 
Assignment to variablesare done with the := sign.
 
   variable o  : std_logic_vector ( 0 to 5 ) ;
 
 
         signal a, b : std_logic_vector ( 0 to 5 );
 
 
                            .....
 
 
                    o := a and not b ;
 
 
 
Variable assignments can only be used in sequential environments.
Typeson left and right hand sides of the := sign
must match. Otherwise will get misleading compiler results.
 
There is one important difference between assignments to signals
and assignments to variables: when the values are updated. The
value of a variable in a variable assignment is updated
immediately after the assignment. The value of a signal in
a signal assignment is not updated immediately, but gets "scheduled"
a until after a delta (delay) time. This delay time is not related
to actual time, but is actually a characteristic of the simulator
used. This behavior of the signal assignment does not have any
effect for signal assignments in a dataflow environment, since
assignments are done concurrently there. However, in a process,
the actual value of the signal changes only after the
complete execution of the process.
 
The following example illustrates this effect. It shows the description
of a multiplexer that can select one bit out of a four bit vector
using two select signals.
 
   entity mux is                        
 
 
         port ( s1, s2 : in bit ;
 
 
                    inputs : in bit_vector ( 0 to 3 );
 
 
                    result : out bit 
 
 
                    ) ;
 
 
    end mux ;
 
 
 
    architecture wrong_way of mux is        
 
 
         begin
 
 
             process ( s1, s2, inputs )
 
 
                  signal muxval : integer range 0 to3 ;
 
 
             begin   
 
 
                 muxval <= 0 ;
 
 
                 if ( s1 = '1' ) then muxval <= muxval +1;
 
 
                         if ( s2 = '1' ) then muxval <= muxval +2;
 
 
                            -- use muxval as index of array 'inputs'
 
 
                            result <= inputs ( muxval) ;
 
 
                         end if;
 
 
                 end if;
 
 
          end process;
 
 
    end wrong_way ;  
 
 
 
This description does not behave as intended. The problem
is because muxval is a signal; the value of muxval
is not immediately set to the value defined by bit a
and b. Instead, muxval still has the same value
it had when the process started when the case statement is executed.
All assignments to muxvalare scheduled until
after the process finishes. This means that muxval still
has the value it got from the last time the process was executed,
and that value is used to select the bit from the input vector.
 
The solution to this problem is to make muxval a variable.
In that case, all assignments done to muxval are immediate,
and the process works as intended.
 
   entity mux is
 
 
         port (s1, s2 : in bit :
 
 
                    inputs : in bit_vector ( 0 to 3 );
 
 
                    result : out bit 
 
 
                    ) ;
 
 
    end mux ;  
 
 
   architecture right_way of mux is
 
 
         begin
 
 
            process ( s1, s2, inputs )
 
 
                 variable muxval : integer range 0 to3 ;
 
 
            begin
 
 
                 muxval := 0 ;
 
 
                 if (s1 = '1' ) then muxval := muxval+1;
 
 
                      if (s2 = '1' ) then muxval := muxval+2;
 
 
                            -- use muxval as index of array 'inputs'
 
 
                            result <= inputs ( muxval ) ;
 
 
         end process ;
 
 
    end right_way;
 
 
As a general rule, if you use signal assignments in processes,
do not use the value of the signal after the assignment,
unless you explicitly need the previous value of the signal.
Alternatively, you can use a variable instead.
 
Return to top of document.

   

VHDL Operators.

 

 
 
VHDL predefines a large number of operators for operations on
objects of various types. The following is an overview:
 
Relational operators an ALL types ( predefined or not):
 
           =, /=, <, <=, >, >=
 
 
 
Logical operators on pre-defined types BIT and BOOLEAN:
 
           AND, OR, NAND, NOR, XOR, NOT     
 
 
 
Arithmetic operators on all integer types:
 
           +, -, *, /, **, mod, rem, abs 
 
 
 
Concatenation of elements into an array of elements:
 
           &, (,,,,)
 
 
 
Relational operators operate on any type. The
basis of comparing two values is derived from the order of definition.
For example, in the std_logictype the value 'U'
is smaller than the value '1' because 'U' is defined first in
the order of values in the type. Jump to section on Predefined Types
for more information on 'U', 'X', '1', '0', 'Z', etc. The comparison
of two arrays is accomplished by comparing each element of the
array. The left most element is the most significant one for comparisons.
 
        signal a : bit_vector ( 7 downto 0 ) ;
 
 
         signal b : bit_vector ( 5 to 9 ) ;
 
 
 
In this example, a( 7 )is the most significant
bit for comparisons with vector a, and b( 5 )
is the most significant bit for comparisons with vector b.
 
 
Logical operators work in a straightfoward manner and do the appropriate
operation of types BIT and BOOLEAN, and also for one-dimensional
arrays of BIT and BOOLEAN. In the latter case, the logical operation
is executed on each element of the array. The result is an array
with the same size and  type as the operands.
 
Arithmetic operators work on integers and on all types
derived from integers. Concatenation operators can group elements
of the same type into an array of that type.
Consider the following examples:
 
   signal a, b, c : bit ;
 
 
    signal x : bit_vector( 5 downto 0 ) ;
 
 
    signal y : bit_vector ( 0 to 3 );
 
 
                 ,,,,,                             
 
 
                    -- using concatenation operator
 
 
            x <= a & b & c & B"00" & '0';
 
 
                    -- using an aggregate
 
 
            y <= ('1', '0', b, c ); 
 
 
 
This description is the same as the following one:
 
   signal a, b, c : bit ;    
 
 
    signal x: bit_vector( 5 downto 0 ) ;
 
 
    signal y : bit_vector ( 0 to 3 );
 
 
            ,,,,,
 
 
         x( 5 ) <= a ;
 
 
         x( 4 ) <= b ;
 
 
         x( 3 ) <= c ;
 
 
         x( 2 downto 1 ) <= "00" ;
 
 
         x(0) <= 0;
 
 
         y( 0 ) <= '1' ;
 
 
         y( 1 ) <= '0' ;
 
 
         y( 2 ) <= b ; 
 
 
         y( 3 ) <= c ; 
 
 
 
The aggregate operator in VHDL is especially useful when assigning
a vector of unknown or large size:
 
   signal o : bit_vector ( 0 to 255 );
 
 
                    ,,,,
 
 
            o <= (0 => '1', others => '0' );
 
 
 
 
In this example, o( 0 ) is assigned '1' and all other elements
of o (independent of it's size) get the value '0'.
 
Return to top of document.

   

Attributes.

 

 
 
In VHDL, attributes can be set on a variety of objects, such as
signals and variables, and many other
identifiers, like  types, functions, labels etc.
 
An attribute indicates a specific property of the signal,
and is of a defined type. Using attributes at the right places
creates a very flexible style of writing VHDL code. An example
of this is given at the end of this section Jump to Attribute Example.

 
Predefined VHDL Attributes.
 
 
VHDL pre-defines a large set of attributes for signals. The following
example shows the definition of two vectors and the values of
the VHDL predefined attributes for them.
 
   signal vector_up : bit_vector ( 4 to 9 ) ;
 
 
    signal vector_down : bit_vector (25 downto0 ) ;
 
 
                    ,,,,,
 
 
            vector_up'LEFT -- returns integer 4
 
 
            vector_down'LEFT -- return integer 25 
 
 
            vector_up'RIGHT -- returns integer 9
 
 
            vector_down'RIGHT -- returns integer 0
 
 
            vector_up'HIGH -- returns integer 9   
 
 
            vector_down'HIGH -- returns integer 25
 
 
            vector_up'LOW -- returns integer 4
 
 
            vector_down'LOW -- returns integer 0
 
 
            vector_up'LENGTH -- returns integer  6
 
 
            vector_down'LENGTH -- returns integer 26
 
 
            vector_up'RANGE -- returns range 4 to 9 
 
 
            vector_down'RANGE -- returns range 25 to 0
 
 
            vector_up'REVERSE_RANGE -- returns range 9 to 4
 
 
            vector_down'REVERSE_RANGE -- returns range 0 to 25 
 
 
 
These attributes are the most important ones that reveal the properties
of vectors. The attributes do not have to be written in capitals;
VHDL is case-insensitive for identifiers.
 
An important predefined attribute for synthesis is EVENT
attribute. It's value reveals the edges or transitions of signals.
Information about the EVENT attribute can be found at
VHDL Document #2, Flip-Flops, and Event Attributes
 
 
Return to top of document.

   

Attribute Usage.

 

 
 
To indicate where attributes in a VHDL description would be useful,
consider the following example:
 
   entity masked_parity is
 
 
         port ( source : in bit_ vector ( 0 to5 );
 
 
                    mask : in bit_vector ( 0 to 5 );
 
 
                    result : out bit
 
 
                    );
 
 
     end masked_parity ;
 
 
    architecture marginal_example of masked_parity is
 
 
         begin
 
 
           process (source, mask )
 
 
                 variable temp : bit ;
 
 
                 variable masked_source : bit_vector ( 0 to5 ) ;
 
 
          begin 
 
 
                 masked_source := source and mask ;
 
 
                 temp := masked_source( 0 );       
 
 
                 for I in 1 to 5 loop
                            
 
                            temp := temp xor masked_source( I ) ;
 
 
                 end loop ; 
 
 
                            result <= temp;
 
 
         end process ;
 
 
     end marginal_example; 
 
 
 
This example calculates the parity of the bits of a source vector,
where each bit can be masked. This VHDL description is correct,
but it is not very flexible. Suppose the application changes slightly
and requires a different size input. Then the VHDL description
has to be modified significantly, since the range of the vector
affects many places in the description. The information is not
concentrated, and there are many discrepancies. Attributes can
resolve these dependencies.
 
Here is an improved version of the same example, where attributes
LEFT, RIGHT, and RANGE define the dependencies
on the size of the vector.
 
   entity masked_parity is
 
 
         generic ( size : integer := 5 );
 
 
         port ( source : in bit_ vector ( 0 to size );
 
 
                    mask : in bit_vector ( source'RANGE );
 
 
                    result : out bit;
 
 
                   );
 
 
         end masked_parity ;
 
 
 
        architecture better_example of masked_parity is
 
 
            begin
 
 
              process (source, mask )
 
 
                      variable temp : bit ;
 
 
                      variable masked_source : bit_vector ( source'RANGE ) ;
 
 
              begin 
 
 
                      masked_source := source and mask ;
 
 
                      temp = masked_source( source'LEFT );
 
 
                      for I in source'LEFT+1 to source'RIGHTloop
 
                            temp := temp xor masked_source( I ) ;
 
 
                      end loop ; 
 
 
                       result <= temp;
 
 
             end process ;
 
 
         end better_example ;
 
 
 
If the application requires a different sized parity checker,
then this time you only have to modify the source vector range,
and the attributes ensure that the rest of the description gets
adjusted accordingly. Now the information is concentrated.
 
Return to top of document.

   

Blocks.

 
 
When using processes and dataflow statements it is possible to
use VHDL as a high level hardware description language. However,
as the descriptions get more and more complicated, some form of
design partitioning or hierarchy is required or at least is desirable.
 
VHDL offers a variety of methods for design partitioning. One
form of partitioning is to divide a description into various processes.
In the following section four more types f partitioning are discussed:
blocks, subprograms (functions and procedures ), components,
and packages. 
 
A block is a method to cluster a set of related dataflow
statements. signals, subprograms, attributes, etc. that are local
to that block can be defined in a block declarative region.
All statements in a block are executed concurrently,
and thus define a dataflow environment.
 
   architecture xxx of yyy is
 
 
         signal global_sig, g1, g2 ,c bit ;
 
 
    begin           
 
 
         B1 : block -- block declarative region.
 
 
                    signal local_sig : bit ;
 
 
         begin -- block concurrent statements
 
 
                      -- Block in a block.
 
 
                    B2 : block ( c = '1') 
 
 
                           -- Block has a "GUARD"expression
 
 
                         port ( o1, o2 : out bit )
 
 
                              --block port declarations
 
 
                        port map ( o1 => g1, o2 => g2 ) ;
 
 
                   begin 
 
 
                         o1 <= guarded local_sig ;
 
 
                         o2 <= global_sig ;
 
 
                   end block ;
 
 
         endblock;
 
 
    end xxx ;
 
 
 
Blocks can be nested as in the example above.
 
Signals, ports, and generics declared outside the block can be
used inside the block, either directly ( as
global_sig used in block B2 ), or via
a port map ( as g1 is connected to o1
in the block B2 ), or generic maps ( for generics ).
There is no real difference between the two methods, except that
the port (generic)map construct is a cleaner
coding style which could reduce errors when using or assigning
to global objects.
 
A block can also have a GUARD expression ( c='1' in block
B2 ). In that case, an assignment inside the block
that contains the keyword GUARDEDwill only be executed
when the GUARD expression is TRUE. In the example above, o1
only gets the value of local_sig when c
= '1'. GUARDED blocks and assignments provide an interested alternative
to construct latches or flip-flops in a synthesized logic circuit.
See further examples of this at ...... 
VHDL Document #2, Flip-Flops, and Event Attributes
 
 
Return to top of document.

   

Functions and Procedures.

 

 
 
Subprograms ( functions and procedures ) are powerful tools to
implement functionality that is repeatedly used. Functions take
a number of arguments that are all inputs to the function, and
return a single value. Procedures take a number of arguments that
can be inputs, outputs, or inouts depending on the direction of
the flow of information through the argument. All statements in
functions and procedures are executed sequentially, as in a process.
Also, variables that are local to the subprogram can
be declared in the subprogram. Local signals are not allowed.
 
As an example, suppose that you would like to add two vectors.
In this case, you could define a function that performs the additions.
The following segment of code shows how an addition of two 6 bit
vectors can be done.
 
        function vector_adder ( x : bit_vector ( 0 to 5 );
 
 
                  y : bit_vector ( 0 to 5 )
 
 
         return bit_vector ( 0 to 5 ) is 
 
 
                    -- declarative region
 
 
                 variable carry : bit ;
 
 
                 variable result : bit _vector ( 0 to 5 ) ;
 
 
             begin 
 
 
                       -- sequential statements
 
 
                  carry := '0' ;
 
 
                 for I in 0 to 5 loop 
 
 
                            result( I ) := x( I ) xor y( I ) xor carry ;
 
 
                            carry := carry and ( x( I ) or y ( I ) or x ( I ) and y( I ) ;
 
 
                 end loop; 
 
 
             return result ;
 
 
         end vector_adder ;
 
 
 
An example of a procedure is shown below. The procedure
increments a vector only if an enable signal is high.
 
 
   procedure increment  
 
 
            ( vect : inout bit_vector ( 0 to 5 ) ;
 
 
              ena : in bit ;= '1' ) ;
 
 
         is 
 
 
           begin 
 
 
                 if ( ena = '1') then 
 
 
                       vect := vector_adder ( vect, "000001") ;
 
 
                 end if ; 
 
 
    end increment ;
 
 
 
This incrementer procedure shows the behavior of an inout
port. The parameter vect is both set and used
in this procedure. Also, the procedure statements use a call to
the previously defined vector_adder function. In an input
of a function or a procedure is connected when it is used, that
input will get the initial value as declared in the interface
list.
 
For example, the input ena will get the ( initial ) value
'1' if it is not connected in a procedure call to the procedure
increment . It is an error if an input is not connected
and also does not have an initial value specified.
 
One important feature of subprograms in VHDL is that the argument
can be unbound.. The given examples operate on vectors of 6 bits.
If you want to use the subprograms for arbitrary length vectors,
you could specify the length dependent attributes and not specify
a range on the parameters ( leave them unbound ). Here is a redefinition
of both the vector addition function and the incrementer procedure
for arbitrary length vectors
 
   function vector_adder ( x : bit_vector ; y : bit_vector return bit_vector is
 
 
         variable carry : bit ;
 
 
         variable result : bit _vector ( x'RANGE ) ;
 
 
         begin 
 
 
                 -- sequential statements
 
 
            carry := '0' ;
 
 
               for I in x'RANGE loop 
 
 
                    result( I ) := x( I ) xor y( I ) xor carry ;
 
 
                    carry := carry and ( x( I ) or y ( I ) or x ( I ) and y( I ) ;
 
 
               end loop; 
 
 
            return result ;
 
 
    end vector_adder ;
 
 
    procedure increment ( vect : inout bit_vector; ena : in bit := '1' ) is 
 
 
          begin 
 
 
             if ( ena = '1') then 
 
 
                    vect := vector_adder ( vect, "000001") ;
 
 
             end if ; 
 
 
     end increment ;
 
 
 
 
In the procedure increment example, name association was added
in the parameter list of the vector_adder call. The name
association ( i.e. x => vect ) is an alternative way to connect
a formal parameter ( x ) to its actual parameter ( vect ). Name
associations ( as well as positional associations ) are helpful
if the number of parameters is large.
 
Subprograms can be called from the dataflow environment and from
any sequential environment ( processes and other subprograms ).
If a procedure output or inout is a signal, the corresponding
parameter of the procedure should also be declared as a signal.
 
Return to top of document.

   

Component Instantiation.

 

 
 
Components are a method of introducing structure in a VHDL description.
A component represents a structural module in the design. Using
components, it is possible to describe a netlist in VHDL. Components
are instantiated in the dataflow environment. Here is an example
of a structural VHDL description where four one-bit RAMS and a
counter module are instantiated.
 
   entity scanner is
 
 
         port ( reset : in bit ;
 
 
                     stop : in bit ;
 
 
                     load : in bit ;
 
 
                     clk  : in bit ;
 
 
                     load_value : in bit_vector ( 0 to 3 ) ;
 
 
                     data : out bit_vector ( 0 to 3 ) ;
 
 
                  ) ;
 
 
         end scanner ;
 
 
     architecture in_vhdl of scanner is
 
 
         component RAM_32by1
 
 
            port ( a0, a1, a2, a3, a4 : in bit ;
 
 
                                        we, d : in bit ;
 
 
                                        o     : out bit ;
 
 
         end component ;
 
 
        component counter 
 
 
                 generic ( size : integer := 4 ) ;
 
 
                 port(clk : in bit ;
 
 
                          enable : in bit ;
 
 
                           reset : in bit ;
 
 
                          result : out bit_vector( 0 to 4 ) ;
 
 
                        ) ;
 
 
         end component ;
 
 
         signal ena : bit ;
 
 
         signal addr : bit_vector( 0 to 4 ) ;
 
 
            begin
 
 
                  for  I in 0 to 3 generate
 
 
                        ram : RAM_32 by port map
 
 
                          ( a0=>addr( 0 ), a1=>addr( 1 ), a2=>addr( 2 ),a3=>addr( 3 ),
 
 
                            a4=>addr( 4 ), d=>data( I ), we=>load, o=>data(I ) ) ;
 
 
                  end generate ;
 
 
                  ena => not stop ;
 
 
                  count : counter generic map (size=>addr'length)
 
 
                  port map (clk=>clk, enable=>ena, reset=>reset,result=>addr );
 
 
     end in_vhdl ;
 
 
 
The generate statement here is used to instantiate four
RAMS. 
 
Components have to declared before they can be used.
This is done in the declaration area of the architecture,
or in a package Jump to Section on Packages.
The declaration defines the interface of he component ports
with their type and their direction. Actually this example is
just a netlist of components. We added one dataflow statement
(the assignment to ena ) to show that structure and behavior can
be mixed in VHDL.
 
The ports of the component are connected to actual values
with the generic map construct. In this example the generic
size is set to 4 with the attribute length on the array
addr.If no generic value was set to size
( or if the generic map construct was completely absent ), size
get the value 4, as indicated by the initial value on size in
the generic list of the component. It is an error if a generic
( or input port ) is not connected in a generic map (or port map
) construct and there is no initial value given in the component
generic ( or port ) list.
 
The definitions of the components counter and RAM_32by1
have not been given yet. There are two ways to do his in VHDL:
 
1. Define an entity and architecture for the component in the
same, or an included VHDL file
 
 
 
2. Use an input technology that contains a component with the
same name and interface list.
 
 
 
The component counter is a good example of the first
option:
 
 
        entity counter is 
 
 
         generic ( size : integer ) ;
 
 
         port ( clk    : in bit ;
 
 
                   enable : in bit ;
 
 
                   reset  : in bit ;
 
 
                   result  : out bit_vector ( 0 to size-1 )
 
 
                  );
 
 
         end counter;
 
 
        architecture in_vhdl of counter is
 
 
          begin
 
 
              process ( clk, reset )
 
 
              begin
 
 
                    if ( reset = '1' ) then 
 
 
                        result <= (others => '0' )
 
 
                    elsif (clk'event and clk = '1' ) then
 
 
                        if (enable = '1' ) then
 
                              result <= result + "1" ;
 
 
                        end if ;
 
 
                    end if ;
 
 
             end process  
 
 
     end in_vhdl ;
 
 
 
This description includes only behavior. There is no
component instantiated, although it is possible,
and it makes hierarchical design possible. 
 
Note that an asynchronous reset construction is used to reset
the counter value. Details of various synthesizable forms
of reset are given in VHDL Document #2, sections on Sync and Async Resets.
 
 
For the second option, use a source technology in our design environment
that includes the component RAM_32by1, (this is an example that
exists in the Viewlogic VHDL library.) If the source technology
is in a library (i.e. Viewlogic, Altera, Actel, etc. ) the VHDL
compiler will recognize the component in the 'lib_name' library,
and instantiate it in the design.
 
Return to top of document.

   

Packages.

 
 
A package is a cluster of declarations and definitions of objects,
function, procedures, components, a tributes, etc. that can be
used in VHDL descriptions. You cannot define an entity or an architecture
in a package, so a package itself does not represent a circuit.
 
A package consists of two parts. The package header, with declarations,
and the package body, with definitions. An example of a package
is std_logic_1164 the IEEE standard # 1164 logic types
package. It defines types and operations on types for 9 valued
logic. Nine valued logic refers to the types of output signals
that a logic device can create (i.e. H, L, Z, X, and other permutation
of hard / soft high and low logic levels).
 
 
        library ieee ;
 
 
         use std_logic_1164;
 
 
         entity xyz is   
 
 
                 port ( x : std_logic ; 
 
 
                            -- type std_logic is known since it is defined in
 
 
                            -- Package std_logic_1164
 
 
                            ,,,,,
 
 
 
This example shows how the IEEE 1164 standard logic types and
functions become accessible to the description in entity xyz.
This is the general form to include in a package in a VHDL description:
 
   library <lib>;
 
 
            use <lib>.<package>.<selection> ;
 
 
 
The use clause is preceded by a library clause. The predefined
libraries work and std do not have to be declared in
a library clause before they are used in a use clause.
All other libraries do need to be declared.
 
The <selection > can consist of only one name of an object,
component, type or subprogram that is present in the package,
or the word all, in which case a;; functionality described
in the package is loaded in to the VHDL compiler and can be used
in the VHDL description.
 
Return to top of document

   

Aliases.

 
 
An alias is an alternate name for an existing object.
By using an alias of an object, you actually use the
object to which it refers. By assigning an alias, you
actually assign to the object to which the alias refers.
 
 
   signal vec : std_logic_vector ( 4 downto 0 ) ;
 
 
         alias mid_bit : std_logic is vec(2) ;
 
 
                    -- Assignment
 
 
                 mid_bit <  ;= '0' ; -- this is the same as 
 
 
                 vec( 2 ) < ;= '0' ;
 
 
 
Aliases are often useful in unbound function calls. For instance,
if you want to make a function that takes the AND operation of
the two left most bits of an arbitrary array parameter. If you
want to make the function general enough to handle arbitrary sized
arrays, this function could look like this;
 
 
 function left_AND (arr:std_logic_vector ) returnstd_logic is
 
 
         begin                    
 
 
                return arr(arr'left ) and arr( arr'left-1 ) ;
 
 
         end left_AND ;
 
 
                 -- Note the function does not work for ascending 
 
 
                 -- index ranges of arr. 
 
 
 
This function will only work correctly if the index of arr
is descending ( downto ). Otherwise, arr'left-1
is not a valid index number. VHDL does not have a simple attribute
that will the one-but-left most bit out of an arbitrary vector,
so it will be difficult to implement a function that works correctly
both for ascending and descending index ranges. Instead, you could
make an alias of arr, with a known index range, and operate
on the alias: 
 
   function left_AND (arr:std_logic_vector ) returnstd_logic is 
 
 
                 array aliased_arr : std_logic_vector ( 0 to arr'length-1) is arr ;
 
 
         begin
 
 
                 return aliased_arr(0 ) and aliased_arr( 1) ;
 
 
                           -- Function works for ascending and descending index ranges of arr.
 
 
 
 
NOTE: Not all VHDL compilers fully support aliasing.


    Return to top of document

   

End of Document #1, Jump to Document #2.