第五章Tcl 脚本编程

Tcl 基础

Tcl 三大公理

  1. Tcl 中一切都是字符串
  2. 每个字符串都是一个列表
  3. 每个列表由空白分隔的零个或多个元素组成

基本语法

# 变量
set x 42
set name "hello"

# 变量替换 $
puts $x           ;# 输出 42
puts "$name world"  ;# 输出 hello world

# 命令替换 []
set y [expr $x + 1]

# 字符替换(转义) \
puts "Line1\nLine2"

# 大括号 {}:阻止替换
set z {$x + $y}   ;# z 是字符串 "$x + $y",不替换

# 双引号 "": 允许替换
set w "$x + $y"   ;# w 是字符串 "42 + 43"

Procedures(函数)

proc add {{a 0} {b 0}} {
    # 过程定义,a 和 b 有默认值 0
    return [expr $a + $b]
}

add 3 4    ;# 返回 7
add 5      ;# 返回 5

Return Values 和 Return Status

if {{[catch {some_command} result]}} {{
    puts "Error: $result"
}}

Standard Tcl vs Jasper Tcl 的差异

JasperGold 在标准 Tcl 基础上增加了硬件设计相关扩展:

JasperGold 脚本常用任务

-silent 模式

# 静默模式运行,减少输出
jg -fpv script.tcl -silent

Structure Queries(结构查询)

# 查询设计层次
get_design_info

# 列出所有模块
report_modules -list

# 查找信号
find_signal -pattern "fifo*" 

Cone of Influence (COI) Queries

# 查看属性的影响锥
report_coi -property a_assertion_name

# 列出 COI 中的寄存器
report_coi -property a_name -registers

常见脚本模式

# 对所有 failed 属性做处理
foreach prop [get_properties -status failed] {{
    puts "Failed: $prop"
    report_counterexample -property $prop
}}

# 批量设置引擎时间
foreach prop [get_properties -type assert] {{
    set_prove_per_property_time_limit 30s -property $prop
}}

脚本化方法论

为什么要写 Tcl 脚本而不是只用 GUI?脚本让验证流程可复现、可回归、可自动化

为什么需要脚本

标准脚本模板结构

# ===== 标准 FPV 脚本模板 =====
clear -all

# 1. 设置路径
set RTL_PATH ../source/design
set PROP_PATH ../source/properties

# 2. 分析设计和属性
analyze -sv ${RTL_PATH}/top.v
analyze -sva ${PROP_PATH}/bindings.sva

# 3. 展开设计
elaborate -top top

# 4. 时钟和复位
clock clk
reset ~rstN

# 5. 获取设计信息
get_design_info

# 6. 第一轮:快速证明
set_max_trace_length 20
prove -all

# 7. 第二轮:深度证明
set_max_trace_length 50
set_prove_per_property_time_limit 30s
set_engine_mode {K I N}
prove -all

# 8. 报告
report
report -file proof_results.rpt

# 9. CI 检查
set failed [get_property_list -status {failed bounded unknown} -silent]
if {[llength $failed] > 0} {
    puts "ERROR: [llength $failed] properties not proven!"
    exit 1
}

常用脚本技巧

批量操作断言

# 批量操作断言
assert -disable {*}[get_property_list -tag debug_* -silent]
prove -property {top.submodule.*}

# 保存数据库
set proj_dir [get_proj_dir]
save -jdb $proj_dir/session.jdb -capture_setup
脚本最佳实践
  • 总是从 clear -all 开始,确保脚本独立运行
  • 使用变量管理路径,不要硬编码绝对路径
  • 脚本末尾用 exit code 通知 CI 系统是否通过
  • 保存数据库(save -jdb),后续可用 GUI 打开调试
  • 注释每个主要步骤的意图,方便团队理解

来源文档

  • AN_scripting.pdf