View Course Path

VHDL code for ALU (1-bit) using structural method – full code and explanation

An ALU or an Arithmetic Logic Unit is the part of a microprocessor that performs the arithmetic and logical operations.

We’ll start off coding an ALU using VHDL in a series of progressions. This post is important because here, we breakdown every single detail of the coding process. You can expand in on this to code virtually any ALU.

In this post, we will be coding a simple 1-bit ALU that handles three essential functions: Addition, subtraction, and multiplication. We are going to achieve this by using a half -adder, a half-subtractor, and a multiplier. For the sake of progression, we will code only the arithmetic functionality in this post. In the upcoming posts, we will code the logical functionality. And by the end of this VHDL course, we will code a full-fledged ALU.

Arithmetic Logic Circuit (ALU) and its structure

We will be writing the VHDL code for the ALU using structural modeling architecture. We will also write the testbench for our ALU HDL code, generate the simulation waveforms, and the RTL schematic to verify our design. To re-iterate for the sake of clarity, we will be coding a 1-bit ALU.

ALU VHDL Coding

Take a look at the structure above. We have:

  1. Two 4:1 multiplexers. Giving a total of two final outputs. These two share two select lines SEL1 and SEL2. The first multiplexer has one free input that we attach to a GND component. The second multiplexer has two free inputs that, too, are attached to the GND component. We will use these two slots to expand the functionality of the ALU later on.
  2. A half adder with two inputs and two outputs. Sum and Carry. The sum output is given to the first multiplexer. The carry output is given to the second multiplexer.
  3. A half subtractor with two inputs and two outputs. Difference and Borrow. The difference output is given to the first multiplexer. The borrow, to the second multiplexer.
  4. A multiplier with its output given to the first multiplexer.

Truth table for the ALU

Here are the possible values for SEL1 and SEL2 and the operations that will be performed based on them. This is for your understanding. Since we aren’t using the structural modeling style, we won’t be needing the truth table/the behavior of the multiplexers to define the working of the circuit.

SEL 2 SEL 1 Output of MUX 1 Output of MUX 2
0 0 SUM CARRY
0 1 DIFFERENCE BORROW
1 0 PRODUCT GND
1 1 GND GND

Now that we have understood the working of the structure of the circuit let’s finally get down to coding it.

Explanation of the VHDL code for a 1-bit ALU using the structural method. How does the code work?

As we have seen in the post on structural VHDL for full-adder, we have to code in the individual components of the main circuit before we can code the main circuit using structural modeling. Here, the individual components include the half adder, the half subtractor, the multiplier, and the multiplexer. Additionally, recall that we can use any modeling style to code the individual components. So let’s code them first. You can see that each component’s code is the entire code for that component. By that, we mean that even the header files are included for each individual component.

VHDL code for the Half-adder (Component U1)

We code in the component U1 using basic dataflow style of architecture modeling. The logic equations of the half adder and its circuit can be found here.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HA is
Port ( HAA, HAB : in STD_LOGIC;
     SUM, CARRY : out STD_LOGIC);
end HA;

architecture dataflow of HA is

begin

SUM <= HAA XOR HAB;
CARRY <= HAA AND HAB;

end dataflow;

VHDL code for the half subtractor (Component U2)

The VHDL code for the component U2 is also written using the dataflow modeling style. The half subtractors logic equation and working are explained here.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HS is
Port ( HSA, HSB : in STD_LOGIC;
DIFFERENCE, BORROW : out STD_LOGIC);
end HS;

architecture dataflow of HS is

begin

DIFFERENCE <= HSA XOR HSB;
BORROW <= (not HSA) AND HSB;

end dataflow;

VHDL code for the multiplier (component U3)

The VHDL code for component U3 is written using the dataflow style too. The multiplier’s concept and logic are explained here.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity multiplier is
Port ( MA, MB : in STD_LOGIC;
      PRODUCT : out STD_LOGIC);
end multiplier;

architecture dataflow of multiplier is

begin

PRODUCT <= MA AND MB;

end dataflow;

VHDL code for the multiplexer (Components U4 and U5)

The fourth and fifth components are multiplexers. We have previously seen the mux VHDL for dataflow and mux VHDL for behavioral. Here, we will use the dataflow style of modeling to write their VHDL code. The logic circuit and logic equations for multiplexers can be found here.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MUX is
Port ( A1,A2,A3,A4 : in STD_LOGIC;
                 S : in STD_LOGIC_VECTOR (1 downto 0);
                 X : out STD_LOGIC);
end mux;

architecture dataflow of MUX is

begin

with S select
X <=       A1 when "00",
           A2 when "01",
           A3 when "10",
           A4 when others;

end dataflow;

VHDL code for the GND component (U0)

The GND component (U0) is assigned to the STD_LOGIC ‘U,’ which stands for Uninitialized. Here, it means that we are yet to initialize the signal.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ground is
Port ( N : inout STD_LOGIC);
end ground;

architecture dataflow of ground is

begin

N <= 'U';

end dataflow;

Now that all the components are initialized and defined, we can start with the structural modeling of the 1-bit ALU. We start off by declaring the entity. Here we mention all the inputs and outputs of the overall ALU circuit. This means the two inputs, the two select lines, and the two outputs.

entity ALU is
Port ( A,B,SEL1,SEL2 : in  STD_LOGIC;
           ALU1,ALU2 : out  STD_LOGIC);
end ALU;

Next up is the architecture statement.

architecture Structural of ALU is

In structural modeling, between the architecture statement and the begin statement, there are a couple of things we need to do.

So recall the individual components that we declared above. Those need to be CONNECTED to the main program. How do we connect the individual components to the main program in the structural modeling architecture in VHDL?

We do that by using a block known as Component Declaration. This is extremely similar in syntax to an entity declaration. The only difference is that we replace the term entity with component. Watch.

component HA is
Port ( HAA, HAB : in STD_LOGIC;
     SUM, CARRY : out STD_LOGIC);
end component;

component HS is
Port ( HSA, HSB : in STD_LOGIC;
DIFFERENCE, BORROW : out STD_LOGIC);
end component;

component multiplier is
Port ( MA, MB : in STD_LOGIC;
      PRODUCT : out STD_LOGIC);
end component;

component MUX is
Port ( A1,A2,A3,A4 : in STD_LOGIC;
                 S : in STD_LOGIC_VECTOR (1 downto 0);
                 X : out STD_LOGIC);
end component;

component ground is
Port ( N : inout STD_LOGIC);
end component;

Last but not least, we need to declare all the signals that are involved in this operation. The two inputs, the outputs of the arithmetic digital circuits that are fed as inputs to the multiplexers, and the final outputs.

signal S0,S1,S2,S3,S4,S5: STD_LOGIC;

and now we can

begin

The actual part of coding in structural is very straightforward. All you need to do is list each component (U0 to U5) out. And then use PORT MAP to assign the components inputs to the signals that we declared. That’s it. You’re good to go. Remember to end the architecture. You should know by now what that is we hope! (Hint: It’s got the word end in it).

U0: ground PORT MAP(N=>S5);
U1: HA PORT MAP(HAA=>A,HAB=>B,SUM=>S0,CARRY=>S3);
U2: HS PORT MAP(HSA=>A,HSB=>B,DIFFERENCE=>S1,BORROW=>S4);
U3: multiplier PORT MAP(MA=>A,MB=>B,PRODUCT=>S2);
U4: MUX PORT MAP(A1=>S0,A2=>S1,A3=>S2,A4=>S5,X=>ALU1,S(0)=>SEL1,S(1)=>SEL2);
U5: MUX PORT MAP(A1=>S3,A2=>S4,A3=>S5,A4=>S5,X=>ALU2,S(0)=>SEL1,S(1)=>SEL2);

Full VHDL code for an Arithmetic Logic Unit (ALU) using the structural modeling method

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HA is
Port ( HAA, HAB : in STD_LOGIC;
     SUM, CARRY : out STD_LOGIC);
end HA;

architecture dataflow of HA is

begin

SUM <= HAA XOR HAB;
CARRY <= HAA AND HAB;

end dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HS is
Port ( HSA, HSB : in STD_LOGIC;
DIFFERENCE, BORROW : out STD_LOGIC);
end HS;

architecture dataflow of HS is

begin
DIFFERENCE <= HSA XOR HSB;
BORROW <= (not HSA) AND HSB;
end dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity multiplier is
Port ( MA, MB : in STD_LOGIC;
      PRODUCT : out STD_LOGIC);
end multiplier;

architecture dataflow of multiplier is

begin

PRODUCT <= MA AND MB;

end dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MUX is
Port ( A1,A2,A3,A4 : in STD_LOGIC;
                 S : in STD_LOGIC_VECTOR (1 downto 0);
                 X : out STD_LOGIC);
end mux;

architecture dataflow of MUX is

begin

with S select

X <=       A1 when "00",
           A2 when "01",
           A3 when "10",
           A4 when others;

end dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ground is
Port ( N : inout STD_LOGIC);
end ground;

architecture dataflow of ground is

begin

N <= 'U';

end dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ALU is
Port ( A,B,SEL1,SEL2 : in  STD_LOGIC;
           ALU1,ALU2 : out  STD_LOGIC);
end ALU;

architecture Structural of ALU is

component HA is
Port ( HAA, HAB : in STD_LOGIC;
     SUM, CARRY : out STD_LOGIC);
end component;

component HS is
Port ( HSA, HSB : in STD_LOGIC;
DIFFERENCE, BORROW : out STD_LOGIC);
end component;

component multiplier is
Port ( MA, MB : in STD_LOGIC;
      PRODUCT : out STD_LOGIC);
end component;

component MUX is
Port ( A1,A2,A3,A4 : in STD_LOGIC;
                 S : in STD_LOGIC_VECTOR (1 downto 0);
                 X : out STD_LOGIC);
end component;

component ground is
Port ( N : inout STD_LOGIC);
end component;

signal S0,S1,S2,S3,S4,S5: STD_LOGIC;

begin

U0: ground PORT MAP(N=>S5);
U1: HA PORT MAP(HAA=>A,HAB=>B,SUM=>S0,CARRY=>S3);
U2: HS PORT MAP(HSA=>A,HSB=>B,DIFFERENCE=>S1,BORROW=>S4);
U3: multiplier PORT MAP(MA=>A,MB=>B,PRODUCT=>S2);
U4: MUX PORT MAP(A1=>S0,A2=>S1,A3=>S2,A4=>S5,X=>ALU1,S(0)=>SEL1,S(1)=>SEL2);
U5: MUX PORT MAP(A1=>S3,A2=>S4,A3=>S5,A4=>S5,X=>ALU2,S(0)=>SEL1,S(1)=>SEL2);

end Structural;

Testbench

We will write the testbench with a process statement. You can check out all the different types and variations of a testbench in VHDL here.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ALU1bit_tb is
end entity;

architecture tb of ALU1bit_tb is
component ALU is
Port ( A,B,SEL1,SEL2 : in STD_LOGIC;
ALU1,ALU2 : out STD_LOGIC);
end component;

signal A, B, SEL1, SEL2, ALU1, ALU2 : STD_LOGIC;

begin

uut: ALU port map(
A => A, B => B,
SEL1 => SEL1,
SEL2 => SEL2,
ALU1 => ALU1,
ALU2 => ALU2);

stim: process
begin

A <= '0';
B <= '0';

SEL1 <= '0';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '0';
SEL2 <= '1';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '1';
wait for 20 ns;

A <= '0';
B <= '1';

SEL1 <= '0';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '0';
SEL2 <= '1';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '1';
wait for 20 ns;

A <= '1';
B <= '1';

SEL1 <= '0';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '0';
SEL2 <= '1';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '0';
wait for 20 ns;

SEL1 <= '1';
SEL2 <= '1';
wait for 20 ns;

wait;

end process;
end tb;

RTL Schematic

1_bit_ALU-RTL

Simulation Waveform

1_bit_ALU-Waveform

Edit: Post updated with the testbench, RTL Schematic, and Simulation Waveform by Deepak Joshi.

One thought on “VHDL code for ALU (1-bit) using structural method – full code and explanation

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.