Logic Design - VHDL Simple ALU Circuit (part 1)

in #vhdl5 years ago

    Hello my friends its me Drifter programming! Today we get back to VHDL starting off a small Series. I will start writing Components/Hardware of Computers starting off with an Simple ALU (Arithmetic Logic Unit) that we will Code in 3 parts. Today I will get into the basic Layout of the ALU that we will make talking about the Operations that it will handle and we will also write the Adder/Subber  Components! So, without further do let's get started!


ALU Layout/Operations:

     A ALU is a part/unit of a CPU that handles the Arithmetic and Boolean Operations. We will create a 16-bit ALU that will get two 8-bit inputs (a and b) and returns a 16-bit result. The selection code will be a 4-bit binary number. I will write the ALU in structural VHDL, writing most Operations as separate Circuits!

The Operations that the ALU will perform are:

  • ADD -> a + b
  • SUB_1 -> a - b
  • SUB_2 -> b - a
  • INCR_A -> a++
  • INCR_B -> b++
  • DECR_A -> a--
  • DECR_B -> b--
  • MUL -> a * b
  • NOT_A -> a'
  • NOT_B -> b'
  • AND -> a and b
  • OR -> a or b
  • XOR -> a xor b
  • COMP -> a equals b | a less than b | a greater then b


We will get into how we will implement it using with-select in the last part (part 3).


Let's now write the Add, Sub, Incr and Decr Components/Circuits!

Adder Component:

    If you remember from Theory we said that an N-bit Adder is made up of 1 Half Adder and N-1 Full Adders. That's exactly how we will write him! We will also use Basic Gates to implement the Half and Full Adders in the same way I showed you in Theory. For the Half Adder we will be using a AND and XOR Gate and for the Full Adder, two Half Adders and one OR Gate! For sake of simplicity I will implement the Half Adder in dataflow and the Full Adder in structural VHDL. I will also don't write the simple Circuits and suppose we wrote them!

So, the Half Adder looks like this:

library ieee;
use ieee.std_logic_1164.all;
entity half_adder is
port(
    a, b: in std_logic;
    s, c: out std_logic
);
end half_adder;
architecture arch of half_adder is
    begin
    s <= a xor b;
    c <= a and b;
end arch;


And the Full Adder looks like this:

library ieee;
use ieee.std_logic_1164.all;
entity full_adder is
port(
    a, b, c_in: in std_logic;
    s, c_out: out std_logic
);
end full_adder;

architecture arch of full_adder is
    component half_adder
    port(
	a, b: in std_logic;
	s, c: out std_logic
    );
    end component;

    component or2_gate
    port(
        a, b: in std_logic;
	c: out std_logic
    );
    end component;

    signal ha1_to_ha2: std_logic;
    signal ha1_to_or1: std_logic;
    signal ha2_to_or1: std_logic;

    begin

    ha1: half_adder port map(a, b, ha1_to_ha2, ha1_to_or1);
    ha2: half_adder port map(c_in, ha1_to_ha2, s, ha2_to_or1);
    or1: or2_gate port map(ha1_to_or1, ha2_to_or1, c_out);
end arch;


Using those two we can now create an 8-bit Adder:

library ieee;
use ieee.std_logic_1164.all;
entity adder_8_bit is
port(
    a, b: in std_logic_vector(7 downto 0);
    s: out std_logic_vector(7 downto 0);
    c_out: out std_logic
);
end adder_8_bit;

architecture arch of adder_8_bit is

    component half_adder
    port(
	a, b: in std_logic;
	s, c: out std_logic
    );
    end component;

    component full_adder
    port(
	a, b, c_in: in std_logic;
	s, c_out: out std_logic
    );
    end component;

    signal c: std_logic_vector(6 downto 0);

    begin

    adder1: half_adder port map(a(0), b(0),s(0), c(0));
    adder2: full_adder port map(a(1), b(1), c(0), s(1), c(1));
    adder3: full_adder port map(a(2), b(2), c(1), s(2), c(2));
    adder4: full_adder port map(a(3), b(3), c(2), s(3), c(3));
    adder5: full_adder port map(a(4), b(4), c(3), s(4), c(4));
    adder6: full_adder port map(a(5), b(5), c(4), s(5), c(5));
    adder7: full_adder port map(a(6), b(6), c(5), s(6), c(6));
    adder8: full_adder port map(a(7), b(7), c(6), s(7), c_out);
end arch;


Subber Component:

    If you remember from Theory I told you that we can create a Subber out of a Adder putting the second number as an 2's complement! So, the second Input of each Full Adder will be the result of the actual bit in XOR Operation with 1.

This is pretty simple to do and so the 8-bit Subber looks like this:

library ieee;
use ieee.std_logic_1164.all;
entity subber_8_bit is
port(
    a, b: in std_logic_vector(7 downto 0);
    s: out std_logic_vector(7 downto 0)
);
end subber_8_bit;

architecture arch of subber_8_bit is
    component full_adder
    port(
	a, b, c_in: in std_logic;
	s, c_out: out std_logic
    );
    end component;

    component xor2_gate
    port(
	a, b: in std_logic;
	c : out std_logic
    );
    end component;

    signal zero, sub: std_logic;
    signal b_comp: std_logic_vector(7 downto 0);
    signal c: std_logic_vector(8 downto 0);

    begin

    sub <= '1';
    zero <= '0';

    xor1: xor2_gate port map(sub, zero, c(0));
    xor2: xor2_gate port map(sub, b(0), b_comp(0));
    xor3: xor2_gate port map(sub, b(1), b_comp(1));
    xor4: xor2_gate port map(sub, b(2), b_comp(2));
    xor5: xor2_gate port map(sub, b(3), b_comp(3));
    xor6: xor2_gate port map(sub, b(4), b_comp(4));
    xor7: xor2_gate port map(sub, b(5), b_comp(5));
    xor8: xor2_gate port map(sub, b(6), b_comp(6));
    xor9: xor2_gate port map(sub, b(7), b_comp(7));

    adder1: full_adder port map(a(0), b_comp(0), c(0), s(0), c(1));
    adder2: full_adder port map(a(1), b_comp(1), c(1), s(1), c(2));
    adder3: full_adder port map(a(2), b_comp(2), c(2), s(2), c(3));
    adder4: full_adder port map(a(3), b_comp(3), c(3), s(3), c(4));
    adder5: full_adder port map(a(4), b_comp(4), c(4), s(4), c(5));
    adder6: full_adder port map(a(5), b_comp(5), c(5), s(5), c(6));
    adder7: full_adder port map(a(6), b_comp(6), c(6), s(6), c(7));
    adder8: full_adder port map(a(7), b_comp(7), c(7), s(7), c(8));
end arch;


Increment-Decrement Components:

    For the sake of simplicity I will just use the numeric_std library/package and either add or sub with '1'. So, both Component will just get an Input in 8-bit and return an 16-bit value!

The Incrementor looks like this:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity incrementor_numeric is
    port(
        src: in std_logic_vector(7 downto 0);
        result: out std_logic_vector(15 downto 0)
    );
end incrementor_numeric;

architecture arch of incrementor_numeric is
    begin
    result <= std_logic_vector(unsigned(src) + "0000000000000001");
end arch;


By changing the + with a - you then create an Decrementor:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity decrementor_numeric is
    port(
	src: in std_logic_vector(7 downto 0);
	result: out std_logic_vector(15 downto 0)
    );
end decrementor_numeric;

architecture arch of decrementor_numeric is
    begin
    result <= std_logic_vector(unsigned(src) - "0000000000000001");
end arch;


And this is actually all I wanted to talk about today!

Next time we will implement the Multiplier and Comparator Components!

Bye!

Coin Marketplace

STEEM 0.22
TRX 0.06
JST 0.025
BTC 19602.84
ETH 1329.30
USDT 1.00
SBD 2.45