CS232 VHDL Introduction

VHSIC Hardware Description Language [VHDL] is a language used to define and describe the behavior of digital circuits. It allows you to specify a set of inputs and outputs, and to describe a circuit. Just like a circuit evaluates all of the inputs at the same time (and nonstop), VHDL executes its code continuously and in parallel.

This page shows the VDHL code for a 2-to-4 bit decoder. We explain the code as we go.

A Decoder using individual bits

-- We are going to use the std_logic type defined in the
-- iee library. We need these lines to get access to that library.
library ieee;
use ieee.std_logic_1164.all;

-- An entity is like a signature. It describes the input and output signals
-- of a circuit
entity decoder is
	port ( 
		in0, in1 : in std_logic; -- two input signals, both of the same type (std_logic)
		data0, data1, data2, data3 : out std_logic -- four output signals, all of the same type (std_logic)
	);
end entity;

-- An architecture is like the code body. It describes how the circuit behaves.
architecture dec_arch of decoder is
begin
    -- each output depends on the input. These are four assignment
    -- statements. They are run continuously and in parallel
    data0 <= (not in1) and (not in0);
    data1 <= (not in1) and in0;
    data2 <= in1 and (not in0);
    data3 <= in1 and in0;
end dec_arch;

Observations and rules

A Decoder using an array (vector) of bits

If it makes sense to group bits together (think about a bus in the circuit), then we can use vectors. That way each group of bits requires a named signal. It will make our code shorter.

entity decoder_with_array is

	port (
		encoded : in std_logic_vector (1 downto 0); -- the 2 bits will be indexed from left to right from 1 downto 0
		decoded : out std_logic_vector (3 downto 0) -- the 4 bits will be indexed from left to right from 1 downto 0
	);

end entity;

architecture dec_arch of decoder_with_array is
begin
    -- "0001" is an example of a std_logic_vector. It means the 0th bit is on
    -- and the rest are off.
    -- This assignment statement has sort of an if-statement built into it. The 
    -- value given to decoded (the output) depends on the value of encoded (the input).
    decoded <= "0001" when encoded="00" else
            "0010" when encoded="01" else
            "0100" when encoded="10" else
            "1000" when encoded="11";
end dec_arch;

Observations and rules

A Decoder using an unsigned integer

If we want to view our collection of bits as a single entity (e.g. the integer they encode) or arithmetic on the collection of bits, then we should use the unsigned type. It is a vector of std_logic bits one which mathematical operations (such as addition) are defined.

In this example, the std_logic_vector is sufficient. But I would like to show you the unsigned type anyways.

-- We are going to use the std_logic type defined in the
-- iee library. We need these lines to get access to that library.
library ieee;
use ieee.std_logic_1164.all; -- we just about always need this
use ieee.numeric_std.all; -- we need this for the unsigned type

entity decoder_with_unsigned is

	port (
		encoded : in unsigned (1 downto 0); -- the 2 bits will be indexed from left to right from 1 downto 0
		decoded : out unsigned (3 downto 0) -- the 4 bits will be indexed from left to right from 1 downto 0
	);

end entity;

architecture dec_arch of decoder_with_unsigned is
begin
    -- "0001" is an example of a unsigned. It means the 0th bit is on
    -- and the rest are off.
    -- This assignment statement has sort of an if-statement built into it. The 
    -- value given to decoded (the output) depends on the value of encoded (the input).
    decoded <= "0001" when encoded="00" else
            "0010" when encoded="01" else
            "0100" when encoded="10" else
            "1000" when encoded="11";
end dec_arch;

Observations and rules

A testbench file for the decoder that uses individual bits

To simulate the above circuits, we need some way of specifying the values of the input bits over time. We can do that interactively using ModelSim. Or we can write another VHDL file and run it using ghdl (Gnu's VDHL compiler).

Here is the testbench file I used to test decoder that uses individual bits.

library ieee;
use ieee.std_logic_1164.all;

--  A testbench has no ports.
entity decoder_tb is
end decoder_tb;

architecture behav of decoder_tb is
    --  Declaration of the component that will be instantiated.
    component decoder
        port (
            in0, in1 : in std_logic;
            data0, data1, data2, data3 : out std_logic
        );
    end component;
    signal in0, in1 : std_logic;
    signal data0, data1, data2, data3 : std_logic;
begin
    -- this is how I managed to get the simulation to last 15ns.
    decoder_0: decoder port map (in0 => in0, in1 => in1, data0 => data0, data1 => data1, data2 => data2, data3 => data3);
    process
    begin
        in0 <= '0', '1' after 10 ns, '0' after 20 ns, '1' after 30 ns;
        in1 <= '0', '1' after 20 ns;
        wait for 40 ns; -- for the simulation to last at least 40ns
        wait;
    end process;
end behav;

Observations and rules

A testbench file for the decoder that uses bit vectors

Here is the version that uses bit vectors.
library ieee;
use ieee.std_logic_1164.all;

--  A testbench has no ports.
entity decoder_with_array_tb is
end decoder_with_array_tb;

architecture behav of decoder_with_array_tb is
    --  Declaration of the component that will be instantiated.
    component decoder_with_array
        port (
            encoded : in std_logic_vector (1 downto 0);
            decoded : out std_logic_vector (3 downto 0)
        );
    end component;
    signal encoded : std_logic_vector (1 downto 0);
    signal decoded : std_logic_vector (3 downto 0);
begin
    decoder_with_array_0: decoder_with_array port map (encoded => encoded, decoded => decoded);
    process
    begin
        encoded <= "00", "01" after 10 ns, "10" after 20 ns, "11" after 30 ns;
        wait for 40 ns; -- for the simulation to last at least 40ns
        wait;
    end process;
end behav;