Contact me for VHDL projects or assignments

Thursday, June 23, 2011

VHDL code for a simple ALU

   ALU(Arithmetic Logic Unit) is a digital circuit which does arithmetic and logical operations. Its a basic block in any processor. 
  In this article I have shared vhdl code for a simple ALU. Note that this is one of the simplest architecture of an ALU. Most of the ALU's used in practical designs are far more complicated and requires good design experience. 
  The block diagram of the ALU is given below. As you can see, it receives two input operands 'A' and 'B' which are 8 bits long. The result is denoted by 'R' which is also 8 bit long. The input signal 'Op' is a 3 bit value which tells the ALU what operation to be performed by the ALU. Since 'Op' is 3 bits long we can have 2^3=8 operations.



   Our ALU is capable of doing the following operations:

ALU OperationDescription
Add SignedR = A + B : Treating A, B, and R as signed two's complement integers.
Subtract SignedR = A - B : Treating A, B, and R as signed  two's complement integers.
Bitwise ANDR(i) = A(i) AND B(i).
Bitwise NORR(i) = A(i) NOR B(i).
Bitwise ORR(i) = A(i) OR B(i).
Bitwise NANDR(i) = A(i) NAND B(i).
Bitwise XORR(i) = A(i) XOR B(i).
Biwise NOTR(i) = NOT A(i).

These functions are implemented using a case statement. The ALU calculates the outputs at every positive edge of clock cycle. As soon as the outputs are calculated it is available at the port signal 'R'. See the code below, to know how it is done:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity simple_alu is
port(   Clk : in std_logic; --clock signal
        A,B : in signed(7 downto 0); --input operands
        Op : in unsigned(2 downto 0); --Operation to be performed
        R : out signed(7 downto 0)  --output of ALU
        );
end simple_alu;

architecture Behavioral of simple_alu is

--temporary signal declaration.
signal Reg1,Reg2,Reg3 : signed(7 downto 0) := (others => '0');

begin

Reg1 <= A;
Reg2 <= B;
R <= Reg3;

process(Clk)
begin

    if(rising_edge(Clk)) then --Do the calculation at the positive edge of clock cycle.
        case Op is
            when "000" =>
                Reg3 <= Reg1 + Reg2;  --addition
            when "001" =>
                Reg3 <= Reg1 - Reg2; --subtraction
            when "010" =>
                Reg3 <= not Reg1;  --NOT gate
            when "011" =>
                Reg3 <= Reg1 nand Reg2; --NAND gate
            when "100" =>
                Reg3 <= Reg1 nor Reg2; --NOR gate              
            when "101" =>
                Reg3 <= Reg1 and Reg2;  --AND gate
            when "110" =>
                Reg3 <= Reg1 or Reg2;  --OR gate   
            when "111" =>
                Reg3 <= Reg1 xor Reg2; --XOR gate  
            when others =>
                NULL;
        end case;      
    end if;
   
end process;   

end Behavioral;

The testbench code used for testing the ALU code is given below:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS

   signal Clk : std_logic := '0';
   signal A,B,R : signed(7 downto 0) := (others => '0');
   signal Op : unsigned(2 downto 0) := (others => '0');
   constant Clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.simple_alu PORT MAP (
          Clk => Clk,
          A => A,
          B => B,
          Op => Op,
          R => R
        );

   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;
   
   -- Stimulus process
   stim_proc: process
   begin       
      wait for Clk_period*1;
        A <= "00010010"; --18 in decimal
        B <= "00001010"; --10 in decimal
        Op <= "000";  wait for Clk_period; --add A and B
        Op <= "001";  wait for Clk_period; --subtract B from A.
        Op <= "010";  wait for Clk_period; --Bitwise NOT of A
        Op <= "011";  wait for Clk_period; --Bitwise NAND of A and B
        Op <= "100";  wait for Clk_period; --Bitwise NOR of A and B
        Op <= "101";  wait for Clk_period; --Bitwise AND of A and B
        Op <= "110";  wait for Clk_period; --Bitwise OR of A and B
        Op <= "111";  wait for Clk_period; --Bitwise XOR of A and B
      wait;
   end process;

END;
This is the simulation waveform:

The code is sythesisable. I haven't used std_logic_vector in this code. You can read this post to know why. 

The block diagram was adopted from this original article. To make sure you have understood the concepts well, try implementing the block diagram given in the original article.

3 comments:

  1. Thanks for posting such a nice code but please make it correct, i think simulation will give result only for op 111, to correct result in simulation you must remove wait statements from last part of test bench.

    look like this

    -- Stimulus process
    stim_proc: process
    begin

    A <= "00010010"; --18 in decimal
    B <= "00001010"; --10 in decimal
    Op <= "000"; wait for Clk_period; --add A and B
    Op <= "001"; wait for Clk_period; --subtract B from A.
    po Op <= "010"; wait for Clk_period; --Bitwise NOT of A
    Op <= "011"; wait for Clk_period; --Bitwise NAND of A and B
    Op <= "100"; wait for Clk_period; --Bitwise NOR of A and B
    Op <= "101"; wait for Clk_period; --Bitwise AND of A and B
    Op <= "110"; wait for Clk_period; --Bitwise OR of A and B
    Op <= "111"; wait for Clk_period; --Bitwise XOR of A and B

    end process;

    END;

    ReplyDelete
  2. why do we need a clk fo the alu isn't it a combinational block?

    ReplyDelete
  3. Hi!
    Can you clarify a bit why do we need temporary signals Reg1, Reg2 and Reg3?

    Thank you!

    ReplyDelete

Related Posts with Thumbnails

Download this article as PDF