Try โ€‚โ€‰HackMD

Hardware Description Languages Lab 3

Using Components & Test Benches

The Islamic University of Gaza
Engineering Faculty
Department of Computer Engineering
Author: Mohammed Nafiz ALMadhoun2021/02/26

In this lab, we are going to talk about how to use components, which allows you to create and use/reuse your old component and to organize your design into multiple components, then we will talk about test benches, which allows you to easily verify and test your VHDL code.

Using components

The first thing we will talk about is ssignals, which are wires, we will use these s to connect components together, and more!

Signals

To create a signal, you will need to write

signal name : type;

for example:

architecture test of test is signal not_a : std_logic; begin not_a = not a; -- anything! end architecture;

Notice that we've created a signal called not_a and its type is std_logic.

Declaring components

To use an entity as a component, you should declare this component in the architecture that will use that entity, for example:

architecture full_adder of full_adder is component half_adder port( a, b: in std_logic; s, c: out std_logic ); end component; begin

Instacting a components

Now after declaring the components you want to use, you can now create instances of this component and map its ports to your signals, for example:

library ieee; use ieee.std_logic_1164.all; entity full_adder is port( a, b, cin: in std_logic; s, cout : out std_logic ); end entity; architecture full_adder of full_adder is component half_adder port( a, b: in std_logic; s, c: out std_logic ); end component; signal s1, c1, s2, c2: std_logic; begin ha1: component half_adder port map (a, b, s1, c1); ha2: component half_adder port map (a => s1, b => cin, s => s2, c => c2); s <= s2; cout <= c1 or c2; end architecture;

Notice in lines 19,20, we created two instances of the half_adder component.

We named the first instance ha1, and we mapped it to our signals a, b, s1, c1, which will be mapped in the component declaration order.

In line 20, we created ha2 and mapped each signals with its name.

Test Benches

A Test bench is just a regular VHDL file, which will use your entities and assert expected results, to write a test bench you will create a new VHDL file, then change its type to VHDL Test Bench File.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

Figure 1: VHDL File Proparites.

Then you should edit your simulation settings and choose Compile test bench.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

Figure 2: Simulation Settings.

Then click on Test Benches, and add your test bench to the list of test benches.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

Figure 3: Adding a file as a test bench.

Test Process

To write a test code, you will create an empty entity (doesn't have any inputs or outputs), then you will create an architecture for that entity.

The architecture of a test bench will usually contain processes, the processes behave like a sequential code, so don't expect a test bench to be synthesised.

And don't forget that you will use the tested entity as a component, so you should declare it and create an instance of it inside the architecture, for example:

library ieee; use ieee.std_logic_1164.all; entity ha_testbench is end entity; architecture ha_testbench of ha_testbench is component half_adder port( a, b: in std_logic; s, c: out std_logic ); end component; signal a, b, s, c: std_logic; begin uut: half_adder port map (a, b, s, c); ...

Notice that we have signals declared, so we could change the inputs and read the outputs of the component.

Now, we will create a process, which contains some signal assessment, waiting statements, and assertion statements, notice that this is just a simple test bench.

begin 
    uut: half_adder port map (a, b, s, c);
    
    process begin
        a <= '0';
        b <= '0';
        wait for 100 ns;
        assert s = '0' and c = '0' report "Case 0,0 fail!";
        
        a <= '1';
        b <= '0';
        wait for 100 ns;
        assert s = '1' and c = '0';
        
        a <= '0';
        b <= '1';
        wait for 100 ns;
        assert s = '1' and c = '0';
        
        a <= '1';
        b <= '1';
        wait for 100 ns;
        assert s = '0' and c = '1';
        
        wait; -- just waiting forever!
    end process;
end architecture;

Now after running the simulator, you will notice that the signals will show up in the wave view, and if there is any fail assertion it will be reported in the console.

Figure 4: Wave view
Figure 4: Wave view

Lab Tasks

Task 1: 4 Bit Adder

In this task, you should create 3 entites, half_adder, full_adder, and adder_4bit.
As you might expect, the adder_4bit, should use the full_adder, and it should have 3 inputs and 2 outputs:

  • a 4-bit input
  • b 4-bit input
  • c 1-bit input
  • s 4-bit output
  • cout 1-bit output

Task 2: Create a test bench for the full adder

In this task, you should create a test bench for your full adder, and it should cover all possible values.

tags: VHDL IUG
End Of Lab 3