Carry/Borrow 在 VHDL ALU 中
Carry/Borrow in VHDL ALU
我正在用 VHDL 制作一个通用的 N 位 ALU。我无法为加法的进位分配值,或为减法借位。我尝试了以下方法:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity alu is
generic(n: integer :=1); --Default to 1
port (
a : in std_logic_vector(n-1 downto 0);
b : in std_logic_vector(n-1 downto 0);
op : in std_logic_vector(1 downto 0);
output : out std_logic_vector(n-1 downto 0);
carryborrow: out std_logic
);
end alu;
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "01" =>
result(n) <= '0';
result(n-1 downto 0) <= a or b; --or gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "10" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) + signed(b)); --addition
output <= result(n-1 downto 0);
carryborrow <= result(n);
when "11" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) - signed(b)); --subtraction
output <= result(n-1 downto 0);
carryborrow <= result(n);
when others =>
NULL;
end case;
end process;
end Behavioral;
这似乎将 carryborrow
位设置为始终为 0。我怎样才能将它分配给它应该是什么而不会出现类型错误?
我通常这样做:
result <= std_logic_vector(signed(a(n-1) & a) + signed(b(n-1) & b));
result <= std_logic_vector(signed(a(n-1) & a) - signed(b(n-1) & b));
当结果多出一位长时,对扩展进行签名,然后执行处理溢出的操作。
您的代码中存在错误:
i) 您没有考虑到信号不会立即更新的事实。因此,以下行不会像我认为的那样执行:
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
相反,您需要在组合过程之外使用驱动 output
和 carryborrow
的线路,如下所示。
ii) 假设您希望此代码是可综合的,只需将 NULL
放在您的 always 分支中即可推断出锁存器。您也需要在 others 分支中驱动 result
。
所以,假设你的进位输出如何与 and
和 or
操作一起工作,这就是我编写你的代码的方式:
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result <= '0' & (a and b); --and gate
when "01" =>
result <= '0' & (a or b); --or gate
when "10" =>
result <= std_logic_vector(resize(signed(a), n+1) + resize(signed(b), n+1)); --addition
when "11" =>
result <= std_logic_vector(resize(signed(a), n+1) - resize(signed(b), n+1)); --subtraction
when others =>
result <= (others => 'X');
end case;
end process;
output <= result(n-1 downto 0);
carryborrow <= result(n);
end Behavioral;
嗯,在 4 位环境中考虑这个,比如 a="0101"
和 b="1001"
。添加它们将得到 output="1110"
,没有进位。
然而,用 resize(signed(a), n+1)
和 resize(signed(b), n+1)
扩展符号将设置 a="00101"
和 b="11001"
,因此设置 result="11110"
和 carryborrow='1'
,这是错了!
通过符号扩展向量a
和b
,数字范围增加到5位,因此result
需要6位才能容纳进位,并且我们回到正题。
向量 a
和 b
应该只进行零扩展,即 '0' & a
和 '0' & b
在将它们添加到 result
之前,然后 carryborrow
,如result
的 MSB(Most Significant Bit),将得到正确的值。
我正在用 VHDL 制作一个通用的 N 位 ALU。我无法为加法的进位分配值,或为减法借位。我尝试了以下方法:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity alu is
generic(n: integer :=1); --Default to 1
port (
a : in std_logic_vector(n-1 downto 0);
b : in std_logic_vector(n-1 downto 0);
op : in std_logic_vector(1 downto 0);
output : out std_logic_vector(n-1 downto 0);
carryborrow: out std_logic
);
end alu;
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "01" =>
result(n) <= '0';
result(n-1 downto 0) <= a or b; --or gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "10" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) + signed(b)); --addition
output <= result(n-1 downto 0);
carryborrow <= result(n);
when "11" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) - signed(b)); --subtraction
output <= result(n-1 downto 0);
carryborrow <= result(n);
when others =>
NULL;
end case;
end process;
end Behavioral;
这似乎将 carryborrow
位设置为始终为 0。我怎样才能将它分配给它应该是什么而不会出现类型错误?
我通常这样做:
result <= std_logic_vector(signed(a(n-1) & a) + signed(b(n-1) & b));
result <= std_logic_vector(signed(a(n-1) & a) - signed(b(n-1) & b));
当结果多出一位长时,对扩展进行签名,然后执行处理溢出的操作。
您的代码中存在错误:
i) 您没有考虑到信号不会立即更新的事实。因此,以下行不会像我认为的那样执行:
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
相反,您需要在组合过程之外使用驱动 output
和 carryborrow
的线路,如下所示。
ii) 假设您希望此代码是可综合的,只需将 NULL
放在您的 always 分支中即可推断出锁存器。您也需要在 others 分支中驱动 result
。
所以,假设你的进位输出如何与 and
和 or
操作一起工作,这就是我编写你的代码的方式:
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result <= '0' & (a and b); --and gate
when "01" =>
result <= '0' & (a or b); --or gate
when "10" =>
result <= std_logic_vector(resize(signed(a), n+1) + resize(signed(b), n+1)); --addition
when "11" =>
result <= std_logic_vector(resize(signed(a), n+1) - resize(signed(b), n+1)); --subtraction
when others =>
result <= (others => 'X');
end case;
end process;
output <= result(n-1 downto 0);
carryborrow <= result(n);
end Behavioral;
嗯,在 4 位环境中考虑这个,比如 a="0101"
和 b="1001"
。添加它们将得到 output="1110"
,没有进位。
然而,用 resize(signed(a), n+1)
和 resize(signed(b), n+1)
扩展符号将设置 a="00101"
和 b="11001"
,因此设置 result="11110"
和 carryborrow='1'
,这是错了!
通过符号扩展向量a
和b
,数字范围增加到5位,因此result
需要6位才能容纳进位,并且我们回到正题。
向量 a
和 b
应该只进行零扩展,即 '0' & a
和 '0' & b
在将它们添加到 result
之前,然后 carryborrow
,如result
的 MSB(Most Significant Bit),将得到正确的值。