以下文章来源于AdriftCoreFPGA芯研社,作者CNL中子
对于许多FPGA/IC工程师而言,设计实现游刃有余,验证仿真却常成短板——传统验证方法面临两难困局:学习UVM需投入大量时间成本,而纯Verilog自仿又会陷入重复造轮子的低效循环。以通信协议仿真为例,仅报文解析就需要重写整套解析逻辑,相当于用Verilog再实现一次协议栈,耗时费力。
此时,Python的生态优势便锋芒尽显。其丰富的字符串处理库可直接解析报文,配合Cocotb框架,仅需少量Python代码即可构建高效测试平台,将验证工作量压缩70%以上。Cocotb的独特价值正在于此:用Python解放验证生产力,让工程师专注于设计创新而非重复劳动。
• 前言
• cocotb+pytest
• 开源cocotb仿真环境介绍
前言
在日常开发中,我们的仿真一般是串行执行的。如果想批量做回归测试,就会明显感受到速度之慢:当我们焦急等待仿真结果时,CPU 却在“摸鱼”,只有一个核心在跑,其余核心几乎闲置。这时难免会想——我花了几千块钱搭的配置,不是让CPU在这里摸鱼的
那能不能把 CPU 的每一个核心都压榨起来呢?
答案是肯定的。借助 cocotb + pytest,我们可以轻松实现多核并行仿真,最大化利用 CPU 资源。
如下图所示,图一为普通串行仿真,共 9 个 case,耗时 358.90 s;而使用 6 核并行仿真,仅用 117.03 s,速度提升足足 3 倍。乍看只是节省了 4 分钟,但这还只是一个简单的测试用例集。若你的用例规模很大,多核可能只需 1 小时,而单核却要 3 小时甚至更久,可见效率差距巨大。
下面我将介绍如何充分压榨 CPU 的性能,并顺带介绍一下本公众号开源的 AFX-Cocotb-Pytest 库,让你无需繁琐配置即可开箱即用,实现真正意义上的高效并行仿真。


介绍
pytest-xdist
pytest-xdist 是 pytest 的增强插件,通过 并行执行测试用例 与 分布式运行测试 来显著加速整个测试流程。
借助多进程并行、任务负载均衡以及跨机器分布式执行,它能够最大化利用 CPU 资源,特别适用于包含大量测试的大型工程。
如果希望在仿真环境中充分压榨多核性能,就需要在我们的 cocotb 测试框架中引入并配置 pytest-xdist,以实现高效的并行仿真执行。
安装插件
pip install pytest-xdist
并行运行所有测试
pytest -n auto
-n auto 会自动根据 CPU 核心数分配 worker 数量。
你也可以手动指定 worker 数:
pytest -n 8
cocotb+pytest
pytest
在 cocotb 进阶专栏的《用 Python 给 Verilog 设计自仿进阶(二):实现仿真平台 Linux/Win 多平台兼容》以及《用 Python 给 Verilog 设计自仿进阶(三):FPGA 仿真,如何兼容 VCS、Iverilog、Modelsim 等多平台仿真器》中,我们已经借助 pytest 实现了跨系统、跨仿真器的批量自动化仿真。
然而,这些批量仿真仍未真正发挥出多核 CPU 的计算潜力。接下来,我将介绍如何将 pytest-xdist 融入现有 pytest 测试体系,从而实现更高效的并行仿真加速。
pytest-xdist
要实现多核并行仿真,关键在于正确管理仿真过程中使用的文件资源。在单核环境下,所有测试用例共用同一套文件进行仿真,彼此之间不存在竞争关系,因此不会发生读写冲突。然而,当启用多核并行时,多个 worker 可能会同时对同一文件进行增删查改,从而导致仿真过程出现竞争条件,最终引发报告错误。
对于 Verilog 仿真而言,最核心的文件包括 filelist 和 sim_build,其中 sim_build 是仿真的实际工作目录。因此,为了保证并行仿真的独立性,我们需要根据 worker 的 ID(即每个 CPU 核心对应的 worker 进程)为它们分别创建并访问独立的 filelist 和 sim_build,从而避免任何文件级冲突。
首先获取当前worker进程的id
worker_id = os.getenv("PYTEST_XDIST_WORKER", "gw0")
filelist
基于 worker ID 创建独立的 filelist 时,这里的 filelist 是通过 指定 RTL 根目录,由 Python 自动遍历所有 .v 与 .sv 文件生成的。随后,我们根据生成的 filelist 获取文件路径,并将其传递给 cocotb_run 的 verilog_sources。
这样做的好处在于:
1. 无需手写 filelist
只需将 RTL 文件放入指定目录,即可自动收集所有 Verilog/SV 模块,降低维护成本。
2. 生成的 filelist 可直接供波形工具使用
例如 VCS、ModelSim、Verdi 等工具可以利用 filelist 实现源码追踪(trace),无需重复配置路径。
3. 并行仿真时便于为每个 worker 创建独立 filelist
避免文件竞争问题。
如果你的项目不是通过 filelist 动态生成 verilog_sources,而是手动指定 RTL 文件列表,那么你可以忽略这一机制。
filelist_path = Path(filelist+worker_id+".f").resolve()
sim_build
在并行仿真中,每个 worker 需要使用独立的仿真工作目录(sim_build),以避免多个进程同时读写同一目录而导致文件冲突。基于 worker ID 创建独立的 sim_build 可以这样实现:
sim_build = os.path.join(sim_path, "sim_build", f"{safe_test_name(request.node.name)}_{worker_id}")
随后,将生成的 sim_build 传递给 cocotb_run 即可让每个 worker 使用独立的仿真空间:
cocotb_test.simulator.run( python_search=[str(tb_files)], verilog_sources=verilog_sources, toplevel=toplevel, module=module, compile_args=compile_args, sim_args=sim_args, parameters=parameters, sim_build=sim_build, extra_env=extra_env, waves=waves )
这样即可确保每个并行任务都在自己的仿真目录中独立运行,避免竞争条件,提高并行执行的稳定性。
开源cocotb仿真环境介绍
当然,如果你觉得上述配置流程较为繁琐,也可以直接使用我提供的 afx_cocotb_test_run 库。该库的目标是简化 pytest + cocotb 仿真环境的代码编写与配置复杂度。
只需将该文件放在你的 Python 仿真脚本所在目录,并直接调用即可完成仿真运行。
目前该库已支持 VCS 和 Icarus 等主流仿真器。如果你需要支持其他仿真器,也可以参考我提供的 VCS 与 Icarus 示例进行扩展,非常方便。
from afx_cocotb_test_run import *
在自己的Python代码末尾加上类似下面代码的模板即可
################################################################### RUN TEST ###################################################################
import os
import pytest
@pytest.mark.parametrize("cycle", [10,30,40,80])
@pytest.mark.parametrize("a", [3,5])
def test_run(request,cycle,a):
simulator = os.environ.get("SIM", "")
waves = os.environ.get("WAVES", "")
parameters = {k.upper(): v for k, v in request.node.callspec.params.items()}
afx_test_run(request,ctb="cocotb_top",tc="tb_top",wave=waves,sim=simulator,parameters=parameters)
在使用 afx_cocotb_test_run 进行仿真时,我们可以通过 afx_test_run 提供的多种参数灵活配置整个运行环境。
这些参数覆盖了仿真器选择、波形开关、测试平台路径、RTL 文件路径以及可选的参数传递等内容,使得 cocotb + pytest 的仿真流程高度可控、易扩展。
以下是 afx_test_run 支持的主要配置项:
sim: str = "vcs", # 指定使用的仿真器,如 "vcs" 或 "icarus"
wave: str = "1", # 波形开关,1 表示生成波形,0 表示关闭
ctb: str = "cocotb_top", # cocotb Python 顶层模块名
tc: str = "tb_top", # Verilog/SystemVerilog 顶层 testbench 模块名
filelist: str = '../sim/filelist', # 自动生成或指定的 filelist 路径
tests_dir: str = '../sim/', # 工作空间路径
include_list: str = '../../design/incl', # include 头文件目录
tb_list: str = '../../verify/tb', # Verilog/SV/Python testbench文件路径
pkg: str = '../../design/pkg', # package 所在目录
rtl: str = '../../design/rtl', # RTL 源码目录
sim_ip: str = '../ip', # 仿真依赖的 IP 文件目录
parameters: dict[str, int] = {} # Verilog/SystemVerilog 顶层的可配置参数
这些参数的设计使得用户可以根据自己的工程结构轻松适配,无需修改大量路径或脚本,即可快速构建 cocotb 的跨平台仿真环境,同时让 pytest-xdist 并行加速的配置更自然、易于集成。
以上述模板为例,我们将仿真器类型和是否生成波形配置为环境变量,在使用 pytest 时可以灵活指定。
WAVE=1 SIM=vcs pytest cocotb_top.py
测试用例参数
同时,我们可以传入 RTL 顶层参数(如 parameter A)以及测试环境参数(如表示仿真时钟频率的 cycle)。
对于测试环境参数,需要特别注意:cycle 并不是直接传入 RTL,而是作为测试用例的参数,用于控制仿真时的行为,例如仿真时钟频率、数据流中反压的概率,或者其他与特定测试场景相关的设置。
例如,如果我们在测试用例中使用:
# @pytest.mark.parametrize("a", [3,5])
@pytest.mark.parametrize("cycle", [10,20])
@pytest.mark.parametrize("press", [0.3,0.8])
def test_run(request,cycle,press):
parameters = {k.upper(): v for k, v in request.node.callspec.params.items()}
afx_test_run(request,ctb="cocotb_top",tc="tb_top",wave=waves,sim=simulator,parameters=parameters)
则会生成 4 个不同的测试 case:
1. 时钟频率 10,反压概率 0.8
2. 时钟频率 10,反压概率 0.3
3. 时钟频率 20,反压概率 0.8
4. 时钟频率 20,反压概率 0.3
在 Python 脚本中,需要配合从环境变量获取参数,例如:
@cocotb.test()
async def dff_simple_test(dut):
cycle = int(os.getenv("PARAM_CYCLE", "20"))
press = float(os.getenv("PARAM_PRESS", "0.3"))
# clock
await cocotb.start(generate_clock(dut,cycle,"ns",0))
这样就可以保证测试用例能够根据不同参数自动生成,并与仿真环境动态关联。
波形查看
在Python仿真文件夹下输入命令即可仿真:
WAVES=1 pytest cocotb_top.py -v -s -n auto
在sim_build产生四个仿真结果
AdriftCore@AdriftCore:/sim_build$ ls test_run_0_3_10_gw0 test_run_0_3_20_gw1 test_run_0_8_10_gw2 test_run_0_8_20_gw3
每个仿真结果都会有其对应的波形
AdriftCore@AdriftCore:/sim_build/test_run_0_3_10_gw0$ ls cocotb_top cocotb_top.daidir cocotb_top_ucli.do com.log Makefile novas_dump.log pli.tab simulate.log tb_top.fsdb ucli.key um8pni2k_results.xml vcs_lib
链接
AFX-CocotbSIMENV 的功能不仅限于 pytest 的并行仿真,这只是其中的一部分。由于篇幅所限,这里无法一一展开说明。后续版本中,AFX-CocotbSIMENV 会将实际仿真中常用的功能封装为函数或方法集成到库中,从而减少重复操作,提高仿真效率。
https://github.com/AdriftXCore/CocotbSIMENV https://github.com/AdriftXCore/CocotbSIMENV/blob/master/verify/tb/afx_cocotb_test_run.py
全部0条评论
快来发表一下你的评论吧 !