简介 VerilogA是电路设计特别是IC设计常用的建模语言。它使用电压和电流的数学计算来模拟电路模块仿真。VerilogA模型可以准确描述电路的各种特性。因此可以很好的在系统设计前期进行建模。 但是,由于VerilogA完全使用Spice连续时间仿真引擎,在准确描述系统行为的同时带来了相对比较大的仿真计算量,也意味着相对比较长的仿真时间。这在含有高频的信号的系统仿真中尤为明显。 加速系统仿真,特别是含有大量时钟/逻辑行为的系统的其中方法是使用WReal模型。 WReal语言使用数字仿真的引擎,用浮点数来表示节点的电压值。由于不需要连续时间仿真,外加一些属于数字域的加速技巧,在系统仿真中使用WReal模型可以很好地加快仿真。

我们下面利用一个VeriloA搭建的模型和部分优化为WReal的模型进行仿真时间对比。

PFC模型电路 我们在这里搭建了一个CCM的PFC控制器的模型。并不完美但是可以展示两种建模技术之间的差异了。 AC电源经过二极管桥后进入一个Boost电路。控制电路电流环调节电感电流等于AC电压值X输出电压。电压环路保持输出电压为400V。 enter image description here 这里使用模型实现的模块包括:

  • AC电压检测
  • 电感电流检测
  • 输出电压Gm放大器
  • 乘法器
  • 电流Gm放大器
  • 斜坡比较器
  • 驱动电路

VerilogA仿真

第一个版本,所有以上模块都是用VerilogA模型。 做瞬态仿真,仿真上电后的瞬态10mS。为避免磁盘读写占用太多时间,只保存主要的13个节点电压。使用Spectre单进程仿真。 仿真结果Log如下:

Intrinsic tran analysis time:    CPU = 404.168 s, elapsed = 408.992 s.
Total time required for tran analysis `tran': CPU = 404.174 s (6m  44.2s), elapsed = 409.009 s (6m  49.0s).
Time accumulated: CPU = 404.669 s (6m  44.7s), elapsed = 410.611 s (6m  50.6s).
Peak resident memory used = 165 Mbytes.

也就是总共使用了大约410秒。

修改模型

为了加快仿真速度,我们可以打开Diagnose选项,观察仿真器主要花费时间比较多的模块和节点。

在第一版的VerilogA模型中,以下模块花费了比较多的计算时间:

  1. AC电压和电感电流检测放大器。主要原因是考虑了放大器带宽的影响,在模型中使用了S域函数。 解决:由于带宽是我们设计要考虑的一个比较重要的问题,因此这部分计算时间我们并不打算节省。因此这里保留VerilogA的S域计算函数。
  2. Gm放大器导致一些收敛性问题而花费的计算时间。 解决:Gm放大器需要电流输出,这样才能验证不同的补偿网络带来的差异。电流输出只能在模拟域中实现。因此这部分也不做修改。
  3. 比较器和驱动电路。实际上在输出Log里面可以看到PWM信号输出点,占据了15%的Convergence failure counts。是仅次于电流检测电阻两端的计算点。 我们尝试将原本的VerilogA实现的比较器和驱动电路修改为WReal。

原本的比较器代码如下:

analog begin

@(initial_step) begin
    vos = (hysmode==0)?vhys/2:(-vhys);
    i = 0;
end
    i = (V(ip, in)- vos)>0?1:0;

    if(hysmode==0) begin
        vos = (i>0)?(-vhys/2):(vhys/2);
    end
    else begin
        vos = (i>0)?-vhys:0;
    end

V(vout) <+ transition(i*V(vcc, gnd), tdelay, trise, tfall);

end

VerilogA代码本身并不复杂。可以优化的主要是两个方面: 1. 上电过程中,VCC变化的时候可以不进行计算。我们只希望输入变化可能导致输出变化的时候再进行计算。 2. 输出波形transition语句会由于离散的i变化而产生大量的点。 我们修改为WReal模型如下:

always @(ip, in) begin
    i = (ip-in-vos)>0?1:0;
    if(hysmode==0) begin
        vos = (i>0)?(-vhys/2):(vhys/2);
    end
    else begin
        vos = (i>0)?-vhys:0;
    end
    xout = i*(vcc-gnd);
end
assign vout = xout;

注意在这里所有的输入输出都已经设置为WReal类型也就是浮点数值。 敏感列表只在ip和in发生变化的时候进行处理,避免了上电过程中VCC变化导致的计算。 将浮点数直接赋值给WReal网线,由于输出信号进入驱动模块,而驱动模块的输入也是WReal类型,使得这个网线不会被转换为Electrical,也意味着这个网线上没有多余的点和计算量。

我们进一步分析还可以发现,由于比较器的输入是环路的补偿点。缓慢变化的补偿点电压导致敏感列表响应了大量的事件。实际上我们并不关心ip和in的微小变化。我们只关心什么时候输入会导致输出翻转。因此我们进一步将模型修改为如下:

always @(absdelta(ip-in-last, `vtol, 1n)) begin // save even more event
    last = ip-in;
    i = (ip-in-vos)>0?1:0;
    if(hysmode==0) begin
        vos = (i>0)?(-vhys/2):(vhys/2);
    end
    else begin
        vos = (i>0)?-vhys:0;
    end
    xout = i*(vcc-gnd);
end

assign vout = xout;

我们每次保存下当前的输入差分电压。我们只在输入差分电压变化大于预先定义的`Vtol(这里定义为1mV)的时候才进行计算。这样进一步减小了计算量。

对于驱动模块我们使用相同的思路进行修改。

WReal仿真 在经过以上WReal 修改后,我们的系统中含有VerilogA的模型,也含有修改后的比较器和驱动模块的WReal模型。我们再进行同样的仿真:

Intrinsic tran analysis time:    CPU = 53.0514 s, elapsed = 52.0369 s.
Total time required for tran analysis `tran': CPU = 53.0572 s, elapsed =
        52.0454 s.
Time accumulated: CPU = 53.8021 s, elapsed = 59.6655 s.
Peak resident memory used = 125 Mbytes.

仿真时间从410秒变成了59秒,我们得到了7倍的仿真加速。

从前后两次仿真的波形对比可以看到,输出电压几乎没有差异。电感电流检测输出电压,蓝色的VerilogA波形比较“规整”而WReal毛刺多一些,但也基本上可以看到上电inrush到开始跟随AC电压波形的状态。 enter image description here