VHDL:CLA减法器模块级联

时间:2014-09-23 15:42:42

标签: vhdl

美好的一天,

我已经实现了一个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

第一个加法器:加入11111010后生成正确的值。这很酷。现在第二个加法器,是一个问题。它会做(1' s恭维+​​ 1),它将给出00000000(带进位)。它应该是(11111111),但由于算法中的+ 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;

3 个答案:

答案 0 :(得分:1)

问题是,你在计算50的2的补码时出错:

在你的等式中你使用:

50 in 2's compliment: 11111111 11001101   <--- WRONG.

只有50,所有位都被反转。然而,通过首先反转这些位来构建二进制补码,然后将其加一。

16位整数中-50的正确表示是:

50 in 2's compliment: 11111111 11001110

如果我们现在做300到50的数学运算,我们会得到:

  00000001 00101100   | 300
+ 11111111 11001110   | -50 in 2's complement form
-------------------
  00000000 11111010   | 250 (expected result)

对于VHDL实现,这意味着您可以通过重用加法部分来实现减法。为此,分两步建立两个补码:

如果是减法模式:

  • 在添加之前否定B的所有位
  • 强制低8位加法器的进位为高电平。

第二步将把一个添加到否定的B,然后是正确的二进制补码。现在你像往常一样添加你的数字并得到一个功能性减法器。

答案 1 :(得分:0)

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位等)我将Carry设置为(Binv xor Adder_0_Carry)。因此,如果第一个加法器因为2的恭维而有一个进位,那么它将从进位中传出,并且由于我用Binv对其进行测量,我告诉第二个加法器不要添加进位。

这个想法是,如果我们减去(做2的恭维),如果第一个加法器没有进位,我们应该做(1的恭维)

我无法对所有测试用例进行确认。这只是一个理论,到目前为止似乎有效

答案 2 :(得分:0)

这是对你自己答案的补充。

嗯......如果我将B_inv设置为0,意味着我正在添加,我传入两个有符号的位。说50和-250,它将无法工作,因为第二个加法器的C_in由Binv xor Adder_0_carry确定

我认为您的手动算术有问题:

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;

给出:

tb_add_sub_ganged.png

(我更新了有符号减法/加法的波形图像。)

cla_add_sub中的binv选择器相当于BinvC_in之间的XOR。对于最高有效Binv位加法器,在外部再次进行异常n会为您提供偶数个XOR来消除其影响,并执行最低有效加法器的执行。

正确的做法实际上只是用B反转Binv并使用Binv来反转LS加法器的进位。因为除了减法之外你永远不会携带它,直接将它挂钩到Binv。这将解决所有问题。

cla_add_sub中发表评论:

-- WITH Binv  SELECT
-- C_in_mod <= C_in WHEN '0',
--         not C_in WHEN '1',
--         C_in WHEN OTHERS;

C_in_mod声明:

-- SIGNAL  C_in_mod: STD_LOGIC := C_in;

直接使用C_in

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)

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
        );

这给出了与上面显示的相同的结果。

请注意这与Nils的回答一致。

如果你只有一个n位加法器/减法器,你将在你的答案中使用这个方法,其中进位(LS)进位(MS)将再次被反转为将两个8位操作链接在一起。

这实例化两个恰好反转B的加法器,即2的补语的1的补码部分,减去'B'。您可以向cla_add_sub添加输入,表示何时是LS加法器,然后只有XOR Binv。这样它既可以作为独立的n位加法器,也可以作为菊花链接的。