← All guides

VHDL data types and their ranges

VHDL is strongly typed. Every signal, variable and port has one type, which determines the values it can hold and the operators that apply to it, and influences how synthesis represents it in hardware. This page covers the types used in synthesizable designs. Converting between them is covered in VHDL type conversions.

Quick reference

TypeDefined inValues / rangeSynthesizableUse for
std_logicieee.std_logic_11649 values: 'U' 'X' '0' '1' 'Z' 'W' 'L' 'H' '-'yessingle bits: clocks, resets, enables
std_ulogicieee.std_logic_1164same 9 values, unresolvedyessingle bits with exactly one driver
std_logic_vectorieee.std_logic_1164N bits, no numeric valueyesports, buses, raw data
unsignedieee.numeric_std0 to 2N − 1yescounters, addresses, unsigned arithmetic
signedieee.numeric_std−2N−1 to 2N−1 − 1yessigned arithmetic
integerstd.standardimplementation-dependent; 32-bit in most tools (see below)yesconstants, generics, indices
naturalstd.standard0 to integer'highyessizes, counts, indices
positivestd.standard1 to integer'highyeswidths and depths
booleanstd.standardfalse, trueyesconditions, generics
bitstd.standard'0', '1'yesrarely used; superseded by std_logic
enumerationuser-definedthe listed namesyesFSM states
realstd.standardIEEE 754 floating point, at least 64 bitsconstant calculations onlycomputing constants and generics
timestd.standardphysical type, e.g. 10 nsno; some tools allow it in constant calculationstestbenches

The IEEE types require these clauses. The std.standard types are always visible.

library ieee;
use ieee.std_logic_1164.all;  -- std_logic, std_ulogic, std_logic_vector
use ieee.numeric_std.all;     -- unsigned, signed

std_logic and std_ulogic

std_logic has nine values. Most exist so that simulation can show faults.

ValueMeaningIn simulationWritten as a literal in synthesizable code
'U'uninitializednever assigned, e.g. a register with no resetnot meaningful
'X'forcing unknownconflicting drivers or unknown inputdon’t-care in most tools
'0', '1'forcing 0, forcing 1logic levelslogic levels
'Z'high impedanceundriven, e.g. an idle tri-state bustri-state buffer (FPGA: device pins only)
'W'weak unknownconflicting weak driversnot meaningful
'L', 'H'weak 0, weak 1pull-down, pull-upread as 0 and 1
'-'don’t careoptimizer chooses 0 or 1

The last column describes values written in the code, and tool behaviour varies. A value that appears during simulation, such as an 'X' from two conflicting drivers, has no hardware equivalent.

Resolution

std_logic is a resolved subtype of std_ulogic. When several drivers assign the same signal, the resolution function in std_logic_1164 combines them using this table:

UX01ZWLH-
UUUUUUUUUU
XUXXXXXXXX
0UX0X0000X
1UXX11111X
ZUX01ZWLHX
WUX01WWWWX
LUX01LWLWX
HUX01HWWHX
-UXXXXXXXX

Resolution determines how multiple drivers behave:

std_logic_vector

An array of std_logic. It has a width and an index direction, but no numeric value: the bits alone do not say whether "1000" is 8 or −8.

signal data : std_logic_vector(7 downto 0);  -- data(7) is the leftmost element
signal lane : std_logic_vector(0 to 7);      -- lane(0) is the leftmost element

When a vector is interpreted as unsigned or signed, the leftmost element is the MSB.

Convert to unsigned or signed for any arithmetic or numeric comparison.

unsigned and signed

Both are defined in numeric_std as arrays of std_logic. In hardware they are N wires, like std_logic_vector; the type sets the interpretation. The leftmost bit is the MSB.

Widthunsignedsigned
40 to 15−8 to 7
80 to 255−128 to 127
160 to 65,535−32,768 to 32,767
320 to 4,294,967,295−2,147,483,648 to 2,147,483,647

Arithmetic rules:

integer, natural and positive

integer is a numeric type, not a vector: it cannot be sliced or indexed by bit. Its range is implementation-dependent:

natural and positive are subtypes of integer:

subtype natural  is integer range 0 to integer'high;
subtype positive is integer range 1 to integer'high;

A constrained range reduces the synthesized width

The language does not define how many bits an integer occupies in hardware. Synthesis tools derive the width from the range: Vivado and Synplify, for example, implement an unconstrained integer as 32 bits (64 in Vivado’s VHDL-2019 mode), and integer range 0 to 9 as 4 bits.

Interactive schematic by RapidRTL

In this schematic (GHDL and Yosys, 32-bit integer), the register is 4 bits. The addition n + 1 is drawn at integer width: the register value is zero-extended (0x0 into bits 4:31), added, and truncated back to 4 bits by the 0:3 slice. Other tools may build the adder at 4 bits directly.

Exercise: delete range 0 to 9 from both declarations and click Run. The register, adder and comparator become 32 bits wide. With plain natural, they become 31 bits, since no sign bit is needed.

Range checks are simulation-only

Types and subtypes

subtype byte    is std_logic_vector(7 downto 0);     -- subtype
subtype count_t is natural range 0 to 9;             -- subtype
type    word_t  is array (15 downto 0) of std_logic; -- new type

signal b : byte;
signal v : std_logic_vector(7 downto 0);
signal w : word_t;
signal c : count_t;
signal i : integer;

b <= v;             -- legal: byte is a std_logic_vector
c <= i;             -- legal: count_t is an integer (range checked in simulation)
w <= v & v;         -- error: word_t is not a std_logic_vector
w <= word_t(v & v); -- legal: explicit conversion

Applied to the standard types:

Enumerations and boolean

Enumerations define a set of named values. Use them for FSM states:

type state_t is (idle, load, run, done);
signal state : state_t;

The compiler rejects undefined names, and synthesis selects the encoding (binary, one-hot or Gray). See FSM design.

boolean is the type of conditions: comparisons return it, and if and while require it. It synthesizes to one bit. In VHDL-2008, if en then is accepted for a std_logic signal en, and is true when en is '1' or 'H'.

Choosing a type

PurposeType
Top-level ports, vendor IP interfacesstd_logic, std_logic_vector
Ports between your own entitiesany; unsigned or signed documents numeric data
Arithmetic and comparisonunsigned, or signed if values can be negative
Generics, constants, loop and array indicesinteger, natural, positive
Counters up to 31 bitsconstrained integer or natural, or unsigned
Counters over 31 bits, or where individual bits are neededunsigned
FSM statesenumeration
Constant calculations onlyreal
Testbenches onlytime

Non-standard packages: std_logic_arith and std_logic_unsigned

use ieee.std_logic_arith.all;     -- Synopsys, not IEEE
use ieee.std_logic_unsigned.all;  -- Synopsys, not IEEE

These are Synopsys packages that predate numeric_std (1997). Vendors install them in library ieee, but they are not IEEE standards. Avoid them:

Use numeric_std. For unsigned arithmetic directly on std_logic_vector, VHDL-2008 provides the standard package ieee.numeric_std_unsigned. There is no standard signed equivalent; use signed.

References

Current standard:

Previous edition (clause numbers on this page refer to it):

Historical origins:

Package sources and tools: