Making a 16-bit ALU using 1-bit ALUs

谁都会走 提交于 2019-12-01 11:03:08

Here is an example of how you can create a N-bit adder component. First of all you need to create a full adder which is a adder that also takes a carry in bit into account.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY fullAdder IS
    PORT (a     : IN STD_LOGIC;
          b     : IN STD_LOGIC;
          cin   : IN STD_LOGIC;
          y     : OUT STD_LOGIC;
          cout  : OUT STD_LOGIC);
END fullAdder;

ARCHITECTURE arch_fullAdder OF fullAdder IS
BEGIN
    y <= a XOR b XOR cin;
    cout <= (a AND b) OR 
            (b AND cin) OR 
            (a AND cin);
END arch_fullAdder;

When you have this 1-bit adder you can easily generate a N-bit ripple carry by generating multiple cells of the full adder we have above.

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY ripple_adder IS 
    GENERIC (WIDTH : NATURAL := 32);
    PORT(a      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         b      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         cin    : IN STD_LOGIC := '0';
         y      : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         cout   : OUT STD_LOGIC);
END ripple_adder;

ARCHITECTURE arch_ripple_adder OF ripple_adder IS

    SIGNAL carry    : STD_LOGIC_VECTOR(WIDTH DOWNTO 0);
    SIGNAL y_temp   : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);

    COMPONENT fullAdder IS
        PORT(a      : IN STD_LOGIC;
             b      : IN STD_LOGIC;
             cin    : IN STD_LOGIC;
             y      : OUT STD_LOGIC;
             cout   : OUT STD_LOGIC);
    END COMPONENT;
BEGIN  

    N_bit_adder_generate : FOR N IN 0 TO WIDTH-1 GENERATE
    N_bit_adder : fullAdder
        PORT MAP(a      => a(N),
                 b      => b (N),
                 cin    => carry(N),
                 y      => y_temp(N),
                 cout   => carry(N + 1));
    END GENERATE;

    carry(0) <= cin;
    cout <= carry(WIDTH);
    y <= y_temp;

END arch_ripple_adder;

When you have the adder you can easily put the adder component into an ALU and specify the different operations that the ALU should be able to perform.

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

ENTITY ALU IS 
    GENERIC(WIDTH : NATURAL := 32);
    PORT(Clk    : IN STD_LOGIC := '0';
         Reset  : IN STD_LOGIC := '0';
         A      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
         B      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
         Op     : IN STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0');
         Outs   : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END ALU;

ARCHITECTURE arch_ALU OF ALU IS

    COMPONENT ripple_adder
    PORT(a      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         b      : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         cin    : IN STD_LOGIC := '0';
         y      : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
         cout   : OUT STD_LOGIC);
END COMPONENT;

    SIGNAL RCA_output   : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
    SIGNAL B_neg        : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
    SIGNAL c_flag       : STD_LOGIC := '0';
    SIGNAL c_reg        : STD_LOGIC := '0';
    SIGNAL cin          : STD_LOGIC := '0';

BEGIN

RCA_comp : ripple_adder
   PORT MAP(a => A,
            b => B_neg,
            Cin => cin,
            y => RCA_output,
            Cout => c_flag);        

    WITH Op SELECT 
        B_neg <= NOT(B) WHEN "1000",
                     B  WHEN OTHERS;

    WITH Op SELECT
        cin <= '1'      WHEN "1000", -- SUB
                c_reg   WHEN "0111", -- ADDC
                '0'     WHEN OTHERS; -- ADD/ADDS    

    ALU_Process:
    PROCESS(Clk, Reset)
    BEGIN
        IF Reset = '0' THEN
            Outs <= (OTHERS => '0');
            c_reg <= '0';
        ELSIF rising_edge(Clk) THEN
            CASE Op IS
                WHEN "0001" => Outs <= A AND B;
                WHEN "0010" => Outs <= A OR  B;
                WHEN "0011" => Outs <= A NOR B;
                WHEN "0100" => Outs <= A XOR B;
                WHEN "0101" => Outs <= RCA_output; -- ADD 
                WHEN "0110" => Outs <= RCA_output; -- ADDS
                    c_reg <= c_flag;    
                WHEN "0111" => Outs <= RCA_output; -- ADDC
                WHEN "1000" => Outs <= RCA_output; -- SUB
                WHEN "1001" => Outs <= STD_LOGIC_VECTOR(UNSIGNED(A) SLL to_integer(UNSIGNED(B(4 DOWNTO 0))));
                WHEN "1010" => Outs <= STD_LOGIC_VECTOR(unsigned(A) SRL to_integer(UNSIGNED(B(4 DOWNTO 0))));
                WHEN "1011" => Outs <= STD_LOGIC_VECTOR(shift_right(SIGNED(A),to_integer(UNSIGNED(B(4 DOWNTO 0)))));
                WHEN OTHERS => Outs <= (OTHERS => '0');
            END CASE;
        END IF;
    END PROCESS;
END arch_ALU; 

This ALU however is not that complex and don´t have that many operations but that functionality can easily be added. I hope the example code I have given you will help you.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!