VHDL cheat sheet

All the code in this cheat sheet is synthesizable, except in the part about simulation.

Data types

All signals, inputs, outputs and constants have a type in VHDL.

-- Signal of one bit (no arithmetic)
signal my_signal: std_logic;
-- Signal of 4 bits (no arithmetic)
signal my_bus: std_logic_vector(3 down to 0);

-- Signal of 12 bits made to store unsigned integers
signal my_count: unsigned(11 downto 0);
-- Signal of 10 bits made to store signed integers
signal my_number: signed(9 downto 0);

Basic structure

One file per entity, with this skeleton:

----------------------------------------------------------------
-- Lines starting with  -- are comments
--
-- Always put a comment explaining the role of the
-- entity at the top of the file
----------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; -- required for signed/unsigned

entity my_example_entity is
    generic (
        -- Constant parameters that can be used in code below (optional)
        PARAM_ONE : std_logic_vector(7 downto 0) := x"01";
        PARAM_TWO : std_logic_vector(7 downto 0) := x"02"
    );
    port(
        -- Input and output ports of the entity
        -- Only std_logic and std_logic_vector types are accepted here
        CLK      : in std_logic;
        RESET    : in std_logic;
        DATA_OUT : out std_logic_vector(7 downto 0);
    );
end my_example_entity;

architecture Behavioral of my_example_entity is
    -- Declaration of internal signals
    signal store_conf : std_logic;
begin

    -- Here goes the code describing the behavior of the entity
    -- This is where most of the code is written

end Behavioral;

Processes

All processes in an entity are executed in parallel. They can describe synchronous or combinatorial circuit parts.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity process_examples is
    port(
        CLK    : in std_logic;
        RESET  : in std_logic;
        A      : in std_logic;
        B      : in std_logic;
        RESULT : out std_logic_vector(2 downto 0);
    );
end process_examples;

architecture Behavioral of process_examples is
begin

    -- Synchronous circuit without reset.
    -- RESULT(0) is updated at each rising edge of CLK
    -- if A or B changed during the last clock cycle.
    process(CLK) begin
        if rising_edge(CLK) then
            RESULT(0) <= A and B;
        end if;
    end process;

    -- Synchronous circuit with asynchronous reset active at 1.
    -- RESULT(1) is updated at each rising edge of CLK
    -- if A or B changed during the last clock cycle.
    -- Its initial value is set to 0 immediately when RESET is set to 1.
    process(CLK, RESET) begin
        if RESET = '1' then
            RESULT(1) <= '0';
        elsif rising_edge(CLK) then
            RESULT(1) <= A and B;
        end if;
    end process;

    -- Combinatorial circuit.
    -- RESULT(2) is updated immediately when A or B changes.
    process(A, B) begin -- Sensitivity list: ALL read signals
        RESULT(2) <= A and B;
    end process;

end Behavioral;

Combinatorial shortcuts

Processes can be avoided for simple combinatorial circuits.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity shortcut_examples is
    port(
        DATA_IN  : in std_logic_vector(2 downto 0);
        DATA_OUT : out std_logic_vector(1 downto 0);
        AND_OUT  : out std_logic;
    );
end shortcut_examples;

architecture Behavioral of shortcut_examples is
begin

    -- The line below
    AND_OUT <= DATA_IN(0) and (DATA_IN(1) or DATA_IN(2));
    -- is equivalent to the process below
    process(DATA_IN) begin
        AND_OUT <= DATA_IN(0) and (DATA_IN(1) or DATA_IN(2));
    end process;

    -- The line below
    DATA_OUT <= "01" when DATA_IN = "001" else
        ("10" when DATA_IN = "010" else "11");
    -- is equivalent to the process below
    process(DATA_IN) begin
        case DATA_IN is
            when "001" =>
                DATA_OUT <= "01";
            when "010" =>
                DATA_OUT <= "10";
            when others =>
                DATA_OUT <= "11";
    end process;

end Behavioral;

Data manipulation

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity manip_examples is
    port(
        MSB    : in std_logic_vector(2 downto 0);
        LSB    : in std_logic_vector(3 downto 0);
        RESULT : out std_logic;
    );
end manip_examples;

architecture Behavioral of manip_examples is
    signal to_add: unsigned(6 downto 0);
    signal input_bits: std_logic_vector(6 downto 0);
    signal input_value: unsigned(6 downto 0);
    signal sum: unsigned(6 downto 0);
    signal sum_bits: std_logic_vector(6 downto 0);
begin

    process begin
        -- Set a bus of any size to 0
        to_add <= (others => '0');
        -- Set only bits 1, 2 and 3 of a bus
        to_add(3 downto 1) <= "101";
        -- Set a bus of any size to "11"
        to_add <= (0 => '1', 1 => '1', others <= '0');
    end process;

    -- Merge two buses
    input_bits <= MSB & LSB;
    -- Convert std_logic_vector to unsigned
    input_value <= unsigned(input_bits);
    -- Add two unsigned values (does not work with std_logic_vector)
    sum <= input_value + to_add;
    -- Convert from unsigned to std_logic_vector
    sum_bits <= std_logic_vector(sum);
    -- Select bit with index 3 in a bus
    RESULT <= sum_bits(3);
end Behavioral;

Instantiating an entity

An entity can be used as part of another. This is how complex systems are done. Here is an example instantiating the entity of the first example. Entities have to be in the same project so that the right definition file is found.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity my_including_entity is
    port(
        -- Input and output ports of the entity
        -- Only std_logic and std_logic_vector types are accepted here
        CLK      : in std_logic;
        RESET    : in std_logic;
        XOR_OUT : out std_logic_vector(7 downto 0);
    );
end my_including_entity;

architecture Behavioral of my_including_entity is
    -- Declaration of the included entity, with its interface
    -- It should be identical to the one in the original file
    component my_example_entity
    generic (
        -- Constant parameters that can be used in code below (optional)
        PARAM_ONE : std_logic_vector(7 downto 0) := x"01";
        PARAM_TWO : std_logic_vector(7 downto 0) := x"02"
    );
    port(
        -- Input and output ports of the entity
        -- Only std_logic and std_logic_vector types are accepted here
        CLK      : in std_logic;
        RESET    : in std_logic;
        DATA_OUT : out std_logic_vector(7 downto 0);
    );
    end component;
    -- Internal signal to connect to the entity
    signal data_out : std_logic_vector(7 downto 0);
begin

    -- Connect the entity
    -- with generic parameters and
    -- internal signals
    my_entity: my_example_entity
    generic map (
        PARAM_ONE => x"10",
        PARAM_TWO => x"02"
    )
    port map (
        CLK => CLK,
        RESET => RESET,
        DATA_OUT => data_out
    );

    -- Use the output of the entity
    XOR_OUT <= DATA_OUT(0) xor DATA_OUT(5);
end Behavioral;

Simulation test bench

To test an instance, simultation data must be specified for each of its input signals. This is done by creating a specific VHDL entity with no input or output, called test bench.
Some special commands can be used in test benches, but not in synthesizable VHDL. Here is an example of test bench for the first example entity:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity testbench is
end testbench;

architecture Behavioral of testbench is
    -- Declaration of the simulated entity
    component my_example_entity
    generic (
        -- Constant parameters that can be used in code below (optional)
        PARAM_ONE : std_logic_vector(7 downto 0) := x"01";
        PARAM_TWO : std_logic_vector(7 downto 0) := x"02"
    );
    port(
        -- Input and output ports of the entity
        -- Only std_logic and std_logic_vector types are accepted here
        CLK      : in std_logic;
        RESET    : in std_logic;
        DATA_OUT : out std_logic_vector(7 downto 0);
    );
    end component;
    -- One signal for each input and output
    -- Signals used as inputs have default values
    signal clk      : std_logic := '0';
    signal reset    : std_logic := '1';
    signal data_out : std_logic_vector(7 downto 0);
begin

    -- Connect the entity
    my_entity: my_example_entity
    generic map (
        PARAM_ONE => x"10",
        PARAM_TWO => x"02"
    )
    port map (
        CLK => clk,
        RESET => reset,
        DATA_OUT => data_out
    );

    -- Generate a fake clock with a period of 8 ns
    clk <= not clk after 4 ns;
    -- Describe a scenario for input values
    process begin
        -- Wait during 5 clock cycles
        wait for 40 ns;
        -- Deactivate the reset
        reset <= '0';
        -- Wait during 50 clock cycles
        wait for 400 ns;
        -- Reactivate the reset
        reset <= '1';
    end process;
end Behavioral;

Useful examples

Counter

--------------------------------------
-- Counter with an output on 4 bits.
-- Starts at 0, counts when enable is 1.
-- Stops at generic MAX parameter.
-- Asynchronous reset active at 1
--------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter is
    generic (
        MAX: unsigned(3 downto 0) := "1100"
    );
    port(
        CLK    : in std_logic;
        RESET  : in std_logic;
        ENABLE : in std_logic;
        COUNT   : out std_logic_vector(3 downto 0);
    );
end counter;

architecture Behavioral of counter is
    signal count_value: unsigned(3 downto 0);
begin

    -- This is where the actual count happens
    process (CLK, RESET) begin
        if RESET = '1' then
            count_value <= (others => '0');
        elsif rising_edge(CLK) then
            if (enable = '1') then
                if count_value < MAX then
                    count_value <= count_value + 1;
                else
                     -- Back to 0 when MAX is reached
                    count_value <= (others => '0');
                end if;
            end if;
        end if;
    end process;

    -- Output the value
    COUNT <= std_logic_vector(count_value);
end Behavioral;

Finite State Machine

Finite State Machines are often used in electronics as the control part of the system. They have an internal state and react to changing inputs depending on this internal state.

--------------------------------------
-- FSM that checks a button sequence.
-- The sequence is left, right.
-- The LED is green while the sequence is OK
-- It becomes red if there is an error.
--------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity fsm is
    port(
        CLK          : in std_logic;
        RESET        : in std_logic;
        BUTTON_LEFT  : in std_logic;
        BUTTON_RIGHT : in std_logic;
        LED_GREEN    : out std_logic;
        LED_RED      : out std_logic;
    );
end fsm;

architecture Behavioral of fsm is
    -- Specific type with clear state names
    type fsm_state is (Step1, Step2, Success, Error);
    -- Current state, stored in a register
    signal state     : fsm_state
    -- Future state, depends on inputs and state
    signal state_nxt : fsm_state;
begin

    -- Current state storage, synchronous
    process (CLK, RESET) begin
        if RESET = '1' then
            -- Initial state
            state <= Step1;
        elsif rising_edge(CLK) then
            -- Next state
            state <= state_nxt;
    end process;

    -- Future state and outputs, combinatorial
    process(state, BUTTON_LEFT, BUTTON_RIGHT) begin
        -- By default, the state does not change
        state_nxt <= state;
        -- Default values of outputs
        LED_GREEN <= '0';
        LED_RED <= '0';
        case state is
            when Step1 =>
                -- Waiting for left
                LED_GREEN <= '1';
                if BUTTON_LEFT = '1' then
                    state_nxt <= Step2;
                elsif BUTTON_RIGHT = '1' then
                    state_nxt <= Error;
                end if;
            when Step2 =>
                -- Waiting for right
                LED_GREEN <= '1';
                if BUTTON_RIGHT = '1' then
                    state_nxt <= Success;
                elsif BUTTON_LEFT = '1' then
                    state_nxt <= Error;
                end if;
            when Success =>
                -- Finished, success
                LED_GREEN <= '1';
            when Error =>
                -- Finished, error
                LED_RED <= '1';
    end process;
end Behavioral;