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;