带符号整数乘法器设计

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 验证结果

相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
ZPC82103 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82103 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习