verilog语言设计的32位输入使用Booth两位一乘和华莱士树的定点补码乘法器(附参考仿真文件)

  • Post author:
  • Post category:其他


系统描述采用两位Booth编码和华莱士树的补码乘法器是如何处理



[

x

]

[-x]_{补}






[





x



]






































[

2

x

]

[-2x]_{补}






[





2


x



]


































的部分积的:

解决方式大致如下面代码所示:

    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}







y











i


+


1



















,





y











i



















,





y











i





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

运行后的波形如图,可以看到用verilog自带的乘法和手写的乘法器结果相同:

在这里插入图片描述




版权声明:本文为fcb_x原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。