系统描述采用两位Booth编码和华莱士树的补码乘法器是如何处理 [ − x ] 补 [-x]_{补} [−x]补和 [ − 2 x ] 补 [-2x]_{补} [−2x]补的部分积的:
解决方式大致如下面代码所示:
generate
for(i=1;i<=16;i=i+1)begin
assign Nsum[i-1] = {64{y[2*i-1]==3'b000}} & 64'b0 |
{64{y[2*i-1]==3'b001}} & {{34-2*i{ A[31]}}, A,{2*i-2{1'b0}}} |
{64{y[2*i-1]==3'b010}} & {{34-2*i{ A[31]}}, A,{2*i-2{1'b0}}} |
{64{y[2*i-1]==3'b011}} & {{33-2*i{ A[31]}}, A,{2*i-1{1'b0}}} |
{64{y[2*i-1]==3'b100}} & {{34-2*i{rev2A[31]}},rev2A,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b101}} & {{34-2*i{ revA[31]}}, revA,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b110}} & {{34-2*i{ revA[31]}}, revA,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b111}} & 64'b0 ;
assign Csum[i-1][0] = { 1{y[2*i-1]==3'b100}} & 1'b1 |
{ 1{y[2*i-1]==3'b101}} & 1'b1 |
{ 1{y[2*i-1]==3'b110}} & 1'b1 ;
end
endgenerate
assign Csum[16][0] = 1'b0;
在代码中,大致体现了补码的部分积处理方法。对于减去 [ x ] 补 [x]_{补} [x]补的部分,可以视作加上 [ x ] 补 [x]_{补} [x]补的反码,最后再在末尾 + 1 +1 +1。
具体代码实现如上,首先 y y y数组存储的是 y i + 1 , y i , y i − 1 y_{i+1},y_{i},y_{i-1} yi+1,yi,yi−1的三位码。利用对三位码译码,从而得到相对应的操作,对于三位码100/101/110存在补码减法,可以看到拼接的计算数为A的取反或者A左移1位然后取反,这样就把加上反码的部分完成了。
对于末尾 + 1 +1 +1的部分,在华莱士树中,对于16位乘法,其每位至少包含6个全加器。对于32位乘法,全加器个数则为14。这样子做可以保证对于首位,其有6/14个空闲的进位要求,这至少可满足 n − 2 n-2 n−2个末尾加法操作,剩下的两个一个用在C和S的加法器进位输入,一个用在C左移一位的0号位置上,就满足了减去操作的补码部分积处理。
用verilog语言设计一个32位输入宽度的定点补码乘法器,要求使用booth两位一乘和华莱士树:
主要设计思想是,在华莱士树中设计了十七个全加器(实际上可以只设计14个),但是为了方便代码书写,我用了16个。一共分为五层,第一层6个,第二层4个,第三层2个,第四层1个,第五层1个。这样的话,所有减去部分积操作的 + 1 +1 +1都可以直接放入进位输入。
乘法器代码如下:
`timescale 1ns / 1ps
module mul(
input [31:0] mul1,
input [31:0] mul2,
output [63:0] ans,
output cmp
);
wire [63:0] cmpans;
wire [63:0] A_cmp;
wire [63:0] B_cmp;
assign A_cmp = {{32{mul1[31]}},mul1};
assign B_cmp = {{32{mul2[31]}},mul2};
assign cmpans = A_cmp*B_cmp;
assign cmp = cmpans == ans;
wire [31: 0] A;
wire [31: 0] A_w;
wire [31: 0] A_2;
wire [31: 0] revA;
wire [31: 0] rev2A;
wire [31: 0] B;
wire [31: 0] B_w;
wire [63: 0] Nsum [15: 0];
wire [64: 0] Csum [16: 0];
wire [63: 0] Ssum [16: 0];
wire [ 2: 0] y[31: 0];
assign A = mul1;
assign revA = ~A;
assign A_2 = ~(A<<1);
assign rev2A= A_2;
assign B = mul2;
genvar i;
genvar j;
generate
assign y[1] = {B[1],B[0],1'b0};
for(i=3;i<=31;i=i+2)begin
assign y[i]= {B[i],B[i-1],B[i-2]};
end
endgenerate
generate
for(i=1;i<=16;i=i+1)begin
assign Nsum[i-1] = {64{y[2*i-1]==3'b000}} & 64'b0 |
{64{y[2*i-1]==3'b001}} & {{34-2*i{ A[31]}}, A,{2*i-2{1'b0}}} |
{64{y[2*i-1]==3'b010}} & {{34-2*i{ A[31]}}, A,{2*i-2{1'b0}}} |
{64{y[2*i-1]==3'b011}} & {{33-2*i{ A[31]}}, A,{2*i-1{1'b0}}} |
{64{y[2*i-1]==3'b100}} & {{34-2*i{rev2A[31]}},rev2A,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b101}} & {{34-2*i{ revA[31]}}, revA,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b110}} & {{34-2*i{ revA[31]}}, revA,{2*i-2{1'b1}}} |
{64{y[2*i-1]==3'b111}} & 64'b0 ;
assign Csum[i-1][0] = { 1{y[2*i-1]==3'b100}} & 1'b1 |
{ 1{y[2*i-1]==3'b101}} & 1'b1 |
{ 1{y[2*i-1]==3'b110}} & 1'b1 ;
end
endgenerate
assign Csum[16][0] = 1'b0;
generate
for(i=1;i<=64;i=i+1)begin
addr addr0(.a(Nsum[ 0][i-1]),.b(Nsum[ 1][i-1]),.cin(Nsum[ 2][i-1]),.s(Ssum[ 0][i-1]),.cout(Csum[ 0][i]));
addr addr1(.a(Nsum[ 3][i-1]),.b(Nsum[ 4][i-1]),.cin(Nsum[ 5][i-1]),.s(Ssum[ 1][i-1]),.cout(Csum[ 1][i]));
addr addr2(.a(Nsum[ 6][i-1]),.b(Nsum[ 7][i-1]),.cin(Nsum[ 8][i-1]),.s(Ssum[ 2][i-1]),.cout(Csum[ 2][i]));
addr addr3(.a(Nsum[ 9][i-1]),.b(Nsum[ 10][i-1]),.cin(Nsum[ 11][i-1]),.s(Ssum[ 3][i-1]),.cout(Csum[ 3][i]));
addr addr4(.a(Nsum[ 12][i-1]),.b(Nsum[ 13][i-1]),.cin(Nsum[ 14][i-1]),.s(Ssum[ 4][i-1]),.cout(Csum[ 4][i]));
addr addr5(.a(Nsum[ 15][i-1]),.b(1'b0 ),.cin(1'b0 ),.s(Ssum[ 5][i-1]),.cout(Csum[ 5][i]));
addr addr6(.a(Ssum[ 0][i-1]),.b(Ssum[ 1][i-1]),.cin(Ssum[ 2][i-1]),.s(Ssum[ 6][i-1]),.cout(Csum[ 6][i]));
addr addr7(.a(Ssum[ 3][i-1]),.b(Ssum[ 4][i-1]),.cin(Ssum[ 5][i-1]),.s(Ssum[ 7][i-1]),.cout(Csum[ 7][i]));
addr addr8(.a(Csum[ 0][i-1]),.b(Csum[ 1][i-1]),.cin(Csum[ 2][i-1]),.s(Ssum[ 8][i-1]),.cout(Csum[ 8][i]));
addr addr9(.a(Csum[ 3][i-1]),.b(Csum[ 4][i-1]),.cin(Csum[ 5][i-1]),.s(Ssum[ 9][i-1]),.cout(Csum[ 9][i]));
addr addr10(.a(Ssum[ 6][i-1]),.b(Ssum[ 7][i-1]),.cin(Ssum[ 8][i-1]),.s(Ssum[10][i-1]),.cout(Csum[10][i]));
addr addr11(.a(Ssum[ 9][i-1]),.b(Csum[ 6][i-1]),.cin(Csum[ 7][i-1]),.s(Ssum[11][i-1]),.cout(Csum[11][i]));
addr addr12(.a(Csum[ 8][i-1]),.b(Csum[ 9][i-1]),.cin(1'b0 ),.s(Ssum[12][i-1]),.cout(Csum[12][i]));
addr addr13(.a(Ssum[ 10][i-1]),.b(Ssum[ 11][i-1]),.cin(Ssum[ 12][i-1]),.s(Ssum[13][i-1]),.cout(Csum[13][i]));
addr addr14(.a(Csum[ 10][i-1]),.b(Csum[ 11][i-1]),.cin(Csum[ 12][i-1]),.s(Ssum[14][i-1]),.cout(Csum[14][i]));
addr addr15(.a(Ssum[ 13][i-1]),.b(Ssum[ 14][i-1]),.cin(Csum[ 13][i-1]),.s(Ssum[15][i-1]),.cout(Csum[15][i]));
addr addr16(.a(Ssum[ 15][i-1]),.b(Csum[ 14][i-1]),.cin(Csum[ 15][i-1]),.s(Ssum[16][i-1]),.cout(Csum[16][i]));
end
endgenerate
assign ans = (Ssum[16] + Csum[16]);
endmodule
module addr(
input a,
input b,
input cin,
output s,
output cout
);
assign {cout,s} = a+b+cin;
endmodule
利用随机数生成的仿真文件如下:
`timescale 1ns / 1ps
module mul_tb();
reg [31: 0] mul1;
reg [31: 0] mul2;
wire [63: 0] ans;
wire cmp;
mul mul_top(
.mul1(mul1),
.mul2(mul2),
.ans(ans),
.cmp(cmp)
);
initial begin
mul1=4'h2;
mul2=4'h2;
end
always begin
#2;
mul1=$random();
mul2=$random();
end
endmodule