1 引言
每个设计者在进行Verilog建模时都会形成自己的设计风格,同一个电路设计,用Verilog描述可以写出许多逻辑上等价的模型,而大多数设计者考虑的主要是代码书写上的方便和功能上是否正确,对设计的模型是否最优化结构却考虑甚少,这样不仅加重了逻辑综合的负担,
影响综合效率,而且很可能会导致设计出的芯片未达到最优的面积和速度。因此,在Verilog建模时,很有必要进行模型优化。
2 模型优化概述
影响一个芯片性能的指标主要有两个:面积和速度。模型优化就是通过一定的手段对模型的结构进行调整、组合和精简,从而使设计出的芯片达到更小的面积和更快的速度。
综合所生成的逻辑易受模型描述方式的影响。把语句从一个位置移到另一个位置,或者拆分表达式都会对所生成的逻辑产生重大影响,这可能会造成综合出的逻辑门数有所增减,也可能改变其定时特性。因此,采取一定的手段可以实现对逻辑的优化。但是由于优化终点包含的两个方面面积和速度是互相矛盾的,优化一个方面必定影响另一个方面,而无法实现面积和速度都达到最优,这就需要设计者对两者进行权衡,看设计偏重于哪个方面,而采取不同的优化起点。
下面分别从面积和速度两个方面对模型优化的手段进行介绍。
3 面积的优化
3.1 提取公共子表达式
如果条件语句的互斥分支中有公共子表达式,可以提取该公共子表达式。如下面的模型可以提取公共子表达式:
if(enable)
P = A&(B+C);
else
Q = (B+C)|D;
此模型中条件语句的互斥分支中都
计算了表达式B+C,因此,应将该表达式提取出来放在条件语句之前进行赋值,新模型如下所示:
Tmp = B+C; //引入一个临时变量
if(enable)
P = A&Tmp;
else
Q = Tmp |D;
这样,综合工具就会综合出一个加法器,而原来的模型则会综合出两个加法器。引申到一般情况,若在逻辑中找到有公共子表达式,就可以将该公共子表达式赋值给一个临时变量,然后用该临时变量来表示该公共子表达式,这样就可以减少综合出的ALU单元的数量,以实现面积的优化。
3.2 代码移位
如果在循环语句内某个表达式的值在每次循环中都不变化,可以将该表达式移至循环之外。如下面的模型可以进行代码移位:
P = …
…
for(i=1;i<=5;i++)
begin
…
Q = P+5; //假设循环中未对P赋新值
…
end
赋值语句“Q = P+5;”右端的表达式不随循环变量而变,因此,应将该表达式移至循环之外,新模型如下所示:
P = …
…
Tmp = P+5; //引入一个临时变量
for(i=1;i<=5;i++)
begin
…
Q = Tmp;
…
end
这样,综合工具对“P+5”只会综合出一个加法器,而原来的模型会产生5个加法器,每循环一次就产生一个,造成了代码冗余。优化后的新模型不仅减少了综合出的ALU单元的数量,而且提高了仿真效率。
3.3 资源共享
资源共享是指在互斥条件下共享算术逻辑单元(ALU)的过程。如下面的模型:
if(num>5)
P = A+B;
else
P = A-C;
如果不采用资源分配,算符“+”和“-”就会被综合成两个单独的ALU。而如果采用了资源分配,仅需一个ALU就可以实现“+”和“-”这两种运算。这是因为这两种算符总是互斥地使用。此外还生成了一个多路选择器,用来从B和C中选择合适的量接到ALU的第二个输入端上。实际上,资源分配就是共享算符的过程。共享算符有以下几种可能的情况:
(1)算符相同,运算量相同。如:A+B和A+B,这种情况同“提取公共子表达式”,显然必须共享。
(2)算符相同,有一个运算量不同。如:A+B和A+C,这时需引入一个多路选择器,要进行面积与速度之间的权衡。
(3)算符相同,运算量都不同。如:A+B和C+D,这时需引入两个多路选择器,要进行面积与速度之间的权衡。
(4)算符不同,运算量相同。如:A+B和A-B,可以将“+”和“—”合成一个ALU单元,要共享。
(5)算符不同,有一个运算量不同。如:A+B和A-C,这时需引入一个多路选择器,要进行面积与速度之间的权衡。
(6)算符和运算量都不同。如:A+B和C-D,这时需引入两个多路选择器,要进行面积与速度之间的权衡。
在共享ALU的时候,要在ALU的某个输入端引入多路选择器,这样会增加路径的延迟。因此,设计者应根据实际情况权衡是优化面积重要还是优化速度重要,如果是在“定时至上”的设计中,最好不要采用资源共享。
此外,对于复杂的运算单元,可以采用函数和任务来定义这些共享的数据处理模块,以减少器件资源的消耗,降低成本。
3.4 消除触发器
有些设计者为了图编写代码的方便,喜欢将同一条件控制下的赋值语句写在一个时序控制语句中,如下面的模型:
always @(posedge CLK)
begin
case(State)
0:
begin
preState <= 1;
Dout <= 16’h56;
end
1:
begin
preState <= 0;
Dout <= 16’h29;
end
endcase
end
设计者的本意仅是要把preState的值保存在上升沿触发的触发器中,而Dout的值只是受State影响的组合逻辑,原本只需要1个触发器即可,而上述模型综合后的网表会生成17个触发器,浪费了资源,优化后的模型如下所示:
always @(posedge CLK) //推导出触发器
begin
case(State)
0: preState <= 1;
1: preState <= 0;
endcase
end
always @(State) //组合逻辑
begin
case(State)
0: Dout <= 16’h56;
1: Dout <= 16’h29;
endcase
end