VHDL:CLA减法器模块级联

VHDL:CLA减法器模块级联,vhdl,Vhdl,你好 我已经实现了一个8位CLA加/减模块,它工作得非常好。代码如下:我将下面的两个模块串联起来,创建了一个16位加法器/减法器。这个16位版本的加法效果非常好,进位是由1个8位加法器为低位生成的,然后将进位传递到下一个加法器,以便为高位处理 问题在于减法。即使在纸上也不行。让我给你举个例子。假设我想做350-50 300: 00000001 00101100 50: 00000000 00110010 因此,如果我让一个加法器处理低位,另一个处理高位,那么它根本不起作用。原因如下: 300

你好

我已经实现了一个8位CLA加/减模块,它工作得非常好。代码如下:我将下面的两个模块串联起来,创建了一个16位加法器/减法器。这个16位版本的加法效果非常好,进位是由1个8位加法器为低位生成的,然后将进位传递到下一个加法器,以便为高位处理

问题在于减法。即使在纸上也不行。让我给你举个例子。假设我想做350-50

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加法器时,只有XOR
Binv
。这样一来,它既可以作为一个独立的
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
        );