VHDL-2--Scalar data types

Learn VHDL syntax

Scalar data types

Objectives:

Data types

Though VHDL has a limited number of “buld-in” data types, libraries in VHDL extend this number.

Scalar data types

Scalar data types in VHDL represent single values. These includes:

1. Bit & boolean

BIT

architecture Behavioral of mux is
signal A, B, SEL, Z : bit;
begin
    Z <= A when (SEL = '1') else B;
end Behavioral;

A,B, SEL, and Z declared with the bit data type. It executes a simple multiplexer behavior.

Boolean

Both the data type declarations are taken from library STD and the package Standard. These are predefined and implicit for every VHDL model and, therefore, no explicit library declaration is ever required.

2. std_ulogic & std_logic

std_ulogic

std_ulogic was developed from the Multi-Value Logic (MVD) system. It provides a detailed hardware modeling option

The u in std_ulogic means unresolved.

This indicates that a function, at some point after the initial compilation, returns to a resolve state.

std_ulogic takes values as shown in the example here:

It supports different signal strengths, don’t care conditions, and tristate drivers.

It is defined in the package std_logic_1164 of IEEE.

std_ulogic

std_logic is the resolved form of std_ulogic and is more commonly used.

It takes the same nine values as std_ulogic.

The table shown here is called the resolution table used for the std_logic data type. This table resolves the question of which value is to be assigned when multiple values are assigned to the same signal.

Both the std_logic and std_ulogic types are actually enumerated types and their values must always be capitalized

std_ulogic vs std_logic

Both the std_logic and std_ulogic data types have same set of values. The difference is implementation.

If a user wants to drive two or more signals to a common output

architecture rtl of example is
signal OUT_1: std_ulogic;
signal A, B, C, RES_OUT: std_logic;

begin
    OUT_1 <= A;
    OUT_1 <= B;
    OUT_1 <= C;
    
    RES_OUT <= A;
    RES_OUT <= B;
    RES_OUT <= C;
end architecture;

For example, the OUT_1 signal will give an error here, whereas the RES_OUT signal with the std_logic type will make it through compile but will not often make it through implementation due to multiple drivers.

Signal resolution

How do we resolve the multiple drivers issue?

It can be resolved by using the tristate buffer modeling technique.

Atthe board level, these signals are combined via open-drain or open-collector outputs-in which case, std_logic weak high (H) and weak low (1) could be used to model

signal A, B, C, RES_OUT: std_logic;
RES_OUT <= A when EN0 = '1' else 'Z';
RES_OUT <= B when EN1 = '1' else 'Z';
RES_OUT <= C when EN2 = '1' else 'Z';

Integer and Real

Integer

The syntax and an example of the type integer is shown here

Syntax

type integer is range ...

Example

signal A: integer range 0 to 7;
signal B: integer range 15 downto 0;

Real

Syntax

type real is range ...

Example

type CAPACITY is range -25.0 to 25.0;
signal SIG_1: CAPACITY := 3.0;

What can & cannot be done with Integers & Reals

Data Type Conversion

Since VHDL is a strongly typed language by its nature, assigning one type to another is illegal. Performing this change requires a conversion mechanism.

The conversion processes in VHDL are:

Type casting

For example:

signal ex1 : std_logic_vector(3 downto 0);
signal ex2 : signed(3 downto 0);
signal ex3 : unsigned(3 downto 0);

ex2 <= signed(ex1);
ex3 <= unsigned(ex1);
ex1 <= std_logic_vector(ex2);

Conversion function

signal ex1: signed(3 downto 0);
signal ex2: integer;

ex1 <= to_signed (ex2, ex1'length);
ex2 <= to_integer(ex1);

Data Type Conversion

Since VHDL is a strongly typed language by its nature, assigning one type to another is illegal. Performing this change requires a conversion mechanism.

The conversion processes in VHDL are:

Type casting

For example:

signal ex1 : std_logic_vector(3 downto 0);
signal ex2 : signed(3 downto 0);
signal ex3 : unsigned(3 downto 0);

ex2 <= signed(ex1);
ex3 <= unsigned(ex1);
ex1 <= std_logic_vector(ex2);

Conversion function

signal ex1: signed(3 downto 0);
signal ex2: integer;

ex1 <= to_signed (ex2, ex1'length);
ex2 <= to_integer(ex1);

std_logic_vector to/from integer

Common conversions required in VHDL are

To convert from std logic_vector to integer:

integer_value <= to_integer( unsigned(slv_value));

To convert from integer to std_logic_vector:

slv_value <= std_logic_vector(to_unsigned( integer_value, n ));

Types & subtypes

Types

type mem_array is array (integer range 0 to 1023) of std_logic_vector(15 downto 0);

The example shown here creates a new type called mem_array. Once created, this mem array becomes a full-blown type that a new signal or variable may be defined as. In this example, the created type is an array of std_logic_vector with length of 16 bits. The array has 1024 elements.

Subtypes

subtype <new subtype name> is <type or subtype name>;

subtype ROM_MEMORY_RANGE is integer range 0 to 255;

The syntax always has a pre-defined type as subtype only refines the use of a previously defined type or subtype by further limiting its scope.

The example shown here creats a subtype ROM_MEMORY_RANGE that limits the integer range (by default, a minimum of 32 bits) to 8 bits.

Characters & Strings

Characters

type character is (nul, sol, stx, ...);

constant MY_CHAR : character := 'Q';

The constant MY_CHAR is of the character type and has been assigned a value equal to ‘Q.

Strings

type string is array (positive range <>) of character;
constant msg: string (1 to 10) := "setup time";

A constant msg of string type with the range equal to ten characters. It has been assigned a value of “setup time”.

Physical

type time is range -2147483647 to 2147483647
units
fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
ms = 1000 us;
...
end units;
constant TPD : time := 3 ns;
...
Z <= A after TPD;

In the example here, a constant TPD is of the type time and has been initialized with a 3ns value.

Enumerated types

The syntax for this enumerated type is for this enumerated type is given onscreen:

type <new type name> is (<list of items>);
type MY STATE is (RST, LOAD, FETCH, STORE, SHIFT);
...
signal STATE, NEXT STATE: MY STATE;
...

case (STATE) is
    when LOAD =>
        if COND_A and COND B then
            NEXT STATE <= FETCH;
        else
            NEXT_STATE <= STORE;
        ...

In this example,

type rx_states is (IDLE, START, DATA, PARITY, STOP);
type tx_states is (IDLE, START, DATA, PARITY, STOP);

signal rx_states: rx states := IDLE;
signal tx_states: tx states := IDLE;

Consider an example of a UART transmitter and receiver. Here, rx_states and tx_states are of the enumerated type.

For ease of understanding, the states list in rx_states can be considered as rx_states.IDLE, rx_States.START etc. Similarly, the states in tx_states can be considered as tx_states.IDLE, tx_states.START, etc