|
LCS-2016-026a |
|
1 {10-Jan-2017} 2 {11-Jan-2017} 3 {13-Jan-2017} 4 {26-Jan-2017} |
|
26-Jan-2017 |
|
Voting |
|
Patrick Lehmann |
|
Main.PatrickLehmann |
|
Long Integers |
|
Extends the range of integer types values. |
LONG_INTEGER
). It also declares INTEGER
as a subtype using only 32 bit. It also drops LONG_NATURAL
.
Version 3: INTEGER64
, POSITIVE64
, NATURAL64
, INTEGER32
, POSITIVE32
, NATURAL32
and created aliases to the old names.
Version 4: SYSTEM_INTEGER
as a longterm name for a integer of growing size with an guaranteed minimal range.
subtype INTEGER64 is SYSTEM_INTEGER range -2**63 to 2**63-1;
subtype NATURAL64 is SYSTEM_INTEGER range 0 to INTEGER64'HIGH;
subtype POSITIVE64 is SYSTEM_INTEGER range 1 to INTEGER64'HIGH;
subtype INTEGER32 is SYSTEM_INTEGER range -2**31 to 2**31-1;
subtype NATURAL32 is SYSTEM_INTEGER range 0 to INTEGER32'HIGH;
subtype POSITIVE32 is SYSTEM_INTEGER range 1 to INTEGER32'HIGH;
For compatibility, the following aliases are defined:
alias INTEGER is INTEGER32;
alias NATURAL is NATURAL32;
alias POSITIVE is POSITIVE32;
The values of the predefined types BOOLEAN_VECTOR, BIT_VECTOR, SYSTEM_INTEGER_VECTOR, INTEGER64_VECTOR, INTEGER32_VECTOR, REAL_VECTOR, andsubtype POSITIVE is INTEGER range 1 to INTEGER'HIGH;type STRING is array (POSITIVE64 range <>) of CHARACTER;
For compatibility, the following aliases are defined:subtype NATURAL is INTEGER range 0 to INTEGER'HIGH;type BOOLEAN_VECTOR is array (NATURAL64 range <>) of BOOLEAN; type BIT_VECTOR is array (NATURAL64 range <>) of BIT; type SYSTEM_INTEGER_VECTOR is array (NATURAL64 range <>) of SYSTEM_INTEGER; type INTEGER64_VECTOR is array (NATURAL64 range <>) of INTEGER64; type INTEGER32_VECTOR is array (NATURAL64 range <>) of INTEGER32; type REAL_VECTOR is array (NATURAL64 range <>) of REAL; type TIME_VECTOR is array (NATURAL64 range <>) of TIME;
alias INTEGER_VECTOR is INTEGER32_VECTOR;
Operator | Operation | Left operand type | Right operand type | Result type |
---|---|---|---|---|
sll | Shift left logical |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
srl | Shift right logical |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
sla | Shift left arithmetic |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
sra | Shift right arithmetic |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
rol | Rotate left logical |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
ror | Rotate right logical |
Any one-dimensional array type whose element type is BIT or BOOLEAN |
SYSTEM_INTEGER | Same as left |
Operator | Operation | Left operand type | Right operand type | Result type |
---|---|---|---|---|
* | Multiplication | Any physical type | SYSTEM_INTEGER | Same as left |
Any physical type | REAL | Same as left | ||
SYSTEM_INTEGER | Any physical type | Same as right | ||
REAL | Any physical type | Same as right | ||
/ | Division | Any physical type | SYSTEM_INTEGER | Same as left |
Any physical type | REAL | Same as left | ||
Any physical type | The same type | Universal integer | ||
mod | Modulus | Any physical type | Same type | Same type |
rem | Remainder | Any physical type | Same type | Same type |
Operator | Operation | Left operand type | Right operand type | Result type |
---|---|---|---|---|
** | Exponentiation | Any integer type | SYSTEM_INTEGER | Same as left |
Any floating-point type | SYSTEM_INTEGER | Same as left |
package STANDARD is [...] type SYSTEM_INTEGER is range implementation_defined; -- The predefined operations for this type are as follows: -- function "**"(anonymous: universal_integer; anonymous: SYSTEM_INTEGER) return universal_integer; -- function "**"(anonymous: universal_real; anonymous: SYSTEM_INTEGER) return universal_real; -- function "="(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function "/="(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function "<"(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function "<="(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function ">"(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function ">="(anonymous, anonymous: SYSTEM_INTEGER) return BOOLEAN; -- function "+"(anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "-"(anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "abs"(anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "+"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "-"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "*"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "/"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "mod"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "rem"(anonymous, anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function "**"(anonymous: SYSTEM_INTEGER; anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function MINIMUM (L, R: SYSTEM_INTEGER) return SYSTEM_INTEGER; -- function MAXIMUM (L, R: SYSTEM_INTEGER) return SYSTEM_INTEGER; [...] -- Predefined type TIME: type TIME is range implementation_defined units fs; -- femtosecond ps = 1000 fs; -- picosecond ns = 1000 ps; -- nanosecond us = 1000 ns; -- microsecond ms = 1000 us; -- millisecond sec = 1000 ms; -- second min = 60 sec; -- minute hr = 60 min; -- hour end units; -- The predefined operations for this type are as follows: -- function "="(anonymous, anonymous: TIME) return BOOLEAN; -- function "/="(anonymous, anonymous: TIME) return BOOLEAN; -- function "<"(anonymous, anonymous: TIME) return BOOLEAN; -- function "<="(anonymous, anonymous: TIME) return BOOLEAN; -- function ">"(anonymous, anonymous: TIME) return BOOLEAN; -- function ">="(anonymous, anonymous: TIME) return BOOLEAN; -- function "+"(anonymous: TIME) return TIME; -- function "- (anonymous: TIME) return TIME; -- function "abs"(anonymous: TIME) return TIME; -- function "+"(anonymous, anonymous: TIME) return TIME; -- function "-"(anonymous, anonymous: TIME) return TIME; -- function "*"(anonymous: TIME; anonymous: SYSTEM_INTEGER) return TIME; -- function "*"(anonymous: TIME; anonymous: REAL) return TIME; -- function "*"(anonymous: SYSTEM_INTEGER; anonymous: TIME) return TIME; -- function "*"(anonymous: REAL; anonymous: TIME) return TIME; -- function "/"(anonymous: TIME; anonymous: SYSTEM_INTEGER) return TIME; -- function "/"(anonymous: TIME; anonymous: REAL) return TIME; -- function "/"(anonymous, anonymous: TIME) return universal_integer; -- function "mod"(anonymous, anonymous: TIME) return TIME; -- function "rem"(anonymous, anonymous: TIME) return TIME; -- function MINIMUM (L, R: TIME) return TIME; -- function MAXIMUM (L, R: TIME) return TIME; [...] -- Predefined numeric subtypes: subtype INTEGER64 is SYSTEM_INTEGER range -2**63 to 2**63-1; subtype NATURAL64 is SYSTEM_INTEGER range 0 to INTEGER64'HIGH; subtype POSITIVE64 is SYSTEM_INTEGER range 1 to INTEGER64'HIGH; subtype INTEGER32 is SYSTEM_INTEGER range -2**31 to 2**31-1; subtype NATURAL32 is SYSTEM_INTEGER range 0 to INTEGER32'HIGH; subtype POSITIVE32 is SYSTEM_INTEGER range 1 to INTEGER32'HIGH; alias INTEGER is INTEGER32; alias NATURAL is NATURAL32; alias POSITIVE is POSITIVE32; [...] -- Predefined array types: type STRING is array (POSITIVE64 range <>) of CHARACTER; -- The predefined operations for these types are as follows: [...] type BOOLEAN_VECTOR is array (NATURAL64 range <>) of BOOLEAN; -- The predefined operations for this type are as follows: [...] type BIT_VECTOR is array (NATURAL64 range <>) of BIT; -- The predefined operations for this type are as follows: [...] type SYSTEM_INTEGER_VECTOR is array (NATURAL64 range <>) of SYSTEM_INTEGER; -- The predefined operations for this type are as follows: -- function "="(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function "/="(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function "<"(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function "<="(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function ">"(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function ">="(anonymous, anonymous: SYSTEM_INTEGER_VECTOR) return BOOLEAN; -- function "&"(anonymous: SYSTEM_INTEGER_VECTOR; anonymous: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER_VECTOR; -- function "&"(anonymous: SYSTEM_INTEGER_VECTOR; anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER_VECTOR; -- function "&"(anonymous: SYSTEM_INTEGER; anonymous: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER_VECTOR; -- function "&"(anonymous: SYSTEM_INTEGER; anonymous: SYSTEM_INTEGER) return SYSTEM_INTEGER_VECTOR; -- function MINIMUM (L, R: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER_VECTOR; -- function MAXIMUM (L, R: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER_VECTOR; -- function MINIMUM (L: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER; -- function MAXIMUM (L: SYSTEM_INTEGER_VECTOR) return SYSTEM_INTEGER; type INTEGER64_VECTOR is array (NATURAL64 range <>) of INTEGER64; -- The predefined operations for this type are as follows: -- function "="(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function "/="(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function "<"(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function "<="(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function ">"(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function ">="(anonymous, anonymous: INTEGER64_VECTOR) return BOOLEAN; -- function "&"(anonymous: INTEGER64_VECTOR; anonymous: INTEGER64_VECTOR) return INTEGER64_VECTOR; -- function "&"(anonymous: INTEGER64_VECTOR; anonymous: INTEGER64) return INTEGER64_VECTOR; -- function "&"(anonymous: INTEGER64; anonymous: INTEGER64_VECTOR) return INTEGER64_VECTOR; -- function "&"(anonymous: INTEGER64; anonymous: INTEGER64) return INTEGER64_VECTOR; -- function MINIMUM (L, R: INTEGER64_VECTOR) return INTEGER64_VECTOR; -- function MAXIMUM (L, R: INTEGER64_VECTOR) return INTEGER64_VECTOR; -- function MINIMUM (L: INTEGER64_VECTOR) return INTEGER64; -- function MAXIMUM (L: INTEGER64_VECTOR) return INTEGER64; type INTEGER32_VECTOR is array (NATURAL64 range <>) of INTEGER32; -- The predefined operations for this type are as follows: -- function "="(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function "/="(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function "<"(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function "<="(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function ">"(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function ">="(anonymous, anonymous: INTEGER32_VECTOR) return BOOLEAN; -- function "&"(anonymous: INTEGER32_VECTOR; anonymous: INTEGER32_VECTOR) return INTEGER32_VECTOR; -- function "&"(anonymous: INTEGER32_VECTOR; anonymous: INTEGER32) return INTEGER32_VECTOR; -- function "&"(anonymous: INTEGER32; anonymous: INTEGER32_VECTOR) return INTEGER32_VECTOR; -- function "&"(anonymous: INTEGER32; anonymous: INTEGER32) return INTEGER32_VECTOR; -- function MINIMUM (L, R: INTEGER32_VECTOR) return INTEGER32_VECTOR; -- function MAXIMUM (L, R: INTEGER32_VECTOR) return INTEGER32_VECTOR; -- function MINIMUM (L: INTEGER32_VECTOR) return INTEGER32; -- function MAXIMUM (L: INTEGER32_VECTOR) return INTEGER32; alias INTEGER_VECTOR is INTEGER32_VECTOR; [...] type REAL_VECTOR is array (NATURAL64 range <>) of REAL; -- The predefined operations for this type are as follows: [...] type TIME_VECTOR is array (NATURAL64 range <>) of TIME; -- The predefined operations for this type are as follows: [...] -- Predefined TO_STRING operations on scalar types -- function TO_STRING (VALUE: BOOLEAN) return STRING; -- function TO_STRING (VALUE: BIT) return STRING; -- function TO_STRING (VALUE: CHARACTER) return STRING; -- function TO_STRING (VALUE: SEVERITY_LEVEL) return STRING; -- function TO_STRING (VALUE: universal_integer) return STRING; -- function TO_STRING (VALUE: universal_real) return STRING; -- function TO_STRING (VALUE: SYSTEM_INTEGER) return STRING; -- function TO_STRING (VALUE: REAL) return STRING; -- function TO_STRING (VALUE: TIME) return STRING; -- function TO_STRING (VALUE: FILE_OPEN_KIND) return STRING; -- function TO_STRING (VALUE: FILE_OPEN_STATUS) return STRING; -- Predefined overloaded TO_STRING operations -- function TO_STRING (VALUE: REAL; DIGITS: NATURAL64) return STRING; -- function TO_STRING (VALUE: REAL; FORMAT: STRING) return STRING; -- function TO_STRING (VALUE: TIME; UNIT: TIME) return STRING;
IMPL_INTEGER
for implementation integer, UNI_INTEGER
or VHDL_INTEGER
... Such an
integer could grow in each revision.
Personally, I wouldn't be so friendly with the EDA industry (vendor and users). If they rely on false code, then they might get
broken code when using a new VHDL revision. But language designers are still willing to satisfy their audience at every cost.
Creating a subtype INTEGER, catches every design which falsely relies on fixed 32-bit integers, by using e.g. 'LEFT
or hoping
for overflow arithmetic in the tool.
@Kevin
If you really want to make 512 bit or even more possible, then we need a "derived types LCS" and especially derived integers.
I don't know if I have enough time to write such a big text, because I still need to write the Spaceship LCS ...
-- Patrick Lehmann - 2017-01-11
PL: Creating a subtype INTEGER, catches every design which falsely relies on fixed 32-bit integers, by using e.g. 'LEFT or hoping
for overflow arithmetic in the tool.
MZ: The new INTEGER (backed up by a >= 64-bit implementation) will not overflow as the old INTEGER which is often backed-up
by a 32-bit implementation. An out-of-bounds exception should be happen now.
Having a subtype INTEGER with range -2**31 to 2**31-1 only catches designs which falsely rely on the values of INTEGER'LEFT, 'RIGHT,
and so on.
Another (major) benefit of a such a subtype INTEGER is that the simulator can (!) keep the memory footprint the same for existing
designs and finally also the simulation performance.
-- Martin Zabel - 2017-01-12
MZ: Another (major) benefit of a such a subtype INTEGER is that the simulator can (!) keep the memory footprint the same for
existing designs and finally also the simulation performance
KJ: Doesn't that assumes that all intermediate calculations do not overflow 64 bit? When I went looking, I didn't see anything
specifying what to do if an intermediate calculation overflows so an implementation today might use 64 bit operations (or at least
something larger than 32 bits) in order to try to guarantee correct 32 bit results. If they now have to guarantee correct 64 bit
results and they applied a similar strategy then 64 bit low level operations wouldn't cut it. Either that or it assumes that the
operations to use are determined based on the subtype ranges.
-- Kevin Jennings - 2017-01-12
KJ: When I went looking, I didn't see anything specifying what to do if an intermediate calculation overflows so an implementation
today might use 64 bit operations (or at least something larger than 32 bits) in order to try to guarantee correct 32 bit results.
MZ: My interpretation of the LRM is: one has to use an arbitrary precision during calculation of an integer expression, and then
check the range during assignment. This cannot be even achieved by using a 64-bit arithmetic for a 32-bit INTEGER type as you already
demonstrated by your exponentiation example in the e-mail discussion between you and Tristan. Another example is n*n*n/n/n
where n is INTEGER'high.
Unfortunately the current situation is even worse: I have tested 4 simulators: G, M, I, X. Given a variable n
of type INTEGER,
all of them use 32-bit modulo arithmetic for the expression n :
n+1=, thus the result is -2**31 (negative!) if n
was 2**31-1.
Only I and X detect the overflow if it is visible from static elaboration. When requesting 64-bit for universal integer, the
intermediate result would be 2**31 (positive) and the range check during the assignment to the INTEGER n
will fail as expected.
Nevertheless, the simulator can still use only 4 bytes to store n
in memory, thus the memory footprint for the current state of
the model will not grow.
Addendum: I do not expect that simulators will ever use arbitrary precision for integer expressions. I think, if the vendors are
lazy then they will use 64-bit arithmetic and 8 byte storage for any integer type. If they optimize a bit, then they will use 64-bit
for arithmetic and 8 byte storage for LONG_INTEGER, but only 4 byte storage for INTEGER. Having a small memory footprint (cache
utilization) is important for simulation speed.
-- Martin Zabel - 2017-01-12
After the renaming to INTEGER64, one might intuitively expect that the size is exactly 64 bits as is the case for the int64_t in C
or C++ for example.
Thus, I would argue to change Section 5.2.3.2 so that INTEGER64 is defined as exactly the range -2**63 to 2**63-1.
-- Martin Zabel - 2017-01-13
No technical objections. However, I do not like the approach of fuzzing things up and introduce (INTEGER|NATURAL|POSITIVE)(32|64)
or whatever. Couldn't we just require implementors of the new language revision to have INTEGER
support, at least, the range
of signed 64-bit values: no new types, only new bounds.
-- Thomas Preusser - 2017-01-13
What is the impact if we alias INTEGER to INTEGER64 instead of INTEGER32, and do the same for the other 64-bit types?
-- Daniel Kho - 2017-01-19
I am fine with having INTEGER64 and INTEGER32, with INTEGER aliasing to either of these. In future revisions, INTEGER could alias
UNIVERSAL_INTEGER which could be a more generic and complete implementation of the integer type.
-- Daniel Kho - 2017-01-19
@Danielkho: If we alias INTEGER to INTEGER64 instead of INTEGER32, then the memory footprint will increase because now each INTEGER
has to be stored in 8 bytes instead of 4 bytes. Having a small memory footprint (cache utilization) is important for simulation speed.
The intention of Patrick was to "catch every design which falsely relies on fixed 32-bit integers, by using e.g. 'LEFT", see
his comment dated from 2017-01-11.
-- Martin Zabel - 2017-01-21
I feel that no code should exist that relies on the range of VHDL's INTEGER type being exactly -2**31 to 2**31+1. Wherever this was needed, the user could have declareded, e.g., "type integer_32 is integer range -2**31 to 2**31-1". Users who failed to handle this properly can make the correction going forward.
VHDL users have always known that the range of integer could be more than 32 bits. In some ways it is surprising that no vendor has supported 64 bits (or at least, say, -2**31 to 2**32-1) for a competitive advantage.
-- Farrell Ostler - 2017-01-31
RG: New types will require explicit typecasts all over the place.