In this post, we will take a look at implementing the VHDL code for half adder & full adder using dataflow modeling architecture. First, we will take a look at the logic equations of the circuits and then the syntax for the VHDL code. We’ll also write the testbench in VHDL for the circuit and generate the RTL schematic. We will use the final simulation waveforms to verify our code.
Contents
Half-Adder
Logic equation and logic circuit of a half adder
A half adder is an arithmetic combinational circuit that takes in two binary digits and adds them. The half adder gives out two outputs, the SUM of the operation and the CARRY generated in the operation. Since this carry is not added to the final answer, the addition process is somewhat incomplete. Hence, it’s known as the half adder.
Below you will find the logic circuit and the corresponding logic equation of the half adder. This circuit is made using simple digital logic gates; the EX-OR and AND gates. We will use this equation to program a half adder circuit using VHDL.
SUM =
CARRY = A.B
Explanation of the VHDL code for half adder using its logic equation and the dataflow method
We always start the code by including needed libraries and importing the necessary packages from them using the use
clause.
library IEEE; use IEEE.std_logic_1164.all;
Then we define the entity, where we define the input and output ports of our design. Here we have two input bits and two output bits.
entity H_adder is port( a,b : IN std_logic; sum,carry : OUT std_logic); end H_adder;
Then we write an architecture for the above entity. Inside the architecture, we define the functionality of our design.
architecture dataflow of H_adder is begin sum <= a xor b; carry <= a and b; end dataflow;
Never forget to end the architecture.
VHDL Code for half-adder using dataflow via logic equation
library IEEE; use IEEE.std_logic_1164.all; entity H_adder is port( a,b : IN std_logic; sum,carry : OUT std_logic); end H_adder; architecture dataflow of H_adder is begin sum <= a xor b; carry <= a and b; end dataflow;
Testbench
We will be using the testbench with a process type in this post. You can learn all about writing testbenches in VHDL in this guide.
library IEEE; use IEEE.std_logic_1164.all; entity half_adder_tb is end entity; architecture tb of half_adder_tb is component H_adder is port( a,b : IN std_logic; sum,carry : OUT std_logic); end component; signal a,b,sum,carry: std_logic; begin uut: H_adder port map( a => a, b => b, sum => sum, carry => carry); stim: process begin a <= '0'; b <= '0'; wait for 20 ns; a <= '0'; b <= '1'; wait for 20 ns; a <= '1'; b <= '0'; wait for 20 ns; a <= '1'; b <= '1'; wait for 20 ns; wait; end process; end tb;
RTL Schematic
Simulation Waveforms
Full-Adder
Logic equation and logic circuit of a full adder
A full adder, unlike the half adder, has a carry input. And thus, since it performs the full addition, it is known as a full adder. Accordingly, the full adder has three inputs and two outputs. The relation between the inputs and the outputs is described by the logic equations given below. We will use these equations for the VHDL program.
SUM =
CARRY = Y(A+B) + AB
Explanation of the VHDL code for full adder using its truth table and the dataflow method. How does the code work?
Next, we will use another feature given to us by the dataflow architecture. We will use a circuits truth table to design it using VHDL.
Truth table for a 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 |
The entity-architecture declaration for the VHDL code of a full adder will have only one difference. We will declare the entities as vectors.
But why? Why not declare each input/output separately?
The reason is that since we are using the truth table of the full adder, we have three inputs and two outputs. We can easily assign two vectors, one to inputs and one to outputs. The input vector will have three slots. And the output vectors will have two slots. The first one will be the SUM, and the second one will be the CARRY. And generally speaking, when we are dealing with multiple inputs of the same kind, using vectors saves us a lot of complexity. Entity name: FULLADDER_VIATRUTHTABLE
.
entity FULLADDER_VIATRUTHTABLE is Port ( A : in STD_LOGIC_VECTOR (2 downto 0); O : out STD_LOGIC_VECTOR (1 downto 0)); end FULLADDER_VIATRUTHTABLE; architecture dataflow of FULLADDER_VIATRUTHTABLE is begin
Dataflow architecture has when-else statements that are very handy when coding with truth tables. We saw the syntax for the when-else statements in our post on the dataflow architecture. So using that syntax, we will assign the inputs to the output vector as follows:
O <= "00" when A = "000" else "10" when A = "001" else "10" when A = "010" else "10" when A = "100" else "11" when A = "111" else "01";
VHDL code for full adder using dataflow method – via truth table
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity FULLADDER_VIATRUTHTABLE is Port ( A : in STD_LOGIC_VECTOR (2 downto 0); O : out STD_LOGIC_VECTOR (1 downto 0)); end FULLADDER_VIATRUTHTABLE; architecture dataflow of FULLADDER_VIATRUTHTABLE is begin O <= "00" when A = "000" else "10" when A = "001" else "10" when A = "010" else "10" when A = "100" else "11" when A = "111" else "01"; end dataflow;
Testbench
We will be using the testbench with a process type in this post. You can learn all about writing testbenches in VHDL in this guide.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity FULLADDER_VIATRUTHTABLE_TB is end entity; architecture tb of FULLADDER_VIATRUTHTABLE_TB is component FULLADDER_VIATRUTHTABLE 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_VIATRUTHTABLE 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;
RTL Schematic
Simulation Waveforms
Half-adder and Full-adder (together)
Explanation of the VHDL code for half adder & full adder using dataflow method. How does the code work?
In the dataflow architecture approach, we can either use the logic equations of a circuit or its truth table to write the code using VHDL. We will be coding the circuits of the half adder and the full adder using the former option first. We will also write the VHDL code for the full adder with the dataflow architecture using its truth tables later in this post.
We will begin writing the code by first declaring the entity-architecture pair. As we have earlier in this VHDL course, the entity-architecture pair completes two main objectives of a VHDL program.
- The entity declares all the input, output, or bi-directional ports and assigns their datatype as scalar or vector. Basically, the entity describes the external part of a logic circuit.
- The architecture defines the relations between these entity items. And there are three types (Dataflow, Behavioral, and Structural).
The syntax for the entity-architecture pair declaration for our program is as follows. The entity name that we have chosen is mix_adder_ff
.
entity mix_adder_ff is port( a,b,cin : IN std_logic; HA_sum, HA_carry, FA_sum, FA_carry : OUT std_logic); end mix_adder_ff; architecture dataflow of mix_adder_ff is begin
Once we have the begin
statement, we can use the powers given to us by the dataflow architecture and start assigning the ports using logic equations. To do this, we use the assignment operator, as shown below. For the half adder:
HA_sum <= a xor b; HA_carry <= a and b; FA_sum <= (a xor b) xor cin; FA_carry <= (a and b) or (b and cin) or (cin and a); end dataflow;
Always remember to end the architecture.
VHDL code for half adder & full adder using dataflow method
library IEEE; use IEEE.std_logic_1164.all; entity mix_adder_ff is port( a,b,cin : IN std_logic; HA_sum, HA_carry, FA_sum, FA_carry : OUT std_logic); end mix_adder_ff; architecture dataflow of mix_adder_ff is begin HA_sum <= a xor b; HA_carry <= a and b; FA_sum <= (a xor b) xor cin; FA_carry <= (a and b) or (b and cin) or (cin and a); end dataflow;
Testbench
We will be using the testbench with a process type in this post. You can learn all about writing testbenches in VHDL in this guide.
library IEEE; use IEEE.std_logic_1164.all; entity mix_adder_tb is end entity; architecture tb of mix_adder_tb is component mix_adder_ff is port(a,b,cin : IN std_logic; HA_sum, HA_carry, FA_sum, FA_carry : OUT std_logic); end component; signal a, b, cin, HA_sum, HA_carry, FA_sum, FA_carry : std_logic; begin uut: mix_adder_ff port map( a => a, b => b, cin => cin, HA_sum => HA_sum, HA_carry => HA_carry, FA_sum => FA_sum, FA_carry => FA_carry); stim: process begin a <= '0'; b <= '0'; cin <= '0'; wait for 10 ns; a <= '0'; b <= '0'; cin <= '1'; wait for 10 ns; a <= '0'; b <= '1'; cin <= '0'; wait for 10 ns; a <= '0'; b <= '1'; cin <= '1'; wait for 10 ns; a <= '1'; b <= '0'; cin <= '0'; wait for 10 ns; a <= '1'; b <= '0'; cin <= '1'; wait for 10 ns; a <= '1'; b <= '1'; cin <= '0'; wait for 10 ns; a <= '1'; b <= '1'; cin <= '1'; wait for 10 ns; wait; end process; end tb;
RTL Schematic
Simulation Waveform
As always, if you have any queries, we would love to address them. Just drop in a comment in the comments section below.