最近做了一个四位的booth乘法器的实验,在这里记录一下我的实验过程,需要说明的是,我认为最好的方法是使用有限状态机的方法(做完之后才知道),我这里的方法是根据比较的结果来生成使能信号,进而控制运算模块的运算。
算法流程
先简单介绍一下在这篇文章中booth乘法的前期准备及算法流程:
首先,符号是会参与运算的,booth乘法也是计算补码的,得出的结果也是补码。
1、先对被乘数进行符号拓展,就是将被乘数变成双符号位。
2、部分积寄存器pi置0,乘数寄存器放入乘数,但是乘数寄存器需要在最后一位添加一位0,所以乘数寄存器是有5位的,还需要一个计数器来计数运算了多少次。
3、比较乘数寄存器的末两位,如果两位是00或者11,则部分积寄存器和乘数寄存器都右移一位,如果是01,则部分积寄存器加乘数的补码,部分积寄存器和乘数寄存器再右移一位,如果是10,则部分积寄存器减乘数的补码,部分积寄存器和乘数寄存器再右移一位。同时计数器加1。(这里的右移一位会把部分积寄存器的最后一位移入乘数寄存器,而乘数寄存器的最后一位会被舍弃)
4、重复4次(4位的乘法器是比较4次),结果的低4位是乘数寄存器的高四位,结果的高3位是部分积寄存器的低3位。(这里结果取了7位,因为取8位也只不过是多了一位的符号位)
比较结果 | 运算 |
---|---|
00 | 部分积寄存器和乘数寄存器都右移一位 |
01 | 则部分积寄存器加乘数的补码,部分积寄存器和乘数寄存器再右移一位 |
10 | 部分积寄存器减乘数的补码,部分积寄存器和乘数寄存器再右移一位 |
11 | 部分积寄存器和乘数寄存器都右移一位 |
使能信号表如下:
乘数低两位比较结果 | 使能信号g |
---|---|
00 | 00 |
11 | 00 |
01 | 01 |
10 | 10 |
得出最终实现方案的尝试
下面是我做的第一个没有用计数器的方案,这是一个存在问题的方案。
module subtracter(input [3:0]X1,X2,output [6:0]Y
);
reg [9:0]p=0;
reg [4:0]x_0;
reg [4:0]x_1;
reg z1,c1,z2,c2,z3,c3,z4,c4,c5,z5;
reg [3:0]t;
always @ (*) begin
p=10'b0;
p[4:1]=X2; //这里是一个全加器,用来算乘数[-x]补码,因为可能是我本地软件的原因,我用+运算符算不出来,所以只能这样。
{c1,z1}=!X1[0]+1;
{c2,z2}=!X1[1]+c1;
{c3,z3}=!X1[2]+c2;
{c4,z4}=!X1[3]+c3;
t={z4,z3,z2,z1};
x_0={!X1[3],t};
x_1={X1[3],X1};
repeat (4) begin
if(p[1]^~p[0]) begin
p={p[9],p[9:1]};
end
else if(p[1]===1'b0) begin
{c1,z1}=p[5]+x_1[0]+1'b0;
{c2,z2}=p[6]+x_1[1]+c1;
{c3,z3}=p[7]+x_1[2]+c2;
{c4,z4}=p[8]+x_1[3]+c3;
{c5,z5}=p[9]+x_1[4]+c4;
p[9:5]={z5,z4,z3,z2,z1};
p={p[9],p[9:1]};
end
else begin
{c1,z1}=p[5]+x_0[0]+1'b0;
{c2,z2}=p[6]+x_0[1]+c1;
{c3,z3}=p[7]+x_0[2]+c2;
{c4,z4}=p[8]+x_0[3]+c3;
{c5,z5}=p[9]+x_0[4]+c4;
p[9:5]={z5,z4,z3,z2,z1};
p={p[9],p[9:1]};
//p[8]=1'b1;
end
end
end
assign Y=p[7:1];
endmodule
问题
可以发现的是,这里没有用计数器而是用了repeat来让模块重复运算4次,这样就存在着在综合的过程中加法器会出现不确定个数的情况,可能会有多个加法器,在芯片的加法器个数有限的情况下,显然是不符合实际的,因此我改用了生成使能信号来告诉运算模块进行专门运算,这样就能够解决上述的问题。但是我的这种方法还是用了两个加法器。
接下来就是最终方案:
module subtracter(input [3:0]X1,X2,output [6:0]Y,input CLK
);
reg [9:0]p=0;//我将乘数寄存器与部分积寄存器定义为一个10位的寄存器类型的数据
reg [4:0]x_0;//用来存拓展符号位之后的[-x]补码
reg [4:0]x_1;//用来存拓展符号位之后的[x]补码
reg [1:0]f; //用来存乘数寄存器低两位,其实可以不用
reg [1:0]g;//使能信号寄存器
reg [3:0]t;
wire [9:0]p_1;//用来接收运算模块的结果
reg re;//使能信号,初始化各个寄存器的值
integer count;//计数器
reg z1,c1,z2,c2,z3,c3,z4,c4,c5,z5;
always @ (X1 or X2) begin
re=1'b1; //当乘数或者被乘数发生变化的时候,这个信号会置1
end
always @ (posedge CLK) begin
if (re) begin
p=10'b0;
p[4:1]=X2;
{c1,z1}=!X1[0]+1;
{c2,z2}=!X1[1]+c1;
{c3,z3}=!X1[2]+c2;
{c4,z4}=!X1[3]+c3;
t={z4,z3,z2,z1};
x_0={!X1[3],t};
x_1={X1[3],X1};
count=0;
re=1'b0;
end
else begin
f={p[1],p[0]};
case(f)
2'b00: g=2'b00;
2'b11: g=2'b00;
2'b01: g=2'b01;
2'b10: g=2'b10;
default: g=2'b11;//表示保持之前的p寄存器的结果
endcase
if(count==4||count>4) begin
g=2'b11;//当运算过4次之后,运算不会进行
end
count=count+1;
end
end
AL ALU (x_0,x_1,g,p,p_1,CLK);
always @ (CLK) begin
p=p_1;
end
assign Y=p_1[7:1];
endmodule
module AL(input [4:0]x_0,x_1,input [1:0]g,input [9:0]p,output reg[9:0]p_1,input CLK
);
reg c1,c2,c3,c4,c5,z1,z2,z3,z4,z5;
always @ (posedge CLK) begin
p_1=p;
case (g)
2'b00: begin
p_1={p_1[9],p_1[9:1]};
end
2'b01: begin
{c1,z1}=p[5]+x_1[0]+1'b0;
{c2,z2}=p[6]+x_1[1]+c1;
{c3,z3}=p[7]+x_1[2]+c2;
{c4,z4}=p[8]+x_1[3]+c3;
{c5,z5}=p[9]+x_1[4]+c4;
p_1[9:5]={z5,z4,z3,z2,z1};
p_1={p_1[9],p_1[9:1]};
end
2'b10: begin
{c1,z1}=p[5]+x_0[0]+1'b0;
{c2,z2}=p[6]+x_0[1]+c1;
{c3,z3}=p[7]+x_0[2]+c2;
{c4,z4}=p[8]+x_0[3]+c3;
{c5,z5}=p[9]+x_0[4]+c4;
p_1[9:5]={z5,z4,z3,z2,z1};
p_1={p_1[9],p_1[9:1]};
end
2'b11: p_1=p_1;
default: p_1=p_1;
endcase
end
endmodule
验证
仿真能够看出模块的逻辑功能是否正确,在仿真的时候,我们的乘法器需要至少4个时钟上升沿才能够算完,如果不满足的话是会显示中间计算结果的。
module one_true_from_subtracter_bench;
reg [3:0]X1,X2;
wire [6:0]Y;
reg CLK;
initial
begin
CLK=0;
end
always #10
CLK=~CLK;
one_true_from_subtracter U0 (X1,X2,Y,CLK);
initial begin
X1=4'b1101;X2=4'b0101;
#200 X1=4'b1001;X2=4'b1100;
#150 X1=4'b1111;X2=4'b1100;
#150 X1=4'b1101;X2=4'b0101;
#150 X1=4'b1000;X2=4'b1011;
//#1 X1=4'b1101;X2=4'b1010;
end
endmodule
波形图如下,可以看出我们的模块逻辑功能是正确的。经过4个时钟周期,算出来结果,而在没有新的数据输入的时候,结果是会保持的。
我没有综合,无法得知综合的结果,因为我电脑的问题,综合的时候软件会闪退(哭~)。
可能存在的问题:
我的方法不是一个最佳的解决方式,我用了两个加法器,并且没有综合,不知道综合的时候会不会有问题。
总结
这次的实验做下来,在编程中我其实出现了许多的问题,比如说在判断条件的小于等于,如果用 ‘<=’ 是不行的,在verilog里面这个是非阻塞赋值的符号。我一开始的第一种实现方案其实还是用了软件的思维去写硬件,仿真出来结果也确实是对的。但是硬件与软件不同,虽然说软件跟硬件用代码能够实现某种东西,但是在硬件里面,还需要考虑到的是能不能综合,实际做成电路有没有难度,会不会造成歧义,模块的是否有必要重复存在,成本会不会更高等等。