二进制乘法器的主要操作就是加发法操作和移位操作。
我们知道计算机存储数据都是以二进制形式进行存储的,以4位数为例解释一下被乘数和乘数如何操作,首先把被乘数扩展成2倍的位宽,高4位为0,低4位为被乘数,结果为8为0,
先检测乘数的最低位,如果是1,则被乘数和结果想加,然后乘数右移,被乘数左移,如果是0,则被乘数左移,乘数右移。依次类推。
如下图:开始,product=00000000,Mcand=00000110,
Mer[0]==1,product==product+Mcand==00000110;Mer=0010,Mcand==00001100;
Mer[0]==0,Mer==0001,Mcand==00011000;
Mer[0]==1,product==product+Mcand==00011110;Mer=0000,Mcand==00110000;
Mer[0]==0,Mcand==01100000,Mer==0000;
end,product==00011110
代码入下:
module multiplier (clk,rst_n,multiplier,multiplicand,start,done,product);
input clk;//50M
input rst_n;
input [7:0]multiplier;
input [7:0]multiplicand;
input start;
output done;
output [15:0]product;
reg [2:0]i;
reg isdone;
reg [15:0]temp;
reg isneg;
reg [7:0]Mer;
reg [15:0]Mcand;
reg [2:0]cnt;
always @ (posedge clk or negedge rst_n)
if(!rst_n)
begin
i<=1'b0;
isdone<=1'b0;
temp<=16'd0;
Mer<=8'd0;
Mcand<=1'b0;
isneg<=1'b0;
cnt<=1'b0;
end
else if (start)
case
(i)
0:
begin i<=i+1'b1;
isneg<=multiplier[7]^multiplicand[7];
Mer<=multiplier[7]?(~multiplier+1'b1):multiplier;
Mcand<={multiplicand[7]?(~multiplicand+1'b1):multiplicand}&16'h00ff;
temp<=16'd0;
cnt<=1'b0;
end
1:
if(cnt==6)
i<=3'd3;
else if
(Mer[0]) begin temp<=temp+Mcand;
i<=i+1'b1;
end
else
i<=i+1'b1;
2: begin
Mer<=Mer>>1;
Mcand<=Mcand<<1;
i<=i-1'b1;
cnt<=cnt+1'b1;
end
3:begin isdone<=1'b1;
i<=i+1'b1;
end
4:begin isdone<=1'b0;
i<=1'b0;
end
default
:i<=3'b000;
endcase
assign done=isdone;
assign product=isneg?(~temp+1'b1):temp;
endmodule
加粗行用于执行加法操作,斜体部分用于执行移位操作。
测试代码:
`timescale 1 ns/ 1
ps
module multiplier_vlg_tst();
reg clk;
reg [7:0] multiplicand;
reg [7:0] multiplier;
reg rst_n;
reg start;
wire done;
wire [15:0] product;
multiplier i1 (
.clk(clk),
.done(done),
.multiplicand(multiplicand),
.multiplier(multiplier),
.product(product),
.rst_n(rst_n),
.start(start)
);
initial
begin
rst_n=0;
#30;
rst_n=1;
clk=1;
forever #10 clk=~clk;
end
reg [3:0]i;
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin i<=4'd0;
start<=1'b0;
multiplier<=8'd0;
multiplicand<=8'd0;
end
else
case(i)
0:
if (done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd2;
multiplicand<=8'd10;
start<=1'b1;
end
1:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd10;
multiplicand<=8'd2;
start<=1'b1;
end
2:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd20;
multiplicand<=8'd5;
start<=1'b1;
end
3:
if
(done)
begin
start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd2;
multiplicand<=8'b11110110;
//-10
start<=1'b1;
end
4:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11111110;
//-2
multiplicand<=8'd10;
start<=1'b1;
end
5:
if
(done)
begin
start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11110110;
//-10
multiplicand<=8'd2;
start<=1'b1;
end
6:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11111110;
//-2
multiplicand<=8'b11110110;
//-10
start<=1'b1;
end
7:
if (done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11110110;
//-10
multiplicand<=8'b11111110;
//-2
start<=1'b1;
end
8:i<=4'd8;
default:i<=4'd8;
endcase
endmodule
仿真结果:
结果看出:8位有符号的数,7位标志数的大小,一位符号位,所以每一位数据都要进行加和移操作耗2个时钟周期,共消耗2*7=14个时钟周期。所以无论8位多大的数都消耗14个时钟周期用于计算。
修改之后二进制乘法器
module multiplier
(clk,rst_n,multiplier,multiplicand,start,done,product);
input
clk;//50M
input rst_n;
input
[7:0]multiplier;
input [7:0]multiplicand;
input start;
output done;
output [15:0]product;
reg [1:0]i;
reg isdone;
reg [15:0]temp;
reg isneg;
reg [7:0]Mer;
reg [15:0]Mcand;
reg [2:0]cnt;
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
i<=1'b0;
isdone<=1'b0;
temp<=16'd0;
Mer<=8'd0;
Mcand<=1'b0;
isneg<=1'b0;
cnt<=1'b0;
end
else if (start)
case (i)
0:
begin
i<=i+1'b1;
isneg<=multiplier[7]^multiplicand[7];
Mer<=multiplier[7]?(~multiplier+1'b1):multiplier;
Mcand<={multiplicand[7]?(~multiplicand+1'b1):multiplicand}&16'h00ff;
temp<=16'd0;
cnt<=1'b0;
end
1:
if(cnt==6)
i<=2'd2;
else if
(Mer[0]) begin temp<=temp+Mcand;
Mer<=Mer>>1;
Mcand<=Mcand<<1;
cnt<=cnt+1'b1;
end
else
begin
Mer<=Mer>>1;
Mcand<=Mcand<<1;
cnt<=cnt+1'b1;
end
2:
begin
isdone<=1'b1;
55
i<=i+1'b1;
end
3:begin
isdone<=1'b0;
i<=1'b0;
end
default
:i<=2'b00;
endcase
assign done=isdone;
assign
product=isneg?(~temp+1'b1):temp;
endmodule
行把加法和移位放在一起。
测试代码无变化,如下:
`timescale 1 ns/ 1 ps
module multiplier_vlg_tst();
reg clk;
reg [7:0] multiplicand;
reg [7:0] multiplier;
reg rst_n;
reg start;
wire done;
wire [15:0] product;
multiplier i1 (
.clk(clk),
.done(done),
.multiplicand(multiplicand),
.multiplier(multiplier),
.product(product),
.rst_n(rst_n),
.start(start)
);
initial
begin
rst_n=0;
#30;
rst_n=1;
clk=1;
forever #10 clk=~clk;
end
reg [3:0]i;
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin i<=4'd0;
start<=1'b0;
multiplier<=8'd0;
multiplicand<=8'd0;
end
else
case(i)
0:
if (done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd2;
multiplicand<=8'd10;
start<=1'b1;
end
1:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd10;
multiplicand<=8'd2;
start<=1'b1;
end
2:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd20;
multiplicand<=8'd5;
start<=1'b1;
end
3:
if
(done)
begin
start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'd2;
multiplicand<=8'b11110110;
//-10
start<=1'b1;
end
4:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11111110;
//-2
multiplicand<=8'd10;
start<=1'b1;
end
5:
if
(done)
begin
start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11110110;
//-10
multiplicand<=8'd2;
start<=1'b1;
end
6:
if
(done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11111110;
//-2
multiplicand<=8'b11110110;
//-10
start<=1'b1;
end
7:
if (done)
begin start<=1'b0;
i<=i+1'b1;
end
else
begin
multiplier<=8'b11110110;
//-10
multiplicand<=8'b11111110;
//-2
start<=1'b1;
end
8:i<=4'd8;
default:i<=4'd8;
endcase
endmodule
仿真结果:
从结果中可以看出只消耗了7个时钟周期用于计算,比前面的二进制加法器的用于计算消耗的时钟周期少了一倍。
Booth乘法器
它是对乘数重新编码,以减少乘法运算所需要的加法运算次数,他是只对乘数重新编码,而被乘数保持不变。得到的形式称为基4重新编码或比特对编码。使用booth乘法可以对两个数直接相乘,不需要考虑正数和负数。
具体操作:以8位为例
Product定义为17为用于保存结果,初始为product={8’b0,乘数,1’b0}
定义两个8位寄存器:A和B,A=被乘数,B=被乘数取反加1;
如果product最低两位为,01,product高8位加A,然后product右移一位;
如果product最低两位为10,product高8位加B,然后product右移一位;
如果product最低两位为11或00, product右移一位;
直到8位右移结束。