2014-09-23 79 views
1

好日子,VHDL:CLA减法器模块级联

我实现了一个8个CLA加法/减法模块和它的伟大工程。代码如下:我已将以下模块中的2个串联起来以创建一个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 

第1加法器:加法后产生正确的值11111010.这很酷。现在第二个加法器是个问题。它会做(1的恭维+ 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; 
+0

你的数学片段说'250应该是00000000 11111010'。在那之下你说第二个加法器输出'00000000'。然后你说这是错误的。我认为我不明白... – fru1tbat 2014-09-23 16:05:05

+0

顺便说一句,50中的2补码是'11001110',而不是'11001101'。 – fru1tbat 2014-09-23 16:07:59

+0

这个想法是,如果我们正在减去(做2的赞美),如果第一个加法器没有进位,我们应该做一个(1的赞美) – raaj 2014-09-23 16:11:07

回答

1

的问题是,你做了一个错误计算2的50补:

在您的公式您使用:

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

这仅仅是50倒置所有位。然而,二进制补码是通过首先反转比特来构建的,然后添加一个。

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

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实现,意味着您可以通过重新使用添加部分来实现减法。为此建立补两个步骤:

如果减法模式:

  • 否定另外
  • 力的低8位加法器高的搬入之前B的所有位。

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

+0

嗯,我明白了,实际上我所做的是为所有随后的加法器(比特7-15等),我将它们设置为(Binv xor Adder_0_Carry)。因此,如果第一加法器由于2的恭维而有+ 1的进位,它将从进位中传出,并且因为我用Binv进行异或,所以我告诉第二加法器不加进位。 – raaj 2014-09-23 16:05:30

+0

另外,是的,我搞砸了50我的坏。我应该编辑这个问题 – raaj 2014-09-23 16:06:38

+0

你是否已经试过你的代码了?修复应该很容易。 – 2014-09-23 16:07:08

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位等),我设置那些(彼女XOR Adder_0_Carry)进位。因此,如果第一加法器由于2的恭维而有+ 1的进位,它将从进位中传出,并且因为我用Binv进行异或,所以我告诉第二加法器不加进位。

的想法是,如果我们扣除(做2的补),我们应该做一个(1补码),如果第一个加法没有进

我无法证实这一点对所有的测试用例。这只是一个理论,到目前为止它似乎工作

+0

嗯..如果我将B_inv设置为0,这意味着我在做加法,并且我传入两个有符号位。例如50和-250,它将无法工作,因为第二个加法器的C_in由Binv xor Adder_0_carry决定。 – raaj 2014-09-23 16:16:16

0

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

嗯..如果我设置B_inv为0,这意味着我在做加法,并且传入两个有符号位。说50和-250,它不会工作,因为第二加法器的C_IN由彼女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之间的异或。对于最重要的n位加法器,再次异或Binv会给您一个偶数数量的异或,以消除它们的影响,并执行最低有效加法器。

正确的做法实际上只是将翻转为B,并使用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的Complement的1的补码部分以减去'B'。你可以添加一个输入到cla_add_sub表示什么时候是LS加法器,然后是XOR Binv。这样它可以作为一个独立的n位加法器或一个可以菊花链接的加法器。