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