1前言
很多FPGA/IC工程师擅长设计,但在仿真方面较为薄弱。我认为主要问题在于,完整的仿真实现学习成本较高,如学习UVM需要掌握大量新的内容。而单纯使用Verilog自仿又难以满足需求,以报文仿真为例,我们需要解析报文,若仅依赖Verilog自仿,就相当于要自己编写一个报文解析模块,工作量非常庞大。而Python在数据处理方面则更加高效,如果加以利用,完全可以快速构建一个完整的仿真模型。Cocotb的诞生,为硬件工程师提供了一条更轻量、更灵活的路径——用Python脚本直接驱动Verilog/VHDL仿真。
Cocotb是一款基于协程的协同仿真库,通过Python的简洁语法和丰富生态,可直接操作硬件端口、生成测试激励并断言结果,甚至能与SystemVerilog UVM混合验证 。相较于UVM需要从类库、方法学到脚本的完整学习,Cocotb只需掌握Python基础即可快速上手,且能复用Python生态中的数据处理、随机化测试等工具,将验证代码量减少70%以上。
如今,Cocotb已成为开源硬件项目的宠儿。例如GitHub高星项目verilog-ethernet利用Cocotb实现模块级自动化测试;AXI总线验证库(如cocotb-axi)通过Python脚本简化复杂协议测试。
本系列将从零搭建Cocotb环境,解析其协程调度、自动化测试与开源生态,让Python成为你手中最高效的“验证加速器”。
2安装前置条件
cocotb 的当前稳定版本需要:
Python 3.6+
GNU Make 3+
Verilog 或 VHDL 仿真器,取决于您的 RTL 源代码
支持以下系统
#Supported Windows Versions
Windows 10 x86_64
Windows 11 x86_64
#Supported macOS Versions
macOS 11 (Big Sur)
macOS 12 (Monterey) x86_64
macOS 13 (Ventura) x86_64
Cocotb建议Linux经验较少的用户使用下面列出的经过支持和测试的发行版,以确保cocotb的顺畅体验。当然其他版本Linux也不是不行。
Red Hat Enterprise Linux (RHEL) 7.7+ amd64, shipping with Python 3.6, pip 9, and glibc 2.17. Upstream support until June 2024.
Red Hat Enterprise Linux (RHEL) 8 amd64, shipping with Python 3.6 (newer versions of Python are available), pip 9, and glibc 2.28. Upstream support until May 2029.
Red Hat Enterprise Linux (RHEL) 9 amd64, shipping with Python 3.9 (newer versions of Python are available), pip 21, and glibc 2.34. Upstream support until May 2032.
Ubuntu 20.04 LTS amd64, shipping with Python 3.8, pip 20, glibc 2.31. Upstream support until April 2025.
Ubuntu 22.04 LTS amd64, shipping with Python 3.10, pip 22, glibc 2.35. Upstream support until April 2027.
请根据自己的系统安装对应的前置环境
#Linux-Debian
sudo apt-get install make python3 python3-pip libpython3-dev
#Linux-Red Hat
sudo yum install make python3 python3-pip python3-libs
#macOs
brew install python
#windows-Windows Subsystem for Linux(WSL)
conda install -c msys2 m2-base m2-make
3安装cocotb
pip install "cocotb~=1.9"
安装cocotb可重用的总线接口和测试台组件(可选)
pip install cocotb[bus]
如果没有用户权限安装cocotb,可尝试在pip中添加–user选项。
4搭建测试环境
创建TestBench
一个典型的cocotb TestBench不需要额外的HDL代码。DUT作为顶级模块在仿真器中实例化,不需要任何HDL包装代码。 测试是用Python编写的。 在cocotb中,可以通过传递给每个测试的对象(dut)访问设计的所有内部内容,例如信号、端口、参数等。
# test_my_design.py (extended)
import cocotb
from cocotb.triggers import FallingEdge, Timer
async def generate_clock(dut):
"""Generate clock pulses."""
for cycle in range(10):
dut.clk.value = 0
await Timer(1, units="ns")
dut.clk.value = 1
await Timer(1, units="ns")
@cocotb.test()
async def my_second_test(dut):
"""Try accessing the design."""
await cocotb.start(generate_clock(dut)) # run the clock "in the background"
await Timer(5, units="ns") # wait a bit
await FallingEdge(dut.clk) # wait for falling edge/"negedge"
dut._log.info("my_signal_1 is %s", dut.my_signal_1.value)
assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!"
1.时钟信号驱动
#在顶层模块的clk端口上驱动10个周期的方波时钟。
async def generate_clock(dut):
"""Generate clock pulses."""
for cycle in range(10):
dut.clk.value = 0
await Timer(1, units="ns")
dut.clk.value = 1
await Timer(1, units="ns")
2.监控与断言
# 打印my_signal_1的实时值
ut._log.info("my_signal_1 is %s", dut.my_signal_1.value)
# 断言my_signal_2[0]是否为低电平,失败时抛出错误
assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!"
# 打印my_signal_1的实时值
ut._log.info("my_signal_1 is %s", dut.my_signal_1.value)
# 断言my_signal_2[0]是否为低电平,失败时抛出错误
assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!"
3.测试函数与协程控制
# 使用@cocotb.test()装饰器定义测试用例
@cocotb.test()
async def basic_test(dut):
# 创建时钟驱动协程(后台运行)
cocotb.start_soon(generate_clock(dut))
# 给信号赋值(二进制字面量语法)
dut.my_signal_1.value = 0b1010
# 等待3个时钟周期后读取信号
await ClockCycles(dut.clk, 3)
current_value = dut.my_signal_2.value
-
使用@cocotb.test()装饰器标记需要运行的测试函数。每个@cocotb.test()函数独立运行,仿真器会在测试间自动复位DUT。 -
使用.value = value语法为信号赋值 -
使用.value获取信号的当前值 -
显示的测试是顺序运行的,从开始到结束。每个await表达式都会暂停测试的执行,直到测试等待的事件发生并且仿真器将控制权返回给cocotb。必须通过await Timer()或await ClockCycles()主动推进仿真时间,否则陷入死循环。 -
建议使用dut._log.debug()/info()/error()分级输出调试信息
# Makefile
# defaults
SIM ?= icarus
TOPLEVEL_LANG ?= verilog
VERILOG_SOURCES += $(PWD)/my_design.sv
# use VHDL_SOURCES for VHDL files
# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = my_design
# MODULE is the basename of the Python test file
MODULE = test_my_design
# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim
SIM:模拟器,默认使用icarus,可支持以下模拟器
ctivehdl cvc ghdl icarus ius modelsim nvc questa riviera vcs verilator xcelium
TOPLEVEL_LAN: 顶层模块语言,在我们的例子中是Verilog
# Makefile
# defaults
SIM ?= vcs
TOPLEVEL_LANG ?= verilog
VERILOG_SOURCES += $(PWD)/my_design.sv
# use VHDL_SOURCES for VHDL files
# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = my_design
# MODULE is the basename of the Python test file
MODULE = test_my_design
# 指定VCS编译选项
EXTRA_ARGS += -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS "-Wl,--no-as-needed" -debug_access+all
# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim
创建Verilog顶层文件
// This file is public domain, it can be freely copied without restrictions.
// SPDX-License-Identifier: CC0-1.0
module my_design(input logic clk);
timeunit 1ns;
timeprecision 1ns;
logic my_signal_1;
logic my_signal_2;
assign my_signal_1 = 1'bx;
assign my_signal_2 = 0;
//verdi波形仿真,如果不用verdi则不需要
initial begin
$fsdbDumpfile("my_design.fsdb");
$fsdbDumpvars(0, my_design);
end
endmodule
注意:这三个文件需放在同级文件夹中
![图片[1]-用Python给Verilog设计自仿(一):Cocotb环境初探-Anlogic-安路社区-FPGA CPLD-ChipDebug](http://chipdebug.com/wp-content/uploads/2025/03/20250302140854903-61740895734.png?v=1740895734)
5初探
执行:
make
也可以指定对应的仿真器执行:
make SIM=vcs
可以看到执行了多长时间和用例是否通过
![图片[2]-用Python给Verilog设计自仿(一):Cocotb环境初探-Anlogic-安路社区-FPGA CPLD-ChipDebug](http://chipdebug.com/wp-content/uploads/2025/03/20250302140857995-81740895737.png?v=1740895738)
verdi -sv +v2k my_design.sv -ssf my_design.fsdb
![图片[3]-用Python给Verilog设计自仿(一):Cocotb环境初探-Anlogic-安路社区-FPGA CPLD-ChipDebug](http://chipdebug.com/wp-content/uploads/2025/03/20250302140901765-41740895741.png?v=1740895742)
7写在最后
下期主要更新,Makefile实战,用模块化Makefile模板实现一键编译、仿真、调试;DUT实战演练,以D触发器模块为例,演示从测试平台搭建到波形分析的完整链路;
没有回复内容