带符号整数乘法器设计

1.设计思路

本文主要讲解带符号整数乘法器设计思路,以及verilog电路实现 。

1.1 补码表示

有符号数表示都是使用补码表示,我们都知道,正数的补码是它本身,负数的补码是对应正数取法加一。对于一个4bit整数,如果表示无符号整数,它的范围是0-15;如果表示有符号整数。它的范围是-8到7。4bit表示有符号整数如下表:

|---------|-----|
| 二进制 | 十进制 |
| 4'b0000 | 0 |
| 4'b0001 | 1 |
| 4'b0010 | 2 |
| 4'b0011 | 3 |
| 4'b0100 | 4 |
| 4'b0101 | 5 |
| 4'b0110 | 6 |
| 4'b0111 | 7 |
| 4'b1000 | -8 |
| 4'b1001 | -7 |
| 4'b1010 | -6 |
| 4'b1011 | -5 |
| 4'b1100 | -4 |
| 4'b1101 | -3 |
| 4'b1110 | -2 |
| 4'b1111 | -1 |

1.2 乘法器设计思路

根据上表,可以得到对于两个4bit带符号数A4=a3a2a1a0,B4=b3b2b1b0

A4=-a3*2^3+a2*2^2+a1*2^1+a0*2^0 例:A4=4'b1111=-1 = -8+4+2+1=-1

B4=-b3*2^3+b2*2^2+b1*2^1+b0*2^0 例:B4=4'b1010=-6 = -8+0+2+0=-6

注意:1bit乘法器本质上就是与(&)操作。

根据上面化简关系,A4=-a3*2^3+A3,其中,A3可以表示为使用低三位表示的无符号整数A3=a2a1a0。由此,可以推导出如下表达式:

A4*B4=(-a3*2^3+A3)*(-b3*2^3+B3)=a3b3*2^6 - a3B3*2^3 - b3A3*2^3 + A3B3

A3B3=(a2a1a0)*(b2b1b0)

a3B3*2^3=a3(b2b1b0)*2^3 这里乘2^3可以理解为左移3位

b3B3*2^3表示方法与上图类似如下表

对 - a3B3*2^3 - b3A3*2^3重新整理,可以得到(-a3B3-b3A3)*2^3,再利用-x=~x+1(~表示取反)得到如下图:

由上述推到最终可以得到如下结果:

A4*B4=(-a3*2^3+A3)*(-b3*2^3+B3)=a3b3*2^6 - a3B3*2^3 - b3A3*2^3 + A3B3

2.电路实现

具体代码如下:数据位宽通过参数化定义,但是最后结果计算,需要要实验一个逻辑的累加器,目前这个部分没有办法参数化处理,如果有人有好的思路,希望可以交流。

复制代码
/*
有符号乘法基本算法如下(以4bit有符号数为例子):
A4=a3a2a1a0    用十进制表示:A4=-a3*2^3 + a2*2^2 + a1*2^1 + a0*2^0 = -a3*2^3 + A3 ;
B4=b3b2b1b0    用十进制表示:B4=-b3*2^3 + b2*2^2 + b1*2^1 + b0*2^0 = -b3*2^3 + B3 ;
A4*B4 = (-a3*2^3 + A3) * (-b3*2^3 + B3) = a3b3*x^6 -a3B3*2^3 -A3b3*2^3 + A3B3 

补充:1bit乘法相当于and操作     A  B   S
                               0  0   0
                               0  1   0
                               1  0   0
                               1  1   1      
              a3b3*x^6
-a3B3*2^3 = -(a3b0*2^3 + a3b1*2^4 + a3b2*2^5)
-A3b3*2^3 = -(b3a0*2^3 + b3a1*2^4 + b3a2*2^5) 
A3B3= (a2a1a0)*(b2b1b0) = (a2a1a0)*b0 + (a2a1a0)*b1*2^1 + (a2a1a0)*b2*2^2 ;


    7       6       5       4       3       2       1       0
                                            a2b0    a1b0    a0b0
                                    a2b1    a1b1    a0b1
                            a2b2    a1b2    a0b2
                            -A3b3*2^3
                            -a3B3*2^3
+                           a3b3*x^6

继续推  将-A3b3*2^3 写成 -(a0b3*2^3 + a1b3*2^4 + a2b3*2^5)

    7       6       5       4       3       2       1       0
                                            a2b0    a1b0    a0b0
                                    a2b1    a1b1    a0b1
                            a2b2    a1b2    a0b2
                   -a2b3   -a1b3   -a0b3
                            -a3B3*2^3
+                           a3b3*x^6

继续推  将-a3B3*2^3 写成-(a3b0*2^3 + a3b1*2^4 + a3b2*2^5) 这里斜着写

    7       6       5       4       3       2       1       0
                                   -a3b0    a2b0    a1b0    a0b0
                           -a3b1    a2b1    a1b1    a0b1
                   -a3b2   a2b2    a1b2    a0b2
                   -a2b3   -a1b3   -a0b3
+                           a3b3*x^6

继续推  将a3b3*x^6 写到最后一行 

    7       6       5       4       3       2       1       0
                                   -a3b0    a2b0    a1b0    a0b0
                           -a3b1    a2b1    a1b1    a0b1
                   -a3b2    a2b2    a1b2    a0b2
            a3b3   -a2b3   -a1b3   -a0b3

如何去掉负号 :对于二进制表示的数 -x = ~x + 1 
-a3B3*2^3 -A3b3*2^3 = (-a3B3 -A3b3)*2^3  = (~a3B3 +1 + ~A3b3 +1)*2^3   2^3先不考虑
(~a3B3 +1 + ~A3b3 +1)表示为

        4       3       2       1       0
                1      ~a3b2   ~a3b1   ~a3b0
                1      ~b3a2   ~b3a1   ~b3a0
                0       0       0       1
                0       0       0       1
转换为   
        4       3       2       1       0
                1      ~a3b2   ~a3b1   ~a3b0
                1      ~b3a2   ~b3a1   ~b3a0
                0       0       1       0
转换为   
        4       3       2       1       0
                0      ~a3b2   ~a3b1   ~a3b0
                0      ~b3a2   ~b3a1   ~b3a0
        1       0       0       1       0
转换为  乘2^3 左移3位 
        7       6       5       4       3       2       1       0
                0      ~a3b2   ~a3b1   ~a3b0
                0      ~b3a2   ~b3a1   ~b3a0
        1       0       0       1       0   


将这个结果带入到之前表达式中
    7       6       5       4       3       2       1       0
                                   -a3b0    a2b0    a1b0    a0b0
                           -a3b1    a2b1    a1b1    a0b1
                   -a3b2    a2b2    a1b2    a0b2
            a3b3   -a2b3   -a1b3   -a0b3
转变为
    7       6       5       4       3       2       1       0
                            1      ~a3b0    a2b0    a1b0    a0b0
                           ~a3b1    a2b1    a1b1    a0b1
                   ~a3b2    a2b2    a1b2    a0b2
    1       a3b3   ~a2b3   ~a1b3   ~a0b3
*/

`timescale 1ns/1ps

module signed_mul 
#(
    parameter    DATA_LEN = 8 
)
(
    input  [ DATA_LEN -1   : 0 ] signed_mul_a_i    ,
    input  [ DATA_LEN -1   : 0 ] signed_mul_b_i    ,

    output [ DATA_LEN*2 -1 : 0 ] signed_mul_s_o    
);

wire [ DATA_LEN -1 : 0 ] a_bi [ DATA_LEN -1 : 0 ] ;

//-----------------------------------------------------------------------
//----每一行计算
//-----------------------------------------------------------------------
generate
    genvar i ;
    genvar j ;

    //AB
    for( i=0 ; i < DATA_LEN - 1 ; i=i+1 )begin
        for( j=0 ; j < DATA_LEN - 1 ; j=j+1)begin
            assign a_bi[i][j] = signed_mul_a_i[i] & signed_mul_b_i[j] ;
        end
    end

    //A4*B4 = (-a3*2^3 + A3) * (-b3*2^3 + B3) = a3b3*x^6 -a3B3*2^3 -A3b3*2^3 + A3B3 
    //aB
    for( i=0 ; i < DATA_LEN - 1 ; i=i+1 )begin
        assign a_bi[i][DATA_LEN - 1] = ~(signed_mul_a_i[DATA_LEN - 1] & signed_mul_b_i[i]) ;
    end

    //Ab
    for( i=0 ; i < DATA_LEN - 1 ; i=i+1 )begin
        assign a_bi[DATA_LEN - 1][i] = ~(signed_mul_a_i[i] & signed_mul_b_i[DATA_LEN - 1]) ;
    end

    //ab
    assign a_bi[DATA_LEN - 1][DATA_LEN - 1] = signed_mul_a_i[DATA_LEN - 1] & signed_mul_b_i[DATA_LEN - 1] ;

endgenerate

//-----------------------------------------------------------------------
//----求和
//-----------------------------------------------------------------------
wire [DATA_LEN*2 -1 : 0]add_sum[DATA_LEN -1 : 0];

generate
    genvar k ;

    assign add_sum[0] = {1'b1 , a_bi[0][DATA_LEN - 1] , a_bi[0][DATA_LEN - 2 : 0]} ;
    for( k=1 ; k<DATA_LEN-1 ; k=k+1 )begin
        assign add_sum[k] = { a_bi[k][DATA_LEN - 1] , a_bi[k][DATA_LEN - 2 : 0] } << k ;
    end
    assign add_sum[DATA_LEN - 1] = { 1'b1 , a_bi[DATA_LEN - 1][DATA_LEN - 1] , a_bi[DATA_LEN - 1][DATA_LEN - 2 : 0] } << (DATA_LEN - 1) ;

endgenerate

//根据实际多少位需要自己添加  可以使用类似于累加器  但是循环好像并不好写
assign signed_mul_s_o = add_sum[0] + add_sum[1] + add_sum[2] + add_sum[3] +
                        add_sum[4] + add_sum[5] + add_sum[6] + add_sum[7]   ;

endmodule //signed_mul

3.仿真验证

3.1验证代码

复制代码
`timescale 1ns/1ps

module signed_mul_tb;

// Parameters
localparam  DATA_LEN = 8;

//Ports
reg [ DATA_LEN -1   : 0 ] signed_mul_a_i;
reg [ DATA_LEN -1   : 0 ] signed_mul_b_i;
wire [ DATA_LEN*2 -1 : 0 ] signed_mul_s_o;

signed_mul # (
    .DATA_LEN(DATA_LEN)
  )
  signed_mul_inst (
    .signed_mul_a_i(signed_mul_a_i),
    .signed_mul_b_i(signed_mul_b_i),
    .signed_mul_s_o(signed_mul_s_o)
);

integer i;
integer j;

initial begin
    signed_mul_a_i = 8'hff ;
    signed_mul_b_i = 8'hff ;
    #40;
    signed_mul_a_i = 8'h1  ;
    signed_mul_b_i = 8'hff ;
    #40;
    for(i=0 ; i<256 ; i=i+1 )begin
        for(j=0 ; j<256 ; j=j+1)begin
            signed_mul_a_i = i ;
            signed_mul_b_i = j ;
            #20 ;
        end
    end

    #100;
    $stop;
end

endmodule

3.2 验证结果

相关推荐
Tolines3 小时前
PCIe外接卡标准尺寸
嵌入式硬件·硬件工程·设计规范
霅昪忞昉3 小时前
四线调速风扇-转速频率计算PWM调速电路
硬件工程
斌斌有理77943 小时前
二极管,看这篇就够了~
硬件工程
Black doncky prince3 小时前
QR反激电源副边整流二极管电压波形分析
单片机·嵌入式硬件·硬件工程
currycheng63 小时前
开关电源测试及方法
单片机·嵌入式硬件·硬件架构·硬件工程
Focus5173 小时前
Altium Designer设置敷铜连接类型为间隙/十字连接后,连接方式没有改变
硬件工程
Daimxiaocai3 小时前
AD-批量过孔
学习·硬件工程·射频工程
一只豌豆象3 小时前
【经验&技巧】ADS中如何快速获取信号瞬态仿真眼图?
经验分享·硬件工程·ads·使用技巧·眼图·瞬态仿真
天将夜3 小时前
AD20软件PCB设计规则的设置
硬件工程·pcb工艺