Some operators and functions are arguably missing from the standard packages. This requirement intends to collect the proposed changes.
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
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.
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.
function "*" (a : signed; b : unsigned) return signed
implements the usual arithmetic. Use the normal numeric_std
sizing rules, they work perfectly.
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.
function ">" (a : signed; b : unsigned) return boolean
implements the usual comparison.
function ">" (a : unsigned; b : signed) return boolean
implements the usual comparison.
function "<" (a : signed; b : unsigned) return boolean
implements the usual comparison.
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
.
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