VHDL Tutorial

Array types in VHDL and array operations
Introduction
Fundamental concepts
Modelling concepts
Elements of behaviour
Elements of structure
Analysis elaboration
Lexical elements
Identifiers
Numbers
Characters and strings 
Syntax descriptions
Constants and variables
Scalar type
Integer types
Floating point types
Time type
Enumeration types
Character types
Boolean type 
Bits type
Standard logic
Sequential statements
Case statements
Loop and exit statements
Assertion statements
Array types & array operations

Architecture bodies
Entity declarations
Behavioral descriptions 
Wait statements
Delta delays
Process statements
Conditional signal assignment 
Selected signal assigment
Structural descriptions
Library and library clauses
Procedures
Procedure parameters
Signal parameters
Default values
Unconstrained array parameter
Functions
Package declarations and bodies
Subprograms in package
Use clauses
Resolved signals and subtypes
Resolved signals and ports
Parameterizing behavior
Parameterizing structure

Array Types and Operations

 

An array consists of a collection of values, all of which are of the same type as each other.   The position of each element in an array is given by a scalar value called its index To create an array object in a model, we first define an array type in a type declaration.   The syntax rule for an array type definition is

 

array_type_definition

array ( discrete_range ) of element_subtype_indication

 

This defines an array type by specifying the index range and the element type or sub- type A discrete range is a subset of values from a discrete type (an integer or enu- meration type).   It can be specified as shown by the simplified syntax rule

 

Want To have highly paid VLSI jobs ?? then you may contact at

Contact : webmaster@freehost7com

 

discrete_range

type_mark

I simple_expression ( to I downto ) simple_expression

We illustrate these rules for defining arrays with a series of examples.   Here is a simple example to start off with, showing the declaration of an array type to represent words of data:

 

type word is array (0 to 31) of bit;

 

Each element is a bit, and the elements are indexed from 0 up to 31.  An alterna- tive declaration of a word type, more appropriate for “little-endian” systems, is

 

type word is array (31 downto 0) of bit;

 

The difference here is that index values start at 31 for the leftmost element in val- ues of  this  type  and continue down to 0  for the rightmost.   The  index  values of an array do not have to be numeric.   For example, given this declaration of an enumer- ation type:

 

type controller_state is (initial, idle, active, error);

 

we could then declare an array as follows:

 

type state_counts is array (idle to error) of natural;

 

If we need an array element for every value in an index type, we need only name the index type in the array declaration without specifying the range.   For example:

 

subtype coeff_ram_address is integer range 0 to 63;

type coeff_array is array (coeff_ram_address) of real;

 

Once we have declared an array type, we can define objects of that type, includ- ing constants, variables and signals.  For example, using the types declared above, we can declare variables as follows:

 

variable buffer_register, data_register : word;

variable counters : state_counts;

variable coeff : coeff_array;

 

Each  of  these  objects  consists  of  the  collection  of  elements  described  by  the  corre- sponding type declaration.  An individual element can be used in an expression or as the  target  of  an  assignment  by  referring  to  the  array  object  and  supplying  an  index value, for example:

 

coeff(0) := 0.0;

 

If active is a variable of type controller_state, we can write

 

counters(active) := counters(active) + 1;

 

An array object can also be used as a single composite object For example, the assignment

 

data_register := buffer_register;

copies all of the elements of the array buffer_register into the corresponding elements of the array data_register.

 

Array Aggregates

 

Often we also need to write literal array values, for example, to initialize a variable or constant  of  an  array  type.   We  can  do  this  using  a  VHDL  construct  called  an  array aggregate, according to the syntax rule

 

aggregate ( ( [ choices => ] expression ) { , … } )

 

Let us look first at the form of aggregate without the choices part.  It simply con- sists of a list of the elements enclosed in parentheses, for example:

 

type point is array (1 to 3) of real;

constant origin : point := (0.0, 0.0, 0.0);

variable view_point : point := (10.0, 20.0, 0.0);

 

This form of array aggregate uses positional association to determine which value in the list corresponds to which element of the array.  The first value is the element with the leftmost index, the second is the next index to the right, and so on, up to the last value,  which  is  the  element  with  the  rightmost  index.   There  must  be  a  one-to-one correspondence between values in the aggregate and elements in the array.

An alternative form of aggregate uses named association, in which the index val- ue for each element is written explicitly using the choices part shown in the syntax rule.   The choices may be specified in exactly the same way as those in alternatives

of a case statement.  For example, the variable declaration and initialization could be rewritten as

 

variable view_point : point := (1 => 10.0, 2 => 20.0, 3 => 0.0);

 

EXAMPLE

 

Figure 3-9  is  a  model  for  a  memory  that  stores  64  real-number  coefficients, initialized to 0.0.   We assume the type  coeff_ram_address is previously declared

as above.  The architecture body contains a process with an array variable repre- senting  the  coefficient  storage.    The  array  is  initialized  using  an  aggregate  in which all elements are 0.0.  The process is sensitive to all of the input ports.  When

rd is ‘1’, the array is indexed using the address value to read a coefficient.  When

wr is ‘1’, the address value is used to select which coefficient to change.

 

FIGURE 3-9

 

entity coeff_ram is

port ( rd, wr : in bit;  addr : in coeff_ram_address;

d_in : in real;  d_out : out real );

end entity coeff_ram;

–– ––– –––– ––– –––– ––– –––– –––– ––– –––– ––– –––– ––– –––– ––––

architecture abstract of coeff_ram is begin

memory : process (rd, wr, addr, d_in) is

type coeff_array is array (coeff_ram_address) of real;

variable coeff : coeff_array := (others => 0.0);

begin

if rd = '1' then

d_out <= coeff(addr);

end if;

if wr = '1' then

coeff(addr) := d_in;

end if;

end process memory;

end architecture abstract;

 

An entity and architecture body for a memory module that stores real-number coefficients.  The mem-

ory storage is implemented using an array.

Array Attributes

 

VHDL provides a number of attributes to refer to information about the index ranges

of array types and objects.  Attributes are written by following the array type or object name with the symbol ' and the attribute name.   Given some array type or object A, and an integer N between 1 and the number of dimensions of A, VHDL defines the following attributes:

 

A'left                      Left bound of index range of A A'right        Right bound of index range of A A'range           Index range of A

A'reverse_range    Reverse of index range of A

 

A'length                 Length of index range of A

 

For example, given the array declaration

 

type A is array (1 to 4) of boolean;

 

some attribute values are

 

A'left = 1                                  A'right = 4

 

A'range is 1 to 4                      A'reverse_range is 4 downto 1

 

A'length = 4

 

The attributes can be used when writing for loops to iterate over elements of an array.   For example, given an array variable free_map that is an array of bits, we can write a for loop to count the number of ‘1’ bits without knowing the actual size of the array:

 

count := 0;

for index in free_map'range loop if free_map(index) = '1' then

 

count := count + 1;

end if;

end loop;

 

The 'range and 'reverse_range attributes can be used in any place in a VHDL model where a range specification is required, as an alternative to specifying the left and right bounds and the range direction.  Thus, we may use the attributes in type and subtype definitions, in subtype constraints, in for loop parameter specifications, in case state- ment choices and so on.  The advantage of taking this approach is that we can specify the size of the array  in  one  place  in the  model and  in all other places use array at- tributes.   If  we  need  to  change  the  array  size  later  for  some  reason,  we  need  only change the model in one place.

 

Unconstrained Array Types

 

The array types we have seen so far in this chapter are called constrained arrays, since the type definition constrains index values to be within a specific range.   VHDL also allows us to define unconstrained array types, in which we just indicate the type of the index values, without specifying bounds.   An unconstrained array type definition

is described by the alternate syntax rule

 

array_type_definition

array ( type_mark range <> ) of element_subtype_indication

 

The symbol “<>”, often called “box,” can be thought of as a placeholder for the index

range, to be filled in later when the type is used An example of an unconstrained array type declaration is

 

type sample is array (natural range <>) of integer;

 

An important point to understand about unconstrained array types is that when we declare an object of such a type, we need to provide a constraint that specifies the index bounds.  We can do this in several ways.  One way is to provide the constraint when an object is created, for example:

 

variable short_sample_buf : sample(0 to 63);

 

This indicates that index values for the variable short_sample_buf are natural num- bers in the ascending range 0 to 63.  Another way to specify the constraint is to declare

a subtype of the unconstrained array type.  Objects can then be created using this sub- type, for example:

 

subtype long_sample is sample(0 to 255);

variable new_sample_buf, old_sample_buf : long_sample;

 

These are both examples of a new form of subtype indication that we have not yet seen.   The syntax rule is

 

subtype_indication type_mark [ ( discrete_range ) ]

The  type  mark  is  the  name  of  the  unconstrained  array  type,  and  the  discrete  range specifications constrain the index type to a subset of values used to index array ele- ments.

 

Strings

 

VHDL provides a predefined unconstrained array type called string, declared as

 

type string is array (positive range <>) of character;

 

For example:

 

constant LCD_display_len : positive := 20;

subtype LCD_display_string is string(1 to LCD_display_len);

variable LCD_display : LCD_display_string := (others => ' ');

 

Bit Vectors

 

VHDL also provides a predefined unconstrained array type called bit_vector, declared as

 

type bit_vector is array (natural range <>) of bit;

 

For example, subtypes for representing bytes of data in a little-endian processor might be declared as

 

subtype byte is bit_vector(7 downto 0);

 

Alternatively, we can supply the constraint when an object is declared, for example:

 

variable channel_busy_register : bit_vector(1 to 4);

 

Standard-Logic Arrays

 

The standard-logic package  std_logic_1164 provides an unconstrained array type for vectors of standard-logic values.   It is declared as

 

type std_ulogic_vector is array ( natural range <> ) of std_ulogic;

 

We can define subtypes of the standard-logic vector type, for example:

 

subtype std_ulogic_word is std_ulogic_vector(0 to 31);

 

Or we can directly create an object of the standard-logic vector type:

 

signal csr_offset : std_ulogic_vector(2 downto 1);

 

Unconstrained Array Ports

 

An important use of an unconstrained array type is to specify the type of an array port. This use allows us to write an entity interface in a general way, so that it can connect

to array signals of any size or with any range of index values.   When we instantiate

the entity, the index bounds of the array signal connected to the port are used as the bounds of the port.

 

EXAMPLE

 

Suppose we wish to model a family of and gates, each with a different num- ber of inputs.  We declare the entity interface as shown in Figure 3-10.  The input port is of the unconstrained type bit_vector.  The process in the architecture body performs a logical and operation across the input array.  It uses the 'range attribute

to  determine  the  index  range  of  the  array,  since  the  index  range  is  not  known until the entity is instantiated.

 

FIGURE 3-10

 

entity and_multiple is

port ( i : in bit_vector;  y : out bit );

end entity and_multiple;

–– ––– –––– ––– –––– ––– –––– –––– ––– –––– ––– –––– ––– –––– ––––

architecture behavioral of and_multiple is begin

and_reducer : process ( i ) is variable result : bit;

begin

result := '1';

for index in i'range loop

result := result and i(index);

end loop;

y <= result;

end process and_reducer;

end architecture behavioral;

 

An entity and architecture body for an and gate with an unconstrained array input port.

 

To  illustrate  the  use  of  the  multiple-input  gate  entity, suppose we have  the following signals:

 

signal count_value : bit_vector(7 downto 0);

signal terminal_count : bit;

 

We instantiate the entity, connecting its input port to the bit-vector signal:

 

tc_gate : entity work.and_multiple(behavioral)

port map ( i => count_value, y => terminal_count);

 

For this instance, the input port is constrained by the index range of the sig-

nal.   The instance acts as an eight-input and gate.


 

 

 

 

 

 

 

 

 

Home