Data Types

VHDL fundamental types: std_logic, std_logic_vector, integer, unsigned, signed.

Type Overview

VHDL is strongly typed: each signal, variable, or port has a fixed type. Conversions must be explicit.

TypeLibraryTypical Usage
std_logicSTD_LOGIC_11641-bit signal
std_logic_vectorSTD_LOGIC_1164N-bit bus (no arithmetic)
unsignedNUMERIC_STDN-bit unsigned bus (arithmetic)
signedNUMERIC_STDN-bit signed bus (two's complement)
integerSTD (native)Integer — simulation, parameters
booleanSTD (native)true / false
bitSTD (native)0 or 1 — avoid in synthesis

std_logic

The most used type in synthesizable VHDL. It models an electrical wire with 9 possible values:

ValueMeaning
'0'Logic zero
'1'Logic one
'Z'High impedance (tristate)
'U'Uninitialized (simulation)
'X'Unknown — driver conflict (simulation)
'W', 'L', 'H', '-'Weak values, don't care

In synthesis, only '0', '1' and 'Z' have physical meaning.

signal w_enable : std_logic;
signal r_data   : std_logic;
 
w_enable <= '1';
r_data   <= 'Z';  -- high impedance

std_logic_vector

N-bit bus. No arithmetic operations available directly.

signal w_bus : std_logic_vector(7 downto 0);   -- 8 bits, bit 7 = MSB
signal w_adr : std_logic_vector(0 to 7);       -- 8 bits, bit 0 = MSB (rare)
 
-- Assignment
w_bus <= "10110011";       -- binary
w_bus <= x"B3";            -- hexadecimal
w_bus <= (others => '0'); -- all bits to 0
 
-- Bit or sub-vector access
w_bit3   <= w_bus(3);              -- bit 3
w_nibble := w_bus(7 downto 4);    -- 4 MSBs

Convention: always use downto (7 downto 0) — this is the standard convention.


unsigned and signed

These types enable arithmetic operations on bit vectors.

library IEEE;
use IEEE.NUMERIC_STD.ALL;
 
signal r_counter : unsigned(7 downto 0);
signal w_diff    : signed(8 downto 0);
 
-- Arithmetic
r_counter <= r_counter + 1;
r_counter <= r_counter + to_unsigned(5, 8);
 
-- Comparison
if r_counter = to_unsigned(255, 8) then
  -- ...
end if;

Type Conversions

Conversions are mandatory and explicit in VHDL.

std_logic_vector ←→ unsigned  : direct cast (same binary structure)
std_logic_vector ←→ signed    : direct cast
unsigned ←→ integer           : to_integer() / to_unsigned()
signed   ←→ integer           : to_integer() / to_signed()
signal w_vec  : std_logic_vector(7 downto 0);
signal w_uns  : unsigned(7 downto 0);
signal w_sig  : signed(7 downto 0);
signal w_int  : integer;
 
-- std_logic_vector ↔ unsigned
w_uns <= unsigned(w_vec);
w_vec <= std_logic_vector(w_uns);
 
-- unsigned ↔ integer
w_int <= to_integer(w_uns);
w_uns <= to_unsigned(w_int, 8);   -- 8 = number of bits
 
-- signed ↔ integer
w_int <= to_integer(w_sig);
w_sig <= to_signed(w_int, 8);

integer

Native type for parameters and counters in simulation. Avoid in synthesizable entity ports.

constant c_MAX_COUNT : integer := 100;
signal   w_index     : integer range 0 to 255;   -- constrained = better synthesis
 
-- In generics (common usage)
generic (
  g_WIDTH : integer := 8;
  g_DEPTH : integer := 256
);

Conversion Reference Table

From → Tostd_logic_vectorunsignedsignedinteger
std_logic_vectorunsigned(x)signed(x)to_integer(unsigned(x))
unsignedstd_logic_vector(x)signed(x)to_integer(x)
signedstd_logic_vector(x)unsigned(x)to_integer(x)
integerstd_logic_vector(to_unsigned(x,N))to_unsigned(x,N)to_signed(x,N)

Enumeration Types

Enumeration types let you name states or codes explicitly. This is the type used in state machines.

-- Declared in the architecture declarative region
type t_state is (IDLE, INIT, RUN, DONE, ERROR);
type t_color  is (RED, ORANGE, GREEN);
type t_dir    is (NORTH, SOUTH, EAST, WEST);
 
signal r_state : t_state := IDLE;
signal r_color : t_color := RED;
-- Used inside a process
process(i_clk)
begin
  if rising_edge(i_clk) then
    case r_state is
      when IDLE  => r_state <= INIT;
      when INIT  => r_state <= RUN;
      when RUN   =>
        if i_done = '1' then
          r_state <= DONE;
        end if;
      when others => r_state <= IDLE;
    end case;
  end if;
end process;

Enumeration types are automatically encoded by the synthesizer (binary or one-hot depending on the tool). Encoding can be forced through synthesis attributes.


User-Defined Array Types

VHDL lets you define multi-dimensional arrays or arrays of custom types.

-- Array of 8 bytes (simple ROM)
type t_rom_8x8 is array (0 to 7) of std_logic_vector(7 downto 0);
 
constant c_ROM : t_rom_8x8 := (
  x"00", x"1F", x"3C", x"7E",
  x"FF", x"7E", x"3C", x"1F"
);
 
-- 2D array (4×- bit matrix)
type t_matrix is array (0 to 3, 0 to 3) of std_logic;
 
-- Array of std_logic_vector (inferred RAM)
type t_ram is array (0 to 255) of std_logic_vector(7 downto 0);
signal r_mem : t_ram;
-- Synchronous RAM inferred from an array
process(i_clk)
begin
  if rising_edge(i_clk) then
    if i_we = '1' then
      r_mem(to_integer(unsigned(i_addr))) <= i_data;
    end if;
    o_data <= r_mem(to_integer(unsigned(i_addr)));
  end if;
end process;

Record Type

A record groups multiple fields of different types under one name. Equivalent to a struct in C.

-- Record declaration (in a package or architecture)
type t_pixel is record
  red   : unsigned(7 downto 0);
  green : unsigned(7 downto 0);
  blue  : unsigned(7 downto 0);
  valid : std_logic;
end record t_pixel;
 
-- Usage
signal r_pixel_in  : t_pixel;
signal r_pixel_out : t_pixel;
 
-- Individual field assignment
r_pixel_in.red   <= to_unsigned(255, 8);
r_pixel_in.green <= to_unsigned(128, 8);
r_pixel_in.blue  <= to_unsigned(0,   8);
r_pixel_in.valid <= '1';
 
-- Aggregate assignment
r_pixel_out <= (red => x"FF", green => x"80", blue => x"00", valid => '1');
 
-- Full record copy
r_pixel_out <= r_pixel_in;

Records are very useful for bus interfaces (AXI, structured data) and for passing related signals together through a port map.

When records are used in entity ports, they must be declared in a shared package visible to all files.