2

VHDL で単純な 32 ビット Alu を作成することになっています。2 つのことを除いて、すべて正常に動作しています。ALU にはキャリーアウトとオーバーフローのフラグがあるはずですが、それを実装する方法がわかりません。

まずは一般質問。回路図は、減算の場合、ALU が減算を反転し、「1」を追加して、2 の補数で入力値の負の等価物を作成することを示しています。これは、入力に符号なしの値を使用する必要があるということですか? または、std_logic_vector に固執する必要がありますか?

キャリーアウトビットは結果ワードに「適合」しないビットであるため、サマンドをゼロ拡張し、一時的な33ビットサム信号を作成してから、結果をキャリーアウトと実際の合計に単純に分割しようとしました。残念ながら、シミュレートするときに得られるのは、合計の出力として「UU ... U」だけです

オーバーフロー フラグの場合: ALU の説明は動作に基づいているため、キャリーにアクセスすることはできません。つまり、最後の 2 つのキャリーを単純に xor するだけでは、オーバーフローが発生したかどうかを判断できません (値が 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にまったく慣れていないので(講義の半分で話しました...)、コードに関するコメントは大歓迎です。これは、グーグルで遊んで調べた結果です。

それが与えられた回路図です:

CDiag

//編集:

別物。「000」以降、マイゼロフラグが正常に動作しません。最初のケースを除いて、出力が良い理由は何ですか?

4

2 に答える 2

5

最初の質問への回答: はい、ライブラリ IEEE.std_numeric から unsigned を使用します。このような操作に最適です。

次に、出力と入力を比較することでオーバーフローを検出できます。たとえば、2 の補数で、+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 に答える