2

我应该用 VHDL 编写一个简单的 32 位 Alu。一切都很好,除了两件事。ALU 应该有一个执行和溢出标志,我不知道如何实现它。

首先是一个一般性问题。电路图显示,对于减法,ALU 将减数取反并加“1”以在 2 秒补码中创建输入值的负等效值。这是否意味着我应该为输入使用无符号值?还是我应该坚持使用 std_logic_vector?

由于进位位是不“适合”结果字的位,因此我尝试将 Summands 零扩展,创建一个临时的 33 位 Sum 信号,然后简单地将结果分为进位和实际总和。不幸的是,我在模拟时得到的只是“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;

对代码的任何评论将不胜感激,因为我对 VHDL 完全陌生(我们讨论了半场讲座......),这是我通过谷歌搜索和玩耍发现的。

这是给定的电路图:

诊断

//编辑:

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

4

2 回答 2

5

回答您的第一个问题:是的,使用库 IEEE.std_numeric 中的无符号。它非常适合这种操作。

其次,可以通过比较输出和输入来检测溢出。例如,在二进制的恭维中,如果您执行 +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   |       -       |      -        |
-----------------------------------------------------------------------------

可以为乘法和除法制定类似的规则,但涉及程度略高。

编辑

以下是解决此问题的建议方法(您确实意识到我希望 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;
于 2013-07-31T21:17:29.490 回答
1

这个答案可能会有所帮助:https ://stackoverflow.com/a/15499109/47453 。注意关于信号和变量之间差异的解释。

基本上,您应该稍微改变一下您的流程。

process (Clk)
    variable temp : std_logic_vector (32 downto 0);
begin
        ...
        case OP is
            when "010" =>
                temp := std_logic_vector((unsigned("0" & Smd0) + unsigned(Smd1)));
                sum <= temp(31 downto 0);
                cry <= temp(32);
        ...
于 2013-07-31T21:23:07.073 回答