Date: January 6/9
Lecture: 2
Next lecture HW#2
Status Complete
Code lec02.vhdl
Lesson SlidesECE_383_Lec2.pptx


When doing digital design, there is more than one way to skin a cat. This expression should make you happy regardless of your feelings towards cats because it means that your personality can be expressed through the code that you write. In Lecture 1, we examined a structural method of describing a circuit; we transformed the circuit diagram into a textual description. Today, we will examine another method of VHDL coding: behavioral.


The majority circuit, using components, can be seen coded in VHDL below.
-- Author:      Maj Jeff Falkinburg
-- Date:        Spring 2017
-- Purp:	Structural Majority circuit
library IEEE;						-- These lines are similar to a #include in C
use IEEE.std_logic_1164.all;
library unisim;					-- Use these libraries if you are using primitive components
use unisim.vcomponents.all;

entity majority is
	port(	a, b, c:	in std_logic; 
			f:			out std_logic);
end majority;

architecture structure of majority is
component AND2
	port ( i0, i1	: in std_logic;
			 o 		: out std_logic);
end component;
component OR3
	port ( i0, i1, i2	: in std_logic;
			 o 			: out std_logic);
end component;
signal	s1, s2, s3: std_logic;	-- wires which begin and end in the component

	unit1:	AND2
	port map (		-- s1 <= a and b;			
		i0 => a,
		i1 => b,
		o => s1);
	unit2:	AND2
	port map (		-- s2 <= b and c;			
		i0 => b,
		i1 => c,
		o => s2);
	unit3:	AND2
	port map (		-- s3 <= a and c;			
		i0 => a,
		i1 => c,
		o => s3);
	unit4:	OR3
	port map (		-- f <= s1 or s2 or s3;			
		i0 => s1,
		i1 => s2,
		i2	=>	s3,
		o => f);

end structure;


A behavioral description of a component describes what the circuit does rather than how it is done. For example, we will consider the majority circuit from lecture 1 in the code below.
-- Author:      Maj Jeff Falkinburg
-- Date:        Spring 2017
-- Purp:	Behavior Majority circuit
library IEEE;
use IEEE.std_logic_1164.all;

entity majority is
        port(	a, b, c	: in std_logic; 
		f	: out std_logic);
end majority;

architecture behavior of majority is

	f <=	'0' when a='0' and b='0' and c='0' else
		'0' when a='0' and b='0' and c='1' else
		'0' when a='0' and b='1' and c='0' else
		'1' when a='0' and b='1' and c='1' else
		'0' when a='1' and b='0' and c='0' else
		'1' when a='1' and b='0' and c='1' else
		'1' when a='1' and b='1' and c='0' else

end behavior;
It is important to note that the single (very long) statement in the architecture is a concurrent signal assignment (CSA) statement. This means that this statement is simply another hardware statement and can be mixed together with some ANDs and some component instantiation statements.

Coding using the behavioral architecture, while much more intuitive than the combinational logic description that was presented in lecture 1, still has some room for improvement. We could take advantage of the concatenation operator to make the code more readable. The idea is to replace the (a='0' and b='0' and c='0') statement with something like (temp = "000"). This can be done by creating a local variable (a signal) which is just the concatenation of the three input variables. This temporary variable will then be used in the "when" statement. The new streamlined architecture for the majority circuit is shown below.

architecture behavior of majority is

	signal temp: std_logic_vector(2 downto 0);
	temp <= a & b & c;
	f <=	'0' when temp = "000" else
		'0' when temp = "001" else
		'0' when temp = "010" else
		'1' when temp = "011" else
		'0' when temp = "100" else
		'1' when temp = "101" else
		'1' when temp = "110" else
end behavior;

A note on literals

Notice that individual bits are surrounded with single quotes and that std_logic_vectors are surrounded with double quotes. Any multi-bit literal must be surrounded by double quotes. Another important note is that you can specify hexadecimal literals by putting an x in front of the constant. So for example, x"4E" is a valid VHDL literal.

Component Instantiation

In order for VHDL to be useful in the design process, it must allow hierarchical design - the ability to include a design unit as a component in a higher level design component. This is called creating an instance of the entity. Hierarchical design allows us to abstract away some of the details of a design and focus on the high level behavior. This is the same concept as writing subroutines in a high level language.

The reason to bring this concept up now is because we use VHDL modules to test our VHDL designs. In the following discussion, we are going to build a module to test our majority circuit developed above. The VHDL module that will do the testing of the majority circuit is called a testbench. Inside this testbench, we will create an instance of the majority circuit and apply signals to the majority circuit and check to see if the circuit responds with the correct value. It is important to state up front that testbenches are only created for simulations; they are not intended to be synthesized onto the fabric of an FPGA.

In order to instantiate an instance of the majority circuit inside the testbench, you will need make 2 declarations; specify the entity description of the component (lines 4-9 below) and create an instance of the component (line 12-16 below).
1.  ENTITY majority_tb IS
2.  END majority_tb;

3.  ARCHITECTURE behavior OF majority_tb IS 
4.     COMPONENT majority
5.     PORT(	a : IN  std_logic;
6. 		b : IN  std_logic;
7.		c : IN  std_logic;
8.		f : OUT  std_logic);
10.    signal s1, s2, s3, s4: std_logic;
11. begin
12.    uut: majority PORT MAP (
13.          a => s1,
14.          b => s2,
15.          c => s3,
16.          f => s4);
17. end
Let's discuss these two steps further. The first, declaring the entity description of the entity to be instantiated (lines 4-9), is really quite easy. Just replace the term "entity" in the description of the majority circuit with the term "component". Note that this is done inside the architecture of the testbench. The second will require some more explanation, aided by the following picture.

The description of the majority circuit defines what goes on inside the architecture. In terms of the picture above, this includes all the gates and wires in the box labeled "uut:majority". the variables a,b,c,f inside this box are the port variables in the entity description of the majority circuit. The box labeled majority_tb is the testbench which creates an instance of the majority circuit. The signals labeled s1, s2, s3, s4 are created inside the testbench circuit and used to communicate to the majority circuit. The relationship between these signals and the signals inside the majority circuit are described by lines 13,14,15,16. For example, line 13 states that the signal a inside the majority circuit is connected to s1 outside the circuit.

One final note about line 12, the one that declares the instance of the majority circuit: Each instance of an entity should be given a distinct name. This is because we will frequently need to create several instances of the same component. For example, when creating a 4-bit adder, we will require 4 instances of a full adder. This is what the "uut" label is for, it uniquely identifies the instance of the majority circuit for the compiler.

You may have noticed that the testbench does not have any signals in its entity description. This is because the testbench will contain code which drives the signals going to the majority circuit. We will go into this further in the next section.

Simulation and Testbench

You have been provided an example testbench at the top of this page in lab02.vhdl. We have already discussed how to instantiate the majority circuit. Now for the part about applying signals to the majority circuit. Just inside the architecture statement, you should see the following four lines of code. Line 1 just makes a constant, the value of TEST_ELEMENTS cannot be changed. Lines 2 and 3 create a pair of new data types. Line 4 is really the business, creating an array of test values that are going to be applied to the majority circuit. In this case, it is just every combination of 3-bits. A similar array is defined, called TEST_OUTPUT, which contains the corresponding output for each of these inputs. These two arrays are used in the body of the testbench.
2.	SUBTYPE INPUT is std_logic_vector(2 downto 0);
4.	SIGNAL TEST_INPUT: TEST_INPUT_VECTOR := ("000", "001", "010", "011", "100", "101", "110", "111");
I want to take this opportunity to reiterate that test benches are not synthesized onto the Xilinx chip, so consequently, the coding style used should not be used on any circuit that you intend to synthesize.
Now, for the business end of the testbench shown in the following code snippet from lab02.vhdl, The main purpose of the loop below is to apply each of the 8 TEST_INPUT vectors to the majority circuit and check that the output is correct. Line 2 is where the array is read. Elsewhere in the body of the architecture, testVector is broken into individual std_logic bits and applied to the instantiated majority circuit. The delay in line 3 allows the circuit outputs to settle. Line 4 is a curious artifact only available in a simulation; if the output of the majority circuit, f, does not equal test_output(i), the value that the majority should equal, then the code in lines 5 and 6 is executed. Line 5 prints an error message in the console area of ISim. Line 6 halts the simulation.
1.	for i in 1 to TEST_ELEMENTS loop
2.	    testVector <= test_input(i);
3.	    wait for 1 us;
4.	    assert f = test_output(i)
5.		report "Error in majority circuit for input "  & integer'image(i)
6.		severity failure;
7.	    end loop;
In class, we will experiment with the simulator. Some things I would like to go over are: