传统乘法器设计
传统乘法器我们以传统的乘法竖式计算为例说明一下。以10*9为例,即二进制1010*1001有
1 0 1 0
X 1 0 0 1
--------------
1 0 1 0
0 0 0 0
0 0 0 0
1 0 1 0
------------------------
1 0 1 1 0 1 0
1011010即64+16+8+2=90与十进制的计算结果相同,所以十进制的乘法竖式计算在二进制也是成立的。
1010*1001根据乘法分配律可以分解为1010*1000+1001*1,分开每一个位来计算。在这里我们设乘数10为a[3:0]=1010,乘数9为b[3:0]=1001,首先第一步计算a[3:0]*b[0]得到1010,第二步和第三步计算a[3:0]*b[1]和a[3:0]*b[2]都为0,最后一步计算a[3:0]*b[3]=1010,此处b[3]因为为低位起第4位,所以后面应该还跟3个0,即为1010000依次把结果加起来,便可以获得最后的结果。
在这里,我们以一个8*8的乘法器为例子说明,两个乘数为8位,最后的积最多为16位。
module mul8(clk,rst_n,a,b,y,start,done);
input clk;
input rst_n;
input [7:0]a;//8位乘数a
input [7:0]b;//8位乘数b
input start;//开始信号,如果没有start信号,则乘法器不工作
output [15:0] y;//16位的积
output done;//完成乘法时输出一个方波表示完成了一次乘法计算
reg[7:0]a_reg;//锁存乘数a的值计算
reg[7:0]b_reg;//锁存乘数b的值计算
reg[15:0]y_reg;//积的寄存器
reg[3:0] i; //状态寄存器
reg done;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
a_reg<=8'd0;
b_reg<=8'd0;
y_reg<=16'd0;
done<=1'b0;
i<=4'd0;
end
else if(start)
case (i)
0:
begin
a_reg<=a;//把乘数a锁存进a_reg
b_reg<=b;//把乘数a锁存进b_reg
y_reg<=16'd0;//清0,避免上一次的乘法所得的积保存在这里
i<=i+4'd1;
end
1,2,3,4,5,6,7:begin
if(a_reg[i-1])
y_reg<={1'b0,y_reg[14:7]+b_reg,y_reg[6:1]};
else
y_reg<=y_reg>>1;
i<=i+4'd1;
end
8:begin
if(a_reg[7])
y_reg<={y_reg[15:7]+b_reg,y_reg[6:0]};
i<=i+4'd1;
end
9:begin
done<=1'b1;
i<=i+4'd1;
end
10:begin
done<=1'b0;
i<=4'd0;
end
endcase
end
assign y=y_reg;
endmodule
这个模块的重点在1,2,3,4,5,6,7:begin
if(a_reg[i-1])
y_reg<={1'b0,y_reg[14:7]+b_reg,y_reg[6:1]};
else
y_reg<=y_reg>>1;
i<=i+4'd1;
end
8:begin
if(a_reg[7])
y_reg<={y_reg[15:8]+b_reg,y_reg[7:0]};
i<=i+4'd1;
end
下面我们来分析一下这段逻辑
我们计算 10101010*11010111的时候
1 0 1 0 1 0 1 0
X 1 1 0 1 0 1 1 1
---------------------------
1 0 1 0 1 0 1 0 (第1步)
1 0 1 0 1 0 1 0 (第2步)
..............
1 0 1 0 1 0 1 0 (第8步)
这里便是i=1时我们所做的事情,,即a_reg[0]=1,把这个结果装进去了y_reg的高8位后,再向右移1位,相当于这时y_reg=0(101_0101_0)000_0000,括号中即为a_reg,因为乘法分配律的缘故即可看成
10101010*11010111=10101010*(10000000+1000000+10000+100+10+1),所以我们只考虑a_reg[0]*b_reg后最后变成怎么样。当i=2时,y_reg=00(10_1010_10)00_0000,
i=3时,y_reg=000(1_0101_010)0_0000,如此类推到了i=7时变成y_reg=0000_000(1_0101_010)0,我们始终关注着括号中的数据,因为这是a_reg[0]*b_reg,
到了最后一步i=8,y_reg=0000_0000_(1010_1010)刚好这就是我们竖式计算上的第一步,同理i=2时,我们计算的是a_reg[1]*b_reg,经过7次移位后,最后会变成y_reg=0000_000(1_0101_010)0,同理之后的过程都是一样的逻辑。i=8的时候,我们只用需要直接高9位加上b_reg,不需要再移位了,可以看到第8步操作。
这个传统的乘法器的模块实现,通过仿真,也得到了和理想中一样的结果。
文章评论(0条评论)
登录后参与讨论