A packages is used as a collection of often used datatypes, components, functions, and so on. Once these object are declared and defined in a package, they can be used by different VHDL design units. In particular, the definition of global information and important shared parameters in complex designs or within a project team is recommended to be done in packages.
It is possible to split a package into a declaration part and the so-called body. The advantage of this splitting is that after changing definitions in the package body only this part has to be recompiled and the rest of the design can be left untouched. Therefore, a lot of time consumed by compiling can be saved.
As the name implies, a package declaration includes all globally used declarations of types, components, procedures and functions. A possible package declaration is presented by means of an example:
Example:
package MY_PACK is
type SPEED is (STOP, SLOW, MEDIUM, FAST);
component HA
port (I1, I2 : in bit; S, C : out bit);
end component;
constant DELAY_TIME : time;
function INT2BIT_VEC (INT_VALUE : integer)
return bit_vector;
end MY_PACK;
The name of this package is MY_PACK. It consists of different declarations, such as a type SPEED, a component HA, and so on. Attention should be paid to the declaration of the constant DELAY_TIME and the function INT2BIT_VEC which are declared but are not defined. Their definitions will be done in the package body but it would be possible to define the constant DELAY_TIME in the package declaration part as well. The definition of functions must be done in a package body.
If the above package had been compiled into the library MY_LIB (Section 2.7) then the following statements were also needed in the VHDL model which uses this package:
Example:
library MY_LIB;
use MY_LIB.MY_PACK.all;
entity EXAMPLE is
...
The library statement makes the library MY_LIB accessible for the following VHDL description. With the subsequent use statement all elements (indicated by the keyword all) from the package MY_PACK are included in the entity of the module EXAMPLE.
In the package body the definition of functions and procedures that were only declared in the package declaration must be specified. Constants which were declared only must get a value assigned to them in the package body.
The body of the package MY_PACK could be defined as:
Example:
package body MY_PACK is
constant DELAY_TIME : time := 1.25 ns;
function INT2BIT_VEC (INT_VALUE : integer)
return bit_vector is
begin
- sequential behavioral description (omitted here)
end INT2BIT_VEC;
end MY_PACK;
The binding between the package declaration and the body is established by using the same name. In the above example it is the package name MY_PACK.
There are four important packages often used in VHDL descriptions.
This package is also a part of the library STD. It is not included in every VHDL description by default. Therefore, if required, it has to be included by the statement use STD.TEXTIO.all;.
The type std_ulogic consists of the following elements:
Declaration:
type std_ulogic is (
'U', - uninitialized
'X', - forcing unknown
'0', - forcing 0
'1', - forcing 1
'Z', - high impedance
'W', - weak unknown
'L', - weak 0
'H', - weak 1
'-' ); - "don't care"
Besides this type used for modeling single wires other types are declared in the STD_LOGIC_1164 package. Frequently used in descriptions of bus systems are the types std_ulogic_vector and std_logic_vector. In addition, the also includes the definitions of resolution functions (see Section 2.6.2) and simple boolean functions.
The use of the types std_ulogic and std_logic is strongly recommended. The package STD_LOGIC_1164, if it is available on the system installation, is usually be kept in the logical library IEEE. It could be referenced with the two statements:
Syntax:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
Example:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
architecture DETAILED of EXAMPLE is
signal A, B : std_logic_vector (7 downto 0);
signal SUM : std_logic_vector (8 downto 0);
signal SUM_S : signed (8 downto 0);
signal PROD : std_logic_vector (15 downto 0);
signal PROD_S :signed (15 downto 0);
begin
- extension by one digit, conversion into a two's
- complement number and calculation of the sum:
SUM_S <= signed(A(7) & A) + signed(B(7) & B);
- conversion to 9 bit std_logic_vector:
SUM <= conv_std_logic_vector(SUM_S, 9);
- calculation of the product:
PROD_S <= signed(A) * signed(B);
- conversion to 16 bit std_logic_vector:
PROD <= conv_std_logic_vector(PROD_S, 16);
end DETAILED;
In the above example the sum and the product of the two busses A and B are calculated. Because the width of the resulted
sum is the same as those of the operands, the width of A and
B has to be extended by one bit in order to avoid an overflow.
Since both A and B are two's complement numbers their
MSB's have to be doubled. This is achieved by the catenations A(7) & A and B(7) & B. After converting signals A and
B with the signed(...) and adding, the result is
assigned to a temporary signal SUM_S. This signal is then
converted back to a 9 bit wide bus of the type std_logic_vector with the function conv_std_logic_vector(SUM_S, 9). For the
multiplication, the width of the result is 16 bit, which is equal to
the sum of the widths of the operands A and B. The
appropriate information is required in the conversion of PROD_S to PROD.