上一次发博客,已经是2个月前了,这中间两个月,干了件很有意义的事情,尤其是对于自己来说,感觉学到了非常多的知识和经验,每天都很忙,忙到没时间逛网站博客,终于忙完闲下来了,连载的事情可不能忘,终于可以书接上回了。 经过前面的几节内容,相信大家已经对时序约束的魅力有了一个大致的印象,而且也都认同了时序约束对于保证一个系统能够可靠运行起着至关重要的作用。那么,为什么时序约束能够解决这些问题?时序约束的原理又是什么?我们又该如何正确的去进行时序约束,以达到想要的性能呢?接下来,我先把我学习时序约束的时候对于时序的理解笔记分享出来。 要把这些问题都研究清楚,不能急,我们首先得知道, FPGA 中是如何实现相应的逻辑功能的。 FPGA 可编程原理 FPGA 是如何实现现场可编程的?大家可能都知道, FPGA 是基于查找表原理实现任意组合逻辑的,那么时序逻辑呢?大家又都知道, FPGA 中有很多的 D 触发器,既然有了 D 触发器,加上时钟,就能实现时序逻辑了。那么不同的 D 触发器之间怎么连接起来呢?答案就是内部连线。 FPGA 内部有大量的长的短的连线,这些连线能够将不同的 LE 的输入和输出连接起来。这样,假设每个 LE 实现一个单独的功能,然后多个 LE 的输入输出按照一定的规则使用连线连接起来,就能实现复杂的功能了。光写文字估计大家越看越迷糊,那我就画图吧。 上图为一个最最基本的 FPGA 架构,且不包括 I/O 块。通过上图右半部分可以看到,一个 FPGA 中以阵列的形式分布着很多的小逻辑块,这个块就是我们熟知的逻辑单元( Logic Elements ,简称 LE ),这些所有的小块共同构成了 FPGA 的可编程逻辑门阵列,而为了把不同的逻辑单元连接起来, FPGA 中分布着大量的可编程互联资源,通过对这些可编程互联资源编程,就能够把各个不同的逻辑单元的输入输出连接起来,在上图的上半部分就演示了部分互联资源将多个逻辑单元按照一定的规则连接了起来。这样看起来,是不是和我们的电路板模型非常的相似,在电路板上有各种芯片,每个芯片都有很多的管脚,通过 PCB 板走线把这些管脚按照正确的方式连接到一起,就能够形成一个可以实现特定功能的电路板了。 那么,上面说到的逻辑单元又是什么呢?在上图的左半部分,绘制了一个逻辑单元的内部示意图(简化版),可以看到,一个逻辑单元由一个查找表( LUT )和 D 触发器( DFF )组成,当然,真实的逻辑单元里面可能还包含了很多其他辅助的电路,这里省略。 LUT 有 4 个输入端口( a 、 b 、 c 、 d ),一个输出端口( o )。 LUT 的输出 o 可以送给 D 触发器的数据输入端口 D ,也可以不经过 D 触发器直接输出。当然了,实际上 D 触发器的输入也可以不来自于 LUT 的输出,而来自于其他逻辑单元的输出。不经过 D 触发器输出,那这个 LE 实现的就是一个纯组合逻辑,经过 D 触发器输出,那这个 LE 实现的就是一个时序逻辑。 一个 LUT 里面可以实现各种组合逻辑,与门、或门、非门等等, LUT 里面实际有 16 个 1bit 的基于 SRAM 结构的存储器,能够对应 a 、 b 、 c 、 d 四个输入的逻辑组合的所有可能, Quartus 通过向这 16bit 的存储器里写入不同的初始值,就能使 a 、 b 、 c 、 d 四个输入在不同的状态下输出不同的逻辑结果,从而实现使用一个 LUT 实现各种组合逻辑的功能。 既然 FPGA 已经能够实现各种的基本逻辑门功能了,而且还有 D 触发器能够实现时序逻辑功能,那么,要实现复杂逻辑功能,无非就是把众多的基本逻辑功能联合起来,从而达到复杂逻辑功能的目的。所以,我们可以认为, FPGA 中实现复杂的逻辑功能,大概就是下面的样子(当然下图所示的逻辑远远算不上复杂逻辑,只是我自己简画的一个 FPGA 内部数据在逻辑单元间的传输模型图)。 我们先对上图进行一个简单的分析,从图中可以归纳出以下信息: l 整个设计有 6 个输入信号( a, b, c, d, e, clk )一个输出信号( out ) l 5 个输入信号 a, b, c, d, e 进入设计后先分别使用一个 LE ( LE0~LE4 )中的 D 触发器打了一拍(设经过 D 触发器后的信号分别为 r_a, r_b, r_c, r_d, r_e ) l D 触发器输出的 r_a, r_b, r_c, r_d 信号进入一个 LE ( LE-5 )中的 LUT 进行了相关的逻辑运算后直接输出,没有经过 LE 的 D 触发器 , 。设 LUT 的输出信号名称为( w_g ) l LE-5 的输出信号 w_g 与 LE-4 的输出信号 r_e 再送入一个 LE ( LE6 )中进行逻辑运算, LUT 的运算结果输出命名为 w_h l w_h 进入 LE6 的 D 触发器,经过该触发器寄存一拍后输出,输出信号命名为 r_o 所以,通过上图我们可以清楚的看到, FPGA 中各种复杂的逻辑,都是使用基本的逻辑单元( LE )构建各种特定的简单的组合逻辑或时序逻辑功能,然后使用片上的可编程互联线资源将这些独立的逻辑功能连接起来实现的。事实上,上图逻辑,可以对应下述使用 Verilog 描述的电路: module logic ( input clk , input a , input b , input c , input d , input e , output out ); // 定义 5 个内部寄存器 reg r_a , r_b , r_c , r_d , r_e ; wire w_g , w_h ; // 输出寄存器 reg r_o ; // 将 IO 输入信号首先使用 D 触发器寄存 always @( posedge clk ) begin r_a <= a ; r_b <= b ; r_c <= c ; r_d <= d ; r_e <= e ; end // 第一级组合逻辑 assign w_g = r_a & r_b | r_c | r_d ; // 第二级组合逻辑 assign w_h = r_e | w_g ; // 寄存器输出 always @( posedge clk ) r_o <= w_h ; // 将寄存器输出信号连接到输出端口 assign out = r_o ; endmodule 当然了,不是说上面的图只能对应这一段代码,毕竟 LUT 内部实现的组合逻辑功能是可以不同的,而组合逻辑功能不同,对应实现的功能也就不一样了。上述代码只是结构上符合上图。 好了, FPGA 的可编程原理讲到这里就 Over 了,这里所谓的 Over ,不是说知识点讲完了,而是有了这些内容,已经差不多可以辅助我们进行下一步的传输分析了,更多 FPGA 可编程原理性的知识,这里暂时没用到,也就不介绍了。 嗯哼,一本正经的敷衍完事了。下楼买泡面去罗。呲溜。