Felix

技术源于积累,成功始于执着!

Lattice FPGA中的Ripple Mode之——关于加法器实现的讨论

0
阅读(300) 评论(0)

为什么写这篇博文呢?因为鄙人无意中发现了一个有趣的问题,所以和大家分享一下。其实加法器是很简单的东西,大部分人可能并不注意其在FPGA的具体实现方式。一般情况下,对于简单的加法运算(如三个4bits的数相加),大部分人都是在HDL中直接使用了如下的写法:

module top(a,b,c,d,cout,cin);
    input [3:0] a,b,c;
    output [3:0] d;
    input cin;
    output cout;
    
    assign {cout,d} = {1'b0,a} + {1'b0,b} + {1'b0,c} + cin;
endmodule

经过Synplify Pro综合得到的结果为:

image.png

Diamond中的报告为:

Design Summary
   Number of registers:             0 out of  6047 (0%)
      PFU registers:            0 out of  5936 (0%)
      PIO registers:            0 out of   111 (0%)
   Number of SLICEs:               13 out of  2968 (0%)
      SLICEs as Logic/ROM:          13 out of  2968 (0%)
      SLICEs as RAM:            0 out of  2226 (0%)
      SLICEs as Carry:           3 out of  2968 (0%)
   Number of LUT4s:                19 out of  5936 (0%)
      Number used as logic LUTs:            13
      Number used as distributed RAM:         0
      Number used as ripple logic:          6
      Number used as shift registers:         0

可以发现,综合工具很机智地直接调用了调用了加法器的原语(primitive),综合的结果为,花费了19个LUT4,其中13个用于Logic LUTs,6个用于Ripple Logic。

这里需要简单介绍一下Logic LUTs和Ripple Logic的区别,首先看一下PFU的结构图:

image.png

Logic LUTs主要用的是上图中的LUT部分的资源,而Ripple Logic则主要用的是上图中的Carry Chain的资源。

所谓Ripple Mode,实际上指的是用于实现一些算术运算的模式,如加法,减法,计数等等。

在Lattice的Datasheet中有这样一句话:

image.png

由此,我们可以知道使用进位链(Carry Chain)来实现加法等运算,可以获得更高的性能(更快的速度,更小的Latency),那么是否意味着需要更多的资源呢?莫急,请继续往下看!

首先,我们需要知道,如何让综合工具使用进位链来生成加法器呢?一般来说有两种方法:

方法一:使用约束的方式,在Synplify Pro for Lattice Attribute Reference Manual的文档中,可以找到一个叫做syn_use_carry_chain的Attribute,使用该Attribute,可以实现上述的需求,这里就不详细介绍了,有兴趣地可以自己去尝试一下,该文档可以在Diamond的安装目录中找得到。

方法二:通过IPexpress或者Clarity来生成加法器的IP,默认情况下(位数较低时,当位数高于一定数值时,其会采用LUTs或者DSPs来实现),其将采用Carry Chain来实现加法。具体的过程特别简单,此处不再详述,直接来看看结果:

下图为使用Charity生成的模块框图:

image.png

顶层的Verilog代码如下:

module top(a,b,c,d,cout,cin);
    input [3:0] a,b,c;
    output [3:0] d;
    input cin;
    output cout;
    
    test1 instant1(.adder2_DataA(a),
    .adder2_DataB(b),
    .adder1_DataB(c),
    .adder2_Cin(cin),
    .adder1_Cout(cout),
    .adder1_Result(d));
    
endmodule

使用Synplify Pro综合的结果图:

image.png

image.png

image.png

扁平视图为:

image.png

可以看到,此时生成了CCU2的原语,即Carry Chain。那么Diamond报告中的资源使用情况如何呢?

   Number of registers:             0 out of  6047 (0%)
      PFU registers:            0 out of  5936 (0%)
      PIO registers:            0 out of   111 (0%)
   Number of SLICEs:               8 out of  2968 (0%)
      SLICEs as Logic/ROM:         8 out of  2968 (0%)
      SLICEs as RAM:            0 out of  2226 (0%)
      SLICEs as Carry:           8 out of  2968 (0%)
   Number of LUT4s:                16 out of  5936 (0%)
      Number used as logic LUTs:          0
      Number used as distributed RAM:        0
      Number used as ripple logic:          16
      Number used as shift registers:        0

可以看到,此时只使用了16个LUTs,并且全部都用于了Ripple Logic。

再来看看,具体的实现图,第一个为未使用进位链的某个Slice的图,第二个为使用进位链的某个Slice的图。

image.png

image.png

图中的左下角,标明了当前PFU的配置模式。

综上所述,既然CCU2模式并未相对于普通模式使用了更多的资源,同时还能获得更高的性能,所以,在使用加法器时,推荐通过IPexpress或者Clarity来配置生成。