Verilog-A 调试与收敛

Verilog-A 语法简单,问题多在仿真中出现。调试手段基本就是打印语句 + 良好的参数设计。

调试输出基本套路

1. initial_step 打印参数(+%m 区分实例)

parameter integer DEBUG = 0;
parameter integer par1 = 100;
parameter real par2 = 20.1;

analog begin
    @(initial_step) begin
        $strobe("Instance is %m, par1 = %d, par2 = %g", par1, par2);
    end
    V(out) <+ 1;
end

2. DEBUG 参数开关

@(initial_step) begin
    if(DEBUG > 0)
        $strobe("Instance is %m, par1 = %d", par1);
end

3. 运行时输出(加时间戳)

$strobe("Sim Time is %g, Instance is %m, xout = %g", $abstime, xout);

4. 定时输出(timer 事件)

@(timer(0, 10u)) begin
    if(DEBUG > 0)
        $strobe("Instance is %m, time=%g, par1=%d", $abstime, par1);
end

5. 条件触发输出

6. 输出到文件(CSV 便于处理)

integer fhandle;
analog begin
    @(initial_step) begin
        if(DEBUG > 0) begin
            fhandle = $fopen("/home/user/debug.csv","w");
            $fstrobe(fhandle, "This_is_a_debug_data_table");
        end
    end
    @(timer(0, 10u)) begin
        if(DEBUG > 0)
            $fstrobe(fhandle, "%m, %g, %g", $abstime, V(in));
    end
    V(out) <+ 0;
    @(final_step) begin
        if(DEBUG > 0) $fclose(fhandle);
    end
end
endmodule

随机数种子技巧

问题

Verilog-A 无法获取真实时间作为种子 → 每次仿真随机数序列相同。

解决方案 1:系统随机文件(Linux)

integer seed, fhandle;
@(initial_step) begin
    fhandle = $fopen("/dev/urandom", "r");
    $fscanf(fhandle, "%c", seed);   // %c 取一个字符(ASCII 值作种子,有告警但可用)
end

⚠️ /dev/random 可能阻塞(系统随机值不足);用 /dev/urandom 非阻塞更稳。

解决方案 2:Monte Carlo 专用(Cadence)

@(initial_step) begin
    seed = $cds_get_mc_trial_number();   // 每次 MC 仿真唯一种子
end
@(timer(0, 10u))
    vos_number = rdist_normal(seed, 0, 1);
V(out, gnd) <+ vos_number;

收敛问题排查

1. 先检查代码本身

很多"不收敛"其实是代码写错但语法合法。常见错误:

2. 初始态收敛问题

3. 上电或不上电

4. 设定电压而非电流

// 单端限制
I(out) <+ iconst*(1-1/100^V(out));
// 两端限制
I(out) <+ iconst*(1-1/100^V(out) - 1/100^(5-V(out)));

5. 输入输出阻抗

6. 内部限制(防开环巨大输出)

开环增益 10e6 时,1mV 失调 → 1000V 输出灾难。用 tanh 限幅:

V(sigout) <+ 0.5*(out_high - out_low)
            * tanh(gain*(V(sigin, sigref) - offset))
            + (out_high + out_low)/2;

tanh 中间线性度好、两端饱和、处处连续可导,是建模限幅首选。

7. 反馈

调试思维导图

不收敛/不稳定
 ├── 审视代码(位序/begin-end/运算次序/叠加特性/自循环)
 ├── 初始态(initial_step 初值、模块间匹配)
 ├── 上电过程(真实器件 vs 自写模型差异)
 ├── 电压 vs 电流描述(电压优先、电流加限制)
 ├── 阻抗(限压即限阻、高频 LC)
 ├── 内部限制(tanh 限幅防 1000V 输出)
 └── 反馈(放电路结构,模型只写开环)

相关笔记