当前位置:   article > 正文

从底层结构开始学习FPGA(2)----LUT查找表

从底层结构开始学习fpga

文章目录

        系列目录与传送门

        一、概述

        二、实现原理


系列目录与传送门

        《从底层结构开始学习FPGA》目录与传送门


1、概述

        记得刚接触FPGA的时候,总能看见类似这样的一句话----FPGA是基于查找表LUT的可编程逻辑器件。FPGA常常被人比作“数字积木”,就是因为底层资源的丰富和灵活,要做任何“玩具”(项目要实现的功能,也可以说是电路),只需要设计好“图纸”(RTL),即可使用积木(FPGA丰富的底层逻辑资源,如LUT、FF、MUX等等)来实现。

        在最底层,可配置逻辑模块有着两种最基本的部件:触发器和查找表(LUT)。这很重要,因为各种FPGA家族之所以各不相同,就是因为触发器和查找表组合的方式不同。LUT查找表可以算其中相当重要的一个底层资源,通常用来实现所需的组合逻辑功能。而FF触发器则一般用来实现时序逻辑功能。

        在7系列器件之前的器件多使用LUT4,即4输入LUT;而7系列后则多使用LUT6,即6输入LUT。

2、实现原理

        LUT(look up table),即查找表,其原理其实也就是一个一个查找表,根据输入去找到相应位置的信号,然后做输出。说白了就好像一个小容量的ROM,把输入当作地址信号,对LUT里面预存的内容进行寻址。

        7系列的FPGA的LUT有6个输入端口(I0~I5),然后有两个输出端口(O5,O6),如下所示:

        6个输入端口一共有2^6 = 64种输入,所以可以将一个LUT6视为一个容量为64的ROM,其中存储的是64种不同的逻辑运算的结果,而不同的输入则组成了ROM的地址线。所以逻辑运算的实现实际上就是对LUT6的一个译码过程。

        假设有这样一个逻辑: y = a0 & a1 & a2 & a3 & a4 & a5。

        这个例子比较简单,其只在所有输入均为1的情况下输出才为1,其他情况输出均为0。将其写成Verilog的形式:

  1. module test(
  2. input a0,
  3. input a1,
  4. input a2,
  5. input a3,
  6. input a4,
  7. input a5,
  8. output y
  9. );
  10. assign y = a0 & a1 & a2 & a3 & a4 & a5;
  11. endmodule

        用Vivado analysis一下,看看分析出来的门级电路是什么样子的:

        很显然,就是5个与门实现6输入相与的功能。如果FPGA中没有LUT这种结构,而是由不同的逻辑门组成,那么实现上述逻辑功能则最终会映射到5个与门。可是随着设计的复杂化,仅仅使用与门显然是无法满足设计需求的,我们还需要其他逻辑门,如或门、非门、异或门等。当然这些逻辑门都可以由数个与非门或者或非门实现,但是这无疑需要进行一个译码过程以及会造成资源的浪费。

        而LUT将所有可能的逻辑值均存起来,用的时候再查表就方便多了。我们不需要知道这个电路会映射成什么样的、多少个逻辑门,我们只需要根据输入直接查表找对应的输出就行了。这大大提高了灵活性以及资源的利用效率。

        此外,采用传统逻辑门电路实现逻辑关系的方法也存在一些严重的缺点:

  • 输入变量从通过逻辑电路到输出变量,存在一定的延迟,该延迟的大小和逻辑电路的复杂程度密切相关。逻辑电路越复杂,延迟越大,因此,延迟是不确定的;
  • 延时的倒数是频率,频率和时序电路的工作速率密切相关。因为延迟不确定,所以频率也不确定,这将严重影响整个电路的工作性能;
  • 逻辑电路的复杂程度和输入逻辑变量的个数、逻辑门的个数有关。因此输入逻辑变量越多,逻辑电路就越复杂。

        说回正题,我们把上述代码再综合(synthesis)一下,看看最终的电路实现是什么样子的:

        和料想的一样,就是综合出来一个LUT6。

        下图是LUT6的源语形式(也可以说是网表形式),其中的INIT例化的值即是载入的64个输入的对应值。

        我们把上述代码的网表文件导出来看看(我只截取了LUT6部分):

        注意INIT的值,64bit中只有最高位为1,其他63位为0。也就是说,只有当6输入均为1时输出才为1,其他输入情况下输出均为0。与料想的逻辑值一致,也就是说INIT载入的是要查表的值,也就是要写入LUT这个小ROM的初始值。

        再把上述代码再实现(implementation)一下,看看映射到FPGA芯片的具体实现是什么样子:

        很简单,就是6个输入+1个输出+1个LUT6,LUT6的结构与理论一致。注意:LUT6中的O5输出并没有使用。


       

        再看下LUT6的结构:

        其实1个LUT6是由2个LUT5 + 1个MUX组成的。2个LUT5共用5个输入,其中一个LUT5的输出直接连接到O5;同时该输出也连接到MUX,另一个LUT5的输出也连接到MUX,而输入I5则作为MUX的选择控制信号。

  • 当LUT6作为6输入查找表使用时,则其中一个LUT5存放I5为1时的结果,而另一个LUT5则存放I5为0时的结果,此时O5输出不使用。而O6输出则通过I5的控制来实现6输入的查找结果
  • 当LUT6作为2个5输入查找表使用时,则将I5固定为1,则其中一个LUT5实现逻辑功能y1,并固定通过MUX到O6输出,而另一个LU5则实现逻辑功能y2,并直接通过O5输出

        

        举例如下:

                逻辑 y1 = a0 & a1 & a2 & a3 & a4;

                逻辑 y2 = a0 | a1 | a2 | a3 | a4;

        Verilog如下:

  1. module test(
  2. input a0,
  3. input a1,
  4. input a2,
  5. input a3,
  6. input a4,
  7. output y1,
  8. output y2
  9. );
  10. assign y1 = a0 & a1 & a2 & a3 & a4 ;
  11. assign y2 = a0 | a1 | a2 | a3 | a4 ;
  12. endmodule

        vivado综合的电路:

        结果是2个LUT5,但是我们知道7系列的FPGA是没有独立的LUT5这玩意儿的,所以最终映射到具体芯片上还不是这样子。

        最后来看看vivado实现的电路(映射到FPGA芯片的具体实现):

        和预想的一样,就是一个2输出的LUT6。

        其他位数输入的逻辑实现就可以采用多个LUT6级联来实现,当输入位数过多,即组合逻辑复杂时,则会造成级联的LUT6过多,即逻辑级数多大,其结果是通常会造成组合逻辑延时多大,导致时序紧张,一般采用插入FF的方法来切割组合逻辑,使得每一段的逻辑级数都不过于长,从而优化时序。

3、缺点

        虽然LUT6可以实现6输入内的所有组合逻辑,但它的缺点也很明显,因为它太灵活了!灵活即意味着通用,既然通用,那自然不可能面面俱到。

        就像速度和面积是一对矛盾体一样,通用和面积也是一对矛盾体。6输入的LUT6需要64个SRAM单元,假设一个SRAM的构成是6个晶体管,那么一个LUT6则至少需要64*6 = 384个MOS管(还没加上译码电路所用的晶体管)。

        假设要实现电路 y = a0 & a1 & a2 & a3 & a4 & a5; 那么需要5个and与门,每个与门由6个MOS管构成:

        由门电路来构成这个电路的话,只需要5*6 = 30 个MOS管!这可比LUT6的近400个MOS管不知道小到哪里去了。

        再假设电路变为 y = a0 | a1 | a2 | a3 | a4 | a5; 此时的电路就变成了需要5个or或门了。类似的,电路也可能是5个与非门、或非门等等。因为FPGA的可编程特性,也为了通用性,FPGA就把这些不同的门电路给“转换”成了查找表LUT。

        FPGA的通用性其实是用面积换来的。当然了,面积大那功耗自然也大。

4、总结

        LUT的逻辑实现是通过将期望结果存入SRAM中,通过不同的输入等于不同地址这一索引方式,来实现对逻辑真值表的查找。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/731140
推荐阅读
相关标签
  

闽ICP备14008679号