## Proposal Information

• Date Proposed: 2013-04-18
• Date Last Updated: 2013-04-18
• Priority:
• Complexity:
• Focus: General Language

## Summary

Some operators and functions are arguably missing from the standard packages. This requirement intends to collect the proposed changes.

## Requirements

### Common or multiple

#### Implicit shift and/or rotate operators

Implicit shift/rotate operators for every single-dimensional array type. Maybe just define the rotation operators because a logical (vs. arithmetic) shift of an arbitrary element/array type doesn't make sense. For example, implementing an FIR filter with any numeric type ( `signed`, `sfixed`, `real`, `integer`, `complex`, ...) involves a vector of that type that needs to shift. If we can implicitly, naturally, unambiguously define the shift (and/or rotate) for any vector type, that saves me time. (I think the rotate in particular is natural and unambiguous for any one-dimensional array type. -- RyanHinton - 2013-04-20)

• `function "sll" (a : VECTOR_TYPE; b : integer) return VECTOR_TYPE`
• `function "srl" (a : VECTOR_TYPE; b : integer) return VECTOR_TYPE`
• `function "ror" (a : VECTOR_TYPE; b : integer) return VECTOR_TYPE`
• `function "rol" (a : VECTOR_TYPE; b : integer) return VECTOR_TYPE`

VHDL-2008 defines these for std_logic_vector, unsigned, signed, ufixed, sfixed Not implemented for float, do we need it? If you are going to define these for real and integer, then we probably also want to consider the logic operators. Particularly if we nail down the sizing of integers and reals -- JimLewis - 2013-04-22

No, I'm not asking for this for real, integer, etc. Just for vectors. So it would be implicitly declared for float, but it wouldn't make much sense because the bit positions have heterogeneous meanings for the floating-point types. But I would like these operators defined for arrays of integer, real, float, etc. -- RyanHinton - 2013-04-22

In particular, I sometimes want a vector of std_logic with an INTEGER range. So I define my own type. Then I have to define shift, rotate, etc. operators for my new type. It would be nice to have some of these built-in where they're simple and unambiguous. -- RyanHinton - 2014-06-09

#### Implicit conversions from string back to character array

VHDL-2008 provides implicit functions `to_string`, `to_bstring`, `to_ostring`, and `to_hstring` for any one-dimensional vector with an appropriate element type. But there is no facility to convert the other direction. For each type T from this set, implicitly define the following functions.

• `function from_string (str : string; len : natural) return T` inverse of `to_string`.
• `function from_bstring (str : string; len : natural) return T` inverse of `to_bstring`.
• `function from_ostring (str : string; len : natural) return T` inverse of `to_ostring`.
• `function from_hstring (str : string; len : natural) return T` inverse of `to_hstring`.
• `function from_binary_string (str : string; len : natural) return T` inverse of `to_binary_string`.
• `function from_octal_string (str : string; len : natural) return T` inverse of `to_octal_string`.
• `function from_hex_string (str : string; len : natural) return T` inverse of `to_hex_string`.

Simlar to bit string literals, the index range of the result should have the direction of the index type and begin with left-most value of the index type.

#### Decimal text functions

When we defined the `to_Xstring` functions, how did we leave out base-10?! Define a implicit functions as follows for any type `T` meeting the appropriate criterion (see the previous section).

• `function to_dstring (vec : T) return string` returns a string representation in decimal of vec interpreted as binary number.
• `function to_decimal_string (vec : T) return string` alias of to_dstring.
• `function from_dstring (str : string; len : natural) return T` inverse of `to_dstring`.
• `function from_decimal_string (str : string; len : natural) return T` inverse of `to_decimal_string`.

Similarly, define `DWRITE`, `DREAD`, `DECIMAL_READ`, `DECIMAL_WRITE`, etc.

Conversion functions.

• `function to_integer (A : boolean) return integer` needed for coverage modeling
• `function to_integer_vector (A : boolean_vector) return integer_vector` needed for coverage modeling -- Jim

Logical.

• `function shift_left (arg : std_logic_uvector; count : natural) return std_logic_uvector` to match functions of the same name for `signed` and `unsigned` in `numeric_std`.
• `function shift_right (arg : std_logic_uvector; count : natural) return std_logic_uvector` to match functions of the same name for `signed` and `unsigned` in `numeric_std`.
• `function rotate_left (arg : std_logic_uvector; count : natural) return std_logic_uvector` to match functions of the same name for `signed` and `unsigned` in `numeric_std`.
• `function rotate_right (arg : std_logic_uvector; count : natural) return std_logic_uvector` to match functions of the same name for `signed` and `unsigned` in `numeric_std`.

Conversion functions.

• `function to_integer (bit : std_logic) return integer` essentially converts the result of to_01 to an integer. May want to add an optional input for 'X' mapping, e.g. in case the user wants to map 'X' to -1. -- also needed for coverage modeling -- Jim
• `function to_std_logic (bool : boolean) return std_logic` implements the obvious mapping `true => '1', false => '0'`. This is amazingly convenient, I use it all the time. Now we have automatic boolean context handling of `std_logic`, but we don't have a quick, easy, standard way to go from `boolean` back to `std_logic`.
• `function to_std_logic (num : integer) return std_logic` uses C mapping `0 => '0', others => '1'`.
• `function to_integer_vector (A : std_logic_vector) return integer_vector` needed for coverage modeling -- Jim

Predicates.

• `function all (bits : std_logic_vector; are : std_logic) return boolean` returns true if all the bits in the vector equal the given value.
• `function any (bits : std_logic_vector; are : std_logic) return boolean` returns true if any of the bits in the vector equal the given value.
• `function find_rightmost (vec : std_logic_vector; val : std_ulogic) return integer` same as function for numeric types.
• `function find_leftmost (vec : std_logic_vector; val : std_ulogic) return integer` same as function for numeric types.

`All` and `any` seem redundant wrt reduction operations:

```all(a_slv, '1) = and a_slv
all(a_slv, '0') = not any(a_slv, '1') = not (or a_alv) = (a_slv = 0) (numeric_std_unsigned)
any(a_slv, '1) = or a_slv
any(a_slv, '0') = not all(a_slv, '1') = not (and a_alv)
```

-- JimLewis - 2013-04-22

Yes, these functions could be defined in terms of the reduction operations. The main difference is their return value. I think of the reduction operators as combinational logic. I think of `all` and `any` as functional predicates. But yes, they are essentially the same as the reduction operators.

(-- JimLewis - 2014-06-06) I do like the readability of any and all, so I would support them if you keep them in the proposal. I just think it is important to note redundancies where they exist.

<Brent Hayhoe> - I also like the readability, so could we not redefine the reduction operators in terms of these new functions:

(or a_slv) would return any(a_slv, '1')

(and a_slv) would return all(a_slv, '1')

(-- RyanHinton - 2016-11-14) Yes, the reduction operators can be defined in terms of the `any` and `all` functions, but I don't think we want to. Given the multi-valued nature of `std_logic`, I think the `or` and `and` functions should be defined directly. I've defined `any` and `all` to have a boolean return value, so an equivalent expression for `any` is `"??"(or vec)`. Using logical operators gets a little more confusing for the `any(vec, '0')` and `all(vec, '0')` cases. And in testbenches `any` can come in handy to check for metavalues like `'X'` and `'Z'`. Sure, they're syntactic sugar. Sure, I can (and will) define them in my own package. But the same argument applies to nearly all the functions in `std_logic_1164`.

Arithmetic. (Math should be added to numeric_std_unsigned -- JimLewis - 2013-04-2)

• `function "*" (a : integer; b : std_logic) return integer` equivalent to `a * to_integer(b)`. Alternatively could be considered a logical function.
• `function "*" (a : std_logic; b : integer) return integer` see above.
• `function "*" (a : std_logic_vector; b : std_logic) return integer` see above.
• `function "*" (a : std_logic; b : std_logic_vector) return integer` see above.

The multiply-by-=std_logic= functions might be better as an `"and"` operator. The effect is the same. I guess framing it as a multiply shows my C heritage.-- RyanHinton - 2013-04-19

Conversion functions.

• `function to_signed (val : unsigned) return signed` prepends a '0' and changes the type.
• `function to_signed (val : real; width : natural) return signed` equivalent to `to_signed(integer(val), width)`.
• `function to_unsigned (val : real; width : natural) return unsigned` equivalent to `to_unsigned(integer(val), width)`.
• `function to_unsigned (val : std_logic; width : positive :` 1) return unsigned= returns the input bit right-justified in an unsigned object.

Predicates.

• `function all (bits : std_logic_vector; are : std_logic) return boolean` returns true if all the bits in the vector equal the given value.
• `function any (bits : std_logic_vector; are : std_logic) return boolean` returns true if any of the bits in the vector equal the given value.

`All` and `any` seem redundant wrt reduction operations. -- JimLewis - 2013-04-22

```all(a_slv, '1) = and a_slv
all(a_slv, '0') = not any(a_slv, '1') = not (or a_alv) = (a_slv = 0) (numeric_std_unsigned)
any(a_slv, '1) = or a_slv
any(a_slv, '0') = not all(a_slv, '1') = not (and a_alv)
```

(-- RyanHinton - 2013-04-22) Again I agree. I still like them, so I'll probably put them in a package of my own. But whether they belong in the language is debatable. We can always discuss and vote.

(-- JimLewis - 2014-06-06) I do like the readability of any and all, so I would support them if you keep them in the proposal. I just think it is important to note redundancies where they exist.

Arithmetic.

• (withdrawn) `function "*" (a : signed; b : unsigned) return signed` implements the usual arithmetic. Use the normal `numeric_std` sizing rules, they work perfectly.
• (withdrawn) `function "*" (a : unsigned; b : signed) return signed` implements the usual arithmetic.
• `function "*" (a : signed; b : std_logic) return signed` returns `a` when `'1' = to_01(b)` . Alternatively could be considered a logical function.
• `function "*" (a : std_logic; b : signed) return signed` see above.
• `function "*" (a : unsigned; b : std_logic) return unsigned` see above.
• `function "*" (a : std_logic; b : unsigned) return unsigned` see above.

The expression a_std_logic * b_unsigned is redundant with VHDL-2008 addition: a_std_logic and b_unsigned -- JimLewis - 2013-04-23

(RyanHinton - 2013-04-25) Mixed operators withdrawn due to lack of consensus. In particular, they cause problems with math using literals.

Unsigned arithmetic with integers.

• `function "+" (L : UNRESOLVED_UNSIGNED; R : INTEGER) return UNRESOLVED_UNSIGNED` note the change from `natural` to `integer`.
• `function "+" (L : INTEGER; R : UNRESOLVED_UNSIGNED return UNRESOLVED_UNSIGNED` note the change from `natural` to `integer`.
• `function "-" (L : UNRESOLVED_UNSIGNED; R : INTEGER) return UNRESOLVED_UNSIGNED` note the change from `natural` to `integer`.
• `function "-" (L : INTEGER; R : UNRESOLVED_UNSIGNED return UNRESOLVED_UNSIGNED` note the change from `natural` to `integer`.

Yes, this has the possibility of underflowing. But since we define subtraction for `unsigned`, we should allow adding negative numbers. Sometimes the amount we want to add to an `unsigned` is calculated from port lengths, so we can't know beforehand whether the result will be positive or negative. And even for addition, we should be checking for overflow. So there is no loss of safety or robustness here, just an increase in convenience and expressiveness. -- RyanHinton - 2013-04-24

Relational operators.

• (withdrawn) `function ">" (a : signed; b : unsigned) return boolean` implements the usual comparison.
• (withdrawn) `function ">" (a : unsigned; b : signed) return boolean` implements the usual comparison.
• (withdrawn) `function "<" (a : signed; b : unsigned) return boolean` implements the usual comparison.
• (withdrawn) `function "<" (a : unsigned; b : signed) return boolean` implements the usual comparison.

Yikes to mixing signed with unsigned. Will break old code like:

`b_signed <= a_signed * "1010"`

or

`if A_unsigned > "1010"`

(-- RyanHinton - 2013-04-22) I'm not sure how that last statement fits in. I'm not proposing that we make `signed` and `unsigned` equivalent or define mixed operators everywhere. I see how this would break your second example. I consider the second to be really bad coding style. When you have `signed` and `unsigned` both defined identically and strong typing going on, I would ask the designer to change that second snippet if I were reviewing it, e.g. to `if A_unsigned > unsigned'("1010")`. But I don't like to break backward compatibility, so I'll just keep these in my own package for now.

(-- JimLewis - 2013-04-22) I would never support mixing unsigned and signed. One should not have to use type qualifiers to do something with a literal of the given type. When someone mixes two types, I like the heads up that is provided by the type conversion. Providing overloading like this strips away the advantages of strong typing.

(--- RyanHinton - 2013-04-25) Mixed operators withdrawn due to lack of consensus.

(-- JimLewis - 2014-06-06) I consider A_unsigned > B_signed to be bad coding style. Instead I require that a designer use type conversion when mixing types: signed('0' & A_unsigned) > B_signed.

(-- RyanHinton - 2014-06-09) Why is `A_unsigned > B_signed` bad coding style? I want to know if A > B. B is signed and A is unsigned, so if B is negative then A is guaranteed to be greater than B. This is exactly the behavior I want. The negative/positive check should be a small number of gates, i.e. it's not going to blow up in the synthesizer if I forget that A is unsigned and B is signed. It's expressing the intent, and it's hardware-friendly. What makes it bad style? (I am honestly interested in your opinion, and I actively investigate and experiment with coding style.)

(-- DanielKho - 2015-01-04) Jan Decaluwe wrote an essay regarding adding signed and unsigned numbers which I feel is very relevant. I first read his comments on ArbitraryIntegers. Why not we overload the +, -, *, / operators to support mixing of unsigned and signed numbers? Adding a signed and unsigned should result in a signed number. Same goes to the other operations (-, *, /).

```function "+" (L : UNRESOLVED_UNSIGNED; R : UNRESOLVED_SIGNED) return UNRESOLVED_SIGNED;
function "+" (L : UNRESOLVED_SIGNED; R : UNRESOLVED_UNSIGNED) return UNRESOLVED_SIGNED;```

• `type complex_vector is array (natural range <>) of complex` since similar vectors are defined for all other "built-in" types.

Formatting.

If CompositeValueString is not approved, then we should add the following.

• `function to_string (arg : complex) return string` to convert a `complex` value to a `(re, im)` string.
• `function from_string (str : string) return complex` to convert from a string back to `complex`.