32位ALU在VHDL中的实现
我应该用VHDL写一个简单的32位Alu。除了两件事外,一切都很好。ALU应该有一个执行和溢出标志,我不知道如何实现它 首先是一个一般性问题。电路图显示,对于减法运算,ALU将减数反转,并加上“1”,以在2s补码中创建输入值的负等效值。这是否意味着我应该使用输入的无符号值?还是我应该坚持标准逻辑向量 由于进位是不“适合”结果字的位,因此我尝试对总和进行零扩展,创建一个临时的33位总和信号,然后简单地将结果分为进位和实际总和。不幸的是,当模拟时,我得到的只是“UU…U”作为总和的输出 对于溢出标志:由于ALU的描述是行为的,所以我没有访问任何进位的权限,这意味着我无法通过简单地对最后两个进位进行异或来确定是否发生了溢出(假设值是2s补码,但正如我的第一个问题所示,在这一点上我不太确定…)。是否有其他方法来识别溢出?就像简单地将互联网上的“溢出发生时…”规则转换为if语句一样 这是到目前为止我的代码。这个版本在加/减时给我“UUU…U”作为输出32位ALU在VHDL中的实现,vhdl,alu,Vhdl,Alu,我应该用VHDL写一个简单的32位Alu。除了两件事外,一切都很好。ALU应该有一个执行和溢出标志,我不知道如何实现它 首先是一个一般性问题。电路图显示,对于减法运算,ALU将减数反转,并加上“1”,以在2s补码中创建输入值的负等效值。这是否意味着我应该使用输入的无符号值?还是我应该坚持标准逻辑向量 由于进位是不“适合”结果字的位,因此我尝试对总和进行零扩展,创建一个临时的33位总和信号,然后简单地将结果分为进位和实际总和。不幸的是,当模拟时,我得到的只是“UU…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;
IEEE库;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.NUMERIC_STD.ALL;
实体ALU是
端口(时钟:在标准逻辑中;
A:标准逻辑向量(31到0);
B:标准逻辑向量(31到0);
Y:输出标准逻辑向量(31到0);
OP:标准逻辑向量(2到0);
Nul:输出布尔值;
Cout:输出标准逻辑);
末端ALU;
ALU的体系结构是
信号Smd0,Smd1,和:标准逻辑向量(31向下至0);
信号温度:标准逻辑向量(32至0);
信号呼叫:标准逻辑;
信号snul:布尔型;
开始
Smd0在回答您的第一个问题时:
是,使用IEEE.std_库中的无符号数字。这是这种手术的理想选择
其次,可以通过比较输出和输入来检测溢出。例如,在two的赞美中,如果执行+ve+ve和overflow,结果将设置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;
ieee库;
使用ieee.std_logic_164.all;
使用ieee.numeric_std.all;
实体alu是
港口(
信号时钟:在标准逻辑中;
信号a:std_逻辑_向量(31向下至0);
信号b:标准逻辑向量(31至0);
信号y:在标准逻辑向量中(31向下至0);
信号op:标准逻辑向量(3到0);
信号nul:输出布尔值;
信号输出:输出标准逻辑
)
终端实体;
alu的体系结构是
类型op_类型是(op_and,op_a_and_nb,op_a_xor_nb,op_compare,
操作异或、操作添加、操作子、操作nop);
信号枚举操作:操作类型;
信号a_减去_b:std_逻辑_向量(32向下至0);
信号a加b:标准逻辑向量(32向下至0);
信号寄存器:标准逻辑向量(32向下至0);
开始
这个答案可能会有帮助。请注意有关信号和变量之间差异的说明
基本上,你应该改变一下你的流程
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);
...
过程(Clk)
变量温度:标准逻辑向量(32到0);
开始
...
案例OP是
当“010”=>
温度:=标准逻辑向量((无符号(“0”和Smd0)+无符号(Smd1));
你的临时信号不正确。如果要使用这样的临时变量,则需要使用变量,而不是信号。记住,信号会在敏感度列表中的事件上并行更新,因此,使用SignalsHanks时,您不会出现预期的行为,它正在工作。所以,作为一个比我更有经验的人,你会说这很可能奏效吗?稍后我将讨论不同的价值观,但我想有一个一般性的意见。这就是我所说的“互联网规则”,谢谢!为了澄清问题:当考虑ALU处理的数字时,我应该考虑两个补充吗?在这一点上我感到困惑,因为根据电路图,ALU确实以标准二进制形式接收它们(因为ALU在获取用于减法运算的操作码时执行反向+1操作。如果我错了,请纠正我)。您能详细说明为什么要做某些事情吗?我不明白“a(a'high)”部分,也不明白为什么要将其分为两个过程。谢谢你!a(a'high)是使用属性的索引。在这种情况下,它相当于写a(31)。在本例中,它用于对操作数a和b执行符号扩展,我假设它们是两个补码。它分为两个进程,因为我认为它更容易为其他人读取。我必须手动解码您的操作码,因此通过显式地将它们解码为枚举,我希望让其他人更容易阅读这篇文章。@OllieB:您在设置enum\u op
时忘记了信号分配。