![](/img/trans.png)
[英]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.