VHDL NxM 位并行块乘法器

VHDL NxM -bit parallel block multiplier

我正在尝试为 NxM 位并行块乘法器创建原理图,使用通用参数来定义乘法器的大小,并生成描述内部结构的语句。我的求和和进位有一些问题,我无法用 VHDL 代码实现我想做的事情。

这是我目前得到的:

1位乘数:

library IEEE;  
use IEEE.std_logic_1164.all;  
use IEEE.std_logic_arith.all;  
use ieee.numeric_std.all;  
use ieee.std_logic_unsigned.all;

entity mult is  
 port (  
  a     :  in std_logic;  
  b     :  in std_logic;  
  Sin   :  in std_logic;        --sum-in  
  Cin   :  in std_logic;        --carry-in  
  Sout  :  out std_logic;       --sum-out  
  Cout  :  out std_logic        --carry-out  
);  
end mult;  

architecture mult of mult is  
  begin  

    Sout <= '1' when a = '0' and b = '0' and Sin = '0' and Cin = '1' else
            '1' when a = '0' and b = '0' and Sin = '1' and Cin = '0' else
            '1' when a = '0' and b = '1' and Sin = '1' and Cin = '0' else
            '1' when a = '0' and b = '1' and Sin = '0' and Cin = '1' else
            '1' when a = '1' and b = '0' and Sin = '0' and Cin = '1' else
            '1' when a = '1' and b = '0' and Sin = '1' and Cin = '0' else
            '1' when a = '1' and b = '1' and Sin = '0' and Cin = '0' else
            '1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
            '0';
    Cout <= '1' when a = '0' and b = '0' and Sin = '1' and Cin = '1' else
            '1' when a = '0' and b = '1' and Sin = '1' and Cin = '1' else
            '1' when a = '1' and b = '0' and Sin = '1' and Cin = '1' else
            '1' when a = '1' and b = '1' and Sin = '0' and Cin = '1' else
            '1' when a = '1' and b = '1' and Sin = '1' and Cin = '0' else
            '1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
            '0';

end mult;

将其用作 NxM 乘法器中的一个组件:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

entity generic_mult is
        generic (bits: integer);
 port (
  a     :  in std_logic_vector(bits-1 downto 0);
  b     :  in std_logic_vector(bits-1 downto 0);
  answer:  out std_logic_vector(bits*2-1 downto 0)      --sum-out
  );
end entity generic_mult;

architecture behavioral of generic_mult is

 component mult is
  port (
    a    :  in std_logic;
    b    :  in std_logic;
    Sin  :  in std_logic;       --sum-in
    Cin  :  in std_logic;       --carry-in
    Sout :  out std_logic;      --sum-out
    Cout :  out std_logic       --carry-out
  );
 end component;

        type mem_word  is array (0 to bits) of std_logic_vector(bits downto 0);

        signal  carry_internal : mem_word;
        signal  sum_internal : mem_word;

  begin
    this_is_label: for N in 1 to bits generate --Im sorry, my labels are horrible :(
        this_is_label3: for M in 0 to bits-1 generate

            this_is_label2: mult
          port map (
            a => a(N-1),
            b => b(M),
            Cin => carry_internal(M)(N),
            Cout => carry_internal(M+1)(N),
            Sin => sum_internal(M)(N),
            Sout => sum_internal(M+1)(N-1)
        );
    end generate;
end generate;
    labellll: for N in 0 to bits-1 generate
        sum_internal(N+1)(N) <= carry_internal(N)(N);
    carry_internal(0) <= (others => '0');
    sum_internal(0)   <= (others => '0');

    answer(bits*2-1) <= carry_internal(bits)(bits);
    answer(bits downto 0) <= sum_internal(bits);
    end generate;
end behavioral;

及其测试平台:

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

entity NM_mult_tb is
end NM_mult_tb;

architecture behavioral of NM_mult_tb is
    component generic_mult

        generic (bits: integer := 4);
 port (
  a     :  in std_logic_vector(bits-1 downto 0);
  b     :  in std_logic_vector(bits-1 downto 0);
  answer:  out std_logic_vector(bits*2-1 downto 0)      --sum-out
  );
    end component;
   --declaring inputs and initializing them
        signal a  :  std_logic_vector(3 downto 0) :="0101";
        signal b  :  std_logic_vector(3 downto 0) :="1010";
        signal Sin:  std_logic_vector(3 downto 0) :="0000";
        signal Cin:  std_logic := '0';
   --declaring outputs and initializing them
        signal answer :  std_logic_vector(7 downto 0);  --sum-out
        signal correct:  std_logic;                     --carry-out

BEGIN
    -- Instantiating the Design Under Test (DUT)
   dut: generic_mult
        GENERIC MAP (4)
        PORT MAP (
          a => a,
          b => b,
         answer => answer
        );

   -- Stimulus process
    correct <= '1' when to_integer(unsigned(a))*to_integer(unsigned(b)) = 
to_integer(unsigned(answer)) else '0';
  stim_proc: process
   begin
        wait for 1 ns;
        a <= a + 1;
        if a = "0" then b <= b + 1; end if;
  end process;

END;

当我模拟它时,我发现进位和进出总和有问题,我的答案中有未定义的位:

如果您已经阅读了我的 post 到目前为止,非常感谢您的关注。如果有人能抽出时间帮助我解决我的问题,我将不胜感激!

此致,
迷茫的VHDL初学者

图书馆

因此,要进行算术运算,您只需要一个算术库:numeric_std。不要使用 std_logic_arith,因为它不是标准化的,因此实现之间的行为可能不同。

那么std_logic_unsigned可能会有风险。 Jim Lewis 解释说 使用它可能是个好主意,但我认为你不应该这样做。最好使用 integerunsignedsigned 数据类型进行所有比较。


实体mult

您正在实施的是查找表。组合逻辑语句。这不是算术,所以不需要算术库。

但是,您可以简化代码。 让我们以this description ar 参考。

可以使用逻辑运算符定义 1x1 乘法器(基于 here 描述的全加器):

architecture rtl of mult is
    signal FA_a, FA_b : std_logic;
begin
    FA_a <= Sin;
    FA_b <= a AND b;
    Sout <= FA_a XOR FA_b XOR Cin;
    Cout <= (FA_a AND FA_b) OR (Cin AND (FA_a XOR FA_b));
end architecture;

或者跳过这一切并使用加法运算符,它会为您处理逻辑。

architecture rtl of mult is
    use ieee.numeric_std.all;
    signal FA_a, FA_b, FA_Cin : unsigned(1 downto 0) := (others => '0');
    signal FA_out : unsigned(1 downto 0);
begin
    FA_a(0) <= Sin;
    FA_b(0) <= a AND b;
    FA_Cin(0) <= Cin;
    FA_out <= FA_a + FA_b + FA_Cin;
    Sout <= FA_out(0);
    Cout <= FA_out(1);
end architecture;

实体generic_mult

首先,您的乘数是 MxM,而不是 MxN。 接下来你在评论中抱怨你的标签......将花费同样多的努力来改变它们;)。

关于您的实现,您在 labellll 生成块中多次分配信号。应该是:

labellll: for N in 0 to bits-1 generate
    sum_internal(N+1)(N) <= carry_internal(N)(N);
end generate;

carry_internal(0) <= (others => '0');
sum_internal(0)   <= (others => '0');

answer(bits*2-1) <= carry_internal(bits)(bits);
answer(bits downto 0) <= sum_internal(bits);

但这不是最大的问题,可以解决。 您确实遇到的问题与多个驱动程序有关。在 this_is_label2 中,您有以下行:

Sout => sum_internal(M+1)(N-1)

并且在 labellll 中有一行:

sum_internal(N+1)(N) <= carry_internal(N)(N);

两条语句,都在给sum_internal赋值。如果同时分配 10,这将解析为 X

但这不是必须的,因为这是你设计错误的结果。请再次查看 my link 以了解应如何实现乘数。我不会为你做(这并不难,可能是你的家庭作业。如果其他人为你做家庭作业,你什么也学不到。;))


测试平台

您正在组合 unsigned 算术 (to_integer(unsigned(a))*to_integer(unsigned(b))) 与 std_logic_vector 算术 (a <= a + 1;)。不要那样做。最好只使用 unsigned.


使用乘法运算符

如 pev.hall 所述,您可以简化一切并使用 numeric_std 包中的乘法运算符。

entity generic_mult is
    generic (
        M: positive;
        N: positive
        );
    port (
        a : in std_logic_vector(M-1 downto 0);
        b : in std_logic_vector(N-1 downto 0);
        answer : out std_logic_vector(M+N-1 downto 0)
    );
end entity;

architecture rtl of generic_mult is
    use ieee.numeric_std.all;
begin
    answer <= std_logic_vector(unsigned(a)*unsigned(b));
end architecture;