Chapter 4. New and Changed Operations

In VHDL, we model computation by writing expressions that involve application of operations (operators and functions) to operand values. Each operand is of some type, either predefined or user-defined. VHDL defines overloaded versions of operations to perform computation on values of various types. In VHDL-2008, a number of new operations are introduced, and the variety of types to which existing operations can be applied is expanded. We describe the new and changed operations in this chapter.

One point to note is that in earlier versions of VHDL, many of the operations were defined in separate standards. In particular, IEEE Std 1164 specified the package std_logic_l164, which defined the types std_ulogic, stdjogic, std_ulogic_vector, and std_logic_vector and the operations on those types. Also, IEEE Std 1076.3 specified the packages numeric_bit and numeric_std, each of which defined the types unsigned and signed and operations on those types. All of these packages are now included as part of the VHDL-2008 standard. Other changes to the standard packages are described in Chapters 7 and 8.

Array/Scalar Logical Operations

VHDL provides logical operators, and, or, nand, nor, xor, and xnor, that each operate on a pair of values to produce a result. Earlier versions of VHDL provided predefined and standard overloaded definitions of these operators with the following signatures:

[ScalarType, ScalarType return ScalarType]
[ArrayType,  ArrayType  return ArrayType]

ScalarType included the types bit, boolean, and std_ulogic, and ArrayType included arrays of bit, boolean, and std_ulogic (std_ulogic_vector, std_logic_vector, unsigned, and signed). While this was sufficient for many purposes, there were some common modeling problems that required one operand to be an array and the other a scalar, yielding an array result. To meet this requirement, VHDL-2008 provides further overloaded definitions of the logical operators with the following signatures:

[ArrayType,         ArrayElementType return ArrayType]
[ArrayElementType ,ArrayType return         ArrayType]

As before, ArrayType includes arrays of bit, boolean, and std_ulogic. ArrayElementType is the scalar element type of the other operand. Thus, for example, we can apply an operator such as and to a bit_vector and a bit operand. The bit value is ANDed with each element of the array to produce an array result.

Example 4.1. Select Logic

A common problem in coding register read logic is using select bits (each a scalar value) to select among several registers (array values). One possible coding that could be used in earlier versions of VHDL is:

genloop : for i in data_bus' range generate
begin
  data_bus(i) <= (a(i) and a_sel) or
                    (b(i) and b_sel) or
                    (c(i) and c_sel);
end generate;

Here, a_sel, b_sel and c_sel are the scalar select signals, and a, b, and c are the register values. Note that this coding requires the array indices for the register values and the data bus to be the same. An alternate solution that uses intermediate signals is:

signal va_sel, vb_sel, vc_sel :
         std_logic_vector(data_bus'range);
. . .

va_sel <= (others => a_sel);
vb_sel <= (others => b_sel);
vc_sel <= (others => c_sel);
data_bus <= (a and va_sel) or (b and vb_sel) or (c and vc_sel);

Note that this solution does not require the array indices to be the same. The following third alternative is functionally correct if the select signals are mutually exclusive; however, for larger sized “AND-OR” logic, it results in an inefficient hardware implementation known as priority select logic.

data_bus <= a when  a_sel = '1' else
               b when  b_sel = '1' else
               c when  c_sel = '1' else
               (others => '0'),

With the new overloaded definitions introduced in VHDL-2008, these alternatives can be replaced with the simple assignment:

data_bus <= (a and a_sel) or (b and b_sel) or (c and c_sel);

In each and term, the scalar value is applied to each bit of the array value. In effect, the scalar value is replicated in the same manner as the intermediate signal solution, but the statement is much more succinct.

Array/Scalar Addition Operators

The numeric_bit and numeric_std packages define overloaded addition (“+”) and subtraction (“-”) operators for unsigned and signed operands. Prior to VHDL-2008, if we wanted to code an addition with carry in, we had to convert the carry in to an array value, as follows:

signal c_in  : std_logic;
signal a, b  : unsigned(7 downto 0);
signal adder : unsigned(8 downto 0);
. . .

adder <= ('0' & a) + ('0' & b) + ("" & c_in);

Unfortunately, many synthesis tools saw the converted carry in as an additional array value and implemented two adders, where just a single adder with carry in would suffice.

In VHDL-2008, additional overloaded version of the “+” and “—” operators are added to allow the use of a scalar value (such as a std_logic value) with an array value. Hence, we can rewrite the above code as follows:

adder <= ('0' & a) + ('0' & b) + c_in;

It is interesting to note that this same overloading is supported in one vendor’s nonstandard synthesis package and results in a single adder. The signatures for the new overloadings are:

[ArrayType, ArrayElementType return ArrayType]
[ArrayElementType, ArrayType return ArrayType]

ArrayType includes unsigned and signed defined in the numeric_bit and numeric_std packages. ArrayElementType is bit (for the numeric_bit operators) or std_ulogic (for the numeric_std operators). The same signatures are also defined for types ufixed and sfixed defined in the new fixed-point packages (see Section 8.4) and for the type float defined in the new floating-point packages (see Section 8.5).

Example 4.2. A conditional incrementer

The new overloading for the “+” operator allows us to use a scalar control signal as an operand in a conditional incrementer. If the control signal is ‘0’, an unsigned value is not incremented; if the control signal is ‘1’, the value is incremented. The declarations and process are:

signal inc_en  : std_logic;
signal inc_reg : unsigned(7 downto 0);
. . .

inc_reg_proc : process (clk) is

begin
  if rising_edge(clk) then
     inc_reg <= inc_reg + inc_en;
  end if ;
end process inc_reg_proc;

Prior VHDL-2008, the conditional incementer would have been coded as:

inc_reg_proc : process (clk) is
begin
   if rising_edge(clk) then
     if inc_en = '1' then
       inc_reg <= inc_reg + 1;
     end if;
   end if;
end process inc_reg_proc;

The use of the integer value 1 as an operand would have implied an adder, rather than just an incrementer.

Logical Reduction Operators

In earlier versions of VHDL, the logical operators and, or, nand, nor, xor, and xnor were defined only as binary operators; that is, they each operated on two operands. The operands could be bit or boolean values, or they could be arrays of bit or boolean elements. In the case of array operands, the logical operator is applied to corresponding array elements to produce an array result. In some models, we need to apply a logical operator to all of the elements of an array to produce a single scalar result. To do this in earlier versions of VHDL, we had to write a loop to apply the operator to the elements.

VHDL-2008 extends the definition of logical operators to allow them to be used as unary operators. Each such logical reduction operator is applied to a single operand that is an array of bit or boolean elements and produces a bit or boolean result, respectively. The std_logic_l164 package also defines overloaded logical reduction operators for std_ulogic_vector operands. Thus, the signature of each logical reduction operator is:

[ArrayType return ArrayElementType ]

The reduction and, or, and xor operators form the logical AND, OR, and exclusive OR, respectively of the array elements. Thus:

and "0110" = '0' and '1' and '1' and '0' = '0'
or  "0110" = '0' or  '1' or  '1' or  '0' = '1'
xor "0110" = '0' xor '1' xor '1' xor '0' = '0'

In each case, if the array has only one element, the result is the value of that element. If the array is a null array (that is, it has no elements), the result of the and operator is ‘I’, and the result of the or and xor operators is ‘0’.

The reduction nand, nor, and xnor operators are the negation of the reduction and, or, and xor operators, respectively. Thus:

nand "0110" = not ('0' and '1' and '1' and '0') = not '0' = '1'
nor  "0110" = not ('0' or  '1' or  '1' or  '0') = not '1' = '0'
xnor "0110" = not ('0' xor '1' xor '1' xor '0') = not '0' = '1'

In each case, application to a single-element array produces the negation of the element value. Application of nand to a null array produces ‘0’, and application of nor or xnor to a null array produces ‘1’.

The logical reduction operators have the same precedence as the unary not and abs operators. In the absence of parentheses, they are evaluated before binary operators. So the expression:

and A or B

involves applying the reduction and operator to A, then applying the binary or operator to the result and B. In some cases, we need to include parentheses to make an expression legal. For example, the expression:

and not X

is not legal without parentheses, since we cannot chain unary operators. Instead, we must write the expression as:

and (not X)

Example 4.3. Parity of a vector value

Without reduction operators, calculating parity requires the following:

parity <= data(7) xor data(6) xor data(5) xor data(4) xor
             data(3) xor data(2) xor data(1) xor data(0);

With reduction operators, calculating parity becomes

parity <= xor Data;

Since reduction operators have higher precedence than binary logical operators, the following two asignments produce the same value:

parity_error1 <= (xor data) and received_parity;
parity_error2 <= xor data and received_parity;

However, for readability, parentheses are recommended.

Condition Operator

VHDL provides numerous language constructs that use a condition to control what actions are performed. A condition is an expression that produces a boolean result, for example, through application of relational and logical operators. In earlier versions of VHDL, the fact that a condition had to produce a boolean value was a source of inconvenience, particularly in models that used bit or std_ulogic values for control signals. We would typically write a condition using such a control signal as:

if control_sig = '1' then . . .

VHDL-2008 provides two new language features that allow us to treat an expression producing a bit or std_ulogic value as a condition. The first of these features is a condition operator, “??”, that converts from a bit or std_ulogic value to a boolean value. For bit, “??” converts ‘1’ to true and ‘0’ to false. For std_logic, “??” converts both ‘1’ and ‘H’ to true and all other values to false. (We can also overload the operator for other user-defined types.) Thus, we could rewrite the if-statement condition shown above as:

if ?? control_sig = then . . .

Normally, we would not apply the condition operator explicitly like this, as the second of the new features involves implicit application of the operator in conditions. The operator is implicitly applied in a condition when the expression could otherwise not be interpreted as producing a boolean result and there is a unique interpretation using the condition operator that does produce a boolean result. These potential interpretations require use of the rules for resolving overloaded operators to determine the type of the expression. Note that an ambiguous boolean expression is considered a boolean interpretation and still results in an error.

As an example, assuming control_sig is a std_ulogic signal, we would rewrite the if-statement condition shown above as:

if control_sig then . . .

The condition operation is implicitly applied, since that is the one and only way of getting a boolean result from the expression.

The places where the condition operator is considered for application are:

  • after until in a wait statement

  • after assert in an assertion statement

  • after while in a while loop

  • after if or elsif in an if statement

  • after when in a next statement or exit statement

  • after when in a conditional signal or variable assignment statement

  • after if or elsif in an if-generate statement

  • in a Boolean expression in a PSL declaration or a PSL directive

This list includes all of the cases where an expression of type boolean was required in earlier versions of VHDL.

Example 4.4. Std_logic control conditions

With the condition operator implicitly applied, we can write the following in VHDL-2008:

signal cs1, ncs2, cs3 : std_logic;
. . .

if cs1 and not cs2 and cs3 then
. . .

Backward compatibility is maintained, so we can still write:

if cs1 = '1' and ncs2 = '0' and cs3 = '1' then
. . .

Note, however, that we cannot write a condition that mixes std_ulogic and boolean operands for a logical operator, such as:

if cs1 and cs3 and ncs2 = '0' then -- illegal
. . .

The “??” operator is only implicitly applied to the entire condition. There is no overloading for and that has a std_logic left operand and a boolean right operand.

Matching Relational Operators

VHDL provides ordinary relational operators ("=", "/=", "<", "<=", ">", and ">=") that return a result of type boolean. We can use the result as a condition to control what actions are performed in a model. However, if we want to use the result to assign to a signal of type bit or std_ulogic, we have to resort to a form such as:

control_sig >= '1' when X  = Y else '0';

VHDL-2008 has a new set of predefined matching relational operators ("?=", "?/=", "?<", "?<=", "?>", and "?>=") that return bit or std_ulogic results. This allows us to rewrite the assignment as:

control_sig <= X ?= Y;

The matching relational operators are predefined with the following signatures for scalar operands:

[ScalarType, ScalarType return ScalarType]

ScalarType is one of bit or std_ulogic. For bit operands, the results are the same as the ordinary relational operators, except that the matching relational versions return ‘0’ or ‘0’ instead of false or true. For std_ulogic operands, the result values are shown in Tables 4.1, 4.2, and 4.3 VHDL-2008 lists the result values for the “?=” and “?<” operators, and then defines the results for the remaining operators using the not and or operators for std_ulogic. Note that for “?<”, “?<=”, “?>”, and “?>=”, an operand value of ‘-’ produces an assertion-violation error, so the seemingly anomalous results shown in Tables 4.2 and 4.3 are not a concern. They are defined for completeness in case we chose to ignore assertion violations during simulation.

Table 4.1. Result values for the “?=” and “?/=” operators on std_ulogic operands

?=

Right

?/=

Right

Left

‘U’

‘X’

‘o’

‘1’

‘Z’

‘W’

‘L’

‘H’

‘–’

‘Left’

‘U’

‘X’

‘o’

‘1’

’Z’

’W’

’L’

’H’

’– ‘

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

’1‘

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘0’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘0’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘1’

‘0’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘0’

‘1’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘1’

‘1’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘0’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘L’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘1’

‘L’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘0’

‘H’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘1’

‘H’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘0’

‘—’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘—’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

Table 4.2. Result values for the “?<” and “?<= ” operators on std_ulogic operands

?<

Right

?<=

Right

Left

‘U’

‘X’

‘0’

‘1’

‘Z’

‘W’

‘L’

‘H’

‘—’

‘Left’

‘U’

‘X’

‘0’

‘1’

‘Z’

‘W’

‘L’

‘H’

‘—’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘X’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘1’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘0’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘X’

‘0’

‘U’

‘X’

‘1’

‘1’

‘X’

‘X’

‘1’

‘1’

‘1’

‘1’

‘U’

‘X’

‘0’

‘0’

‘X’

‘X’

‘0’

‘0’

‘X’

‘1’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘1’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘1’

‘L’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘X’

‘L’

‘U’

‘X’

‘1’

‘1’

‘X’

‘X’

‘1’

‘1’

‘1’

‘H’

‘U’

‘X’

‘0’

‘0’

‘X’

‘X’

‘0’

‘0’

‘X’

‘H’

‘U’

‘X’

‘0’

‘1’

‘X’

‘X’

‘0’

‘1’

‘1’

‘—’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘—’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

‘1’

Table 4.3. Result values for the “?>” and “?>=” operators on std_ulogic operands

?>

Right

?>=

Right

Left

‘U’

‘X’

‘0’

‘1’

‘Z’

‘W’

‘L’

‘H’

‘—’

‘Left’

‘U’

‘X’

‘0’

‘1’

‘Z’

‘W’

‘L’

‘H’

‘—’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘0’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘U’

‘X’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘X’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘U’

‘X’

‘0’

‘0’

‘X’

‘X’

‘0’

‘0’

‘0’

‘0’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘X’

‘1’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘0’

‘1’

‘U’

‘X’

‘1’

‘1’

‘X’

‘X’

‘1’

‘1’

‘X’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘Z’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘0’

‘W’

‘U’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘L’

‘U’

‘X’

‘0’

‘0’

‘X’

‘X’

‘0’

‘0’

‘0’

‘L’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘X’

‘H’

‘U’

‘X’

‘1’

‘0’

‘X’

‘X’

‘1’

‘0’

‘0’

‘H’

‘U’

‘X’

‘1’

‘1’

‘X’

‘X’

‘1’

‘1’

‘X’

‘—’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘0’

‘—’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

‘X’

In addition, the “?=” and “?/=” operators are predefined with the signature:

[ArrayType, ArrayType return ArrayElementType ]

where ArrayType is any one dimensional array of bit or std_ulogic elements. The array operands must be of the same length. The array “?=” operator applies the scalar “?=” operator to corresponding elements of the arrays, and then forms the logical AND of the resulting values. The array “?/=” operator does the same, but negates the final result.

We can also overload all of these operators. In particular, the “?<”, “?<=”, “?>”, and “?>=” operators are not predefined for arrays of bit or std_ulogic elements; instead they are overloaded in the appropriate numeric packages. They are overloaded for signed and unsigned in numeric_bit and numeric_std; for ufixed and sfixed in fixed_generic_ pkg; for float in float_generic_pkg; for bit_vector in numeric_bit_unsigned; and for std_ulogic_vector in numeric_std_unsigned. (See Chapter 8 for more details about the standard packages.) Thus, we must include a use clause for the appropriate package if we want to apply the operators to bit_vector or std_logic vector operands.

Example 4.5. Assignment of a condition result for a select signal

We can write a Boolean equation for a std_ulogic select signal that includes chip-select control signals and an address signal. In earlier versions of VHDL, we had to write an assignment in the following form, including a condition of type boolean:

dev_sell <= '1' when cs1 = '1' and
                   ncs2 = '0' and addr = X"A5" else '0';

In VHDL-2008, we can use the "?=" operator, which returns a std_ulogic result. We can combine that result with the std_ulogic control signals to produce a std_ulogic form of the Boolean equation:

dev_sel1 <= cs1 and not ncs2 and addr ?= X"A5";

We can also use this form of expression in a condition, since the condition operator, "??" (see Section 4.4), is implicitly applied:

if cs1 and not ncs2 and addr ?= X"A5" then
  . . .

or similarly:

if cs1 and ncs2 ?= '0' and addr ?= X"A5" then
  . . .

Note that, in a condition, we still have backward compatibility. The following forms are still valid:

if cs1 = '1' and ncs2 = '0' and addr = X"A5" then
  . . .

and

if (cs1 and not ncs2) = '1' and addr = X"A5" then
 . . .

Maximum and Minimum

If we want to find the larger or the smaller of two values, we can write an if statement, such as:

if A > B then
  greater := A;
else
  greater := B;
end if;

However, in some cases, it would be more convenient to select the larger or smaller value as part of an expression. VHDL-2008 allows us to do so using new predefined maximum and minimum functions, with the following signatures:

[ScalarType, ScalarType return ScalarType ]
[DiscreteArrayType, DiscreteArrayType
     return DiscreteArrayType]

Here, ScalarType is any scalar type, and DiscreteArrayType is any discrete array type (that is, an array type whose elements are of an integer or enumeration type). These are the types for which the operator "<" is predefined, and the results of the maximum and minimum functions are defined in terms of the "<" operator applied to the operands. For example:

maximum(3, 20) = 20    minimum(3, 20) = 3

maximum('a', 'z')= 'z' minimum('a', 'z') = 'a'

Note that for array types, the "<" operator uses dictionary ordering to compare operands. The two arrays do not have to be of the same length. Corresponding elements are compared, from left to right, until a pair with differing values is encountered (in which case the lesser array is the one containing the lesser element of the pair) or until the end of one array is reached (in which case the lesser array is the shorter of the two). Since the maximum and minimum functions are defined in terms of the "<" operator, they also use dictionary ordering for arrays, for example:

maximum(bit_vector' ("l01"), bit_vector' ("100100")) = "101"

minimum(bit_vector' ("101"), bit_vector' ("100100")) = "100100"

As these examples show, for vectors representing binary-coded numeric values, the predefined maximum and minimum functions are not consistent with numerical ordering. (The same argument also applies to the predefined relational operators.) For this reason, the standard numeric packages define overloaded versions of maximum and minimum (and the relational operators) that do give results consistent with numerical ordering.

Example 4.6. Maximum Function Used In A Declaration

One use of the maximum and minimum is in expressions in declarations. For example, in the following function for saturating addition of unsigned numeric values, we use the maximum function to determine the longer of the two operand values, and then declare the result variable to be of that size.

function saturating_add  (A, B : unsigned) return unsigned is
  constant size : natural := maximum(A'length, B'length);
  variable result : unsigned(size - 1 downto 0);
  variable c_out  : std_ulogic;
begin
  (c_out, result) := ('0' & A) + ('0' & B);
  if c_out then
    result := (others => '1'),
  end if;
  return result;
end function saturating_add;

VHDL-2008 also predefines the maximum and minimum functions as reduction operations on array values. The signature is:

[ArrayType return ArrayElementType ]

Here, ArrayType is an array of any scalar element type (not just a discrete type), and ArrayElementType is the element type. The maximum function of this form returns the largest element in the array, and the minimum function returns the smallest element in the array. Again, the comparisons are performed using the predefined "<" operator for the element type. Thus,

maximum(string'("WYZ")) = 'Z' minimum(string'("WXyZ")) = 'W'

maximum(time_vector'(10 ns, 50 ns, 20 ns)) = 50 ns

minimum(time_vector'(10 ns, 50 ns, 20 ns)) = 10 ns

For a null array (one with no elements), the maximum function returns the smallest value of the element type, and the minimum functions returns the largest value of the element type.

Mod and Rem for Physical Types

Prior to VHDL-2008, the arithmetic operators "+", "-", "*" and "/" were predefined for physical types, including type time, but the mod and rem operators were not predefined. VHDL-2008 adds predefined mod and rem functions for these types, with the following signature.:

[PhysicalType, PhysicalType  return PhysicalType ]

For example, using type time:

  5 ns rem   3 ns =   2 ns
  5 ns mod   3 ns =   2 ns
(-5 ns)rem   3 ns =  -2 ns
(-5 ns)mod   3 ns =   1 ns
  1 ns mod 300 ps = 100 ps
(-1 ns)mod 300 ps = 200 ps

Example 4.7. Generating a Periodic Waveform

We can use the mod operator to simplify generation of a periodic waveform. For example, the following process creates a triangle wave on the real signal triangle_wave. T_period_wave defines the period of the output wave, t_offset defines the offset within the triangle wave, and t_period_sample defines how many points are in the waveform.

signal triangle_wave : real;
. . .

wave_proc : process is
  variable phase : time;
begin
  phase := (now + t_offset) mod t_period_wave;
  if phase <= t_period_wave/2  then
    triangle_wave <= 4.0 * real(phase / t_period_wave) - 1.0;
  else
    triangle_wave <= 3.0 - 4.0 * real(phase / t_period_wave);
  end if;
  wait for tperiod_sample;
end process wave_proc;

Shift Operations

Prior to VHDL-2008, the shift operations (rol, ror, sll, srl, sla, and sra) were predefined only for arrays of bit and boolean elements. The operations can take a positive shift count, in which case they rotate or shift in the direction suggested by the operator name. They can also take a negative shift count, in which case they rotate or shift in the opposite direction. The rotate and logical-shift operations have the expected meanings. The arithmetic-shift operators also have the expected meaning when shifting right; that is, they replicate the leftmost bit. However, when shifting left, they replicate the rightmost bit, treating it as a sign bit. This seems anomalous to many designers, so the operation is rarely (if ever) used.

The numeric_bit and numeric_std packages used in earlier versions of VHDL defined overloaded versions of the rol, ror, sll, and srl operators with similar behavior to that of the predefined operators on bit_vector values. The packages did not, however, overload sla and sra, preferring instead to define shift_left and shift_right functions that perform logical shifts on unsigned values and arithmetic shifts on signed values. A shift left on a signed value fills the vacated positions with ‘O’, rather than replicating the rightmost bit. This is generally more appropriate for arithmetic circuits.

VHDL-2008 extends the definitions of shift operations to include sla and sra in numeric_bit and numeric_std. It also defines all of the shift operations in the new arithmetic packages numeric_bit_unsigned, numeric_std_unsigned, and in the fixed-point packages (see Chapter 8). In all cases, the overloaded sla and sra operators on signed values have the same numeric behavior as the shift_left and shift_right functions.

Strength Reduction and ‘X’ Detection

Prior to VHDL-2008, the strength reduction and ‘X’ detection functions were not uniformly implemented throughout the packages based on the std_ulogic type. The package std_logic_1164 defined the detection function is_X and the strength reduction functions to_X01, to_X01 Z, and to_UX01 for scalar and vector types. The numeric_std package, however, did not define these functions for unsigned or signed. Instead, we had to convert values of those types to std_logic_vector in order to use the functions. The package did, however, define the function to_01 that maps non-logic values to a value of our choice (the default being ‘0’).

In VHDL-2008, the inconsistency is rectified, and the functions are also defined in the new fixed-point and floating-point packages based on the std_ulogic type (see Chapter 8). To summarize, the following functions are defined in the packages:

is_X    [AType return boolean]
to_X01  [AType return AType]
to_X01Z [AType return AType]
to_UX01 [AType return AType]

In std_logic_1164, AType covers std_ulogic, std_logic, std_ulogic_vector and std_logic_vector; in numeric_std, AType covers unsigned and signed; in the fixed-point packages, AType covers ufixed and sfixed; and in the floating-point packages, AType covers float and its subtypes.

In addition, the function to_01 is defined with the following signature:

to_01 [AType, std_ulogic return AType ]

The second parameter is the value to which non-logic values such as ‘X’ are mapped. This function is defined in packages numeric_std, numeric_std_unsigned, the fixed-point packages, and the floating-point packages, with the same types for AType as the other strength-reduction functions.

Example 4.8. Strength reduction and ‘X’ detection in models

We can use the to_X01 function in behavioral models and ASIC or FPGA input cells to promote a resistive strength to a driving level as follows:

ncs_x01 <= to_X01(ncs);

We can use the is_X function to detect ‘X’ values in behavioral models and RTL code, for example, in the input to a state machine:

assert not is_X(ncs) report "ncs is X" severity error;
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.198.129