EETOP 创芯网论坛 (原名:电子顶级开发网)

标题: Verilog补码乘法 [打印本页]

作者: 2441697316    时间: 2024-9-24 18:18
标题: Verilog补码乘法
我在设计一个矩阵乘法模块,输入数据和输出数据都是补码,计算过程可以直接将两个数据相乘然后判断正负吗?还是说要先把补码转换成原码,然后把结果转换成补码输出

作者: ht_lch    时间: 2024-9-24 20:06
乘法的话,不是通过符号位就可以直接得到吗?还有就是verilog 定义成signed的话工具会自动综合成有符号的乘法器吧
作者: 2441697316    时间: 2024-9-24 20:50


   
ht_lch 发表于 2024-9-24 20:06
乘法的话,不是通过符号位就可以直接得到吗?还有就是verilog 定义成signed的话工具会自动综合成有符号的乘 ...


要能软件配置有符号还是无符号,比如有*有,有*无,无*有,无*无,直接定义signed的电路好像不能复用



作者: liuguangxi    时间: 2024-9-25 09:36
可以类似这么来写(tc_*控制输入数据为有符号(1)或无符号(0)):


   

        

                
  1. input [7:0] a, b;
  2. input tc_a, tc_b;
  3. output [15:0] z;

  4. wire signed [8:0] a_sgn, b_sgn;
  5. wire signed [15:0] z_sgn;

  6. assign a_sgn = $signed({tc & a[7], a});
  7. assign b_sgn = $signed({tc & b[7], b});
  8. assign z_sgn = a_sgn * b_sgn;
  9. assign z = $unsigned(z_sgn);

  10.         

   

    复制代码



作者: ht_lch    时间: 2024-9-25 10:19


   
2441697316 发表于 2024-9-24 20:50
要能软件配置有符号还是无符号,比如有*有,有*无,无*有,无*无,直接定义signed的电路好像不能复用


那确实不能复用

作者: catannie    时间: 2024-9-26 18:54
有补码乘法算法,可以参考 Computer arithmetic / Behrooz Parhami. – 2nd ed.有专门讲乘法器的章节, 在 https://bbs.eetop.cn/thread-976509-1-1.html 有提供下载
作者: 2441697316    时间: 2024-9-27 10:45


   
liuguangxi 发表于 2024-9-25 09:36
可以类似这么来写(tc_*控制输入数据为有符号(1)或无符号(0)):


卧槽,确定这样的功能没问题吗,好简单的写法,我现在已经写完了,老老实实补码转源码

作者: 2441697316    时间: 2024-9-27 10:49


   
liuguangxi 发表于 2024-9-25 09:36
可以类似这么来写(tc_*控制输入数据为有符号(1)或无符号(0)):


话说$signed可综合吗
作者: liuguangxi    时间: 2024-9-27 14:46


   
2441697316 发表于 2024-9-27 10:49
话说$signed可综合吗


当然可以综合,主流EDA工具都支持

作者: 2441697316    时间: 2024-9-27 14:56


   
liuguangxi 发表于 2024-9-27 14:46
当然可以综合,主流EDA工具都支持


有个问题,为什么a_sgn要定义为9位

作者: sutaotao2001    时间: 2024-9-27 15:04
Thanks
作者: 2441697316    时间: 2024-9-27 15:37


   
liuguangxi 发表于 2024-9-27 14:46
当然可以综合,主流EDA工具都支持



您看看我写的代码,位宽处理有没有问题
//////
wire signed [7:0] byte3_a;
wire signed [7:0] byte2_a;
wire signed [7:0] byte1_a;
wire signed [7:0] byte0_a;


wire signed [7:0] byte3_b;
wire signed [7:0] byte2_b;
wire signed [7:0] byte1_b;
wire signed [7:0] byte0_b;


assign byte3_a [7:0] = data_in_a[31:24];

assign byte2_a [7:0] = data_in_a[23:16];

assign byte1_a [7:0] = data_in_a[15: 8];



assign byte0_a [7:0] = data_in_a[ 7: 0];



assign byte3_b [7:0] = data_in_b[31:24];

assign byte2_b [7:0] = data_in_b[23:16];
assign byte1_b [7:0] = data_in_b[15: 8];

assign byte0_b [7:0] = data_in_b[ 7: 0];


///////

wire signed [7:0] byte3_a_sgn;
wire signed [7:0] byte2_a_sgn;
wire signed [7:0] byte1_a_sgn;
wire signed [7:0] byte0_a_sgn;


wire signed [7:0] byte3_b_sgn;
wire signed [7:0] byte2_b_sgn;
wire signed [7:0] byte1_b_sgn;
wire signed [7:0] byte0_b_sgn;



assign byte3_a_sgn [7:0] = {sign_a && byte3_a[7] , byte3_a[6:0]};

assign byte2_a_sgn [7:0] = {sign_a && byte2_a[7] , byte2_a[6:0]};
assign byte1_a_sgn [7:0] = {sign_a && byte1_a[7] , byte1_a[6:0]};


assign byte0_a_sgn [7:0] = {sign_a && byte0_a[7] , byte0_a[6:0]};



assign byte3_b_sgn [7:0] = {sign_b && byte3_b[7] , byte3_b[6:0]};

assign byte2_b_sgn [7:0] = {sign_b && byte2_b[7] , byte2_b[6:0]};
assign byte1_b_sgn [7:0] = {sign_b && byte1_b[7] , byte1_b[6:0]};

assign byte0_b_sgn [7:0] = {sign_b && byte0_b[7] , byte0_b[6:0]};



/////

reg signed [15:0] mult_byte3;
reg signed [15:0] mult_byte2;
reg signed [15:0] mult_byte1;
reg signed [15:0] mult_byte0;

always@(...)begin
    if(!rstn)begin
        mult_byte3[15:0] <= 16'b0;
        mult_byte2[15:0] <= 16'b0;
        mult_byte1[15:0] <= 16'b0;
        mult_byte0[15:0] <= 16'b0;
    end
    else if(mult_flag)begin

        mult_byte3[15:0] <= byte3_a_sgn[7:0] * byte3_b_sgn[7:0] ;
        mult_byte2[15:0] <= byte2_a_sgn[7:0] * byte2_b_sgn[7:0] ;
        mult_byte1[15:0] <= byte1_a_sgn[7:0] * byte1_b_sgn[7:0] ;
        mult_byte0[15:0] <= byte0_a_sgn[7:0] * byte0_b_sgn[7:0] ;
    end

end


/////

reg signed [17:0] mult_byte_sum;

always@(...)begin
    if(!rstn)
        mult_byte_sum[17:0] <= 18'b0;
    else if(mult_sum_flag)

        mult_byte_sum[17:0] <= mult_byte3[15:0] +
                                             mult_byte2[15:0] +
                                             mult_byte1[15:0] +
                                             mult_byte0[15:0];
end



/////


reg signed [31:0] sum;
always@(...)begin
    if(!rstn)
        sum[31:0] <= 32'b0;
    else if(sum_flag)

        sum[31:0] <= sum[31:0] + mult_byte_sum[17:0];
    else
        sum[31:0] <= 32'b0;
end









作者: catannie    时间: 2024-9-28 15:30


   
2441697316 发表于 2024-9-24 20:50
要能软件配置有符号还是无符号,比如有*有,有*无,无*有,无*无,直接定义signed的电路好像不能复用




复用跟有无符号无关,应该说一般情况下每个*运算符会综合出一个乘法器,除非公共子表达式之类的优化有可能减少乘法器的数量
作者: liuguangxi    时间: 2024-9-29 10:38


   
2441697316 发表于 2024-9-27 15:37
您看看我写的代码,位宽处理有没有问题
//////
wire signed [7:0] byte3_a;


主要还得确认下byte3_a等几个数在表示无符号数时最高位是不是一定为0?

如果是,那么这么写就行;否则需要符号位再扩展一位到9bit。

作者: 2441697316    时间: 2024-10-8 10:44


   
liuguangxi 发表于 2024-9-29 10:38
主要还得确认下byte3_a等几个数在表示无符号数时最高位是不是一定为0?

如果是,那么这么写就行;否则需 ...


仿真看了下,signed定义的加法怎么是按无符号数算的


/////
这里几个16位有符号数有正有负,加出来的18位结果是无符号加法的结果
reg signed [17:0] mult_byte_sum;
always@(...)begin
    if(!rstn)
        mult_byte_sum[17:0] <= 18'b0;
    else if(mult_sum_flag)
        mult_byte_sum[17:0] <= mult_byte3[15:0] +
                                             mult_byte2[15:0] +
                                             mult_byte1[15:0] +
                                             mult_byte0[15:0];
end
/////
这里也是无符号结果
reg signed [31:0] sum;
always@(...)begin
    if(!rstn)
        sum[31:0] <= 32'b0;
    else if(sum_flag)
        sum[31:0] <= sum[31:0] + mult_byte_sum[17:0];
    else
        sum[31:0] <= 32'b0;
end



作者: 2441697316    时间: 2024-10-8 10:59


   
liuguangxi 发表于 2024-9-29 10:38
主要还得确认下byte3_a等几个数在表示无符号数时最高位是不是一定为0?

如果是,那么这么写就行;否则需 ...


乘法也是按无符号数规则算的,比如这里



mult_byte3[15:0] <= byte3_a_sgn[7:0] * byte3_b_sgn[7:0] ;

byte3_a_sgn等于0x87(-121

byte3_b_sgn等于0xb4(-76

结果应该是23ec(+9196
但仿真结果是5eec(无符号数0x87 * 0xb4的结果

作者: liuguangxi    时间: 2024-10-8 12:22
本帖最后由 liuguangxi 于 2024-10-8 12:23 编辑


   
2441697316 发表于 2024-10-8 10:59
乘法也是按无符号数规则算的,比如这里


应该写成:


mult_byte3 <= byte3_a_sgn * byte3_b_sgn;


信号一旦使用[:]截取就变成unsigned类型了。

前面加法运算代码同理。

作者: 2441697316    时间: 2024-10-9 09:52


   
liuguangxi 发表于 2024-10-8 12:22
应该写成:


用signed系统函数行不行
mult_byte3[15:0] <= $signed(byte3_a_sgn[7:0]) * $signed(byte3_b_sgn[7:0]) ;



作者: liuguangxi    时间: 2024-10-9 13:21


   
2441697316 发表于 2024-10-9 09:52
用signed系统函数行不行
mult_byte3[15:0]


这样写也行,只是更罗嗦

作者: 2441697316    时间: 2024-10-9 13:36


   
liuguangxi 发表于 2024-10-9 13:21
这样写也行,只是更罗嗦


了解了,受益匪浅

作者: 2441697316    时间: 2024-10-11 14:50


   
liuguangxi 发表于 2024-10-9 13:21
这样写也行,只是更罗嗦


nlint检查剩下最后一个问题:
sum[31:0] <= $signed(sum[31:0]) + $(mult_byte_sum[17:0]);

位宽不一致
应该怎么把18位有符号数扩展到32位

作者: 2441697316    时间: 2024-10-11 14:54


   
liuguangxi 发表于 2024-10-9 13:21
这样写也行,只是更罗嗦


我知道了,不写位宽

作者: 数学必考150    时间: 2024-10-11 15:03


   
2441697316 发表于 2024-10-11 14:50
nlint检查剩下最后一个问题:
sum[31:0]


不能用移位拼接符  这样写嘛:{14{DATA[18]},DATA}

作者: 2441697316    时间: 2024-10-11 15:06


   
数学必考150 发表于 2024-10-11 15:03
不能用移位拼接符  这样写嘛:{14{DATA[18]},DATA}


可以,但是我想用“有符号数”的方式实现,刚刚删掉了位宽,但是还是报错,看来只能这样了

作者: 2441697316    时间: 2024-10-11 15:17


   
liuguangxi 发表于 2024-10-9 13:21
这样写也行,只是更罗嗦


现在改成了sum[31:0] <= $signed(sum[31:0]) + $signed({14{mult_byte_sum[17]},mult_byte_sum[17:0]});

作者: 2441697316    时间: 2024-10-21 16:17


   
liuguangxi 发表于 2024-9-27 14:46
当然可以综合,主流EDA工具都支持


哥,8位有符号数乘以8位有符号数得到的结果是16位还是15位

作者: liuguangxi    时间: 2024-10-21 17:02


   
2441697316 发表于 2024-10-21 16:17
哥,8位有符号数乘以8位有符号数得到的结果是16位还是15位


理论上是16位





欢迎光临 EETOP 创芯网论坛 (原名:电子顶级开发网) (https://bbs.eetop.cn/) Powered by Discuz! X3.5