Tải bản đầy đủ (.pdf) (26 trang)

Advanced Topics

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (163.7 KB, 26 trang )

CHAPTER
8
Advanced Topics
In this chapter, some of the more esoteric features of
VHDL are discussed. Some of the features may be useful
for certain types of designs, and not for others. Typical
usage examples are presented to show how these features
might be taken advantage of.
Some of the features discussed include overloading,
qualified expressions, user-defined attributes, generate
statements, aliases, and TextIO. All of these features pro-
vide the user with an advanced environment with which
to do modeling.
8
Chapter Eight
206
Overloading
Overloading allows the designer to write much more readable code. An
object is overloaded when the same object name exists for multiple sub-
programs or type values. The VHDL compiler selects the appropriate
object to use in each instance.
In VHDL, a number of types of overloading are possible. Subprograms
can be overloaded, operators can be overloaded, and enumeration types can
be overloaded. Overloading subprograms allows subprograms to operate
on objects of different types. Overloading an operator allows the oper-
ator to perform the same operation on multiple types. Overloading frees
the designer from the necessity of generating countless unique names for
subprograms that do virtually the same operation. The result of using
overloaded subprograms and operators is models that are easier to read
and maintain.
Subprogram Overloading


Subprogram overloading allows the designer to write multiple subprograms
with the same name, but the number of arguments, the type of arguments,
and return value (if any) can be different. The VHDL compiler, at compile
time, selects the subprogram that matches the subprogram call. If no sub-
program matches the call, an error is generated.
The following example illustrates how a subprogram can be overloaded
by the argument type:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
PACKAGE p_shift IS
TYPE s_int IS RANGE 0 TO 255;
TYPE s_array IS ARRAY(0 TO 7) OF std_logic;
FUNCTION shiftr( a : s_array) return s_array;
FUNCTION shiftr( a : s_int) return s_int;
END p_shift;
PACKAGE BODY p_shift IS
FUNCTION shiftr( a : s_array) return s_array IS
VARIABLE result : s_array;
BEGIN
FOR i IN a’RANGE LOOP
IF i = a’HIGH THEN
result(i) := ‘0’;
207
Advanced Topics
ELSE
result(i) := a(i + 1);
END IF;
END LOOP;
RETURN result;
END shiftr;

FUNCTION shiftr( a : s_int) return s_int IS
BEGIN
RETURN (a/2);
END shiftr;
END p_shift;
The package
p_shift
contains two functions both named
shiftr
. Both
functions provide a right-shift capability, but each function operates on a
specific type. One function works only with type
s_int
, and the other
works only with type
s_array
. The compiler picks the appropriate function
based on the calling argument(s) and return argument.
In the following example, different types of function calls are shown,
and the results obtained with each call:
USE WORK.p_shift.ALL;
ENTITY shift_example IS
END shift_example;
ARCHITECTURE test OF shift_example IS
SIGNAL int_signal : s_int;
SIGNAL array_signal : s_array;
BEGIN
-- picks function that works with s_int type
int_signal <= shiftr(int_signal);
-- picks function that works with

-- s_array type
array_signal <= shiftr(array_signal);
-- produces error because no function
-- will match
array_signal <= shiftr(int_signal);
END test;
The architecture test contains three calls to function
shiftr
. The first
calls
shiftr
with an argument type of
s_int
and a return type of
s_int
.
This call uses the second function described in package body
p_shift
, the
function with input arguments, and return type of
s_int
.
The second call to
shiftr
uses the array type
s_array
, and therefore
picks the first function defined in package
p_shift
. Both the input

Chapter Eight
208
argument(s) type(s) and return type must match for the function to
match the call.
The third call to function
shiftr
shows an example of a call where the
input argument matches the
s_int
type function, but the return type of
the function does not match the target signal. With the functions cur-
rently described in package
p_shift
, no function matches exactly, and
therefore the compilation of the third line produces an error.
To make the third call legal, all that is needed is to define a function
that matches the types of the third call. An example of the function decla-
ration is shown in the following code line. The function body for this
function is left as an exercise for the reader:
FUNCTION shiftr( a : s_int) return s_array;
OVERLOADING SUBPROGRAM ARGUMENT TYPES To overload
argument types, the base type of the subprogram parameters or return
value must differ. For example, base types do not differ when two subtypes
are of the same type. Two functions that try to overload these subtypes pro-
duce a compile error. Following is an example:
PACKAGE type_error IS
SUBTYPE log4 IS BIT_VECTOR( 0 TO 3);
SUBTYPE log8 IS BIT_VECTOR( 0 TO 7);
-- this function is Ok
FUNCTION not( a : log4) return integer;

-- this function declaration will cause an
-- error
FUNCTION not( a : log8) return integer;
END type_error;
This package declares two subtypes
log4
and
log8
of the uncon-
strained
BIT_VECTOR
type. Two functions named
not
are then declared
using these subtypes. The first function declaration is legal, but the second
function declaration causes an error. The error is that two functions have
been declared for the same base type. The two types
log4
and
log8
are
not distinct, because they both belong to the same base type.
All of the examples shown so far have been overloading of functions.
Overloading of procedures works in the same manner.
SUBPROGRAM PARAMETER OVERLOADING Two or more sub-
programs with the same name can have a different number of parameters.
209
Advanced Topics
The types of the parameters can be the same, but the number of
parameters can be different. This is shown by the following example:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
PACKAGE p_addr_convert IS
FUNCTION convert_addr(a0, a1 : std_logic) return integer;
FUNCTION convert_addr(a0, a1, a2 : std_logic)return
integer;
FUNCTION convert_addr(a0, a1, a2, a3 : std_logic) return
integer;
END p_addr_convert;
PACKAGE BODY p_addr_convert IS
FUNCTION convert_addr(a0, a1 : std_logic) RETURN
INTEGER IS
VARIABLE result : INTEGER := 0;
BEGIN
IF (a0 = ‘1’) THEN
result := result + 1;
END IF;
IF (a1 = ‘1’) THEN
result := result + 2;
END IF;
RETURN result;
END convert_addr;
FUNCTION convert_addr(a0, a1, a2 : std_logic) RETURN
INTEGER IS
VARIABLE result : INTEGER := 0;
BEGIN
result := convert_addr(a0, a1);
IF (a2 = ‘1’) THEN
result := result + 4;
END IF;

RETURN result;
END convert_addr;
FUNCTION convert_addr(a0, a1, a2, a3 : std_logic) RETURN
INTEGER IS
VARIABLE result : INTEGER := 0;
BEGIN
result := convert_addr(a0, a1, a2);
IF (a3 = ‘1’) THEN
Chapter Eight
210
result := result + 8;
END IF;
RETURN result;
END convert_addr;
END p_addr_convert;
This package declares three functions that convert 2, 3, or 4 input bits
into integer representation. Each function is named the same, but the
appropriate function is called depending on the number of input arguments
that are passed to the function. If 2 bits are passed to the function, then
the function with two arguments is called. If 3 bits are passed, the func-
tion with three arguments is called, and so on.
Following is an example using these functions:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE WORK.p_addr_convert.ALL;
ENTITY test IS
PORT(i0, i1, i2, i3 : in std_logic);
END test;
ARCHITECTURE test1 OF test IS
SIGNAL int1, int2, int3 : INTEGER;

BEGIN
-- uses first function
int1 <= convert_addr(i0, i1);
-- uses second function
int2 <= convert_addr(i0, i1, i2);
-- uses third function
int3 <= convert_addr(i0, i1, i2, i3);
END test1;
The first call to the
convert_addr
function has only two arguments in
the argument list, and therefore the first function in package
p_addr_convert
is used. The second call has three arguments in its
argument list and calls the second function. The last call matches the
third function from package
p_addr_convert
.
Overloading Operators
One of the most useful applications of overloading is the overloading of
operators. The need for overloading operators arises because the operators
211
Advanced Topics
supplied in VHDL only work with specific types. For instance, the
+
opera-
tor only works with integer, real, and physical types, while the
&
(concate-
nation) operator only works with array types. If a designer wants to use

a particular operator on a user-defined type, then the operator must be
overloaded to handle the user type. A complete listing of the operators and
the types supported by them can be found in the VHDL Language Refer-
ence Manual.
An example of a typical overloaded operator is the
+
operator. The
+
operator is defined for the numeric types, but if the designer wants to add
two
BIT_VECTOR
objects, the
+
operator does not work. The designer must
write a function that overloads the operator to accomplish this operation.
The following package shows an overloaded function for operator
+
that
allows addition of two objects of
BIT_VECTOR
types:
PACKAGE math IS
FUNCTION “+”( l,r : BIT_VECTOR) RETURN INTEGER;
END math;
PACKAGE BODY math IS
FUNCTION vector_to_int( S : BIT_VECTOR) RETURN INTEGER IS
VARIABLE result : INTEGER := 0;
VARIABLE prod : INTEGER := 1;
BEGIN
FOR i IN s’RANGE LOOP

IF s(i) = ‘1’ THEN
result := result + prod;
END IF;
prod := prod * 2;
END LOOP;
RETURN result;
END vector_to_int;
FUNCTION “+”(l,r : BIT_VECTOR) RETURN INTEGER IS
BEGIN
RETURN ( vector_to_int(l) + vector_to_int(r));
END;
END math;
Whenever the
+
operator is used in an expression, the compiler calls
the
+
operator function that matches the types of the operands. When the
operands are of type
INTEGER
, the built-in
+
operator function is called. If
the operands are of type
BIT_VECTOR
, then the function from package
math
is called. The following example shows uses for both functions:
USE WORK.math.ALL;
ENTITY adder IS

PORT( a, b : IN BIT_VECTOR(0 TO 7);
Chapter Eight
212
PORT( c : IN INTEGER;
PORT( dout : OUT INTEGER);
END adder;
ARCHITECTURE test OF adder IS
SIGNAL internal : INTEGER;
BEGIN
internal <= a + b;
dout <= c + internal;
END test;
This example illustrates how overloading can be used to make very
readable models. The value assigned to signal
internal
is the sum of
inputs
a
and
b
. Since
a
and
b
are of type
BIT_VECTOR
, the overloaded
operator function that has two
BIT_VECTOR
arguments is called. This func-

tion adds the values of
a
and
b
together and returns an integer value to
be assigned to signal
internal
.
The second addition uses the standard built-in addition function that
is standard in VHDL because both operands are of type
INTEGER
. This
model could have been written as shown in the following, but would still
function in the same manner:
PACKAGE math IS
FUNCTION addvec( l,r : bit_vector) RETURN INTEGER;
END math;
PACKAGE BODY math IS
FUNCTION vector_to_int( S : bit_vector) RETURN INTEGER IS
VARIABLE result : INTEGER := 0;
VARIABLE prod : INTEGER := 1;
BEGIN
FOR i IN s’RANGE LOOP
IF s(i) = ‘1’ THEN
result := result + prod;
END IF;
prod := prod * 2;
END LOOP;
RETURN result;
END vector_to_int;

FUNCTION addvec(l,r : bit_vector) RETURN INTEGER IS
BEGIN
RETURN ( vector_to_int(l) + vector_to_int(r));
END addvec;
END math;
USE WORK.math.ALL;
ENTITY adder IS
PORT( a, b : IN BIT_VECTOR(0 TO 7);
PORT( c : IN INTEGER;
213
Advanced Topics
PORT( dout : OUT INTEGER);
END adder;
ARCHITECTURE test2 OF adder IS
SIGNAL internal : INTEGER;
BEGIN
internal <= addvec(a,b);
dout <= c + internal;
END test2;
In this example, a function called
advec
is used to add
a
and
b
. Both
coding styles give exactly the same results, but the first example using
the overloaded
+
operator is much more readable and easier to maintain.

If another person besides the designer of a model takes over the mainte-
nance of the model, it is much easier for the new person to understand
the model if overloading was used.
OPERATOR ARGUMENT TYPE OVERLOADING Arguments to
overloaded operator functions do not have to be of the same type, as the
previous two examples have shown. The parameters to an overloaded
operator function can be of any type. In some cases, it is preferable to
write two functions so that the order of the arguments is not important.
Let’s examine the functions for an overloaded logical operator that mixes
signals of type
BIT
and signals of a nine-state value system:
PACKAGE p_logic_pack IS
TYPE t_nine_val IS (Z0, Z1, ZX,
TYPE t_nine_val IS (R0, R1, RX,
TYPE t_nine_val IS (F0, F1, FX);
FUNCTION “AND”( l, r : t_nine_val) RETURN BIT;
FUNCTION “AND”( l : BIT; r : t_nine_val) RETURN BIT;
FUNCTION “AND”( l : t_nine_val; r : BIT) RETURN BIT;
END p_logic_pack;
PACKAGE BODY p_logic_pack IS
FUNCTION nine_val_2_bit( t : IN t_nine_val) RETURN BIT IS
TYPE t_nine_val_conv IS ARRAY(t_nine_val) OF BIT;
CONSTANT nine_2_bit : t_nine_val_conv :=
(‘0’, — Z0
‘1’, — Z1
‘1’, — ZX
‘0’, — R0
‘1’, — R1
Chapter Eight

214
‘1’, — RX
‘0’, — F0
‘1’, — F1
‘1’); — FX
BEGIN
RETURN nine_2_bit(t);
END nine_val_2_bit;
FUNCTION “AND”(l,r : t_nine_val) RETURN BIT IS
BEGIN
RETURN (nine_val_2_bit(l) AND nine_val_2_bit(r));
END;
FUNCTION “AND”(l :BIT; r : t_nine_val) RETURN BIT IS
BEGIN
RETURN ( l AND nine_val_2_bit(r));
END;
FUNCTION “AND”(l : t_nine_val; r : BIT) RETURN BIT IS
BEGIN
RETURN (nine_val_2_bit(l) AND r);
END;
END p_logic_pack;
The package
p_logic_pack
declares three overloaded functions for the
AND
operator. In one function, both input types are type
t_nine_val
.In
the other two functions, only one input is type
t_nine_val

, and the other
input is type
BIT
. All functions return a result of type
BIT
. Notice that, to
overload the
AND
operator, the syntax is the same as overloading the
+
operator from the previous example.
When the
AND
operator is used in a model, the appropriate function is
called based on the types of the operands. In the following code fragments,
we can see the differences:
SIGNAL a, b : t_nine_val;
SIGNAL c,e : bit;
e <= a AND b;
-- calls first function
e <= a AND c;
-- calls third function
e <= c AND b;
-- calls second function
By having three functions called
AND
, we do not need to worry about
which side of the operator an expression resides on. All of the possible

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×