![]() |
![]() |
Operands specify the data that the operator uses to compute its value. An operand returns its value to the operator.
There are many categories of operands. The simplest operand is a literal, such as the number 7, or an identifier, such as a variable or signal name. An operand itself can be an expression. You create expression operands by surrounding an expression with parentheses.
The operand categories follow.
The next two sections discuss operand bit-widths and explain computable operands. The sections following them describe the operand types listed above.
Foundation Express uses the bit-width of the largest operand to determine the bit-width needed to implement an operator in a circuit. For example, an INTEGER operand is 32 bits wide by default. An addition of two INTEGER operands causes Foundation Express to build a 32-bit adder.
To use hardware resources efficiently, always indicate the bit-width of numeric operands. For example, use a subrange of INTEGER when declaring types, variables, or signals.
type ENOUGH: INTEGER range 0 to 255;
variable WIDE: INTEGER range -1024 to 1023;
signal NARROW: INTEGER range 0 to 7;
Note: During optimization, Foundation Express removes hardware for unused bits.
Some operators, such as the division operator, restrict their operands to be computable. A computable operand is one whose value can be determined by Foundation Express. Computability is important because noncomputable expressions can require logic gates to determine their value.
Examples of computable operands follow.
Additionally, a variable is given a computable value if it is an OUT or INOUT parameter of a procedure that assigns it a computable value.
Examples of noncomputable operands follow.
The following example shows some definitions and declarations, followed by several computable and noncomputable expressions.
signal S: BIT;
. . .
function MUX(A, B, C: BIT) return BIT is
begin
if (C = '1') then
return(A);
else
return(B);
end if;
end;
procedure COMP(A: BIT; B: out BIT) is
begin
B := not A;
end;
process(S)
variable V0, V1, V2: BIT;
variable V_INT: INTEGER;
subtype MY_ARRAY is BIT_VECTOR(0 to 3);
variable V_ARRAY: MY_ARRAY;
begin
V0 := '1'; -- Computable (value is '1')
V1 := V0; -- Computable (value is '1')
V2 := not V1; -- Computable (value is '0')
for I in 0 to 3 loop
V_INT := I; -- Computable (value depends
-- on iteration)
end loop;
V_ARRAY := MY_ARRAY'(V1, V2, '0', '0');
-- Computable ("1000")
V1 := MUX(V0, V1, V2); -- Computable (value is '1')
COMP(V1, V2);
V1 := V2; -- Computable (value is '0')
V0 := S and '0'; -- Computable (value is '0')
V1 := MUX(S, '1', '0');-- Computable (value is '1')
V1 := MUX('1', '1', S);-- Computable (value is '1')
if (S = '1') then
V2 := '0'; -- Computable (value is '0')
else
V2 := '1'; -- Computable (value is '1')
end if;
V0 := V2; -- Noncomputable; V2 depends
-- on S
V1 := S; -- Noncomputable; S is signal
V2 := V1; -- Noncomputable; V1 is no
-- longer computable
end process;
Aggregates create array literals by giving a value to each element of an instance of an array type. Aggregates can also be considered array literals, because they specify an array type and the value of each array element. The syntax follows.
type_name' ([choice=>] expression {, [choice =>] expression})
type_name must be a constrained array type (as required by Foundation Express in the previous example), an element index, a sequence of indexes, or the others expression. Each expression provides a value for the chosen elements and must evaluate to a value of the element's type.
The following example shows an array type definition and an aggregate representing a literal of that array type. The two sets of assignments have the same result.
subtype MY_VECTOR is BIT_VECTOR(1 to 4);
signal X: MY_VECTOR;
variable A, B: BIT;
X <= MY_VECTOR'('1', A nand B, '1', A or B) -- Aggregate
-- assignment
X(1) <= '1'; -- Element assignment
X(2) <= A nand B;
X(3) <= '1';
X(4) <= A or B;
You can specify an element's index by using either positional or named notation. With positional notation, each element receives the value of its expression in order, as shown in the example above.
By using named notation, the choice => construct specifies one or more elements of the array. The choice can contain an expression (such as (I mod 2) =>) to indicate a single element index or a range (such as 3 to 5 => or 7 downto 0 =>) to indicate a sequence of element indexes.
An aggregate can use both positional and named notation. It is not necessary to specify all element indexes in an aggregate. All unassigned values are given a value by including others => expression as the last element of the list.
The following example shows several aggregates representing the same value.
subtype MY_VECTOR is BIT_VECTOR(1 to 4);
MY_VECTOR'('1', '1', '0', '0');
MY_VECTOR'(2 => '1', 3 => '0', 1 => '1', 4 => '0');
MY_VECTOR'('1', '1', others => '0');
MY_VECTOR'(3 => '0', 4 => '0', others => '1');
MY_VECTOR'(3 to 4 => '0', 2 downto 1 => '1');
The others expression must be the only expression in the aggregate. The following example shows two equivalent aggregates.
MY_VECTOR'(others => '1');
MY_VECTOR'('1', '1', '1', '1');
To use an aggregate as the target of an assignment statement, see the Assignment Statements and Targets section of the Sequential Statements chapter.
VHDL defines attributes for various types. A VHDL attribute takes a variable or signal of a given type and returns a value. The syntax of an attribute follows.
object'attribute
Foundation Express supports the following predefined VHDL attributes for use with arrays, as described in the Array Types section of the Data Types chapter.
Foundation Express also supports the following predefined VHDL attributes to use with wait and if statements, as described in the Register and Three-State Inference chapter.
In addition to supporting the predefined VHDL attributes listed above, Foundation Express has a defined set of synthesis-related attributes. You can include these Foundation Express-specific attributes in your VHDL design description to direct Foundation Express during optimization.
Operands can themselves be expressions. You create expression operands by surrounding an expression with parentheses, such as (A nand B).
A function call executes a named function with the given parameter values. The value returned to an operator is the function's return value. The syntax of a function call follows.
function_name ( [parameter_name =>] expression
{, [parameter_name =>] expression }
You can mix positional and named expressions in the same function call if you put all positional expressions before named parameter expressions.
The following example shows a function declaration and several equivalent function calls.
function FUNC(A, B, C: INTEGER) return BIT;
. . .
FUNC(1, 2, 3)
FUNC(B => 2, A => 1, C => 7 mod 4)
FUNC(1, 2, C => -3+6)
Identifiers are probably the most common operand. An identifier is the name of a constant, variable, signal, entity, port, subprogram, or parameter and returns the object's value to an operand.
Identifiers that contain special characters, begin with numbers, or have the same name as a keyword can be specified as an extended identifier. An extended identifier starts with a backslash character (\), followed by a sequence of characters, followed by another backslash character (\).
The following example shows some extended identifiers.
\a+b\ \3state\
\type\ \(a&b)|c\
The following example shows several kinds of identifiers and their usages. All identifiers appear in bold type.
entity EXAMPLE is
port (INT_PORT: in INTEGER;
BIT_PORT: out BIT);
end;
. . .
signal BIT_SIG: BIT;
signal INT_SIG: INTEGER;
. . .
INT_SIG <= INT_PORT; -- Signal assignment from port
BIT_PORT <= BIT_SIG; -- Signal assignment to port
function FUNC(INT_PARAM: INTEGER)
return INTEGER;
end function;
. . .
constant CONST: INTEGER := 2;
variable VAR: INTEGER;
. . .
VAR := FUNC(INT_PARAM => CONST); -- Function call
An indexed name identifies one element of an array variable or signal. The syntax of an indexed name follows.
identifier ( expression )
identifier is the name a signal or variable of an array type. The expression must return a value within the array's index range. The value returned to an operator is the specified array element.
If the expression is computable (see the Computable Operands section of this chapter), the operand is synthesized directly. If the expression is not computable, a circuit is synthesized that extracts the specified element from the array.
The following example shows two indexed names - one computable and one not computable. The figure for the resulting synthesized circuit design follows the example.
signal A, B: BIT_VECTOR(0 to 3);
signal I: INTEGER range 0 to 3;
signal Y, Z: BIT;
Y <= A(I); -- Noncomputable index expression
Z <= B(3); -- Computable index expression
You can also use indexed names as assignment targets; see the Assignment Statements and Targets section of the Sequential Statements chapter.
A literal (constant) operand can be a numeric literal, a character literal, an enumeration literal, or a string literal. The following sections describe these four kinds of literals.
Numeric literals are constant integer values. The two kinds of numeric literals are decimal and based. A decimal literal is written in base 10. A based literal can be written in a base from 2 to 16 and is composed of the base number, an octothorpe (#), the value in the given base, and another octothorpe (#); for example, 2#101# is decimal 5.
The digits in either kind of numeric literal can be separated by n underscores. The following example shows several different numeric literals, all representing the same value, which is 170.
170
1_7_0
10#170#
2#1010_1010#
16#AA#
Character literals are single characters enclosed in single quotation marks, for example, `A'. Character literals are used both as values for operators and to define enumerated types, such as CHARACTER and BIT. See the Enumeration Types section of the Data Types chapter for the valid character types.
Enumeration literals are values of enumerated types. The two kinds of enumeration literals are character literals and identifiers. Character literals were described previously. Enumeration identifiers are those literals listed in an enumeration type definition. The following example shows an enumeration type definition,
type SOME_ENUM is ( ENUM_ID_1, ENUM_ID_2, ENUM_ID_3);
If two enumerated types use the same literals, those literals are overloaded. You must qualify overloaded enumeration literals when you use them in an expression, unless their type can be determined from context (See the Qualified Expressions section of this chapter.) See Enumeration Types section of the Data Types chapter for more information.
The example below defines two enumerated types and shows some enumeration literal values.
type ENUM_1 is (AAA, BBB, 'A', 'B', ZZZ);
type ENUM_2 is (CCC, DDD, 'C', 'D', ZZZ);
AAA -- Enumeration identifier of type ENUM_1
'B' -- Character literal of type ENUM_1
CCC -- Enumeration identifier of type ENUM_2
'D' -- Character literal of type ENUM_2
ENUM_1'(ZZZ) -- Qualified because overloaded
String literals are one-dimensional arrays of characters, enclosed in double quotes (" "). The two kinds of string literals follow.
A string literal's type is a one-dimensional array of an enumerated type. Each of the characters in the string represents one element of the array. The following example shows character string literals.
"10101"
"ABCDEF"
Note: Null string literals ("") are not supported.
Bit strings, like based numeric literals, are composed of a base specific character, a double quotation mark, a sequence of numbers in the given base, and another double quotation mark. For example, B"0101" represents the bit vector 0101. A bit string literal consists of the base specifier B, O, or X, followed by a string literal. The bit string literal is interpreted as a bit vector, a one-dimensional array of the predefined type BIT. The base specifier determines the interpretation of the bit string as follows.
The value is in hexadecimal digits (0 to 9 and A to F). Each hexadecimal digit in the string represents four BITs in the generated bit vector (array).
You can separate the digits in a bit-string literal value with underscores ( _ ) for readability. The following example shows three bit string literals that represent the value AAA.
X"AAA"
B"1010_1010_1010"
O"5252
Qualified expressions state the type of an ambiguous operand. You cannot use qualified expressions for type conversion. (See the Type Conversions section of this chapter.)
The syntax of a qualified expression follows.
type_name'(expression)
type_name is the name of a defined type. The expression must evaluate to a value of an appropriate type.
Note: Foundation Express requires a single quotation mark (tick) between type_name and (expression). If the single quotation mark is omitted, the construction is interpreted as a type conversion (described in the next section).
The following example shows a qualified expression that resolves an overloaded function by qualifying the type of a decimal literal parameter.
type R_1 is range 0 to 10; -- Integer 0 to 10
type R_2 is range 0 to 20; -- Integer 0 to 20
function FUNC(A: R_1) return BIT;
function FUNC(A: R_2) return BIT;
FUNC(5) -- Ambiguous; could be of type R_1,
-- R_2, or INTEGER
FUNC(R_1'(5)) -- Unambiguous
The following example shows how qualified expressions resolve ambiguities in aggregates and enumeration literals.
type ARR_1 is array(0 to 10) of BIT;
type ARR_2 is array(0 to 20) of BIT;
. . .
(others => '0') -- Ambiguous; could be of
-- type ARR_1 or ARR_2
ARR_1'(others => '0') -- Qualified; unambiguous
-----------------------------------------------------
type ENUM_1 is (A, B);
type ENUM_2 is (B, C);
. . .
B -- Ambiguous; could be of
-- type ENUM_1 or ENUM_2
ENUM_1'(B) -- Qualified; unambiguous
Records are composed of named fields of any type. For more information, see the Record Types section of the Data Types chapter.
In an expression, you can refer to a whole record or to a single field. The syntax of field names follows.
record_name.field_name
The example below shows a record type definition and record and field access.
type BYTE_AND_IX is
record
BYTE: BIT_VECTOR(7 downto 0);
IX: INTEGER range 0 to 7;
end record;
signal X: BYTE_AND_IX;
. . .
X -- record
X.BYTE -- field: 8-bit array
X.IX -- field: integer
A field can be any type, including an array, record, or aggregate type. Refer to a field element by using that type's notation as in the following example.
X.BYTE(2) -- one element from array field BYTE
X.BYTE(3 downto 0) -- 4-element slice of array field -- BYTE
Slice names identify a sequence of elements in an array variable or signal. The syntax follows.
identifier ( expression direction expression )
identifier is the name of a signal or variable of an array type. Each expression must return a value within the array's index range and must be computable. See the Computable Operands section of this chapter.
The direction must be either to or downto. The direction of a slice must be the same as the direction of the identifier's array type. If the left and right expressions are equal, they define a single element.
The value returned to an operator is a subarray containing the specified array elements.
The following example uses slices to assign an 8-bit input to an 8-bit output, exchanging the lower and upper 4 bits. The figure for the resulting synthesized circuit design follows the example. Slices are also used as assignment targets. This usage is described in Assignment Statements and Targets section of the Sequential Statements chapter.
signal A, Z: BIT_VECTOR(0 to 7);
Z(0 to 3) <= A(4 to 7);
Z(4 to 7) <= A(0 to 3);
Foundation Express does not support null slices, which are indicated by the following.
The following example shows three null slices and one noncomputable slice.
subtype DOWN is BIT_VECTOR(4 downto 0);
subtype UP is BIT_VECTOR(0 to 7);
. . .
variable UP_VAR: UP;
variable DOWN_VAR: DOWN;
. . .
UP_VAR(4 to 3) -- Null slice (null range)
UP_VAR(4 downto 0) -- Null slice (wrong direction)
DOWN_VAR(0 to 1) -- Null slice (wrong direction)
variable I: INTEGER range 0 to 7;
. . .
UP_VAR(I to I+1) -- Noncomputable slice
IEEE VHDL does not allow noncomputable slices - slices whose range contains a noncomputable expression.
Type conversions change an expression's type. The syntax of a type conversion follows.
type_name (expression)
type_name is the name of a defined type. The expression must evaluate to a value of a type that can be converted into type type_name. The following conditions apply to type conversions.
The following example shows some type definitions and associated signal declarations, followed by valid and invalid type conversions.
type INT_1 is range 0 to 10;
type INT_2 is range 0 to 20;
type ARRAY_1 is array(1 to 10) of INT_1;
type ARRAY_2 is array(11 to 20) of INT_2;
subtype MY_BIT_VECTOR is BIT_VECTOR(1 to 10);
type BIT_ARRAY_10 is array(11 to 20) of BIT;
type BIT_ARRAY_20 is array(0 to 20) of BIT;
signal S_INT: INT_1;
signal S_ARRAY: ARRAY_1;
signal S_BIT_VEC: MY_BIT_VECTOR;
signal S_BIT: BIT;
-- Legal type conversions
INT_2(S_INT)
-- Integer type conversion
BIT_ARRAY_10(S_BIT_VEC)
-- Similar array type conversion
-- Illegal type conversions
BOOLEAN(S_BIT);
-- Can't convert between enumerated types
INT_1(S_BIT);
-- Can't convert enumerated types to other types
BIT_ARRAY_20(S_BIT_VEC);
-- Array lengths not equal
ARRAY_1(S_BIT_VEC);
-- Element types cannot be converted