第四篇:进阶篇(上)—— 用户自定义波形与条件波形
系列:《VCDSTIL 实战:从仿真波形到 ATE 测试向量》第 4 篇(共 5 篇)
前言
前三篇介绍的都是 VCDSTIL 的"自动提取"模式:工具从 VCD 中识别所有波形,如实地将它们翻译成 STIL。在理想情况下,这已经足够用。
但现实世界中,自动提取往往不是终点,而是起点。主要原因有两个:
问题一:异步信号产生海量波形
当 VCD 文件来自纯事件驱动的异步仿真时,同一根信号线在不同周期内可能在不同的时间点发生跳变,导致自动提取产生数十甚至数百个"相似但不完全相同"的波形。这些波形在 ATE 上是无法直接使用的——ATE 要求每个引脚的波形数量有限,且时间点固定。
问题二:需要精确控制驱动/采样时机
工程师往往对"信号应该在周期内哪个时刻被驱动"或"输出应该在何时被采样"有明确的设计意图。自动提取无法理解这种意图,它只是忠实记录 VCD 中发生的事情。
本篇介绍两种解决方案:
- 用户自定义波形(User-defined Waveforms):强制指定波形,替代自动提取结果
- 条件波形(Conditional Waveforms):基于信号状态动态选择波形
第一部分:用户自定义波形
核心概念:true条件 vswaveform条件
理解自定义波形的关键,是区分 timing.csv 中Condition列的两种取值:
| Condition 值 | 含义 | 使用场景 |
|---|---|---|
waveform | 将该波形与 VCD 事件比对,匹配则使用 | 自动提取模式(默认) |
true | 无条件使用该波形,不比对 VCD | 用户强制指定模式 |
将 Condition 设为true的波形,称为“强制波形(Forced Waveform)”。
场景描述
假设我们有如下两个需求:
- CLK0:无论 VCD 中的实际波形如何,总是在 0 ns 拉低、在 200 ns 拉高
- D0:输入周期时在 150 ns 驱动数据,输出周期时在 250 ns 采样数据
修改 timing.csv
打开timing.csv(或创建新的timing_forced.csv),针对上述需求做如下修改:
CLK0 的修改
将原来的 CLK0 行(自动提取,Condition 为waveform)替换为:
| Pin | WFC | Waveform | Condition |
|---|---|---|---|
| CLK0 | D | 0ns:D; 200ns:U | true |
- 这里只定义了一个波形(单行)
Condition = true意味着无论这个周期内 VCD 的 CLK0 实际波形是什么,都强制使用这个波形- 之前自动提取的结果是
0ns:D; 150ns:U,现在我们将拉高时间从 150 ns 改为 200 ns
D0 的修改
D0 需要定义两个强制波形,分别处理输入和输出两种情况:
| Pin | WFC | Waveform | Condition |
|---|---|---|---|
| D0 | 150ns:F | true | |
| D0 | 250ns:R | true |
这里出现了两个特殊的事件符号:F和R,需要重点理解。
特殊事件符号详解
VCDSTIL 定义了三个特殊的波形事件符号,专门用于自定义波形中:
F——驱动占位符(Force Placeholder)
150ns:FF是一个"万能输入驱动符",表示"在 150 ns 时,从 VCD 中取出该信号在此周期的实际逻辑值,并用于驱动"。
关键特性:
F只接受输入状态(0、1 等驱动态),不接受输出状态(L、H 等比较态)- 因为不同周期的实际值可能不同(D0 可能是高也可能是低),VCDSTIL 会为每种可能的值自动生成一个对应波形
- 由于波形是动态生成的,不能手动指定 WFC,WFC 列必须留空,工具自动分配
生成结果:
工具会自动展开F为多个实际波形:
"D0" { D { '150ns' D; } U { '150ns' U; } }R——采样占位符(Read Placeholder)
250ns:RR是一个"万能输出采样符",表示"在 250 ns 时,采样该信号的值,并与期望值进行比较"。
关键特性:
R只接受输出状态(L、H、T 等比较态),不接受输入状态- 同样,工具会自动展开为多个采样波形
生成结果:
"D0" { L { '250ns' L; } T { '250ns' T; } H { '250ns' H; } }S——通用占位符(State Placeholder)
若某个引脚在同一波形中既可能是驱动也可能是采样,可以使用S,它同时接受输入和输出状态。
三种符号对比:
| 符号 | 接受状态 | 典型使用场景 |
|---|---|---|
F | 仅输入态(驱动) | 输入引脚,或双向引脚的输入周期 |
R | 仅输出态(采样) | 输出引脚,或双向引脚的输出周期 |
S | 输入态 + 输出态 | 需要同时处理两种情况的引脚 |
执行转换并验证结果
修改完成后,用新的 Setup 文件运行 VCDSTIL:
VCDSTIL-setupsetup_forced.py(setup_forced.py内容与setup_timing.py相同,仅timing_file指向修改后的文件)
查看生成的 STIL,验证结果符合预期:
"CLK0" { D { '0ns' D; '200ns' U; } ← 拉高时间从 150ns 变为了 200ns ✓ } "D0" { D { '150ns' D; } ← 输入周期,150ns 驱动低 U { '150ns' U; } ← 输入周期,150ns 驱动高 L { '250ns' L; } ← 输出周期,250ns 采样低 T { '250ns' T; } ← 输出周期,250ns 采样高阻 H { '250ns' H; } ← 输出周期,250ns 采样高 }第二部分:条件波形
为什么需要条件波形?
强制波形(true)的粒度是"整个信号的所有周期"——一旦设置,对该信号的每一个周期都生效。但有时我们需要更细的控制:
“当某个信号处于特定状态时,使用 A 波形;否则使用 B 波形。”
这正是条件波形的用途。条件波形通过在Condition列中填写一个布尔表达式,让 VCDSTIL 在每个周期开始时动态评估并选择对应波形。
场景描述
在 CLK0 和 D0 的基础上(沿用timing_forced.csv的配置),对D1新增如下需求:
- 输入周期:在 150 ns 驱动数据
- 输出周期:在 250 ns 采样数据
- 特殊情况:当 CLK2 在周期起点为高电平时,关闭驱动(输出高阻 Z),不驱动也不采样
条件语法
条件表达式的格式为:
信号名 == '值' @ (时间点)常用示例:
CLK2=='D'@(t0) # CLK2 在周期起点(t0)为低电平(Drive Low) CLK2=='U'@(t0) # CLK2 在周期起点(t0)为高电平(Drive Up) CLK2=='D'@(t0+5ns) # CLK2 在周期起点后 5 ns 为低电平其中:
t0代表当前周期的起始时间点(相对时间 0 ns)- 可以加偏移量,如
t0+5ns,对于有延迟要求的采样场景很有用 - 多个条件可以用 AND/OR 组合:
CLK2=='D'@(t0) AND RD_=='U'@(t0)
修改 timing.csv
在timing_forced.csv的基础上,新增 D1 的三行定义(创建timing_cond.csv):
| Pin | WFC | Waveform | Condition |
|---|---|---|---|
| D1 | 150ns:F | CLK2=='D'@(t0) | |
| D1 | 0ns:Z | CLK2=='U'@(t0) | |
| D1 | 250ns:R; | true |
逐行解析:
第 17 行(输入驱动):
Pin=D1, Waveform=150ns:F, Condition=CLK2=='D'@(t0)当 CLK2 在周期起点为低(D)时,D1 在 150 ns 处驱动实际数据值(通过F占位符)。
第 18 行(驱动关闭):
Pin=D1, Waveform=0ns:Z, Condition=CLK2=='U'@(t0)当 CLK2 在周期起点为高(U)时,D1 立即(0 ns)进入高阻态Z,驱动关闭。
第 19 行(输出采样):
Pin=D1, Waveform=250ns:R;, Condition=true在所有输出周期,在 250 ns 采样 D1 的值。true条件确保这一行覆盖所有输出周期。
条件评估顺序
VCDSTIL 按行顺序评估条件,使用第一个条件为真的波形。因此true条件的行应永远放在最后,作为默认项(与switch-case中的default类似)。
执行转换并验证结果
VCDSTIL-setupsetup_cond.py查看 STIL,D1 的波形定义如下:
"D1" { Z { '0ns' Z; } ← CLK2 为高时,立即高阻 D { '150ns' D; } ← CLK2 为低时,150ns 驱动低 U { '150ns' U; } ← CLK2 为低时,150ns 驱动高 H { '250ns' H; } ← 输出周期,250ns 采样高 T { '250ns' T; } ← 输出周期,250ns 采样 }在 Pattern 向量中,可以看到 D1 的波形随 CLK2 状态动态切换:
V { "CLK2"=D; ... "D1"=D; ... } ← CLK2 低,D1 在150ns驱动 V { "CLK2"=U; "D1"=Z; ... } ← CLK2 高,D1 高阻 V { "CLK2"=D; ... "D1"=D; ... } ← CLK2 低,继续驱动两种波形类型总结
| 类型 | Condition 值 | 适用场景 | 主要特点 |
|---|---|---|---|
| 自动波形 | waveform | 默认,自动提取 | 严格匹配 VCD,无需手动干预 |
| 强制波形 | true | 需要统一替换波形 | 对该信号所有周期生效,不比对 VCD |
| 条件波形 | 信号==值@(时间) | 需要按周期动态选择 | 最灵活,支持 AND/OR 组合 |
小结
本篇介绍了两种突破自动提取限制的高级特性:
用户自定义波形:
- 将 Condition 改为
true,工具会无条件使用你定义的波形 - 使用
F(仅输入)、R(仅输出)、S(两者)三种特殊符号作为数据占位符 - 使用
F或R时,WFC 列必须留空,由工具自动生成
条件波形:
- 条件语法:
信号=='值'@(时间点),可用 AND/OR 组合 t0表示周期起点,支持t0+Xns偏移- 条件按行顺序评估,第一个为真的波形生效
true条件行作为最后的默认项
下一篇(本系列最后一篇)将介绍另一种完全不同的时序方法——基于时钟的时序提取(Clock-Based Timing),它可以为时钟同步信号生成极为整洁的单一波形。
上一篇:第三篇:CLI 实操篇 —— 用命令行实现自动化流程
下一篇:第五篇:进阶篇(下)—— 基于时钟的时序提取