LIBRARIES AND PACKAGES
A package provides a convenient mechanism to store and share
declarations that are common across many design units. A package is represented
by
1. a package
declaration, and optionally,
2. a package body.
A package declaration contains a set of declarations that may
possibly be shared by many design units. It defines the interface to the
package, i.e., it defines items that can be made visible to other design units,
for example, a function declaration. A package body, in contrast, contains the
hidden details of a package, for example, a function body.
The syntax of a package declaration is
package package-name is
package-item-declarations ">
These may be:
- subprogram declarations ~ type declarations
- subtype declarations
- constant declarations
- signal declarations
- file declarations
- alias declarations
- component declarations
- attribute declarations
- attribute specifications
- disconnection specifications
- use clauses
end [ package-name ] ;
Eg.,
package SYNTH_PACK is
constant LOW2HIGH: TIME :=
20ns:
type ALU_OP is (ADD,
SUB, MUL, DIV, EQL);
attribute PIPELINE: BOOLEAN;
type MVL is ('U',
'0', '1', 'Z');
type MVL_VECTOR is
array (NATURAL range <>) of MVL;
subtype MY_ALU_OP is ALU_OP
range ADD to DIV;
component NAND2
port (A, B: in MVL; C: out MVL);
end component;
end SYNTH_PACK;
Items declared in a package declaration can be accessed by other
design units by using the library and use context clauses.
The set of common declarations may also include function and
procedure declarations and deferred constant declarations.
In this case, the behavior of the subprograms and the values of
the deferred constants are specified in a separate design unit called the
package body. Since the previous package example did not contain any subprogram
declarations and deferred constant declarations, a package body was not
necessary.
Consider the following package declaration.
use WORK.SYNTH_PACK.all:
package PROGRAM_PACK is
constant PROP_DELAY: TIME; -A deferred constant.
function "and" (L, R: MVL) return MVL;
procedure LOAD (signal ARRAY_NAME: inout
MVL_VECTOR;
START_BIT, STOP_BIT, INT_VALUE: in INTEGER);
end PROGRAM_PACK;
In this case, a package
body is required.
A package body primarily contains the behavior of the subprograms
and the values of the deferred constants declared in a package declaration.
It may contain other declarations as well, as shown by the
following syntax of a package body.
package body package-name is
package-body-item-daclarations "> These are:
- subprogram bodies -- complete constant declarations
- subprogram declarations
- type and subtype declarations
- file and alias declarations
- use clauses
end [ package-name ];
The package name must be the same as the name of its corresponding
package declaration. A package body is not necessary if its associated package
declaration does not have any subprogram or deferred constant declarations. The
associated package body for the package declaration, PROGRAM_PACK, described in
the previous section is
package body PROGRAM_PACK is
constant PROP_DELAY: TIME := 15ns;
function "and" (L, R: MVL) return MVL is
begin
return TABLE_AND(L, R);
-- TABLE_AND is a 2-D constant defined elsewhere.
end "and";
procedure LOAD (signal ARRAY_NAME: inout
MVL_VECTOR;
START_BIT, STOP_BIT, INT_VALUE: in INTEGER) is
-- Local declarations here.
begin
-- Procedure behavior here.
end LOAD;
end PROGRAM_PACK;
An item declared inside a package body has its scope restricted to
be within the package body and it cannot be made visible in other design units.
This is in contrast to items declared in a package declaration that can be
accessed by other design units. Therefore, a package body is used to store
private declarations that should not be visible, while a package declaration is
used to store public declarations which other design units can access. This is
very similar to declarations within an architecture body which are not visible
outside of its scope while items declared in an entity declaration can be made
visible to other design units.
An important difference between a package declaration and an
entity declaration is that an entity can have multiple architecture bodies with
different names, while a package declaration can have exactly one package body,
the names for both being the same.
A subprogram
written in any other language can be made accessible to design units by
specifying a subprogram declaration in a package declaration without a
subprogram body in the corresponding package body. The association of this
subprogram with its declaration in the package is not defined by the language
and is, therefore, tool implementation-specific.
DESIGN LIBRARIES
A compiled VHDL description is stored in a design library. A
design library is an area of storage in the file system of the host
environment. The format of this storage is not defined by the language.
Typically, a design library is implemented on a host system as a
file directory and the compiled descriptions are stored as files in this
directory. The management of the design libraries is also not defined by the
language and is again tool implementation-specific.
An arbitrary number of
design libraries may be specified. Each design library has a logical name with
which it is referenced inside a VHDL description. The association of the
logical names with their physical storage names is maintained by the host environment.
There is one design
library with the logical name, STD, predefined in the language; this library
contains the compiled descriptions for the two predefined packages, STANDARD
and TEXTIO. Exactly one design library must be designated as the working library
with the logical name, WORK.
When a VHDL description is
compiled, the compiled description is always stored in the working library.
Therefore, before compilation begins, the logical name WORK must point to one
of the design libraries.
Fig.1: A Typical Compilation Process
The VHDL source is present in an ASCII file called the design
file. This is processed by the VHDL analyzer, which after verifying the
syntactic and semantic correctness of the source, compiles it into an
intermediate form.
The intermediate form is stored in the design library that has
been designated as the working library.
Design File
The design file is an ASCII file containing the VHDL source. It
can contain one or more design units, where a design unit is one of the
following:
• entity
declaration,
• architecture
body,
• configuration
declaration,
• package
declaration,
• package body.
This means that each design unit can also be compiled separately.
A design library consists of a number of compiled design units.
Design units are further classified as
1. Primary units:
These units allow items to be exported out of the design unit. They are
a. entity declaration: The items declared in an entity
declaration are implicitly visible within the associated architecture bodies.
b. package declaration: Items declared within a package
declaration can be exported to other design units using context clauses.
c. configuration declaration.
2. Secondary units:
These units do not allow items declared within them to be exported out of the
design unit, that is, these items cannot be referenced in other design units.
These are
a. architecture body:
A signal declared in an architecture body, for example, cannot be
referenced in other design units.
b. package body.
There can be
exactly one primary unit with a given name in a single design library.
Secondary units associated with different primary units can have identical
names in the same design library; also a secondary unit may have the same name
as its associated primary unit. For example, assume there exists an entity called
AND_GATE in a design library. It may have an architecture body with the same
name, and another entity, MY_GATE, in the same design library may have an
architecture body that also has the name, AND_GATE.
Secondary units
must coexist with their associated primary units in the same design library,
for example, an entity declaration and all of its architecture bodies must
reside in the same library. Similarly, a package declaration and its associated
package body must reside in a single library.
Even though a
configuration declaration is a primary unit, it must reside in the same library
as the entity declaration to which it is associated.
ORDER OF ANALYSIS
Since it is possible to export items declared in primary units to
other design units, a constraint is imposed in the sequence in which design
units must be analyzed.
A design unit that references an item declared in another primary
unit can be analyzed only after that primary unit has been analyzed.
Eg., if a configuration declaration references an entity, COUNTER,
the entity declaration for COUNTER must be analyzed before the configuration
declaration.
A primary unit must
be analyzed before any of its associated secondary units. For example, an
entity declaration must be analyzed before its architecture bodies are
analyzed.
IMPLICIT VISIBILITY
An
architecture body implicitly inherits all declarations in the entity since it
is tied to that entity by virtue of the statement
architecture
architecture-name of entity-name is . . .
Similarly,
a package body implicitly inherits all items declared in the package
declaration by virtue of its first statement
package
body package-name is. . .
where
the package name is the same as the one in the package declaration.
EXPLICIT VISIBILITY
Explicit
visibility of items declared in other design units can be achieved using
context clauses.
There
are two types of context clauses:
1. library clause,
2. use clause.
Context clauses are associated with
design units and may be written just before the design unit to which visibility
is to be made available.
Fig.2 shows an example. Items
specified in the context clause become visible only to the design unit that
follows the context clause. This means that if a design file contains three
design units as shown in Fig.3, then context clauses must be specified for each
design unit.
Eg., the context clauses specified
before design unit A makes them visible to design unit A only; context clauses
specified before design unit B makes them visible to design unit B only.
Fig.3 Separate Context Clauses
with each design unit
Library Clause
The library clause makes
visible the logical names of design libraries that can be referenced within a
design unit.
The format of a library
clause is
library list-of-logical-library-names;
Eg.,
library TTL, CMOS;
makes the logical names, TTL and CMOS,
visible in the design unit that follows. Note that the library clause does not
make design units or items present in the library visible, it makes only the
library name visible (it is like a declaration for a library name).
Eg., it is illegal to use the
expression "TTL.SYNTH_PACK.MVL" within a design unit without first
declaring the library name using the "library TTL;" clause.
The following library clause
library STD, WORK;
is implicitly declared for every design
unit.
USE CLAUSE
There are two main forms of the use
clause.
use library-name.
primafy-unit-name ; --Form 1.
use library-name.
primafy-unit-name. Item ; --Form 2.
The first form of the use clause allows
the specified primary unit name from the specified design library to be
referenced in a design description.
Eg.,
library CMOS;
use CMOS.NOR2;
configuration...
. . . use entity NOR2(
. . . );
end;
Note that entity NOR2 must be available
in compiled form in the design library, CMOS, before attempting to compile the
design unit where it is used.
The second form of the use clause makes
the item declared in the primary unit visible and the item can, therefore, be
referenced within the following design unit.
Eg.,
library ATTLIB;
use ATTLIB.SYNTH_PACK.MVL;
-- MVL is a type declared in SYNTH_PACK package.
-- The package, SYNTH_PACK, is stored in the ATTLIB
design library.
entity NAND2 is
port (A, B: in
MVL; ...)...
If all items within a primary unit are
to be made visible, the keyword all can be used.
Eg.,
use ATTLIB.SYNTH_PACK.all;
makes all items declared in package
SYNTH_PACK in design library ATTLIB visible.
Items external to a design unit can be
accessed by other means as well. One way is to use a selected name.
Eg., using a selected name
library ATTLIB;
use ATTLIB.SYNTH_PACK;
entity NOR2 is
port (A, B: in
SYNTH_PACK.MVL; ...)...
Since only the primary unit name was
made visible by the use clause, the complete name of the item, that is,
SYNTH_PACK.MVL must be specified.
Eg.,
The type VALUE_9 is defined in package
SIMPACK that has been compiled into the CMOS design library.
library CMOS;
package P1 is
procedure LOAD (A, B:
CMOS.SIMPACK.VALUE_9; ...)...
. . . end P1;
In this case, the primary unit name was
specified only at the time of usage.
If it is necessary to export items from
design units that are in the same library, there is no need to specify a
library clause since every design unit has the following library clause
implicitly declared.
library WORK;
The predefined design library STD
contains the package STANDARD.
The package STANDARD contains the
declarations for the predefined types such as CHARACTER, BOOLEAN, BIT_VECTOR,
and INTEGER.
The following two clauses are also
implicitly declared for every design unit:
library STD;
use STD.STANDARD.all;
Thus
all items declared within the package STANDARD are available for use in every
VHDL description.
The package STANDARD is a predefined package that contains the
definitions for the predefined types and functions of the language. A source
code listing of this package follows.
package STANDARD is
-- Predefined enumeration types:
type BOOLEAN is (FALSE, TRUE);
type BIT is ('0', '1');
type CHARACTER is (
NUL, SOH, STX, ETX, EOT, ENQ, ACK,BEL, BS, HT, LF, VT,
FF, CR,
SO,
SI, DLE, DCI, DC2, DC3, DC4, NAK, SYN, ETB, CAN, EM, SUB, ESC,
FSP,
GSP, RSP, USP, ' ' , ' ! ', ' ” ', ' # ', ' $ ', ' % ', ' & ', ' ’ ', ' ('
, ' ) ', ' * ', ' + ', ' , ', ' - ', ' . ', ' / ', ' 0 ', ' 1 ', ' 2 ', ' 3 ',
' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9', ' : ', ' ; ',' < ', ' = ', ' >
', ' ? ', ' @ ', ' A ', ' B ', ' C ', ' D ', ' E ', ' F ', ' G ', ' H ', ' I ',
' J ', ' K ', ' L ', ' M ', ' N ', ' O ', ' P ', ' Q ', ' R ', ' S ', ' T ', '
U ', ' V ', ' W ', ' X ', ' Y ', ' Z ', ' [ ', ' \ ', ' ] ', ' ^ ', ' _ ', ' `
', ' a ', ' b ', ' c ', ' d ', ' e ', ' f ', ' g ', ' h ', ' i ', ' j ', ' k ',
' l ', ' m ', ' n ', ' o ', ' p ', ' q ', ' r ', ' s ', ' t ', ' u ', ' v ', '
w ', ' x ', ' y ', ' z ', ' { ', ' | ', ' } ', ' ~ ', DEL );
type
SEVERITY_LEVEL is (NOTE, WARNING, ERROR, FAILURE);
--
Predefined numeric types:
type
INTEGER is range implementation_defined;
type
REAL is range implementation_defined;
-
Predefined type TIME:
type
TIME is range implementation_defined
units
fs;
-- femtosecond
ps =
1000 fs; -- picosecond
ns =
1000 ps; -- nanosecond
us =
1000 ns; -- microsecond
ms =
1000 us; -- microsecond
sec
= 1000 ms; -- seconds
min
= 60 sees; -- minutes
hr =
60 min; -- hours
end
units;
--
Function that returns the current simulation time:
function
NOW return TIME;
--
Predefined numeric subtypes:
subtype
NATURAL is INTEGER range 0 to INTEGER'HIGH;
subtype
POSITIVE is INTEGER range 1 to INTEGER'HIGH;
-
Predefined array types:
type
STRING is array (POSITIVE range <>) of CHARACTER;
type
BIT_VECTOR is array (NATURAL range <>) of BIT;
end STANDARD;
Package
TEXTIO contains declarations of types and subprograms that support formatted
ASCII I/O operations. A source code listing of the package follows.
package
TEXTIO is -- Type definitions for text I/O:
type
LINE is access STRING; -- A line is a pointer to a STRING value.
type
TEXT is file of STRING; -- A file of variable-length --ASCII
records.
type
SIDE is (RIGHT, LEFT); -- For justifying output data -- within
fields.
subtype
WIDTH is NATURAL; -- For specifying widths of output fields.
--
Standard text files:
file
INPUT: TEXT is in "STD_INPUT";
file
OUTPUT: TEXT is out "STD_OUTPUT":
--
Input routines for standard types:
procedure
READLINE (F: in TEXT; L: out LINE);
procedure
READ (L: inout LINE; VALUE: out BIT; GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out BIT);
procedure
READ (L: inout LINE; VALUE: out BIT_VECTOR;GOOD; out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out BIT_VECTOR);
procedure
READ (L; inout LINE; VALUE: out BOOLEAN;GOOD: out BOOLEAN);
procedure
READ (L; inout LINE; VALUE: out BOOLEAN):
procedure
READ (L: inout LINE; VALUE: out CHARACTER;GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out CHARACTER);
procedure
READ (L: inout LINE; VALUE: out INTEGER;GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out INTEGER);
procedure
READ (L: inout LINE; VALUE: out REAL;GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out REAL);
procedure
READ (L: inout LINE; VALUE: out STRING;GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out STRING);
procedure
READ (L: inout LINE; VALUE: out TIME;GOOD: out BOOLEAN);
procedure
READ (L: inout LINE; VALUE: out TIME);
--
Output routines for standard types;
procedure
WRITELINE (F: out TEXT; L: in LINE);
procedure
WRITE (L: inout LINE; VALUE: in BIT; JUSTIFIED: in SIDE
:= RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in BIT_VECTOR;
JUSTIFIED:
in SIDE := RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in BOOLEAN:
JUSTIFIED:
in SIDE := RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in CHARACTER;
JUSTIFIED:
in SIDE := RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in INTEGER;
JUSTIFIED:
in SIDE := RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in REAL; JUSTIFIED: in SIDE
:= RIGHT; FIELD: in WIDTH := 0; DIGITS: in NATURAL := 0);
procedure
WRITE (L: inout LINE; VALUE: in STRING;
JUSTIFIED:
in SIDE := RIGHT; FIELD: in WIDTH := 0);
procedure
WRITE (L: inout LINE; VALUE: in TIME; JUSTIFIED: in SIDE
:= RIGHT; FIELD: in WIDTH := 0; UNIT; in TIME := ns); -- File
position predicates:
function
ENDLINE (L: in LINE) return BOOLEAN;
--
function ENDFILE (F: in TEXT) return BOOLEAN;
end TEXTIO;
No comments:
Post a Comment