用VHDL实现定点无符号数阵列乘法器
实现阵列乘法器前,我们先想一想如果手算二进制的乘法,是如何进行的呢?下面给出计算过程:
可以看到:我们是把乘数的每一位与被乘数进行相与操作,然后进行相加操作。而实际的阵列乘法器也是这样实现的。我们这里实现一个4*4的阵列乘法器。
容易想到,阵列乘法器是由以下模块拼接而成的:
实现4*4阵列乘法器只需将16个上述模块拼接:
##一、 基本模块说明
一个基本的模块由与门和一位全加器组成。与门不必多说,我们主要想一想一位全加器如何实现。首先一位全加器的输入端口是两个bit位(记为a和b)和低位的进位(记为cin),输出端口是本位和(记为s)以及向高位的进位(记为cout)。以下是一位全加器的真值表:
可以看到当a、b、cin中有奇数个1时,本位和s为1;偶数个1时,本位和s为0,故本位和是三个输入的异或,即s = a xor b xor cin。
而当a、b、cin中至少有两个1时,向高位的进位cout是1,否则是0。故进位表达式为cout = (a and b) or (a and cin) or (b and cin)。
有了以上的基础,我们就可以用硬件描述语言实现基本模块,以下是代码实现:
s <= (a and b) xor p xor cin;
cout <= ((a and b) and p) or ((a and b) and cin) or (p and cin);
二、模块连接
给每一个模块定义用来存储向高位的进位和部分积信息的信号:
signal temp1 : std_logic_vector(3 downto 0);--第1行部分积
signal temp2 : std_logic_vector(3 downto 0);--第2行部分积
signal temp3 : std_logic_vector(3 downto 0);--第3行部分积
signal temp4 : std_logic_vector(3 downto 0);--第4行部分积
signal ctemp1 : std_logic_vector(3 downto 0);--第1行进位
signal ctemp2 : std_logic_vector(3 downto 0);--第2行进位
signal ctemp3 : std_logic_vector(3 downto 0);--第3行进位
signal ctemp4 : std_logic_vector(3 downto 0);--第4行进位
然后将各个模块连接:
其中第一行的部分积都为0,从第二行开始每一行的前3位部分积来自上一行模块的本位和,最后1位部分积来自上一行的最后一个模块的进位。
每一行的进位依次传递,每行最低位的进位是0。
以下是具体代码:
u1 : faddmul port map(x(0),y(0),'0','0',temp1(0),ctemp1(0));
u2 : faddmul port map(x(1),y(0),'0',ctemp1(0),temp1(1),ctemp1(1));
u3 : faddmul port map(x(2),y(0),'0',ctemp1(1),temp1(2),ctemp1(2));
u4 : faddmul port map(x(3),y(0),'0',ctemp1(2),temp1(3),ctemp1(3));
u5 : faddmul port map(x(0),y(1),temp1(1),'0',temp2(0),ctemp2(0));
u6 : faddmul port map(x(1),y(1),temp1(2),ctemp2(0),temp2(1),ctemp2(1));
u7 : faddmul port map(x(2),y(1),temp1(3),ctemp2(1),temp2(2),ctemp2(2));
u8 : faddmul port map(x(3),y(1),ctemp1(3),ctemp2(2),temp2(3),ctemp2(3));
u9 : faddmul port map(x(0),y(2),temp2(1),'0',temp3(0),ctemp3(0));
u10 : faddmul port map(x(1),y(2),temp2(2),ctemp3(0),temp3(1),ctemp3(1));
u11 : faddmul port map(x(2),y(2),temp2(3),ctemp3(1),temp3(2),ctemp3(2));
u12 : faddmul port map(x(3),y(2),ctemp2(3),ctemp3(2),temp3(3),ctemp3(3));
u13 : faddmul port map(x(0),y(3),temp3(1),'0',temp4(0),ctemp4(0));
u14 : faddmul port map(x(1),y(3),temp3(2),ctemp4(0),temp4(1),ctemp4(1));
u15 : faddmul port map(x(2),y(3),temp3(3),ctemp4(1),temp4(2),ctemp4(2));
u16 : faddmul port map(x(3),y(3),ctemp3(3),ctemp4(2),temp4(3),ctemp4(3));
三、整体代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity faddmul is
port(
a : in std_logic;
b : in std_logic;
p : in std_logic;
cin : in std_logic;
s : out std_logic;
cout: out std_logic
);
end faddmul;
architecture Behavioral of faddmul is
begin
s <= (a and b) xor p xor cin;
cout <= ((a and b) and p) or ((a and b) and cin) or (p and cin);
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mul is
port(
x : in std_logic_vector(3 downto 0);
y : in std_logic_vector(3 downto 0);
sout : out std_logic_vector(7 downto 0)
);
end mul;
architecture Behavioral of mul is
component faddmul
port(
a : in std_logic;
b : in std_logic;
p : in std_logic;
cin : in std_logic;
s : out std_logic;
cout: out std_logic
);
end component;
signal temp1 : std_logic_vector(3 downto 0);
signal temp2 : std_logic_vector(3 downto 0);
signal temp3 : std_logic_vector(3 downto 0);
signal temp4 : std_logic_vector(3 downto 0);
signal ctemp1 : std_logic_vector(3 downto 0);
signal ctemp2 : std_logic_vector(3 downto 0);
signal ctemp3 : std_logic_vector(3 downto 0);
signal ctemp4 : std_logic_vector(3 downto 0);
begin
u1 : faddmul port map(x(0),y(0),'0','0',temp1(0),ctemp1(0));
u2 : faddmul port map(x(1),y(0),'0',ctemp1(0),temp1(1),ctemp1(1));
u3 : faddmul port map(x(2),y(0),'0',ctemp1(1),temp1(2),ctemp1(2));
u4 : faddmul port map(x(3),y(0),'0',ctemp1(2),temp1(3),ctemp1(3));
u5 : faddmul port map(x(0),y(1),temp1(1),'0',temp2(0),ctemp2(0));
u6 : faddmul port map(x(1),y(1),temp1(2),ctemp2(0),temp2(1),ctemp2(1));
u7 : faddmul port map(x(2),y(1),temp1(3),ctemp2(1),temp2(2),ctemp2(2));
u8 : faddmul port map(x(3),y(1),ctemp1(3),ctemp2(2),temp2(3),ctemp2(3));
u9 : faddmul port map(x(0),y(2),temp2(1),'0',temp3(0),ctemp3(0));
u10 : faddmul port map(x(1),y(2),temp2(2),ctemp3(0),temp3(1),ctemp3(1));
u11 : faddmul port map(x(2),y(2),temp2(3),ctemp3(1),temp3(2),ctemp3(2));
u12 : faddmul port map(x(3),y(2),ctemp2(3),ctemp3(2),temp3(3),ctemp3(3));
u13 : faddmul port map(x(0),y(3),temp3(1),'0',temp4(0),ctemp4(0));
u14 : faddmul port map(x(1),y(3),temp3(2),ctemp4(0),temp4(1),ctemp4(1));
u15 : faddmul port map(x(2),y(3),temp3(3),ctemp4(1),temp4(2),ctemp4(2));
u16 : faddmul port map(x(3),y(3),ctemp3(3),ctemp4(2),temp4(3),ctemp4(3));
sout(7) <= ctemp4(3);
sout(6) <= temp4(3);
sout(5) <= temp4(2);
sout(4) <= temp4(1);
sout(3) <= temp4(0);
sout(2) <= temp3(0);
sout(1) <= temp2(0);
sout(0) <= temp1(0);
end Behavioral;
四、测试代码
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY MULT8B_vhd_tst IS
END MULT8B_vhd_tst;
ARCHITECTURE MULT8B_arch OF MULT8B_vhd_tst IS
SIGNAL A : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL B : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL RESULT : STD_LOGIC_VECTOR(7 DOWNTO 0);
constant a_period:time:=20 ns;
COMPONENT mul
port(
x : in std_logic_vector(3 downto 0);
y : in std_logic_vector(3 downto 0);
sout : out std_logic_vector(7 downto 0)
);
END COMPONENT;
BEGIN
i1 : mul
PORT MAP (
x => A,
y => B,
sout => RESULT
);
A_Unit : PROCESS
BEGIN
A<="0001";
wait for a_period;
A<="0011";
wait for a_period;
A<="0111";
wait for a_period;
END PROCESS a_Unit;
B_Unit : PROCESS
BEGIN
B<="0010";
wait for a_period;
B<="0100";
wait for a_period;
B<="1000";
wait for a_period;
END PROCESS B_Unit;
END MULT8B_arch;
五、测试结果
可以看到乘法功能实现正确。