VHDL 执行中的 32 位 ALU

dne*_*lle 2 vhdl alu

我应该用 VHDL 编写一个简单的 32 位 Alu。除了两件事之外,一切都工作正常。ALU 应该有一个进位和溢出标志,但我不知道如何实现它。

首先是一般性问题。该电路图显示,对于减法,ALU 会反转减数并添加“1”以创建 2s 补码形式的输入值的负等效值。这是否意味着我应该使用无符号的输入值?或者我应该坚持使用 std_logic_vector ?

由于进位位是不“适合”结果字的位,因此我尝试对加数进行零扩展,创建临时 33 位求和信号,然后将结果简单地分为进位和实际和。不幸的是,我在模拟时得到的只是“UU...U”作为总和的输出。(我按照此处所述进行操作: https: //en.wikibooks.org/wiki/VHDL_for_FPGA_Design/4-Bit_ALU

对于溢出标志:由于 ALU 的描述是行为性的,所以我无法访问任何进位,这意味着我无法通过简单地对最后两个进位进行异或来确定是否发生溢出(假设值在 2 秒内) -补充,但我在这一点上不太确定,正如我的第一个问题所示......)。还有其他方法来识别溢出吗?就像简单地将在互联网上找到的“当......时发生溢出”规则转换为 if 语句?

这是我到目前为止的代码。这个版本在加/减时给我“UUU...U”作为输出。

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

entity ALU is
Port ( Clk : in STD_LOGIC;
          A : in  std_logic_vector (31 downto 0);
       B : in  std_logic_vector(31 downto 0);
       Y : out  std_logic_vector(31 downto 0);
       OP : in  std_logic_vector(2 downto 0);
          Nul   : out boolean;
       Cout : out  STD_LOGIC);
end ALU;

architecture Behavioral of ALU is

signal Smd0, Smd1, Sum : std_logic_vector (31 downto 0);
signal temp : std_logic_vector (32 downto 0);
signal Cry : STD_LOGIC;
signal snul : boolean;


begin

Smd0 <= A;
Smd1 <= B;
Y <= Sum;
Cout <= Cry;
nul <= snul;
process(Clk) begin

if (rising_edge(Clk)) then

    if ( Sum = "00000000000000000000000000000000") then -------Zero flag
        snul <= true;
    else
        snul <= false;
    end if;

    case OP is
        when "000" =>
            Sum <= Smd0 and Smd1;
        when "001" =>
            Sum <= Smd0 xor Smd1;
        when "010" =>
            temp <= std_logic_vector((unsigned("0" & Smd0) + unsigned(Smd1)));
            Sum <= temp(31 downto 0);
            Cry <= temp(32);
        when "100" =>
            Sum <= Smd0 and not Smd1;
        when "101" =>
            Sum <= Smd0 xor not Smd1;
        when "110" =>
            Sum <= std_logic_vector((unsigned(Smd0) - unsigned(Smd1)));
        when "111" =>
            if (A < B) then
                Sum <= "00000000000000000000000000000001";
            else 
                Sum <= "00000000000000000000000000000000";
            end if;
        when others =>
            NULL;
    end case;

end if;
end process;
end Behavioral;
Run Code Online (Sandbox Code Playgroud)

任何对代码的评论都将不胜感激,因为我对 VHDL 完全陌生(我们讨论了半个讲座......),这就是我通过谷歌搜索和玩弄得出的结果。

这是给定的电路图:

诊断仪

//编辑:

另一件事。我的零标志在“000”之后无法正常工作。知道为什么除了第一种情况之外它的输出很好吗?

Oll*_*ieB 5

回答你的第一个问题:是的,使用 IEEE.std_numeric 库中的 unsigned。它非常适合此类操作。

其次,可以通过比较输出与输入来检测溢出。例如,在二进制补码中,如果执行 +ve 加 +ve 并溢出,结果将设置 msb,因此结果为 -ve。

总结加法和减法

Addition     | (+ve) - (+ve) | (+ve) - (-ve) | (-ve) - (+ve) | (-ve) + (-ve)|
-----------------------------------------------------------------------------
Result (+ve) |       -       |        -      |        -      |    overflow  | 
-----------------------------------------------------------------------------
Result (-ve) |    overflow   |        -      |        -      |       -      | 
-----------------------------------------------------------------------------

Subtraction  | (+ve) - (+ve) | (+ve) - (-ve) | (-ve) - (+ve) | (-ve) - (-ve)|
-----------------------------------------------------------------------------
Result (+ve) |       -       |        -      |    overflow   |      -        |
----------------------------------------------------------------------------- 
Result (-ve) |       -       |    overflow   |       -       |      -        |
-----------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

类似的规则可以用于乘法和除法,但稍微复杂一些。

编辑

下面是解决此问题的建议方法(我希望您确实意识到 vhdl(大部分)不区分大小写?您似乎喜欢使用 Shift 键)。从你的问题来看,我不知道你想要哪个标志作为溢出标志,所以我没有放入一个标志。

library ieee;
use ieee.std_logic_164.all;
use ieee.numeric_std.all;

entity alu is
port ( 
    signal clk   : in  std_logic;
    signal a     : in  std_logic_vector(31 downto 0);
    signal b     : in  std_logic_vector(31 downto 0);
    signal y     : in  std_logic_vector(31 downto 0);
    signal op    : in  std_logic_vector(3  downto 0);
    signal nul   : out boolean;
    signal cout  : out std_logic
)
end entity;

architecture behavioral of alu is
   type op_type is (op_and, op_a_and_nb, op_a_xor_nb, op_compare, 
                    op_xor, op_add, op_sub, op_nop);
   signal enum_op : op_type;

   signal a_minus_b : std_logic_vector(32 downto 0);
   signal a_plus_b  : std_logic_vector(32 downto 0);
   signal reg       : std_logic_vector(32 downto 0);

begin

   a_minus_b <= std_logic_vector(signed(a(a'high) & a) - signed(b(b'high) & b));
   a_plus_b  <= std_logic_vector(signed(a(a'high) & a) + signed(b(b'high) & b));

   process(op)
   begin
      case op is
      when "000" => enum_op <= op_and;
      when "001" => enum_op <= op_xor;
      when "010" => enum_op <= op_add;
      when "100" => enum_op <= op_a_and_nb;
      when "101" => enum_op <= op_a_xor_nb;
      when "110" => enum_op <= op_sub;
      when "111" => enum_op <= op_compare;
      when others => enum_op <= op_nop;
      end case;
   end process;

   process(clk)
   begin
      if rising_edge(clk) then
         case enum_op is
         when op_add       => reg <= a_plus_b;
         when op_sub       => reg <= a_minus_b;
         when op_and       => reg <= '0' & (a and b);
         when op_xor       => reg <= '0' & (a xor b);
         when op_a_and_nb  => reg <= '0' & (a and not b);
         when op_a_xor_nb  => reg <= '0' & (a xor not b);
         when op_compare   => 
            reg(32) <= '0';
            reg(31 downto 1) <= (others => '0'); 
            reg(0)  <= a_minus_b(32);
         when op_nop       =>
            reg(32) <= '0';
      end if;
   end process;

   y <= reg(31 downto 0);
   count <= reg(32);
   nul <= unsigned(reg) = '0';

end architecture;
Run Code Online (Sandbox Code Playgroud)