带符号整数乘法器设计

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

相关推荐
FPGA小迷弟4 分钟前
FPGA 与千兆以太网:各类物理接口的形式、区别、使用方法与应用场景详解
tcp/ip·macos·fpga开发·udp·fpga
李长渊哦8 分钟前
Qoder 自定义子智能体(Subagent)学习笔记
chrome·笔记·学习
NamoAmitabha12827 分钟前
Zynq 的 AXI GPIO,是“ARM 通过一条国际标准高速公路(AXI 总线),去遥控 FPGA 里的一个寄存器”。---deepseek
fpga开发·zynq--ps
代码山河37 分钟前
基本类型转换:自动类型转换与强制类型转换
java·学习·架构·教程·面向对象·项目
旖旎夜光1 小时前
【C++ 基础入门】命名空间、输入输出、缺省参数与函数重载
开发语言·c++·笔记·学习
m4Rk_2 小时前
【论文阅读】Agent 记忆机制(119):EvoLife——让具身 Agent 把主动问到的答案沉淀为可复用的空间经验
论文阅读·人工智能·学习·开源·github
NamoAmitabha1282 小时前
ARM 不懂寄存器,它只懂内存地址---deepseek
fpga开发·zynq--ps
粟米茶2 小时前
LTspice 导入第三方 Spice 模型实操
硬件工程·硬件电路·运放
程序猿乐锅2 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
FPGA小迷弟4 小时前
FPGA 千兆以太网帧格式全解:从 IEEE 802.3 帧结构到 Verilog 收发实现
人工智能·5g·fpga开发·架构·硬件架构