1. 仿真脚本基础

大家好,我是你们这门课的老朋友。今天咱们聊聊仿真脚本的入门知识。说实话,我刚入行那会儿,对脚本这东西也是又爱又恨。爱的是它能帮我省不少力气,恨的是刚开始总写不对。但后来我发现,搞懂这三个问题,脚本这事儿就通了:它到底是什么?为啥要批量跑?用什么语言写?

1.1 什么是仿真脚本?

说白了,仿真脚本就是一段“自动化指挥代码”。你想想看,平时我们跑一个仿真,是不是得敲一堆命令?比如启动仿真器、加载设计文件、设置波形、跑测试用例、最后看结果……这些步骤要是每次都手动来一遍,手都得抽筋。

仿真脚本的作用,就是把这一连串操作打包成一个“一键执行”的流程。 我习惯把它比作一个“机器人助理”——你告诉它今天要跑哪些测试,它自己就去挨个执行,跑完了还给你整理报告。

举个例子,一个最简单的仿真脚本可能长这样:

#!/bin/bash
# 一个简单的仿真脚本示例
vlog -work work *.sv        # 编译所有SystemVerilog文件
vsim -c -do "run -all; quit" work.top_tb  # 跑仿真并退出

嗯,这里要注意:脚本本身不改变仿真器的行为,它只是把你要做的事情“自动化”了。我在项目中遇到过不少新人,以为脚本能“优化”仿真速度,其实不是的——它优化的是你的操作效率。

1.2 为什么需要批量运行?

这个问题,我当年也问过自己。单个测试用例跑得好好的,干嘛非要批量跑?

原因其实很简单:一个芯片设计,少说几十个测试用例,多则上千个。 你一个个手动跑,不仅慢,还容易出错。我印象最深的一次,是手动漏跑了一个边界条件的测试,结果流片回来芯片在低温下直接罢工……从那以后,我再也不敢手动跑了。

批量运行的好处,我总结为三点:

  • 省时间:晚上下班前点一下批量运行,第二天早上结果就出来了。你想想看,这省了多少盯着屏幕的时间。
  • 防遗漏:脚本会按照你设定的列表,一个不落地跑完所有用例。不会出现“哎呀,那个用例我忘了跑”的情况。
  • 好追溯:每次批量运行都会生成日志和报告,哪个用例过了、哪个挂了、挂在哪一步,一目了然。我习惯把这些日志按日期归档,出了问题随时翻旧账。
核心观点: 批量运行不是“偷懒”,而是“工程化”。在团队协作中,批量脚本是保证回归测试质量的基础设施。

1.3 脚本语言选型:Python vs Shell

好,到了大家最纠结的地方了——到底用 Python 还是 Shell?我两个都用过,踩过不少坑,今天把经验分享给你。

先看一张对比图,帮你快速建立认知:

Python vs Shell 仿真脚本选型对比 Python ✅ 适合场景: • 复杂逻辑判断 • 数据处理与分析 • 跨平台兼容 • 与CI/CD集成 ⚠️ 缺点: • 依赖环境配置 • 启动速度略慢 我推荐:中大型项目首选 Shell ✅ 适合场景: • 快速原型验证 • 简单命令组合 • 文件操作 • 环境变量管理 ⚠️ 缺点: • 跨平台差 • 复杂逻辑难维护 我推荐:简单任务、快速上手 ⇄ 可混合使用

我个人习惯是:能用 Shell 搞定的,绝不写 Python;一旦逻辑复杂了,果断切 Python。 为什么?因为 Shell 脚本写起来快,但维护起来真让人头大。我见过一个同事用 Shell 写了 500 行的仿真调度脚本,里面全是 if-else 嵌套,改一个参数得找半天。

来看两个实际例子,你就明白了:

场景一:简单编译+运行(Shell 更合适)

#!/bin/bash
# 编译所有文件
vlog -f filelist.f
# 跑三个测试用例
for test in test_a test_b test_c; do
    vsim -c -do "run -all; quit" work.top_tb -gTEST_NAME=$test
done

这种场景,Shell 一行顶 Python 十行。我在项目中遇到这种需求,基本 5 分钟就写完了。

场景二:带参数解析、日志分析、结果汇总(Python 更合适)

import subprocess
import json
import os

def run_simulation(test_name, seed):
    """运行单个仿真用例"""
    cmd = f"vsim -c -do 'run -all; quit' work.top_tb -gTEST_NAME={test_name} -sv_seed {seed}"
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.returncode

def batch_run(test_list, seed_list):
    """批量运行并汇总结果"""
    results = {}
    for test in test_list:
        for seed in seed_list:
            key = f"{test}_seed{seed}"
            ret = run_simulation(test, seed)
            results[key] = "PASS" if ret == 0 else "FAIL"
            print(f"{key}: {results[key]}")
    
    # 生成报告
    with open("report.json", "w") as f:
        json.dump(results, f, indent=2)
    print("报告已生成:report.json")

# 调用示例
batch_run(["test_a", "test_b"], [1, 42, 100])
我的建议: 如果你刚开始学,先从 Shell 入手,把基本流程跑通。等遇到“Shell 写着太费劲”的时候,再学 Python 也不迟。别一上来就追求“大而全”,容易把自己劝退。
避坑指南: 我曾经在 Windows 上用 Shell 脚本写路径,结果换到 Linux 上全崩了。如果你团队里有人用 Windows 有人用 Linux,建议统一用 Python,或者用 Shell 时注意路径分隔符的兼容性。

小结

这一章我们聊了三件事:

  • 仿真脚本就是自动化执行仿真流程的“机器人助理”
  • 批量运行是为了省时间、防遗漏、好追溯
  • 语言选型上,Shell 适合简单任务,Python 适合复杂逻辑