2.2 面积与速度互换思想
面积和速度是一对对立统一的矛盾体,要求同时具备设计面积最小,运行频率最高是不现实的。更科学的设计目标应该是在满足设计时序要求的前提下,占用最小的芯片面积;或在所规定的面积下,使设计的时序余量更大,频率更高。这两种目标体现了面积和速度的平衡思想。
面积和速度的互换是FPGA设计的一个重要思想,从理论上来说,一个设计如果时序余量较大,所能达到的频率远远高于设计要求,那么就能通过功能模块复用减少整个设计消耗的芯片面积,这就是用速度的优势换取面积的节约。反之,如果一个设计的时序要求很高,普通方法达不到设计频率,那么一般可以将信号流通过流水线转换成具有固定延时的分级或并行处理,也就是用面积换取速度。
本节着重从速度和面积角度出发考虑如何编写代码或设计电路,以获得最佳的效果。但是,有些方法是以牺牲面积来换取速度,而有些方法是以牺牲速度来换取面积,也有些方法可同时获得速度和面积的好处,具体如何操作应当依据实际情况而定。处理速度与面积问题的一个原则是向关键路径部分要时间,向非关键路径部分要面积。为了获得更高的速度,应当尽量减少关键路径上的LUT级数,尽量压缩线延时;为了获得更小的面积,在非关键路径部分上尽量优化电路结构,压缩面积。
2.2.1 利用层次化设计控制设计结构
在FPGA设计中,有时综合器综合出来的电路不是人们希望的电路,也就是说,实际综合出来的电路不能满足系统时序要求。这个时候(大多时候都要通过控制使综合器综合出来的电路是人们希望得到的电路)就需要通过人为的控制实现希望得到的电路。如图2-7所示为串行加法电路综合结果。
add out:process(clk) if(clk′event and clk=′1′)then z< =a+b+c+d; end if; end process
图2-7 串行加法电路综合结果
上面的例子描述了一个4输入的加法器实现结果,通过综合器综合出来的电路如图2-7所示。如果利用分层设计,则有下面的结构,如果如图2-8所示。
add:process(clk) if(clk′event and clk=′1′)then o< =a+b; end if; end process add1:add PORT MAP( clk= >clk, a= >a, b= >b, o= >e ); add2:add PORT MAP( clk= >clk, a= >c, b= >d, o= >f ); add out:add PORT MAP( clk= >clk, a= >e, b= >f, o= >z );
图2-8 并行加法电路综合结果
第一种方法面积小,但整体速度慢。如果信号D是关键路径,其他信号是非关键路径,或设计中关键路径与A、B、C、D无关,则应当采用这种方法。
第二种方法面积大,但整体速度快。如果对A、B、C、D的时序要求都比较苛刻,应当采用这种方法。
2.2.2 if语句和case语句控制实现结构
if语句指定了一个优先级编码逻辑,而case语句生成的逻辑是并行的,不具有优先级。if语句可以包含一套不同的表达式,而 case 语句比较的是一个公共的控制表达式。通常,case语句实现的电路结构速度较快,但占用面积较大,所以用case语句实现对速度要求较高的编解码电路。if-else语句实现的电路结构速度较慢,但占用的面积小,如果对速度没有特殊要求而对面积有较高要求,则可用if-else语句完成编、解码电路。不正确的使用嵌套的if语句,会导致设计需要更大的延时。为了避免较大的路径延时,不要使用特别长的嵌套if语句。用if语句实现对延时要求苛刻的路径(speed-critical paths)时,应将最高优先级给最迟到达的关键信号Critical Signal。有时,为了兼顾面积和速度,可以将if和case语句合用。
例2-1 用if-then-else语句完成8选1多路选择器。
MUX6to1:process(sel,in) begin if(sel="000")then out< =in(0); elseif(sel="001")then out< =in(1); elseif(sel="010")then out< =in(2); elseif(sel="011")then out< =in(3); elseif(sel="100")then out< =in(4); else out< =in(5); end if; end process;
综合后对应的电路结构如图2-9所示。
图2-9 if-else完成多路选择器综合结果
下面的例子是用case语句完成8 选1 多路选择器的VHDL实例。在大多数FPGA结构中,能够在单个CLB中完成一个4选1的多路选择器,Virtex可以在单个CLB中完成一个8选1的多路选择器,而用if-else语句需要多个CLB才能完成相同功能,因此case语句生成的设计速度更快、延时更小。
例2-2 用case语句实现8选1多路选择器。
MUX8to1:process(C,D,E,F,G,H,I,J,S) begin case S is when"000"= >Z< =C; when"001"= >Z< =D; when"010"= >Z< =E; when"011"= >Z< =F; when"100"= >Z< =G; when"101"= >Z< =H; when"110"= >Z< =I; when others= >Z< =J; end case; end process;
结果如图2-10所示。
图2-10 用case语句完成多路选择器综合结果
2.2.3 减少关键路径的逻辑级数
在FPGA中,关键路径(Critical Path)上的每一级逻辑都会增加延时,为了保证能满足时间约束,就必须在对设计的行为进行描述时考虑逻辑的级数。减少关键路径延时的常用方法是给最迟到达的信号最高的优先级,这样能减少关键路径的逻辑级数。下面的实例描述了如何减少关键路径上的逻辑级数。注意,前面提到的串行加法器也是一个案例。
例2-3 通过等效电路赋予关键路径最高优先级,此例中critical信号经过了2级逻辑,如图2-11所示。
if(clk′event and clk=′1′)then if(non critical=′1′and critical=′1′)then out1< =in1; else out1< =in2; end if; end if;
图2-11 critical信号经过2级逻辑
为了减少critical路径的逻辑级数,将电路修改如下,critical信号只经过了1级逻辑,如图2-12所示。
signal out temp:std logic; process(non critical,in1,in2) if(non critical=′1′)then out temp< =in1; else out temp< =in2; end if; end process; process(clk) if(clk′event and clk=′1′)then if(critical=′1′)then out1< =out temp; eles out1< =in2; end if; end if; end process;
图2-12 critical信号只经过1级逻辑
2.2.4 流水线Pipelining
流水线能动态地提升器件性能,它的基本思想是对经过多级逻辑的长数据通路进行重新构造,把原来必须在一个时钟周期内完成的操作分成多个周期完成。这种方法允许更高的工作频率,因此提高了数据吞吐量,因为FPGA的寄存器资源非常丰富,所以对FPGA设计而言,流水线通常是一种先进的结构,且不耗费过多的器件资源;然而,采用流水线后,数据通道变成多时钟周期,必须特别考虑设计的其余部分,解决增加通路带来的延迟。在定义这些路径的延时约束时必须特别小心,当设计的寄存器之间存在多级逻辑时,其延时为源触发器的clock-to-out时间、多级逻辑的延时、多级逻辑的走线延时和目的寄存器的建立时间之和,工作时钟频率的提高受到这个延时的限制。采用流水线减少了寄存器间的逻辑级数,最终的结果是提高了系统的工作频率。
Pipelining结构示意图如图2-13所示。
其实,在一个设计里影响速度的瓶颈经常只有几条,将延时最大的路径称为关键路径。当设计的运行速度不符合系统设计要求时,可以首先找到不能满足要求的关键路径,按照上述的方法将关键路径上的组合逻辑拆分成多个,中间用触发器隔开,如图2-13所示,这样很容易就可以从根本上提升系统的运行速度了。
图2-13 Pipelining结构示意图
例2-4 采用流水线之前的电路。
process(clk,a,b,c)begin if(clk′event and clk=′1′)then a temp< =a; b temp< =b; c temp< =c; end if; end process; process(clk,a temp,b temp,c temp) begin if(clk′event and clk=′1′)then out< =(a temp*b temp)+c temp; end if; end process;
采用流水线之前综合出的电路结构如图2-14所示。
图2-14 采用流水线之前的电路结构
例2-5 采用流水线之后的电路。
process(clk,a,b,c)begin if(clk′event and clk=′1′)then a temp< =a; b temp< =b; c temp1< =c; end if; end process; process(clk,a temp,b temp,c temp1) begin if(clk′event and clk=′1′)then mult temp< =a temp*b temp c temp2< =c temp1; end if; end process; process(clk,mult temp,c temp2) begin if(clk′event and clk=′1′)then out< =mult temp+c temp2; end if; end process;
采用流水线之后综合出的电路结构如图2-15所示。
图2-15 采用流水线之后的电路结构
2.2.5 串行转并行处理
举一个路由器的例子。假设输入数据流的速率是350Mbps,而在FPGA上设计的数据处理模块的处理速度最大为150Mbps,由于处理模块的数据吞吐量满足不了要求,所以看起来直接在FPGA上实现不了。在这种情况下,应该利用“面积换速度”的思想,至少复制3个处理模块。首先将输入数据进行串/并转换,然后利用这3 个模块并行处理分配的数据,最后将处理结果并/串转换,就完成了数据速率的要求。在整个处理模块的两端看,数据速率是350Mbps,而在FPGA的内部看,每个子模块处理的数据速率是150Mbps,其实整个数据的吞吐量的保障是依赖于3个子模块的并行处理完成的,也就是说占用了更多的芯片面积,实现了高速处理,通过“面积的复制换取处理速度的提高”的思想实现了设计。设计的示意图如图2-16所示。
图2-16 串行转并行处理示意图
2.2.6 组合逻辑和时序逻辑分离
包含寄存器的同步存储电路和异步组合逻辑应分别在独立的进程中完成,组合逻辑中关联性强的信号应放在一个进程中,这样在综合后面积和速度指标较高。这种方法常用在设计Mealy状态机中,Mealy状态机的基本结构如图2-17所示。
图2-17 Mealy状态机的基本结构
由图可看出Mealy状态机由次状态逻辑、当前状态寄存器和输出逻辑3部分组成,其中次状态逻辑和输出逻辑为组合逻辑;当前状态寄存器为时序逻辑。因此,Mealy状态机可由3个进程实现,如下面VHDL实例。
例2-6 5个状态的Mealy状态机。
--Example of a 5-state Mealy FSM library ieee; use ieee.std logic 1164.all; entity mealy is port(clock,reset:in std logic; data out:out std logic; data in:in std logic vector(1 downto 0)); end mealy; architecture behave of mealy is type state values is(st0,st1,st2,st3,st4); signal pres state,next state:state values; begin --FSM register statereg:process(clock,reset) begin if(reset=′0′)then pres state< =st0; elsif(clock′event and clock=′1′)then pres state< =next state; end if; end process statereg; --FSM combinational block fsm:process(pres state,data in) begin case pes state is when st0= > case data in is when"00"= >next state< =st0; when"01"= >next state< =st4; when"10"= >next state< =st1; when"11"= >next state< =st2; when others= >next state< =(others< =′x′); end case; when st1= > case data in is when"00"= >next state< =st0; when"10"= >next state< =st2; when others= >next state< =st1;
end case; when st2= > case data in is when"00"= >next state< =st1; when"01"= >next state< =st1; when"10"= >next state< =st3; when"11"= >next state< =st3; when others= >next state< =(others< =′x′); end case; when st3= > case data in is when"01"= >next state< =st4; when"11"= >next state< =st4; when others= >next state< =st3; end case; when st4= > case data in is when"11"= >next state< =st4; when others= >next state< =st0; end case; when others= >next state< =st0; end case; end process fsm; --Mealy output definition using pres state w/data in outputs:process(pres state,data in) begin case pres state is when st0= > case data in is when"00"= >data out< =′0′; when others= >data out< =′1′; end case; when st1= >data out< =′0′; when st2= > case data in is when"00"= >data out< =′0′; when"01"= >data out< =′0′; when others= >data out< =′1′; end case; when st3= >data out< =′1′; when st4= > case data in is
when"10"= >data out< =′1′; when"11"= >data out< =′1′; when others= >data out< =′0′; end case; when others= >data out< =′0′; end case; end process outputs; end behave;