使用 1 位 ALU 制作 16 位 ALU

Posted

技术标签:

【中文标题】使用 1 位 ALU 制作 16 位 ALU【英文标题】:Making a 16-bit ALU using 1-bit ALUs 【发布时间】:2016-05-17 11:21:10 【问题描述】:

您好,我正在尝试从几个 1 位 ALU 创建一个 16 位 ALU 我创建了一个名为 basic_alu1 的包,其中包含 1 位 ALU 的一个组件。代码如下:

library ieee;
use ieee.std_logic_1164.all;
package basic_alu1 is
component alu1
    port (a, b: std_logic_vector(1 downto 0);
            m: in std_logic_vector(1 downto 0);
            result: out std_logic_vector(1 downto 0));
end component;
end package basic_alu1;


library ieee;
use ieee.std_logic_1164.all;
entity alu1 is
    port (a, b: std_logic_vector(1 downto 0);
    m: in std_logic_vector(1 downto 0);
    result: out std_logic_vector(1 downto 0));
end alu1; 
architecture arch1 of alu1 is 
begin
 process(a, b, m)
 begin
 case m is
 when "00" =>
    result <= a + b;
  when "01" =>
    result <= a + (not b) + 1;
  when "10" =>
    result <= a and b;
  when "11" =>
    result <= a or b;
end case
 end process
 end arch1

因此,为了创建 16 位 ALU,我使用了 for generate 循环并实例化 alu1 的多个副本。我的问题是如何将计数器放入和取出,以及如何进行溢出检查。我的主要代码是:

library ieee;
use ieee.std_logic_1164.all;
use work.basic_alu1.all;

entity alu16 is
  port (input_a : in std_logic_vector(15 downto 0);
        input_b : in std_logic_vector(15 downto 0);
        mode : in std_logic_vector(1 downto 0)
        result_x4 : out std_logic);
end alu16;

architecture structural of alu16 is
begin
G1 : for i in 0 to 15 generate
begin
    alu_16 : entity work.basic_alu1
    port map (
    a => input_a(i),
    b => input_b(i),
    m => mode,
    result => result_x4(i));
end generate;

【问题讨论】:

这是一个半加法器result &lt;= a + b;。您将需要一个 full adder(带有一个 carry in 和一个 carry out):(cout, result) &lt;= a + b + ('0'&amp;cin); 然后您连接到菊花链进位:每个进位都由前一个(次要)阶段的进位驱动。然后,您可以通过比较 17 位输出的左侧两个位(执行 MSB 和其他 16 个结果)来检测溢出。如果这两个位不同,则说明溢出。 您的代码不是Minimal, Complete, and Verifiable example。它也有各种语法错误,您的问题不清楚 - 什么计数器? 正如 Matthew 指出的那样,您不是在构建没有进位链的 16 位 ALU。除了一大堆缺少的分号、缺少的 end 语句、声明为单个 std_logic 的 result_x4 以及缺少其他选择的情况之外,没有用于将抽象文字添加到 std_logic 值的“+”运算符重载。为什么要尝试从 1 位 ALU 构建 16 位 ALU?这是课堂作业吗? Charles Steinkuehler 的回答 (vhdl - Making a 4-bit ALU from several 1-bit ALUs) 提到“暂时忽略进位问题,您通常只需设置一个 for generate 循环并实例化您的按位逻辑的多个副本,可能是第一个特殊套管和/ 或最后一个元素”,警告读者进位没有被覆盖,他显示 result_x4(bitindex) ) 一个选定的名称暗示 result_x4 是一个数组值。 【参考方案1】:

这是一个如何创建 N 位加法器组件的示例。首先,您需要创建一个全加器,它是一个还考虑进位的加法器。

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;

当您拥有这个 1 位加法器时,您可以通过生成我们上面的全加器的多个单元来轻松生成 N 位波纹进位。

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;

当您拥有加法器后,您可以轻松地将加法器组件放入 ALU 中,并指定 ALU 应该能够执行的不同操作。

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; 

然而,这个 ALU 并没有那么复杂,也没有那么多操作,但可以轻松添加该功能。希望我给你的示例代码对你有帮助。

【讨论】:

以上是关于使用 1 位 ALU 制作 16 位 ALU的主要内容,如果未能解决你的问题,请参考以下文章

红色输出在 4 位 ALU 上运行测试平台

数字电路 多功能ALU设计实验

计算机组成原理运算器组成实验

alu

ALU(Arithmetic and Logic Unit)原理————CPU的"大脑"

Logisim ALU 红线 - 不了解原因以及如何修复