VHDL:CLA减法器模块级联
你好 我已经实现了一个8位CLA加/减模块,它工作得非常好。代码如下:我将下面的两个模块串联起来,创建了一个16位加法器/减法器。这个16位版本的加法效果非常好,进位是由1个8位加法器为低位生成的,然后将进位传递到下一个加法器,以便为高位处理 问题在于减法。即使在纸上也不行。让我给你举个例子。假设我想做350-50VHDL:CLA减法器模块级联,vhdl,Vhdl,你好 我已经实现了一个8位CLA加/减模块,它工作得非常好。代码如下:我将下面的两个模块串联起来,创建了一个16位加法器/减法器。这个16位版本的加法效果非常好,进位是由1个8位加法器为低位生成的,然后将进位传递到下一个加法器,以便为高位处理 问题在于减法。即使在纸上也不行。让我给你举个例子。假设我想做350-50 300: 00000001 00101100 50: 00000000 00110010 因此,如果我让一个加法器处理低位,另一个处理高位,那么它根本不起作用。原因如下: 300
300: 00000001 00101100
50: 00000000 00110010
因此,如果我让一个加法器处理低位,另一个处理高位,那么它根本不起作用。原因如下:
300: 00000001 00101100
50 in 2's compliment: 11111111 11001110
250 is supposed to be 00000000 11111010
第一加法器:加法11111 010后生成正确值。那很酷。第二个加法器是个问题。它将做(1的赞美+1),这将给00000000(带进位)。本来应该是(11111111),但是由于algo中的+1是一个通用的实现,它把最终的答案搞砸了
右边,因为加法器0没有进位,所以加法器1不应该进行+1运算。如何在通用8位子/加法器的逻辑中实现这一点?这是正确的想法吗?我是否涵盖了所有可能的影响/边缘情况
entity CLA_ADD_SUB is
generic (N : integer := 8);
Port ( A : in STD_LOGIC_VECTOR (N-1 downto 0);
B : in STD_LOGIC_VECTOR (N-1 downto 0);
Binv : in STD_LOGIC;
C_in: in STD_LOGIC;
S : out STD_LOGIC_VECTOR (N-1 downto 0);
TEST : out STD_LOGIC_VECTOR (N-1 downto 0);
C_out : out STD_LOGIC
);
end CLA_ADD_SUB;
architecture CLA_ADD_SUB_ARCH of CLA_ADD_SUB is
SIGNAL h_sum : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_generate : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_propagate : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_in_internal : STD_LOGIC_VECTOR(N-1 DOWNTO 1);
SIGNAL B_mod : STD_LOGIC_VECTOR(N-1 DOWNTO 0) := B;
SIGNAL C_in_mod: STD_LOGIC := C_in;
signal S_wider : std_logic_vector(N downto 0);
begin
WITH Binv SELECT
B_mod <= B WHEN '0',
not B WHEN '1',
B WHEN OTHERS;
WITH Binv SELECT
C_in_mod <= C_in WHEN '0',
not C_in WHEN '1',
C_in WHEN OTHERS;
-- Sum, P and G
h_sum <= A XOR B_mod;
carry_generate <= A AND B_mod;
carry_propagate <= A OR B_mod;
PROCESS (carry_generate,carry_propagate,carry_in_internal,C_in_mod)
BEGIN
carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AND C_in_mod);
inst: FOR i IN 1 TO (N-2) LOOP
carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AND carry_in_internal(i));
END LOOP;
C_out <= carry_generate(N-1) OR (carry_propagate(N-1) AND carry_in_internal(N-1));
END PROCESS;
S(0) <= h_sum(0) XOR C_in_mod;
S(N-1 DOWNTO 1) <= h_sum(N-1 DOWNTO 1) XOR carry_in_internal(N-1 DOWNTO 1);
end CLA_ADD_SUB_ARCH;
实体类添加子类为
泛型(N:整数=8);
端口(A:标准逻辑向量中(N-1到0);
B:标准逻辑向量(N-1到0);
Binv:标准逻辑中;
C_in:标准逻辑中;
S:输出标准逻辑向量(N-1向下至0);
测试:输出标准逻辑向量(N-1向下至0);
输出:输出标准逻辑
);
结束类别添加子类别;
建筑类别添加子类别添加子类别的拱门
信号h_和:标准逻辑向量(N-1向下至0);
信号进位生成:标准逻辑向量(N-1到0);
信号进位传播:标准逻辑向量(N-1到0);
内部信号进位:标准逻辑向量(N-1到1);
信号B_mod:STD_逻辑向量(N-1向下至0):=B;
信号C_in_mod:STD_逻辑:=C_in;
信号S_加宽:标准逻辑向量(N到0);
开始
使用Binv选择
B_mod问题是,您在计算2的补码50时出错:
在方程式中,您使用:
50 in 2's compliment: 11111111 11001101 <--- WRONG.
如果我们现在计算300-50,我们将得到:
00000001 00101100 | 300
+ 11111111 11001110 | -50 in 2's complement form
-------------------
00000000 11111010 | 250 (expected result)
对于VHDL实现,这意味着您可以通过重新使用加法部分来实现减法。为此,分两步构建两者的补充:
如果是减法模式:
- 在加法之前对B的所有位求反
- 强制低8位加法器进位为高李>
第二步将把一加在否定的B上,B是一个正确的二的补码。现在你像往常一样把数字相加,得到一个函数减法器
u_ADDER_0: entity work.CLA_ADD_SUB(CLA_ADD_SUB_ARCH)
port map(
A => ADDER_0_A, -- Bits 0-7
B => ADDER_0_B,
Binv => TOADD_BINV,
C_in => ADDER_0_CARRY_IN,
S => ADDER_0_SUM,
TEST => ADDER_0_TEST,
C_out => ADDER_0_CARRY_OUT
);
u_ADDER_1: entity work.CLA_ADD_SUB(CLA_ADD_SUB_ARCH)
port map(
A => ADDER_1_A, --Bits 7 to 15
B => ADDER_1_B,
Binv => TOADD_BINV,
C_in => TOADD_BINV xor ADDER_0_CARRY_OUT,
S => ADDER_1_SUM,
TEST => ADDER_1_TEST,
C_out => ADDER_1_CARRY_OUT
);
啊,我明白了,实际上我所做的是对所有后续的加法器(对于位7-15等)设置进位(Binv-xor加法器0进位)。因此,如果第一个加法器有一个进位,因为2的补位是+1,它将从进位中传播出去,因为我用Binv对它进行异或,我告诉第二个加法器不要添加进位
这个想法是,如果我们在减法(做2的补码),如果第一个加法器没有进位,我们应该只做a(1的补码)
我不能为所有测试用例确认这一点。这只是一个理论,到目前为止似乎是可行的。这是对你自己答案的补充
Hmm..如果我将B_inv设置为0,这意味着我在做加法,然后传入两个有符号位。假设是50和-250,它将不起作用,因为第二个加法器的C_in由Binv xor加法器的0_进位决定
我认为你的手工算术有问题:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_add_sub_gang is
constant n: natural := 8;
end entity;
architecture foo of tb_add_sub_gang is
signal a: std_logic_vector (2*n-1 downto 0);
signal b: std_logic_vector (2*n-1 downto 0);
signal s: std_logic_vector (2*n-1 downto 0);
signal test: std_logic_vector (2*n-1 downto 0);
signal binv: std_logic;
signal cout0: std_logic;
signal cin1: std_logic;
signal cout1: std_logic;
begin
cin1 <= cout0 xor binv;
uadder0:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a((2*n-1)/2 downto 0), -- bits 0-7
b => b((2*n-1)/2 downto 0),
binv => binv,
c_in => '0',
s => s((2*n-1)/2 downto 0),
test => s((2*n-1)/2 downto 0),
c_out => cout0
);
uadder1:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a(2*n-1 downto n), --bits 8 to 15
b => b(2*n-1 downto n),
binv => binv,
c_in => cin1,
s => s(2*n-1 downto n),
test => test(2*n-1 downto n),
c_out => cout1
);
STIMULUS:
process
begin
wait for 100 ns;
a <= std_logic_vector(to_unsigned(350,a'length));
b <= std_logic_vector(to_unsigned(50,b'length));
binv <= '1';
wait for 100 ns;
binv <= '0';
wait for 100 ns;
a <= std_logic_vector(to_unsigned(50,a'length));
b <= std_logic_vector(to_unsigned(250,b'length));
binv <= '1';
wait for 100 ns;
binv <= '0';
wait for 600 ns;
wait;
end process;
end architecture;
C\u in\u mod
的声明:
-- SIGNAL C_in_mod: STD_LOGIC := C_in;
并直接在
中使用C_:
PROCESS (carry_generate,carry_propagate,carry_in_internal,C_in)
BEGIN
carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AND C_in);
inst: FOR i IN 1 TO (N-2) LOOP
carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AND carry_in_internal(i));
END LOOP;
C_out <= carry_generate(N-1) OR (carry_propagate(N-1) AND carry_in_internal(N-1));
END PROCESS;
在顶层:
-- signal cin1: std_logic;
-- cin1 <= cout0 xor binv;
uadder0:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a((2*n-1)/2 downto 0), -- bits 0-7
b => b((2*n-1)/2 downto 0),
binv => binv,
c_in => binv,
s => s((2*n-1)/2 downto 0),
test => s((2*n-1)/2 downto 0),
c_out => cout0
);
uadder1:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a(2*n-1 downto n), --bits 8 to 15
b => b(2*n-1 downto n),
binv => binv,
c_in => cout,
s => s(2*n-1 downto n),
test => test(2*n-1 downto n),
c_out => cout1
);
——信号cin1:std\U逻辑;
--cin1 a((2*n-1)/2向下至0),--位0-7
b=>b((2*n-1)/2向下至0),
binv=>binv,
c_in=>binv,
s=>s((2*n-1)/2向下至0),
测试=>s((2*n-1)/2向下至0),
c_out=>cout0
);
uadder1:
实体工作.cla\U add\U sub(cla\U add\U sub\U arch)
港口地图(
a=>a(2*n-1到n),--位8到15
b=>b(2*n-1向下到n),
binv=>binv,
c_in=>cout,
s=>s(2*n-1向下到n),
测试=>测试(2*n-1向下至n),
c_out=>cout1
);
这给出了与上面所示相同的结果
注意,这与Nils的答案是一致的
如果你只有一个n
位加法器/减法器,你会在你的答案中使用这样的方法,其中进位(LS)到进位(MS)将被再次反转,以将两个8位操作链接在一起
这将实例化两个加法器,它们恰好反转B
,2的补码中的1的补码部分减去“B”。您可以将一个输入添加到cla\u add\u sub
表示当它是LS加法器时,只有XORBinv
。这样一来,它既可以作为一个独立的n
位加法器,也可以作为一个菊花链加法器。你的数学片段说250应该是00000000 11111 010
。下面是第二个加法器输出的00000000
。那么你说这是错误的。我想我不明白……顺便说一句,2的补码中的50是11001110
,而不是11001101
。这个想法是,如果我们在减法(做2的补码),如果第一个加法器没有任何结转,我们应该只做a(1的补码),这没有任何意义。您的算法不需要检查是否有进位(或者我是否遗漏了一些简单的东西?)。您发布的数学结果表明,只需将2个数字相加并传递进位即可完美实现(您的输入为300和-50,结果为250)。问题似乎是你说“它应该是(11111111)”-你为什么这么说?好吧,我明白了-从你的描述中,我不清楚颠倒论点是问题所在。在那个地方
PROCESS (carry_generate,carry_propagate,carry_in_internal,C_in)
BEGIN
carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AND C_in);
inst: FOR i IN 1 TO (N-2) LOOP
carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AND carry_in_internal(i));
END LOOP;
C_out <= carry_generate(N-1) OR (carry_propagate(N-1) AND carry_in_internal(N-1));
END PROCESS;
S(0) <= h_sum(0) XOR C_in;
-- signal cin1: std_logic;
-- cin1 <= cout0 xor binv;
uadder0:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a((2*n-1)/2 downto 0), -- bits 0-7
b => b((2*n-1)/2 downto 0),
binv => binv,
c_in => binv,
s => s((2*n-1)/2 downto 0),
test => s((2*n-1)/2 downto 0),
c_out => cout0
);
uadder1:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a(2*n-1 downto n), --bits 8 to 15
b => b(2*n-1 downto n),
binv => binv,
c_in => cout,
s => s(2*n-1 downto n),
test => test(2*n-1 downto n),
c_out => cout1
);