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;