[英]How to handle carry out by using 1 bit ALU to create 4 bit alu in VHDL
[英]32 Bit ALU in VHDL Carry Out
我應該在VHDL中編寫一個簡單的32位Alu。 除兩件事外,其他一切正常。 ALU應該有一個進位和溢出標志,我不知道如何實現它。
首先是一個普遍的問題。 電路圖顯示,為了進行減法運算,ALU反轉了減數運算並加“ 1”,以2s補碼形式產生輸入值的負當量。 這是否意味着我應該使用輸入的無符號值? 還是應該堅持使用std_logic_vector?
由於進位位是不“適合”結果字的位,因此,我嘗試對Summands進行零擴展,創建一個臨時的33位求和信號,然后將結果簡單地分為進位和實際和。 不幸的是,我在仿真時得到的只是“ UU ... U”作為總和的輸出。(我按此處所述進行了操作: https : //en.wikibooks.org/wiki/VHDL_for_FPGA_Design/4-Bit_ALU )
對於溢出標志:由於ALU的描述是行為上的,所以我無法訪問任何進位,這意味着我無法通過簡單地對最后兩個進位進行異或來確定是否發生了溢出(假設值在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的新手,所以對代碼的任何評論都將不勝感激(我們在半個演講中談到了它……),這是我通過谷歌搜索和玩耍發現的。
那是給定的電路圖:
//編輯:
另一件事。 “ 000”后,我的零標志無法正常工作。 除了第一種情況外,您知道為什么它的輸出很好嗎?
回答第一個問題:是,請使用庫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 | - | - |
-----------------------------------------------------------------------------
可以為乘法和除法制定類似的規則,但要涉及更多的規則。
編輯
以下是解決此問題的建議方法(您確實意識到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;
這個答案可能會有所幫助: 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);
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.