首页 > 代码库 > 基于VerilogHDL模型优化

基于VerilogHDL模型优化

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

3.5  消除锁存器

    推导锁存器的规则是:
    (1)变量在条件语句(if或case语句)中被赋值。
    (2)变量未在条件语句的所有分支中都被赋值。
    (3)在always语句的多次调用之间需要保存变量值。
    同时满足以上3个条件,就会将变量推导成锁存器。有的设计者可能会图省事没有在所有的条件分支中对变量进行赋值,这样就导致原本不需要产生锁存器的变量产生了锁存器,而浪费了资源。
    消除锁存器的最好方法是在设计时明确哪些变量需要锁存器,哪些则不需要。对不需要推导出锁存器的变量,在其所有条件分支中都对其赋值,或者是在条件语句之前对其进行初始化赋值。

 

4  速度的优化

4.1  使用括号

    在表达式中使用括号,可以控制所综合出的逻辑电路的结构,缩短电路的关键路径,从而实现速度的优化。
    例如对语句P = A+B-C+D,综合工具在综合右端表达式时遵循从左至右进行演算,就会构造出如图1所示的电路。
    使用括号后的语句为:P = (A+B)-(C-D),综合后的电路如图2所示。

                          
图1 未使用括号综合出的电路                              图2 使用括号综合出的电路

很显然,未使用括号时关键路径的深度为3,而使用括号后的关键路径深度为2,优化了速度。

4.2 提取关键路径

   在电路设计中,有些信号的路径比较长,或者信号本身就来得比较晚,从而造成电路的建立时间不够。这种引起电路建立时间不够的信号路径称为关键路径。这种关键信号路径大多要提取出来特别对待,以尽量减少它的延时。
4.2.1 提取重复变量
    如语句P =(a&b&c)|(b&d&e)中的信号b的路径就是关键路径,可以提取出来单独处理,提取关键路径前后的电路模型如图3所示。

 

图3  电路模型比较

   由图中可以看出,信号b的路径由2级变成了1级,增加了其建立时间,缩短了延迟,而且还减少了一个与门,既提高了速度又减少了面积。
4.2.2 提取先行关键路径
如下面的模型所示:
    always @(a or b or c or d or e or current_out)
    begin
        next_out = current_out;
        if(!a)begin
             if(b & !(d & !e)) next_out = !c;
             else next_out = c;
        end
        else if(d &!e)    next_out= c;
    end
其中,输入信号e在always语句块中是个时间非常紧的关键信号,需要进行特殊处理。处理后的模型如下所示:
    always @(a or b or c or d or e or current_out)
    begin
        next_out = current_out;
        if(e)begin
             if(!a)   begin
                  if(b)   next_out = !c;
                  else next_out =c;    
             end
        end
        else begin
             if(!a)   begin
                  if(b&!d) next_out = !c;
                  else next_out = c;
             end

             else if(d)   next_out = c;

        end
    end
    上述模型描述了关键信号e的分步提取方法,改写后的描述都与原always块逻辑等效。

 

5 其它优化手段

5.1 引用工艺库中预定义的宏结构

   设计者可以根据需要使用模块实例化语句来实现预定义功能块,就好像对待元件那样,在模型中对其进行实例化,然后再综合此实例模型。例如,要建立一个加法器,根据面积约束,可以调用一个面积高效的行波加法器,而根据延时约束,可以调用一个快速但面积较大的先行结构加法器。

5.2 使用小型设计

   实验研究表明逻辑电路规模在2000门至5000门时逻辑优化器的优化效果最佳,因此,设计时应尽量组织成多个模块或多个always语句段。
   综合过程的运行时间主要用于逻辑优化,它与设计规模呈指数关系,因此将各个子功能块的规模保持在可处理的设计范围内很关键。

5.3 传播常量

   使用常量传播技术可以增加电路模型修改的灵活性和可移植性。如果有一个确定意义的常量并且在模型中的多处地方都引用到,则可以将该常量值定义为一个常量符号,然后直接引用该常量符号即可,如下所示:
    parameter COUNT = 16;
    …
    P = COUNT*2;
    for(i=0;i<COUNT-1;i++)
    …
   其中,COUNT表示的是循环次数,根据需要可以在语句“parameter COUNT =16;”中修改其值。由于它是一个常量,在综合时不会为表达式“COUNT*2”和“COUNT-1”生成任何硬件,而是在编译时直接计算出表达式的值并将其赋给变量。

 

6  结束语

   一般情况下,综合工具会自动对Verilog模型进行优化,但如果设计者在电路设计时直接就编写出结构优化的电路模型,就会大大减少综合工具的运行时间,甚至有时候综合工具无法优化的结构经过手工调整后实现了优化的目的。因此,养成良好的设计风格是很重要的,在设计时不仅要保证设计的正确性,还要注重设计的高效性,避免不必要的反复修正,这样才能提高设计效率,缩短开发周期。

基于VerilogHDL模型优化