9.1 FPGA系统设计的3个基本原则
9.1.1 面积与速度的平衡互换原则
在FPGA设计领域,面积通常指的是FPGA的芯片资源,包括逻辑资源和I/O资源等。速度一般指的是FPGA工作的最高频率。和DSP或者ARM芯片不同,FPGA设计的工作频率不是固定的,而是和设计本身的延迟紧密相联。
在实际设计中,使用最小的面积设计出最高的速度当然是每一个开发者追求的目标。但往往面积和速度是不可兼得的。想使用最低的成本设计出最高性能的产品是不现实的,只有兼顾面积和速度,在成本和性能之间有所取舍,才能够达到设计者的产品需求。
1.速度换面积
速度优势可以换取面积的节约。面积越小,就意味可以用更低的成本来实现产品的功能。
所谓的速度优势指的是在整个FPGA设计中,有一部分模块的算法运行周期较其他部分快很多,这部分模块就相对与其他的部分具有速度优势。利用这部分模块的速度优势来降低整个FPGA设计的使用资源就是速度换面积原则的体现。
速度换面积原则在一些较复杂的算法设计中常常会用到。在这些算法设计中,流水线设计常常是必须用到的技术。在流水线的每一级,常常有同一个算法被重复的使用,但是使用的次数不一样的现象。在正常的设计中,这些被重复使用但是使用次数不同的模块将会占用大量的FPGA资源。
随着FPGA技术的不断发展,FPGA内部越来越多的内嵌了DSP乘法模块,为一些常用算法的实现提供了很大的方便,也大大提高了运算的速度和能力。因此,在以往设计中那些被重复使用的算法模块的速度可以很高,即相对其他部分具有速度优势。
利用这个特点,重新对FPGA的设计进行改造。将被重复使用的算法模块提炼出最小的复用单元,并利用这个最小的高速单元代替原设计中被重复使用但次数不同的模块。当然在改造的时候必然会增加一些其他的资源来实现这个代替的过程。但是只要速度具有优势,那么增加的这部分逻辑依然能够实现降低面积、提高速度的目的。
如图9.1所示,是一个流水线的n个步骤,每个步骤都相应地运算一定次数的算法,每个步骤的算法都占用独立的资源实现。其中运算次数方框的大小表示占用的设计资源。
图9.1 未使用速度换面积的流水线算法
假设这些算法中有可以复用的基本单元,并且具有速度优势,那么就可以使用如图9.2所示的方式实现面积的节省。在这种方法中,通过将算法提取出最小单元,配合算法次数计数器及流水线的输入输出选择开关,即可实现将原设计中复杂的算法结构简化的目的。
图9.2 使用速度换面积的流水线算法
可以看到,速度换面积的关键是高速基本单元的复用。
2.面积换速度
面积换速度正好和速度换面积相反。在这种方法中,面积的复制可以换取速度的提高。支持的速度越高,就意味着可以实现更高的产品性能。在某些应用领域,比如军事、航天等,往往关注的是产品的性能,而不是成本。这些产品中,可以采用并行处理技术,实现面积换速度。
如图9.3所示是利用并行技术、面积(资源)复制的方法实现了高速的处理能力。
在进行FPGA进行设计时,我们必须注意到,FPGA的工作频率是有限的。因为FPGA是工作在TTL电平下,该电平结构(晶体管-晶体管)所能支持的切换频率是有限的。但是在实际的产品设计中,高频的处理需求越来越多,如何解决这个矛盾?
首先使用简单的串/并转换实现多路的速度降频,如图9.3所示,450Mbit/s的频率分为3路,每路150Mbit/s;其次在每一路上使用相同算法但各占设计资源的处理模块进行低频(相对)的处理;最后再将每一路的处理结果进行并/串转换成为高频的输出数据。
图9.3 面积换速度实现并行高速处理
串/并和并/串转换能够支持那么高的频率吗?这个问题的解决得益于FPGA技术的发展。如今主流的FPGA器件中,都带有高速的I/O资源及内部RAM供用户使用。这些高速I/O资源及内部RAM能够实现I/O接口的稳定高速切换和数据总线宽度的转换。这部分的详细介绍参见9.3节。
9.1.2 硬件可实现原则
FPGA设计通常会采用HDL语言,比如Verilog HDL或者VHDL。当采用HDL语言来描述一个硬件电路功能的时候,一定要保证代码描述的电路是硬件可实现的。Verilog HDL语言的语法与C语言很相似,但是它们之间有本质的区别。
C语言是基于过程的高级语言,编译后可以在CPU上运行。而Verilog HDL语言描述的本身就是硬件结构,编译后是硬件电路。因此,有些语句在C语言的环境中应用没有问题,但是在HDL语言环境下就会导致结果不正确或者不理想。
比如for语句,以下代码在C语言下是一段普通代码:
for (i=0; i<16; i++)
DoSomething(); //实现函数的重复调用
在C语言下运行没有任何问题,但是在Verilog HDL的环境下编译就会导致综合后的资源严重浪费。所以for语句在Verilog HDL环境下一般只用来做仿真或者行为级的描述。那么for语句在HDL语言中如何实现呢?有几种不同的模式,其中最常见的是以下方式。
reg[3:0] counter; //调用次数计数器
always @ (posedge clk) //计数器计数模块
if (syn_rst)
counter <= 4’b0;
else
counter <= counter + 1;
always @ (posedge clk) begin //使用case语句实现分支调用,
case (counter) //配合计数器计数,各分支可使用同样的执行语句
4’b000: DoSomething; //实现该语句的重复调用
4’b0001: DoSomething; //等同于高级语言中的for语句
… …
default: DoSomething;
endcase
end
在counter计数器的不同状态可以设计不同的动作。如果都是完成一样的操作,就是循环for语句了。
9.1.3 同步设计原则
同步电路和异步电路是FPGA设计的两种基本电路结构形式。
异步设计的核心电路是由组合逻辑电路构成的,比如异步的SRAM、FIFO的读写控制信号,地址译码电路等。这类电路的输出信号不依赖于任何时钟信号。异步电路最大缺陷就是会产生毛刺。
同步设计的核心电路是由各种触发器构成的。这类电路的任何输出都是在某个时钟的边沿驱动触发器产生的。所以,同步设计可以很好地避免毛刺的产生。
在专用芯片(ASIC)的设计过程中,同步设计一般会比异步设计占用更多的资源。但是在FPGA设计过程中并不是这样。FPGA内部的最小单元是LE,每个LE里面既包括了实现异步电路需要的查找表资源,也包括了实现同步电路需要的寄存器资源。
如图9.4所示是Altera公司的Cyclone系列FPGA的LE结构图。从图中可以看出,这个LE中包含了输入输出的MUX,同步和异步的控制逻辑,LUT以及可编程寄存器。如果使用这个系列的FPGA(其他的FPGA类似)进行同步电路或异步电路的设计,那么不管使用的是LE中的LUT还是寄存器,综合工具综合的结果都是消耗一个LE。
图9.4 Cyclone LE结构图
因此,单纯的使用异步电路也并不会节省触发器的资源。或者说,使用同步设计电路,并不会带来FPGA资源的浪费。但是全同步的设计对于FPGA的仿真验证是有好处的。因为电路的所有动作都是在相同的时钟边沿来触发,可以减少整个设计的延迟,提高系统的工作频率。