首页 > 其他分享 >无符号乘法器

无符号乘法器

时间:2023-03-04 17:35:40浏览次数:33  
标签:符号 unsigned WIDTH localparam 乘法器 reg prdct

无符号乘法器
与无符号加法类似,无符号乘法器也要求两边的乘数是无符号的,一旦有一方为有符号数,则整个结果为有符号数,否则综合会出现不可预知的结果。与无符号加法不同的是,无符号的乘法,乘积结果位宽为两个乘数位宽相加,而非乘数最大位宽+1,其实从原理上是比较容易理解的,因为二进制乘法,就是几组二进制加法移位的结果,例如:
               1101              4位
   *            110              3位
---------------------------------
               0000
   +        1101
   +      1101
----------------------------------
          1001110             7位

乘法进行Verilog 编写,以前综合工具不是很优化,不能解析*,一般采用例会标准单元的方式,完成乘法运算:
传统古老方式Verilog 无符号乘法写法:

        localparam   A_WIDTH;
        localparam   B_WIDTH;
        localparam   PRDCT_WIDTH = A_WIDTH + B_WIDTH;
        
        reg [A_WIDTH-1:0]                 a;  // Default declaration type is unsigned
        reg [B_WIDTH-1:0]                 b;  // Default declaration type is unsigned
     
        wire [PRDCT_WIDTH-1:0]         prdct;
      
        DW02_MULT #(
                           .A_WIDTH       (A_WIDTH         ),
                           .B_WIDTH       (B_WIDTH         )
                          )
         U_DW_MULT
                          (
                           .TC                 (1'b0                 ), // 0 for unsigned, 1 for signed                       
                           .A                   (a                     ),
                           .B                   (b                     ),
                           .PRODUCT       (prdct               )
                          );

随着工具不断优化,包括Synplify也被synopsys收购后,FPGA综合工具也支持*乘法识别,只需要代码中申明乘法参数的符号属性既可。

推荐乘法运算Verilog 代码:
        localparam   A_WIDTH   =  8;
        localparam   B_WIDTH   =  16;
        localparam   PRDCT_WIDTH = A_WIDTH + B_WIDTH;
        
        reg unsigned [A_WIDTH-1:0]                a;  // Default declaration type is unsigned
        reg unsigned [B_WIDTH-1:0]                b;  // Default declaration type is unsigned
     
        reg unsigned [PRDCT_WIDTH-1:0]         prdct;

        always@(*) begin
              prdct = a * b;
        end
乘法不用显示把a和b位宽扩位到A_WIDTH+W_WIDTH,只要prdct 定义位宽为A_WIDTH+B_WIDTH,工具就不会报错。

以上讲解的是乘法器两边都是变量信号的无符号乘法运算,对于一个变量,一个常量的无符号运算,需要注意一下几点:
1. 常数的位宽要定义清楚;
2. 常数的符号类型要显示定义为无符号;
3. 对于常数无论是是否2的整数次幂,均按照* 写,不需要自己优化移位,因为综合的优化效果,不会比手动移位差。
示例:
        localparam                                            A_WIDTH   =  8;
        localparam                                            B_WIDTH   =  8;
        localparam   unsigned [B_WIDTH -1 : 0]  B              =  32;
        localparam                                             PRDCT_WIDTH = A_WIDTH + B_WIDTH;
        
        reg unsigned [A_WIDTH-1:0]                   a;  // Default declaration type is unsigned

     
        reg unsigned [PRDCT_WIDTH-1:0]         prdct;

        always@(*) begin
              prdct = a * B;
        end

强烈不推荐:
        always@(*) begin
              prdct = a << 5;
        end
原因: 1. 代码可扩展性上讲,后续常数B的值变化不是2的5次方,或者说不是2的整数次幂,这个地方就需要修改为*
         2.  代码可读性上讲,推荐的方式容易看懂,就是两个数相乘,不推荐的方式,还需要推敲一下,这行代码功能
         3.  代码可控性上讲,a往作移位,低位补0,还是补1,还是补a的最低位,工具都可以有不同理解,所以不同工具可能理解会不一样
         4.  两边位宽还不匹配,语法检查工具也会报Warning


顺便讲解一下这个章节代码规范一些细节:
1.  信号定义和申明,一行对应一个信号,不要多个信号定义在一行,否则修改其中一个信号,可能会影响其他信号,另外一行太长,也影响阅读,不建议定义方式:
              localparam   A_WIDTH = 8,B_WIDTH = 16;

2.  对于模块例化,建议按照名字进行例化,不要按照位置进行例化,否则被例化模块端口有修改,例化的上层文件就要重新修改,即不建议这样的例化代码风格:
          DW_MULT #(
                           A_WIDTH         ,
                           B_WIDTH         
                          )
         U_DW_MULT
                          (
                          1'b0                 ,
                           a                     ,
                           b                     ,
                           prdct               
                          );
     甚至很多教科书上的这种写法,可维护性更差,就更不推荐了哈:
       DW_MULT #( A_WIDTH ,  B_WIDTH ) U_DW_MULT(1'b0,a,b,prdct);
     原因很简答,如果a和b位置搞反了,a和b的位宽又不一样,就可能会报错,能够报错都算是不坏结果,就怕语法检查不跑错,最后仿真出错,定位问题会浪费较长时间。

3.  注意一下语法,例化赋值,或者用assign赋值的信号,我们定义为wire,在 always 块中的变量,无论是组合逻辑还是时序逻辑,都需要定义为reg。比如上面例子当中的prdct,第一个写法是通过例化模块得到值,所以定义为wire,第二个写法是在always块中得到,所以定义为reg。这个就是语法规定,没有什么理由,大家记住就行,否则工具就会报语法错误。

4. 在always 块中,组合逻辑采用非阻塞赋值 =, 时序逻辑采用阻塞赋值 <= ,具体原因,这里先不表述,前面章节主要讲组合逻辑,等讲到时序逻辑章节,会详细阐述原因,大家先有这个一个印象即可。

5.常数乘法给大家引申的一个写代码原则,尽量按照功能或者代码行为去写,只要是可综合风格即可,切忌自己觉得自己很聪明,对电路进行电路级的优化。这样会影响代码的可读性,扩展性以及可控性,同时现在综合工具优化功能很强,大家不必担心得不到最好的PPA(Power,Performance,Area),而且大家进行代码风格选择时,考虑的也不光是PPA这几个维度,也要从可以实现性,复杂度,可阅读星,开发周期多方面去考量。

标签:符号,unsigned,WIDTH,localparam,乘法器,reg,prdct
From: https://www.cnblogs.com/chunk998/p/17178661.html

相关文章

  • 有符号数的加法
    有符号数的加法,从无符号的加法章节就提及过,只要加数有一方为有符号数,则和一定是有符号数,重点强调一下,大家千万不要从场景上分析,认为C=A+B一定是>0,则及时A和B有一个是有符......
  • 有符号加法的Verilog实现
    有符号加法的Verilog实现形式,推荐两种方式:方式一:传统方式,手动扩位,实现左右位宽匹配,扩位为符号位,另外信号输入有符号数,一定要显示定义,Verilog默认不定义就是无符号类型1 ......
  • 无符号二进制加法
    无符号二进制加法,需要保证两个相加的加数均为无符号数,如果有一个位有符号数,则均为有符号运算,结果为有符号数,即对于减法来讲,不存在无符号减法。  无符号A+无符号B=无......
  • idea2020版本找不到符号,找不到程序包问题
    本人把网上除了重装idea的方法试了个遍,最后才重装的,根据群体反应2020版本的这个问题是通病,2020版本会出现这种莫名的错误,建议官网下载2019,2021,2022版本的idea(2022版本需......
  • LNK2001 无法解析的外部符号 "int const ROUND"
    今天在写代码时出现了这个错误,网上的解决方法都不合适我的代码是这样,在一个cpp里申明了一个常量//data.cppconstintROUND=3;然后在一个头文件里申明为全局变量......
  • HTML 符号实体
    HTML符号实体本字符实体参考手册包括了数学符号、希腊字符、各种箭头记号、科技符号以及形状。注释: 实体名称对大小写敏感。HTML支持的数学符号字符实体编号实体......
  • mysql: 看不见的空符号 char(9) char(10) char(13)
    trim,消除前后的空格,没有效时果updatetable_namesetcolumn_name=replace(replace(replace(column_name,char(9),''),char(10),''),char(13),'');说明:table_name:表......
  • pat 乙级1024 科学计数法关于stl中size()的一些思考即测试点六,无符号整数问题
    来,先看题目:1024科学计数法分数20作者HOU,Qiming单位浙江大学科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式[+-][1-9].[0-9]+......
  • python 字符串 格式化输出 槽格式 小数的位数与符号控制
    """槽的格式限定冒号:左边填序号或名称,右边填写格式"""#定义一个数num=3.1465926#保留两位小数,并且四舍五入res="{:.2f}".format(num)print(res)#有符号的数字res2=......
  • IDEA在编译的时候报Error: java: 找不到符号符号: 变量 log lombok失效问题
    setting-->Build,Execution,Deployment 点击complier 在SharedbuildprocessVMoptions:中添加配置  -Djps.track.ap.dependencies=false ......