Standard package updates

Proposal Information

  • Who Updates: RyanHinton
  • 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 smile 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.

package standard Additions

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

std_logic_1164 Additions

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')

</Brent Hayhoe>

(-- 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

numeric_std Additions

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;

math_real Additions

math_complex Additions

  • 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.

fixed_pkg Additions

Related Issues: None = General

Competing Issues: None at this time

Supporters

Add your signature here to indicate your support for the proposal

-- JimLewis - 2014-06-06 -- RyanHinton - 2014-06-09 Brent Hayhoe - 2014-06-12

-- PatrickLehmann - 2016-02-11

Topic revision: r15 - 2020-02-17 - 15:34:39 - JimLewis
 
Copyright © 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback