The full adder is one of the most important combinational logic circuits in digital electronics. It adds three 1-bit numbers; the third bit is the carry bit. If a carry generates on the addition of the first two bits, the full adder considers it too.
In this post, we will take a look at implementing the VHDL code for full adder using the behavioral method. First, we will explain the logic and then the syntax before writing the testbench and generating the RTL schematic and simulation waveforms. For the complete code, scroll down.
Contents
Explanation of the VHDL code for full adder using behavioral method. How does the code work?
Since we are going to code this circuit using the behavioral modeling method, we are going to need to understand the truth table. In the behavioral model of VHDL coding, we define the behavior or outputs of the circuit in terms of their inputs. The behavior is described on a case by case basis. Let’s first understand the logic circuit of the full adder.
Logic diagram of the full adder
We don’t care about the logic gates here. In the behavioral model, we will concern ourselves only with the relation between the inputs and the outputs. As you can see, the full adder has three inputs and two outputs. The two outputs are the SUM and CARRY outputs.
We begin the coding process by naming the entity we will be coding. Let’s call this entity as FULLADDER_BEHAVIORAL_SOURCE
.
Next, we will define the ports of the entity. There are three input ports. Let’s define all of them using a single vector A of size three. Since these are vectors, they are STD_LOGIC_VECTOR
input ports. If we would have taken distinct ports for all of them, then the syntax would have been STD_LOGIC
.
We also need two output ports for the SUM and CARRY outputs. We will define them as vectors too.
Hence the syntax and the VHDL code for declaring the entity and the ports will look like this:
entity FULLADDER_BEHAVIORAL_SOURCE is Port ( A : in STD_LOGIC_VECTOR (2 downto 0); O : out STD_LOGIC_VECTOR (1 downto 0)); end FULLADDER_BEHAVIORAL_SOURCE;
A question that might arise in your mind is, why did we declare these ports as vectors. Why not declare them distinctly?
The reason is that since we are using the behavioral model for programming, we will be dealing with the truth table of the full adder. And generally speaking, when we are dealing with multiple inputs of the same kind, using vectors saves us a lot of complexity. We will show you the exact locations where complexities could have arisen if we had used distinct input ports.
Let’s take a look at the full adder circuit’s truth table next. Our entire code will depend on it.
Truth table of Full adder
A | B | Y | SUM | CARRY |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
After declaring the entity and the I/O ports, the next step is to declare the architecture of the VHDL program that we will be using to code the entity. Therefore, since we are using the behavioral model to write the VHDL code for the full adder, this will be the next statement:
architecture Behavioral of FULLADDER_BEHAVIORAL_SOURCE is
Next, since we have now declared that we are using the behavioral model, we need to keep two key syntax points in mind.
- the behavioral model needs two begin statements after the architecture declaration.
- the behavioral model has a process statement between the two begin statements.
begin process (A) begin
We will first write the code for the SUM column of the truth table. Using if-else statements, we assign the cases where the output is 1 (One/High) to the if statement and assign the output to else for all other remaining cases. Notice that we use OR logic in the condition of the if statement. And not AND because the output can be one in any singular of these cases at a given instant.
---for SUM if (A = "001" or A = "010" or A = "100" or A = "111") then O(1) <= '1'; else O(1) < = '0'; end if; ---single inverted commas used for assigning to one bit and double inverted commas are used for vector numbers/more than one bit
Similarly, for the CARRY output:
if (A = "011" or A = "101" or A = "110" or A = "111") then O(0) <= '1'; else O(0) <= '0';
In the end, we close the if statement, the process statement, and the architecture.
end if; end process; end Behavioral;
VHDL code for full adder using behavioral method
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity FULLADDER_BEHAVIORAL_SOURCE is Port ( A : in STD_LOGIC_VECTOR (2 downto 0); O : out STD_LOGIC_VECTOR (1 downto 0)); end FULLADDER_BEHAVIORAL_SOURCE; architecture Behavioral of FULLADDER_BEHAVIORAL_SOURCE is begin process (A) begin ---for SUM if (A = "001" or A = "010" or A = "100" or A = "111") then O(1) <= '1'; ---single inverted commas used for assigning to one bit else O(1) < = '0'; end if; ---for CARRY if (A = "011" or A = "101" or A = "110" or A = "111") then O(0) <= '1'; else O(0) <= '0'; end if; end process; end Behavioral;
Why didn’t we use discreet input ports?
As you can see in the VHDL code for the full adder above, we decided to use vector inputs. If we had used discrete input ports, we couldn’t have assigned the three input bits to A in the if statement’s condition as we did above. We would have had to assign single bits along with logical AND symbol for bit operation (&). A ="111"
would have been written as if ((A='1' & B='1' & C='1') or ....)
. Quite obviously, that would have been a very lengthy conditional statement.
In the post where we write the VHDL code for the full subtractor, we will use vector outputs along with vector inputs and see how that changes the programming approach.
Testbench
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity FullAdder_tb is end entity; architecture tb of FullAdder_tb is component FULLADDER_BEHAVIORAL_SOURCE is Port ( A : in STD_LOGIC_VECTOR (2 downto 0); O : out STD_LOGIC_VECTOR (1 downto 0)); end component; signal A : STD_LOGIC_VECTOR(2 downto 0); signal O : STD_LOGIC_VECTOR(1 downto 0); begin uut: FULLADDER_BEHAVIORAL_SOURCE port map( A => A, O => O); stim: process begin A <= "000"; wait for 20 ns; A <= "001"; wait for 20 ns; A <= "010"; wait for 20 ns; A <= "011"; wait for 20 ns; A <= "100"; wait for 20 ns; A <= "101"; wait for 20 ns; A <= "110"; wait for 20 ns; A <= "111"; wait for 20 ns; wait; end process; end tb;
You can learn how to write a VHDL testbench in detail here.
RTL Schematic
Simulation Waveforms
Edit: Post updated with the testbench, RTL Schematic, and Simulation Waveform by Deepak Joshi.