← All guides

VHDL type conversions

VHDL does not implicitly reinterpret a std_logic_vector as a number. With numeric_std, arithmetic on std_logic_vector, indexing an array with a vector, and assigning an integer to a vector all require an explicit conversion. This page explains why, lists the numeric_std conversions, and shows what each costs in hardware. For the types themselves, see VHDL data types.

Why conversions are required

Conversion table

From ↓ / To →std_logic_vectorunsignedsignedinteger
std_logic_vectorunsigned(v)signed(v)to_integer(unsigned(v)) or to_integer(signed(v))
unsignedstd_logic_vector(u)signed(u)to_integer(u)
signedstd_logic_vector(s)unsigned(s)to_integer(s)
integerstd_logic_vector(to_unsigned(i, N)) or std_logic_vector(to_signed(i, N))to_unsigned(i, N)to_signed(i, N)

All entries require ieee.numeric_std. There are two kinds:

Notes:

Casts generate no hardware

This adder has std_logic_vector ports and casts to unsigned for the addition:

Interactive schematic by RapidRTL

The schematic contains only the adder.

Exercise: change both unsigned casts to signed and click Run. The circuit is unchanged, because at equal widths two’s complement addition produces the same bits as unsigned addition.

resize

resize(arg, new_size) changes the width according to the type:

TypeWideningNarrowing
unsignedfills the new MSBs with '0'keeps the rightmost bits
signedcopies the sign bit into the new MSBs (sign extension)keeps the sign bit and the rightmost bits
y <= resize(a, 8);  -- a: 4 bits, y: 8 bits

With a and y declared signed, bit 3 (the sign) drives bits 4 to 7:

Interactive schematic by RapidRTL

With a and y declared unsigned, bits 4 to 7 are constant 0:

Interactive schematic by RapidRTL

Neither version contains logic; the type alone selects the wiring. shift_right follows the same rule: it shifts in the sign bit for signed and '0' for unsigned.

Narrowing cannot preserve a value that does not fit. Resizing the 4-bit signed −6 ("1010") to 3 bits gives −2 ("110"). Check the range before narrowing.

Preserving the carry

+ returns the width of the wider operand, so the carry of an 8-bit addition is discarded. Widen an operand before the addition:

signal a, b : unsigned(7 downto 0);
signal sum  : unsigned(8 downto 0);

sum <= resize(a, 9) + b;  -- 9-bit addition; the carry is sum(8)

resize(a + b, 9) is incorrect: the addition is performed at 8 bits, and the carry is lost before the resize.

to_integer

Arrays are indexed by integers, so indexing with a vector requires to_integer:

y <= data(to_integer(unsigned(sel)));

Interactive schematic by RapidRTL

In this example, to_integer adds no conversion logic; the indexing synthesizes to the multiplexer.

to_unsigned and to_signed

Both take the target width as the second argument:

count <= to_unsigned(0, count'length);  -- width taken from the declaration
coeff <= to_signed(-75, 8);

VHDL-2008 also provides overloads that take a vector instead of a width; the result takes that vector’s length. They exist for to_unsigned, to_signed and resize:

count <= to_unsigned(0, count);  -- same as to_unsigned(0, count'length)
wide  <= resize(narrow, wide);   -- same as resize(narrow, wide'length)

Common errors

Example messages from GHDL. Wording varies by tool, version and language standard.

ErrorCauseFix
no function declarations for operator "+"arithmetic on std_logic_vectorcast to unsigned or signed
can't match integer literal with type array type "UNRESOLVED_UNSIGNED"integer assigned to a vector, e.g. u <= 5;u <= to_unsigned(5, u'length);
no overloaded function found matching "to_integer"to_integer on a std_logic_vectorto_integer(unsigned(v)) or to_integer(signed(v))
no declaration for "unsigned" (due to conflicts)numeric_std and std_logic_arith in one fileremove std_logic_arith (details)
bound check failure (simulation)value outside a range: to_integer above 31 bits, negative to_unsigned argument, constrained integer overflowwiden the type, use to_signed, or correct the logic

Rules

References