首页 文章

VHDL执行32位ALU

提问于
浏览
2

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

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

由于进位位是结果字中没有"fit"的位,我试图对Summands进行零扩展,创建一个临时的33位Sum信号,然后简单地将结果分成Carry Out和实际和 . 不幸的是,我在模拟时得到的是"UU...U"作为总和的输出 . (我按照这里描述的那样做了:https://en.wikibooks.org/wiki/VHDL_for_FPGA_Design/4-Bit_ALU

并且对于溢出标志:由于ALU的描述是行为的,我无法访问任何进位,这意味着我无法通过简单地对最后两个进位进行xoring来确定是否发生溢出(假设值为2s) - 补充,但我不太确定这一点,因为我的第一个问题显示...) . 还有另一种识别溢出的方法吗?就像简单地将互联网上发现的“溢出发生时...”规则转换成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完全不熟悉(我们谈了半个讲座......)这就是我通过谷歌搜索和玩弄来解决的问题 .

这是给定的电路图:

CDiag

//编辑:

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

2 回答

  • 1

    在回答您的第一个问题时:是的,请使用库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   |       -       |      -        |
    -----------------------------------------------------------------------------
    

    类似的规则可以用于乘法和除法,但稍微涉及更多 .

    EDIT

    下面是一个建议的方法来解决这个问题(你确实意识到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;
    
  • 4

    这个答案可能会有所帮助: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);
            ...
    

相关问题