10.9  Other Declarations

Chapter  start   Previous page  Next  page

10.9  Other Declarations

A declaration is one of the following [VHDL LRM4]:

declaration ::=
  type_declaration 	| subtype_declaration	| object_declaration
| interface_declaration 	| alias_declaration	| attribute_declaration
| component_declaration 	| entity_declaration
| configuration_declaration  | subprogram_declaration
| package_declaration
| group_template_declaration | group_declaration 

I discussed entity, configuration, component, package, interface, type, and subtype declarations in Sections 10.5-10.8. Next I shall discuss the other types of declarations (except for groups or group templates [VHDL 93LRM4.6-4.7], new to VHDL-93, that are not often used in ASIC design).

10.9.1  Object Declarations

There are four object classes in VHDL: constant, variable, signal, and file [VHDL LRM 4.3.1.1-4.3.1.3]. You use a constant declaration, signal declaration, variable declaration, or file declaration together with a type. Signals can only be declared in the declarative region (before the first begin ) of an architecture or block, or in a package (not in a package body). Variables can only be declared in the declarative region of a process or subprogram (before the first begin ). You can think of signals as representing real wires in hardware. You can think of variables as memory locations in the computer. Variables are more efficient than signals because they require less overhead.

You may assign an (explicit) initial value when you declare a type. If you do not provide initial values, the (implicit) default initial value of a type or subtype T is T'LEFT (the leftmost item in the range of the type). For example:

entity Initial_1 is end; architecture
Behave of Initial_1 is
type Fahrenheit is range 32 to 212; 																-- Default initial value is 32.
type Rainbow is (R, O, Y, G, B, I, V);																-- Default initial value is R.
type MVL4 is ('X', '0', '1', 'Z');																-- MVL4'LEFT = 'X'.
-begin end;

The details of initialization and assignment of initial values are important--it is difficult to implement the assignment of initial values in hardware--instead it is better to mimic the hardware and use explicit reset signals.

Here are the formal definitions of constant and signal declarations:

constant_declaration ::= constant
identifier {, identifier}:subtype_indication [:= expression] ;
signal_declaration ::= signal
identifier {, identifier}:subtype_indication [register|bus] [:=expression];

I shall explain the use of signals of kind register or bus in Section 10.13.1. Signal declarations are explicit signal declarations (ports declared in an interface declaration are implicit signal declarations). Here is an example that uses a constant and several signal declarations:

entity Constant_2 is end; 
library IEEE; use IEEE.STD_LOGIC_1164.all;
architecture Behave of Constant_2 is
constant Pi : REAL := 3.14159;																		-- A constant declaration.
signal B : BOOLEAN; signal s1, s2: BIT; 
signal sum : INTEGER range 0 to 15;																		-- Not a new type.
signal SmallBus : BIT_VECTOR (15 downto 0);																		-- 16-bit bus.
signal GBus : STD_LOGIC_VECTOR (31 downto 0); bus; -- A guarded signal.
begin end;

Here is the formal definition of a variable declaration:

variable_declaration ::= [shared] variable
identifier {, identifier}:subtype_indication [:= expression] ;

A shared variable can be used to model a varying quantity that is common across several parts of a model, temperature, for example, but shared variables are rarely used in ASIC design. The following examples show that variable declarations belong inside a process statement, after the keyword process and before the first appearance of the keyword begin inside a process:

library IEEE; use IEEE.STD_LOGIC_1164.all; entity Variables_1 is end;
architecture Behave of Variables_1 is begin process
	variable i : INTEGER range 1 to 10 := 10; -- Initial value = 10.
	variable v : STD_LOGIC_VECTOR (0 to 31) := (others => '0'); 
	begin wait; end process; -- The wait stops an endless cycle.
end;

10.9.2  Subprogram Declarations

VHDL code that you use several times can be declared and specified as subprograms (functions or procedures) [VHDL LRM2.1]. A function is a form of expression, may only use parameters of mode in , and may not contain delays or sequence events during simulation (no wait statements, for example). Functions are useful to model combinational logic. A procedure is a form of statement and allows you to control the scheduling of simulation events without incurring the overhead of defining several separate design entities. There are thus two forms of subprogram declaration: a function declaration or a procedure declaration.

subprogram_declaration ::= subprogram_specification ; ::=
 procedure 
	identifier|string_literal [(parameter_interface_list)]
| [pure|impure] function
	identifier|string_literal [(parameter_interface_list)]
return type_name|subtype_name;

Here are a function and a procedure declaration that illustrate the difference:

function add(a, b, c : BIT_VECTOR(3 downto 0)) return BIT_VECTOR is
-- A function declaration, a function can't modify a, b, or c.
procedure Is_A_Eq_B (signal A, B : BIT; signal Y : out BIT);
-- A procedure declaration, a procedure can change Y.

Parameter names in subprogram declarations are called formal parameters (or formals). During a call to a subprogram, known as subprogram invocation, the passed values are actual parameters (or actuals). An impure function, such as the function now or a function that writes to or reads from a file, may return different values each time it is called (even with the same actuals). A pure function (the default) returns the same value if it is given the same actuals. You may call subprograms recursively. Table 10.13 shows the properties of subprogram parameters.

TABLE 10.13    Properties of subprogram parameters.

Example subprogram declarations:

 function my_function(Ff) return BIT is -- Formal function parameter, Ff.
procedure my_procedure(Fp);           -- Formal procedure parameter, Fp.

Example subprogram calls:

 my_result := my_function(Af); -- Calling a function with an actual parameter, Af.
MY_LABEL:my_procedure(Ap);   -- Using a procedure with an actual parameter, Ap.

Mode of Ff or Fp (formals)

in

out

inout

No mode

Permissible classes for Af

(function actual parameter)

constant (default)

signal

Not allowed

Not allowed

file

Permissible classes for Ap

(procedure actual parameter)

 

constant (default)

variable

signal

constant

variable (default)

signal

constant

variable (default)

signal

file

Can you read attributes of

Ff or Fp (formals)?

Yes, except:

 'STABLE

 'QUIET

 'DELAYED

 'TRANSACTION

of a signal

Yes, except:

 'STABLE 'QUIET

 'DELAYED

 'TRANSACTION

 'EVENT 'ACTIVE

 'LAST_EVENT

 'LAST_ACTIVE

 'LAST_VALUE

of a signal

Yes, except:

 'STABLE

 'QUIET

 'DELAYED

 'TRANSACTION

of a signal

 

A subprogram declaration is optional, but a subprogram specification must be included in the subprogram body (and must be identical in syntax to the subprogram declaration--see BNF [10.19]):

subprogram_body ::=
	subprogram_specification is
	{subprogram_declaration|subprogram_body
	|type_declaration|subtype_declaration
	|constant_declaration|variable_declaration|file_declaration
	|alias_declaration|attribute_declaration|attribute_specification
	|use_clause|group_template_declaration|group_declaration}
	begin
		{sequential_statement}
	end [procedure|function] [identifier|string_literal] ;

You can include a subprogram declaration or subprogram body in a package or package body (see Section 10.6) or in the declarative region of an entity or process statement. The following is an example of a function declaration and its body:

function subset0(sout0 : in BIT) return BIT_VECTOR -- declaration
-- Declaration can be separate from the body.
function subset0(sout0 : in BIT) return BIT_VECTOR is -- body
variable y : BIT_VECTOR(2 downto 0);
begin 
if (sout0 = '0') then y := "000"; else y := "100"; end if;
return result;
end;
procedure clockGen (clk : out BIT) 																												-- Declaration
procedure clockGen (clk : out BIT) is 																					-- Specification
begin -- Careful this process runs forever: 
	process begin wait for 10 ns; clk <= not clk; end process;
end;

One reason for having the optional (and seemingly redundant) subprogram declaration is to allow companies to show the subprogram declarations (to document the interface) in a package declaration, but to hide the subprogram bodies (the actual code) in the package body. If a separate subprogram declaration is present, it must conform to the specification in the subprogram body [VHDL 93LRM2.7]. This means the specification and declaration must be almost identical; the safest method is to copy and paste. If you define common procedures and functions in packages (instead of in each entity or architecture, for example), it will be easier to reuse subprograms. In order to make a subprogram included in a package body visible outside the package, you must declare the subprogram in the package declaration (otherwise the subprogram is private).

You may call a function from any expression, as follows:

entity F_1 is port (s : out BIT_VECTOR(3 downto 0) := "0000"); end;
architecture Behave of F_1 is begin process
function add(a, b, c : BIT_VECTOR(3 downto 0)) return BIT_VECTOR is
begin return a xor b xor c; end;
begin s <= add("0001", "0010", "1000"); wait; end process; end;
package And_Pkg is 
	procedure V_And(a, b : BIT; signal c : out BIT); 
	function V_And(a, b : BIT) return BIT;
end;
package body And_Pkg is 
	procedure V_And(a,b : BIT; signal c : out BIT) is 
		begin c <= a and b; end;
	function V_And(a,b : BIT) return BIT is 
		begin return a and b; end;
end And_Pkg;
entity F_2 is port (s: out BIT := '0'); end;
use work.And_Pkg.all; -- use package already analyzed
architecture Behave of F_2 is begin process begin 
s <= V_And('1', '1'); wait; end process; end;

I shall discuss the two different ways to call a procedure in Sections 10.10.4 and 10.13.3.

10.9.3  Alias and Attribute Declarations

An alias declaration [VHDL 87LRM4.3.4, 93LRM4.3.3] names parts of a type:

alias_declaration ::= 
alias 
	identifier|character_literal|operator_symbol  [ :subtype_indication]
	is name [signature] ;

(the subtype indication is required in VHDL-87, but not in VHDL-93).

Here is an example of alias declarations for parts of a floating-point number:

entity Alias_1 is end; architecture Behave of Alias_1 is
begin process variable Nmbr: BIT_VECTOR (31 downto 0);
-- alias declarations to split Nmbr into 3 pieces :
alias Sign : BIT is Nmbr(31);
alias Mantissa : BIT_VECTOR (23 downto 0) is Nmbr (30 downto 7);
alias Exponent : BIT_VECTOR ( 6 downto 0) is Nmbr ( 6 downto 0);
begin wait; end process; end; -- the wait prevents an endless cycle

An attribute declaration [VHDL LRM4.4] defines attribute properties:

attribute_declaration ::=
 attribute identifier:type_name ; | attribute identifier:subtype_name ;

Here is an example:

entity Attribute_1 is end; architecture Behave of Attribute_1 is
begin process type COORD is record X, Y : INTEGER; end record; 
attribute LOCATION : COORD; -- the attribute declaration
begin wait ; -- the wait prevents an endless cycle
end process; end;

You define the attribute properties in an attribute specification (the following example specifies an attribute of a component label). You probably will not need to use your own attributes very much in ASIC design.

attribute LOCATION of adder1 : label is (10,15);

You can then refer to your attribute as follows:

positionOfComponent := adder1'LOCATION;

10.9.4  Predefined Attributes

The predefined attributes for scalar and array types in VHDL-93 are shown in Table 10.14 [VHDL 93LRM14.1]. There are two attributes, 'STRUCTURE and 'BEHAVIOR , that are present in VHDL-87, but removed in VHDL-93. Both of these attributes apply to architecture bodies. The attribute name A'BEHAVIOR is TRUE if the architecture A does not contain component instantiations. The attribute name A'STRUCTURE is TRUE if the architecture A contains only passive processes (those with no assignments to signals) and component instantiations. These two attributes were not widely used. The attributes shown in Table 10.14, however, are used extensively to create packages and functions for type conversion and overloading operators, but should not be needed by an ASIC designer. Many of the attributes do not correspond to "real" hardware and cannot be implemented by a synthesis tool.

TABLE 10.14    Predefined attributes for scalar and array types.

Attribute

Kind 1

Prefix

T, A, E 2

Parameter X or N 3

Result type 3

Result

T'BASE

T

any

 

base(T)

base(T), use only with other attribute

T'LEFT

V

scalar

 

T

Left bound of T

T'RIGHT

V

scalar

 

T

Right bound of T

T'HIGH

V

scalar

 

T

Upper bound of T

T'LOW

V

scalar

 

T

Lower bound of T

T'ASCENDING

V

scalar

 

BOOLEAN

True if range of T is ascending 4

T'IMAGE(X)

F

scalar

base(T)

STRING

String representation of X in T 4

T'VALUE(X)

F

scalar

STRING

base(T)

Value in T with representation X 4

T'POS(X)

F

discrete

base(T)

UI

Position number of X in T (starts at 0)

T'VAL(X)

F

discrete

UI

base(T)

Value of position X in T

T'SUCC(X)

F

discrete

base(T)

base(T)

Value of position X in T plus one

T'PRED(X)

F

discrete

base(T)

base(T)

Value of position X in T minus one

T'LEFTOF(X)

F

discrete

base(T)

base(T)

Value to the left of X in T

T'RIGHTOF(X)

F

discrete

base(T)

base(T)

Value to the right of X in T

A'LEFT[(N)]

F

array

UI

T(Result)

Left bound of index N of array A

A'RIGHT[(N)]

F

array

UI

T(Result)

Right bound of index N of array A

A'HIGH[(N)]

F

array

UI

T(Result)

Upper bound of index N of array A

A'LOW[(N)]

F

array

UI

T(Result)

Lower bound of index N of array A

A'RANGE[(N)]

R

array

UI

T(Result)

Range A'LEFT(N) to A'RIGHT(N) 5

A'REVERSE_RANGE[(N)]

R

array

UI

T(Result)

Opposite range to A'RANGE[(N)]

A'LENGTH[(N)]

V

array

UI

UI

Number of values in index N of array A

A'ASCENDING[(N)]

V

array

UI

BOOLEAN

True if index N of A is ascending 4

E'SIMPLE_NAME

V

name

 

STRING

Simple name of E 4

E'INSTANCE_NAME

V

name

 

STRING

Path includes instantiated entities 4

E'PATH_NAME

V

name

 

STRING

Path excludes instantiated entities 4

The attribute 'LEFT is important because it determines the default initial value of a type. For example, the default initial value for type BIT is BIT'LEFT , which is '0' . The predefined attributes of signals are listed in Table 10.15. The most important signal attribute is 'EVENT , which is frequently used to detect a clock edge. Notice that Clock'EVENT , for example, is a function that returns a value of type BOOLEAN , whereas the otherwise equivalent not(Clock'STABLE) , is a signal. The difference is subtle but important when these attributes are used in the wait statement that treats signals and values differently.

TABLE 10.15    Predefined attributes for signals.

Attribute

Kind 6

Parameter T 7

Result type 8

Result/restrictions

S'DELAYED [(T)]

S

TIME

base(S)

S delayed by time T

S'STABLE [(T)]

S

TIME

BOOLEAN

TRUE if no event on S for time T

S'QUIET [(T)]

S

TIME

BOOLEAN

TRUE if S is quiet for time T

S'TRANSACTION

S

 

BIT

Toggles each cycle if S becomes active

S'EVENT

F

 

BOOLEAN

TRUE when event occurs on S

S'ACTIVE

F

 

BOOLEAN

TRUE if S is active

S'LAST_EVENT

F

 

TIME

Elapsed time since the last event on S

S'LAST_ACTIVE

F

 

TIME

Elapsed time since S was active

S'LAST_VALUE

F

 

base(S)

Previous value of S, before last event 9

S'DRIVING

F

 

BOOLEAN

TRUE if every element of S is driven 10

S'DRIVING_VALUE

F

 

base(S)

Value of the driver for S in the current process 10


1. T = Type, F = Function, V = Value, R = Range.

2. any = any type or subtype, scalar = scalar type or subtype, discrete = discrete or physical type or subtype, name = entity name = identifier, character literal, or operator symbol.

3. base(T) = base type of T, T = type of T, UI = universal_integer, T(Result) = type of object described in result column.

4. Only available in VHDL-93. For 'ASCENDING all enumeration types are ascending.

5. Or reverse for descending ranges.

6. F = function, S = signal.

7. Time T >= 0 ns. The default, if T is not present, is T = 0 ns.

8. base(S) = base type of S.

9. VHDL-93 returns last value of each signal in array separately as an aggregate, VHDL-87 returns the last value of the composite signal.

10. VHDL-93 only.


Chapter  start   Previous  page   Next  page




© 2024 Internet Business Systems, Inc.
670 Aberdeen Way, Milpitas, CA 95035
+1 (408) 882-6554 — Contact Us, or visit our other sites:
AECCafe - Architectural Design and Engineering EDACafe - Electronic Design Automation GISCafe - Geographical Information Services TechJobsCafe - Technical Jobs and Resumes ShareCG - Share Computer Graphic (CG) Animation, 3D Art and 3D Models
  Privacy PolicyAdvertise