当前位置:   article > 正文

FPGA从入门到精通(2) - LUT_初识fpga clb之lut实现逻辑函数

初识fpga clb之lut实现逻辑函数

LUT:(look up table) 查找表

今天我要讲的与FPGA CLB相关的第一节LUT。根据上一节课的课程大纲,讲CLB应该是讲SLICEL(SLICEM)。不过当我打开用户手册,看了一下SLICE的结构时(图一),一眼望去,这是分分钟会劝退入门者的节奏啊。为了让读者能更好的接受以及理解,我打算先讲清楚SLICE里面的每一个基本单元,然后再将他们联系在一起,和读者一步步推导出SLICE的结构。(LUT, 进位链,MUX,寄存器,几乎所有的FPGA器件的SLICE都是这四大件组成,只是组合不太一样而已)

图1​​​​

在讲正式的课程内容前,我先列出学完这节课,你将会收获什么。

1.理解LUT与真值表的关系,明白FPGA是用LUT来替代门电路的,以及这样做的好处。

2.理解FPGA 是如何通过两个相同输入的LUT5和一个MUX组成LUT6的。(以此类推用两个相同输入的LUT6和一个MUX组成LUT7,这是课后作业。)

 

 

首先我们看例1的verilog代码,以及它编译后的门级电路 ,全都是与门,较为简单。(门电路的输入没标出,自己和代码自行脑补对应,这也是学习的一部分)

  1. //以下是例1
  2. module top(
  3. input clk,
  4. input rst,
  5. input data0,
  6. input data1,
  7. input data2,
  8. input data3,
  9. input data4,
  10. input data5,
  11. output dout
  12. );
  13. assign dout = data0&data1&data2&data3&data4&data5;
  14. endmodule
例1编译后的门级电路图

 

 

然后我们再看看例2的verilog代码,以及它编译后的门级电路  ,相对于例1又有与门,又有或门,还有异或,比较复杂。(门电路的输入没标出,自己和代码自行脑补对应,这也是学习的一部分)

  1. //以下是例2
  2. module top(
  3. input clk,
  4. input rst,
  5. input data0,
  6. input data1,
  7. input data2,
  8. input data3,
  9. input data4,
  10. input data5,
  11. output dout
  12. );
  13. assign dout = ((data0&data1)^data2|data3&data4^data5);
  14. endmodule
例2编译后的门级电路图

 

从上面的结果我们看出两者编译后的门级电路是完全不一样的,那是不是意味着他们最终在FPGA里也不一样呢?未必。请看下面两张图,他们分别是例1和例2的代码在综合后的原理图(忽略三角形符号的IBUF,OBUF,它们只是输入输出缓冲器),这原理图也就是我以上那段代码在FPGA中最终的表达形式。

 

例1综合后的原理图

 

 

 

例2综合后的原理图

 

咦?怎么乍眼一看,除了连入的线的顺序外(例1顺序也可以改成例2的,这影响不大),两张图几乎是一模一样,是不是老哥我在忽悠观众。其实不然,是因为在FPGA中,是用LUT的来替代门电路,只要逻辑表达式是6位以内输入1位输出,无论编译后门电路复杂还是简单,综合后的结果都是一个LUT6。当然因为LUT6的结构的原因,当5位相同输入2位输出时,综合后的结果也是一个LUT6,本章后面会讲解。继续!

那么在这个LUT6里面又蕴含着什么玄机呢?我们不妨导出它的网表来看一看。

  1. //以下是例1网表中的LUT6
  2. LUT6 #(
  3. .INIT(64'h8000000000000000))
  4. dout_OBUF_inst_i_1
  5. (.I0(data5_IBUF),
  6. .I1(data0_IBUF),
  7. .I2(data2_IBUF),
  8. .I3(data1_IBUF),
  9. .I4(data4_IBUF),
  10. .I5(data3_IBUF),
  11. .O(dout_OBUF));
  12. //以下是例2网表中的LUT6
  13. LUT6 #(
  14. .INIT(64'h78FFFFFFFF787878))
  15. dout_OBUF_inst_i_1
  16. (.I0(data0_IBUF),
  17. .I1(data1_IBUF),
  18. .I2(data2_IBUF),
  19. .I3(data3_IBUF),
  20. .I4(data4_IBUF),
  21. .I5(data5_IBUF),
  22. .O(dout_OBUF));

很显然,这两个LUT6中最大的不同,就是.INIT的值。那么,这个INIT的值又代表着是什么呢?下面我列出了例1和例2中的逻辑表达式所对应的真值表供各位看官参考,由于真值表太大了,我就只拿最高的8位与所导出的网表进行比对。不信的小伙伴可以留言跟我要python的源文件以及所导出的csv文件(●ˇ∀ˇ●)。

例1与例2导出的真值表结果图

网表文件中,例1(O=I0&I1&I2&I3&I4&I5)LUT的.INIT高八位为8'h80=8'b1000_0000,与图中相符。

                      例2(O=(I0&I1)^I2|I3&I4^I5)LUT的.INIT高八位为8'h78=8'b0111_1000,也与图中相符。

由上面的结果我们可以得出,LUT6中INIT存放的结果初始值就是我们逻辑表达式真值表的结果,这就是LUT与真值表之间的关系啦,同时这也是FPGA最为“灵性”的地方,它用LUT来实现各式各样的门电路功能。只要是6位以内输入,1位输出的门电路,无论它多么的复杂,只需要我们修改LUT6的INIT值,都可以将其与门电路一一映射。

如果FPGA里面不是LUT而是各式各样的门电路,那么即便我们在器件做了很多门,却有可能,导致最终的利用率十分的低下。因为在实际应用情况不确定的情况下,我们根本不可能知道用与门,或门,非门还是别的门单元,也不可能不知道会有多少位的输入,多少位的输出。最终将导致器件规模巨大,不具有灵活性。但是使用LUT就恰恰相反,LUT可以用来替代各种门,以及它们的结合,因此用LUT作为FPGA的基本单元可以确保更多的LUT可以用上,来达到提高利用率的目的。

相信很多人都听说过LUT6本质上是64x1(深度为64,位宽为1)的ROM,因为当我们把它的输入I5~I0看作ROM的6根地址线,那么O就是当前输入地址所输出的结果。

 

之前我们提到,XILINX的LUT6除了可以做到6位输入1位输出,还可以做到5位相同的输入2位输出,那么它是怎么实现的呢?从下图中,我们可以看到XILINX的LUT6是有两个输出的,那这两个输出是怎么来的呢?不急,继续往下看!

好吧,不卖关子,直接开奖,LUT6是由两个LUT5组成的,具体结构如下图(自己画的略丑,请见谅)。

1.当LUT6作为两个5位相同输入2位输出时,I5被强行写为1,MUX选择下面的LUT5的输出结果到O6,至于上面的那个LUT5输出结果,它是可以直接输出到O5的。所以可以有两个LUT5输出(O5,O6)。

2.当LUT6作为6位输入,1位输出时。上面的LUT5存放I5为0时的输出结果,下面的LUT5存放I5为1时的输出结果 ,将I5接入MUX的数据选择端口,那么两个LUT5和一个MUX就可以组成一个LUT6,此时O6为LUT6的输出,O5为上面的LUT5的输出(O5这个输出我们一般没怎么用到,容易被忽视)。

下面,我简单的举个例子(例3)来验证5位相同输入2位输出的情况

  1. //以下是例3
  2. module top(
  3. input clk,
  4. input rst,
  5. input data0,
  6. input data1,
  7. input data2,
  8. input data3,
  9. input data4,
  10. output dout0,
  11. output dout1
  12. );
  13. assign dout0 = data0&data1&data2&data3&data4;
  14. assign dout1 = data0&data1|data2^data3&data4;
  15. endmodule

例三综合后的原理图如下,从资源占用报告中可以看出,即便原理图是两个LUT5,但最终资源依旧和之前的例1,例2一样,只占用了1个LUT6。

例3综合后的原理图
​​​​

好的,说了那么多6输入1输出,5输入2输出的。但在实际的应用中,输入输出的数量会根据应用所需进行修改。那么应该如何修改呢?

1.当输出是1位,输入比6位少,那么我们只关注有效输入位真值表的结果。举个例子,我只用了两个输入(低2位),将它作为异或门。无论高4位(I5~I2)是啥,我们只需要将I1=0,I0=1或者I1=1,I0=0的真值表输出设为1,然后再把真值表64个输出结果写入LUT6的原语中的.INIT就好。

2.当输出是1位,输入比6位多。或者输出大于1位的情况,我们只需要使用多个LUT6并行处理就好。并行LUT6越多,也就意味着一个完整的多位输入得分为多个路径才能到输出,但实际情况中,路径的延迟很难保持一致,从而导致输出结果错误。所以我们通常需要使用到寄存器来同步后再将结果输出,以确保输出结果正确。同等条件下,如何让FPGA在以高频率运作的同时,输出结果尽可能保持正确,这就是让广大与FPGA相关工作者掉发的原因,-__-!!!!。好吧,今天就说到这。

---------------------------------------------------------------------------------------------------------------------------------------

再哔哔两句:

如今,某国对我国进行出口限制,其中就包括限制某国的FPGA,然而我们国产FPGA的老大哥紫光同创也只能达到X家、A家十年前的水平。这也意味着将来有可能很快会有那么一天,我们现在所用的国外那些高端的FPGA越来越少,越来越贵。到了那时,我们很有可能不得不用国产,用国产会有许许多多的限制,其中很重要的一点限制就是资源数(还有EDA IP 生态等等)。我们不能苛求国产厂家明天就研发出个7nm ,几百K资源的FPGA,但是我们能做到的就是在已有的条件下进一步优(ya)化(zha)FPGA上的资源,这是为什么我一开头会花那么多口水去讲FPGA的片上资源而不是上来就叫你怎么去用IP的原因。

不急不躁,打好基本功,不断的往上爬,终究有一天你会发现原来自己已经爬到那么高的地方了。

 

 

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

闽ICP备14008679号