一、选题目的
1、学会使用quartus软件设计电路及对其进行仿真,设计实现8位二进制乘法器电路。
2、学习并掌握8位二进制乘法器的原理、设计、分析和测试方法。
二、设计目标
采用移位相加的方法实现8位二进制乘法器电路。用户通过输入两个8位二进制数Y和B,八位乘法器可以实现其乘积,并输出结果。
三、实现方案(包括原理框图和HDL设计流程图)
该乘法器是由8位二进制加法器构成的以时序方式设计的乘法器,通过逐项移位相加原理来实现。用乘数的各位数码,从低位开始依次与被乘数相乘,每相乘一次得到的积称为部分积,将第一次(由乘数最低位与被乘数相乘)得到的部分积右移一位并与第二次得到的部分积相加,将加得的和右移一位再与第三次得到的部分积相加,再将相加的结果右移一位与第四次得到的部分积相加。直到所有的部分积都被加过一次即可得到相应的乘积。
在这里,我们用Y代表被乘数,B寄存器存放乘数N,A累加寄存器存放部分积,而A和B相级联又构成了一个16bit的移位寄存器,每次移位时A中最低位的数被移入B的最高位,经过8次部分积相加位的操作,完成1次乘法运算,乘数N恰好被移出寄存器B,寄存器B中保存的就是运算积的低8位数据,而寄存器A中保存的是运算积的高8位数据。
由于乘数的每一位不是0就是1 ,对应的部分积不是0就是被乘数本身,所以实际作部分积相加这一步时,只要根据乘数的对应位判断:如该位为1,则将累加器中的数据加上被乘数再移位;如该位为0时,就不加被乘数而直接移位。
移位相加的次数用一个时钟控制计数器来控制,由于第一个时间脉冲被用于A累加寄存器的置数,并无移位操作,故设计电路时采用了模为9的计数器来实现8位移位操作。当计数器计得9个数时,发出一个信号,使电路停止操作,并输出运算结果。
两个n位二进制数相乘的结果最多可以有2n位的二进制数。
例如:被乘数(M7M6M5M4M3M2M1M0)和乘数(N7N6N5N4N3N2N1N0)
分别为11010101和10010011,其计算过程如下图(a):
原理框图和简单流程图如下图(b)和图(c):
四、设计过程
1、模9计数器cnt9的设计
模9计数器由时钟控制,开始时由异步置数端RST进行清置“1”操作。当RST为高电平且使能端EN为高电平时,每来一个时钟上升沿,计数器计一个数,直到内部变量Q计到“10”时,即在第九个上升沿时,输出端COUT输出1,变量Q回到初始值“1”。
该模块元件的程序如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY cnt9 IS
PORT(CLK,RST,EN:IN STD_LOGIC;
COUT:OUTSTD_LOGIC);
END cnt9;
ARCHITECTURE behav OF cnt9IS
BEGIN
PROCESS(CLK,RST,EN)
VARIABLE Q:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
IF RST='0' THEN Q:="0001";
ELSIF CLK'EVENT AND CLK='1' THEN
IF EN='0'THEN
IFQ<"1010" THEN Q:=Q+1;
ELSE Q:="0001";
END IF;
END IF;
END IF;
IF Q="1010" THEN COUT<='1';
ELSE COUT<='0';
END IF;
END PROCESS;
END behav;
2、具有使能端的d触发器dffen的设计
D触发器由使能端EN控制,当EN为低电平时对输出端Q进行清零操作,当EN为高电平时将输入端D赋给输出端Q。
该模块元件的程序如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY dffen IS
PORT(EN:IN STD_LOGIC;
D:INSTD_LOGIC_VECTOR(7 DOWNTO 0);
Q:OUTSTD_LOGIC_VECTOR(7 DOWNTO 0));
END dffen;
ARCHITECTURE behav OF dffenIS
BEGIN
PROCESS(D,EN)
BEGIN
IF EN='0' THEN Q<=(OTHERS=>'0');
ELSE Q<=D;
END IF;
END PROCESS;
END behav;
3、累加寄存器SHFTA的设计
累加寄存器A虽然与寄存器B相级联构成16位移位寄存器,但就累加寄存器A本来而言并不是严格意义上的寄存器。SHFTA工作时先由清零端CLR高电平清零,之后每一个时钟上升沿置一次数,用于存放部分积的和。输出端DOUT为一个8位二进制数,其最高位存放右移值SR,在乘法器电路中SR存放部分积和的进位;其后7位存放部分积和的高7位,形成模拟的“移位”操作。输出端QB存放部分积的最低位,用于向B寄存器移位。
该模块元件的程序如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY SHFTA IS
PORT(CLK,CLR,SR:IN STD_LOGIC;
DIN:INSTD_LOGIC_VECTOR(7 DOWNTO 0);
QB:OUTSTD_LOGIC;
DOUT:OUTSTD_LOGIC_VECTOR(7 DOWNTO 0));
END SHFTA;
ARCHITECTURE behav OF SHFTAIS
SIGNAL REG8:STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL Q:STD_LOGIC;
BEGIN
PROCESS(CLK,CLR)
BEGIN
IF CLR='1' THENREG8<=(OTHERS=>'0');Q<='0';
ELSIF CLK'EVENT ANDCLK='1' THEN
REG8<=DIN;Q<=SR;
END IF;
DOUT<=Q®8(7 DOWNTO 1);
END PROCESS;
QB<=REG8(0);
ENDbehav;
4、移位寄存器B的设计
移位寄存器B工作时先由输入端LOAD高电平置数,置入乘数B,再由时钟脉冲上升沿控制移位操作,先把内部信号REG8的高7位赋给它的低7位,再把输入端SR接收到的值赋给REG8的最高位,即把A的最低位移入B中。为了在输出最后结果时,乘积的低8位和高8位能够正常的连接,输出端DOUT的设计也与A规则相同,输出最高位为SR,低7位为REG8高7位的8位二进制数,QB输出B的最低位,用于控制加法器中从取出的右移后的部分积的和是与0相加还是与被乘数相加。
该模块元件的程序如下:
LIBRARY IEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY SHFTB IS
PORT(CLK,LOAD,SR:IN STD_LOGIC;
DIN:IN STD_LOGIC_VECTOR(7 DOWNTO 0);
QB:OUT STD_LOGIC;
DOUT:OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END SHFTB;
ARCHITECTURE behav OF SHFTBIS
SIGNAL REG8:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS(CLK,LOAD)
BEGIN
IF LOAD='1' THENREG8<=DIN;
ELSE IF CLK'EVENTAND CLK='1' THEN
REG8(6 DOWNTO0)<=REG8(7 DOWNTO 1);REG8(7)<=SR;
END IF;
END IF;
END PROCESS;
QB<=REG8(0);
DOUT<=SR®8(7DOWNTO 1);
END behav;
5、8位二进制乘法器的顶层设计
其顶层电路图如图:
如图所示,当异步输入端LOAD为高电平时,累加寄存器A清零,同时移位寄存器置乘数,之后每次时钟上升沿到来时,由B中数据最低位控制dffen的EN使能端,当EN为0时,输出0,当EN为1时,输出被乘数Y,由此可实现从A中取出的右移过的部分积的和是与0或被乘数Y相加的判断和选择,即实现了被乘数Y与0相乘或与1相乘的操作。B寄存器每次移位时,最高位置入的均为A中部分积的和的最低位,即实现A与B的级联移位操作。部分积的和移位8次完成时,即计数器计9次时间脉冲时,计数器的COUT端输出1到使能端EN,使计数器停止置数,同时控制乘积输出端的两个普通d触发器输出分别输出乘积的高8位和低8位。。
五、遇到问题及解决方法
1、一开始从电路尽可能简洁这方面考虑,想尽可能使用少一些的模块或者尽可能使用相同的模块简化电路设计,所以花了大量的时间试图让同一个移位寄存器模块实现累加器A和移位寄存器B的功能,但是由于A和B两寄存器工作原理很不相同,导致原理图连线反而更加复杂和逻辑错乱。
解决方法:放弃用同一寄存器同时实现两个功能的想法,改而设计不同寄存器模块SHFTA和SHFTB分别实现累加寄存器A和移位寄存器B的功能。
2、每一次进行累加操作时,部分积需要先移位,再与下一个部分积相加,而累加寄存器A每次时间脉冲到来时只实现置数操作,当我想改变程序实现累加寄存器A在同一时间上升沿既置数又移位时,却发现寄存器A根本不能工作,输出0。据分析,出现这种的原因在于在同一时间上升沿同时实现对同一个内部变量的操作会产生冲突,导致寄存器A不能正常工作。
解决方法:放弃让累加寄存器进行移位操作,改用虚拟“移位”的方式,让8位二进制输出端DOUT的最高位置“右移输入端”SR的值,即将加法器的进位端置最高位,而后7位数据置内部变量REG8的前7位数,实现虚拟的“移位”操作。
3、在进行乘法操作时,计数器cnt9从0计到9,理应在第九个时间脉冲时COUT输出1,控制输出端输出乘积,可是在进行仿真时我发现,COUT端在第八个时间脉冲到来时总要有一个窄脉冲出现(见最后一道波形),导致输出两次乘积。据分析,出现这种情况的原因在于计数器从7计到8,即从“0111”计到“1000”时,由于数据翻转出现延迟,会短暂的出现“1001”,导致计数器感应到“9”,从而COUT输出1,控制输出端输出乘积。
其仿真波形如下:
解决方法:改变计数器从0计到9的计数方式,使其从1计到10,即从“0001”计到“1010”,避免了由于翻转不及时导致的计数错误。
六、实现结果
输入 8位二进制数的乘数B和被乘数Y,该乘法器实现其乘积,并分高8位和低8位输出结果。
仿真波形如下:
如图所示,在第九个时间脉冲上升沿到来时,输出端h输出乘积的高8位,输出端l输出乘积的第8位。
七、对该课程的实施意见及建议
在程序设计和原理图设计的过程中,我通过对quartus的学习和使用,锻炼了自己的编程能力,也学会了如何在遇到错误的时候冷静分析原因,利用对中间量的观测对程序进行调试和改进,对EDA课程和HVDL语言的理解有了很大的提升。