在上一个部分中,说明了几种自己总结的利于设计出高速电路的代码风格。这里其实暗含着下面这样的场景:电路已经设计好了,而且已经很棒,只是需要用风格良好的 HDL 代码进行输入,以保证综合出的电路和设计的一样好。
而在这一部分中,想讨论一下怎样设计高速电路。可以说,是进行 HDL 输入前的工作。
最初的时候,是没有这个部分的。原因是这部分并非是自己总结的内容,更多还是从前辈们那儿吸取的经验。不过,少了这个部分,感觉有点缺乏完整性。毕竟 PART3 和 PART4 的内容,只是一些小技巧。而且我想了一下,将获取的知识再整理整理,也没有什么不好的。
因此,这部分内容是我对 Steve Kilts 的《高级 FPGA 设计:结构、实现和优化》第 1 章 1.3 节(4 至 13 页)的总结。读过这本书的朋友可以跳过这个部分了。其中的例子大都是我自己归纳后想出的简单例子,可能还有些不妥之处,还请各位朋友指出。
这里强烈推荐这本书。一般的 FPGA 书中,讲流程、接口的多,讲电路结构的感觉比较少,而这本书涉及的还挺多的;而比起 Parhi 的《VLSI 数字信号处理系统:设计与实现》这种比较纯粹的 IC 设计的专著(当然这本也很好),这本书又和 FPGA 有着非常紧密的联系。
1 增加寄存器层次
通过在组合逻辑中插入一级寄存器来优化关键路径。
考虑下图所示的三输入加法器。此时电路的关键路径为两个加法器的门延时。
以下是代码片段:
always @ (posedge clk) begin
// 第一层
a_d <= a;
b_d <= b;
c_d <= c;
// 第二层
s <= m+c_d;
end
assign m = a_d+b_d; |
通过在两个加法器之间引入一级寄存器,能够将关键路径缩短为一个加法器的门延时。当然,这会带来一个周期的时延,同时也引入了多余的寄存器,增加了电路面积。
以下是代码片段:
always @ (posedge clk) begin
// 第一层
a_d <= a;
b_d <= b;
c_d <= c;
// 第二层
c_2d <= c_d;
m <= a_d+c_d;
// 第三层
s <= m+c_2d;
end |
2 并行结构
与通常所说的通过增加并行路数从而提高吞吐量的并行架构不同,这里指的是通过重新组织组合逻辑的结构,来优化关键路径。
考虑一个链状的四输入加法器电路。其关键路径为三个加法器的门延时。
以下是代码片段:
assign m1 = a+b;
assign m2 = c+m1;
assign s = d+m2; |
如果采用树状结构,则关键路径仅为两个加法器的门延时。
以下是代码片段:
assign m1 = a+b;
assign m2 = c+d;
assign s = m1+m2; |
3 去除电路中的优先级编码
这点就是 PART3 中所说的“尽量不要使用多层嵌套的条件判断语句”。
考虑一个四状态的独热码状态机,采用优先级编码的电路有四层组合逻辑。
以下是代码片段:
reg [0:3] sta;
always@(posedge clk)
if (sta[0]) ...;
end else if (sta[1]) ...;
end else if (sta[2]) ...;
end else if (sta[3]) ...; |
而如果使用 case 语句,并在【综合选项】中设置好对应的项目(见 PART2),得到的非优先级编码电路则是并行结构,速度更快。
以下是代码片段:
reg [0:3] sta;
always@(posedge clk)
case(1'b1)
sta[0]: ...;
sta[1]: ...;
sta[2]: ...;
sta[3]: ...;
endcase |
这里需要强调的是,如果电路的逻辑确实需要优先级,还应该使用嵌套的条件判断语句,而不该盲目采用无优先级的电路。
4 寄存器平衡(重定时)
电路的速度,是由关键路径决定的。因此在设计电路时,如果有一条路径的门延时特别长,其它路径的门延时再短,该电路的速度也仍然很慢。因此,设计电路时,可以通过改变寄存器的位置,使得各路径的门延时变得平均,以达到提高电路速度的目的。
考虑下面的五输入加法器。可以看到,第一级寄存器和第二级寄存器之间的路径长度是一个加法器的门延时,而第二级寄存器和第三级寄存器之间的关键路径长度是三个加法器的门延时。因此,整个电路的关键路径长度是三个加法器的门延时。
以下是代码片段:
always @ (posedge clk) begin
// 第一层
a_d <= a;
b_d <= b;
c_d <= c;
d_d <= d;
e_d <= e;
// 第二层
m1 <= a_d+b_d;
c_2d <= c_d;
d_2d <= d_d;
e_2d <= e_d;
// 第三层
s <= m4;
end
assign m2 = m1+c_2d;
assign m3 = m2+d_2d;
assign m4 = m3+e_2d; |
经过寄存器平衡后,输入输出之间的逻辑关系没有改变,但两条路径的长度都变为两个加法器的时延,整个电路的关键路径长度缩短为两个加法器的时延。
以下是代码片段:
always @ (posedge clk) begin
// 第一层
a_d <= a;
b_d <= b;
c_d <= c;
d_d <= d;
e_d <= e;
// 第二层
m2 <= m1+c_d;
d_2d <= d_d;
e_2d <= e_d;
// 第三层
s <= m4;
end
assign m1 = a_d+b_d;
assign m3 = m2+d_2d;
assign m4 = m3+e_2d; |
在《高级 FPGA 设计:结构、实现和优化》中,还有一种“重新安排路径”的策略。对于这点,可能我的理解还不够深,感觉这一策略和上面第二种策略类似:都是通过重新组织组合逻辑的结构,以提升电路速度。此处就不对这种策略进行详细的说明了。
总结
-
最基本的策略:在组合逻辑中插入寄存器,通过引入时延与增大电路面积来提升电路速度。
-
组合电路设计策略:提升组合逻辑的并行度,缩短门延时。
-
条件判断电路设计策略:不需要优先级编码的话,采用无优先级的电路。
-
整体设计策略:移动寄存器位置,平衡各组合逻辑路径的门延时。
文章评论(0条评论)
登录后参与讨论