Menu

VHDL Explained

Inside VHDL’s Integer Types -
INTEGER, NATURAL, POSITIVE & Beyond

How many integers are there in VHDL?
 
Let me try to explain some details about VHDL’s type system. VHDL has scalar, composite, access, file, and protected types. Composite data types are either array or record types. Access types are known in other programming languages as pointers. File types are describing the data layout of files and protected types are an encapsulation of data, which can be manipulated by methods. Scalar data types (elementary data types) can be distinguished into enumeration types, integer types, physical types, or floating-point types.
 
At first, we need to distinguish between integer data types and a predefined integer data type called INTEGER (written in upper-case for distinguishability). VHDL has an anonymous integer data type called universal_integer, which reflects the tool’s supported integer range. In VHDL-2019, a minimum of a signed 64-bit integer range is required by all tools. The language only defines a minimum range, tools could implement a wider range.
 
Literals like 25, -178, 3e7 are literals of this universal_integer type. Other integer types have no literals. When assigning literals to an integer data type, these literals get implicitly type converted to the target’s integer type.
 
VHDL has one predefined anonymous integer type (base type) and one predefined subtype thereof called INTEGER with the same range as universal_integer. This is how VHDL defines the type INTEGER in package std.standard:
 

type INTEGER is range implementation_defined;

This is equivalent to:
 

subtype INTEGER is anonymous_integer range -9223372036854775807 – 1 to 9223372036854775807;

 
assuming a 64-bit signed integer range.
 
When using this type in a constant declaration, we see the implicit type conversion:
 

constant CounterCycles : INTEGER := 25;

 
Here we declared an integer constant of type INTEGER and initialized the constant’s value to 25 from a universal_integer literal, which was implicitly converted to INTEGER.
 
The type INTEGER is then further subtyped (constrained) to types NATURAL and POSITIVE:
 

subtype NATURAL is INTEGER range 0 to INTEGER’high;

 

subtype POSITIVE is INTEGER range 1 to INTEGER’high;

As INTEGER, NATURAL and POSITIVE are in a subtype relation to each other and they share the same base type (the predefined anonymous integer type), no type conversion is needed when assigning values between objects of these types:
 

constant CounterInit : POSITIVE := CounterCycles – 1;

 
VHDL allows us to define more integer types like:
 

type UInt8 is range 0 to 255;

 
We can create objects of this UInt8 type like so:
 

variable myVar : UInt8 := 42;

Again, 42 is a universal_integer literal and gets implicitly converted.
 
What about this assignment?
 

myVar := CounterCycles;

 
This will result in an error, because myVar and CounterCycles do not share the same underlying base type, even if the range would be compatible. Here an explicit type conversion is needed by the user.
 
All explained concepts of integers, universal_integer, and INTEGER work as well for floating-point data types, universal_real, and REAL.
 
So, do we need other integer types then INTEGER? Not really. But we could create more restrictive code and avoid accidentally assigning between wrong objects (e.g. signals).

If you would like to deepen your VHDL expertise – covering this topic and much more – join our Compact VHDL for Synthesis training, and take your VHDL skills to the next level.