介绍。
cocotb是使用Python的HDL测试框架。
我已经观看了一段时间,但是自从1.0版发布以来,我决定尝试一下。
可可豆的特点。
cocotb是由Potential Ventures用Python编写的HDL轻量级测试框架。它以BSD许可在GitHub上发布。
https://github.com/potentialventures/cocotb
文档在这里。
http://cocotb.readthedocs.org/en/latest/index.html
我们意识到在FPGA开发中应立即启动验证环境,它比SystemVerilog中编写的UVM和Python中编写的UVM轻得多,因此描述简单易读。
兼容的模拟器与Icarus Verilog,VCS,Riviera-PRO,Questa(ModelSim)和Incisive兼容。
特别是Icarus和VCS似乎具有良好的亲和力。
它还具有xUnit的文件输出功能,可以说很容易与CI工具Jenkins链接。
Python生成器,协程和装饰器技术用于访问DUT(HDL)。它是一种用协程暂停模拟器,插入cocotb处理并重新启动模拟器的机制。
有些使用Python的人并不熟悉它,但是对cocotb而言,如果您知道如何使用它,则无需非常了解它。
这次,我以示例和文档为线索,试图描述一种环境,以使用cocotb验证Verilog的顺序电路。操作系统是CentOS 6.6。
准备
从GitHub下载。
1 | git clone https://github.com/potentialventures/cocotb |
这次,我在
Icarus Verilog用于模拟器。将" icarus"放在
1 2 | # Default to Icarus if no simulator is defined SIM ?= icarus |
DUT
这是一个8位时序电路。
在内部,我正在尝试输出用于波形采集的vcd文件。
dff.v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | module dff( input RST_N, input CLK, input [7:0] D, output reg [7:0] Q ); always @(negedge RST_N, posedge CLK) if(~RST_N) Q <= 8'h0; else Q <= D; initial begin $dumpfile("dump.vcd"); $dumpvars(1, dff); end endmodule |
测试
我放入一个测试平台环境(带有DUT的实例)和一个简单的驱动程序检查器,因为我只需要一个
文件。
在这种情况下,输入一个随机值,并在一个周期后检查DUT的输出值。
tests.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import cocotb from cocotb.triggers import Timer, RisingEdge from cocotb.result import TestFailure from cocotb.clock import Clock import random class DffTB(object): def __init__(self, dut, dubug=True): self.dut = dut @cocotb.coroutine def reset(self, duration=10000): self.dut.log.info("Resetting DUT") self.dut.RST_N <= 0 self.dut.D <= 0 yield Timer(duration) yield RisingEdge(self.dut.CLK) self.dut.RST_N <= 1 self.dut.log.info("Out of reset") @cocotb.coroutine def gen_and_check(self): D = random.randint(0, 255) self.dut.D = D; yield RisingEdge(self.dut.CLK) yield Timer(1) if int(self.dut.Q) != D : raise TestFailure( "[NG] Compre error. D==%s Q==%s" % (D, int(self.dut.Q))) else : self.dut.log.info("[OK]") @cocotb.coroutine def clock_gen(signal): while True: signal <= 0 yield Timer(5000) signal <= 1 yield Timer(5000) @cocotb.test() def basic_test(dut): """basic_test""" tb = DffTB(dut) cocotb.fork(clock_gen(dut.CLK)) yield RisingEdge(dut.CLK) yield tb.reset() for i in range(30): yield tb.gen_and_check() |
在
cocotb中," dut"是保留字,对应于DUT的顶层。
为了简单起见,到目前为止,在类的构造函数中仅描述了dut的实例,但是我们将添加诸如其他验证模块和实用程序的初始化之类的处理。
测试方案是通过修饰cocotb.test()编写的,如最后所述。
进行模拟时,主要处理部分是装饰coroutb.coroutine。在上面的描述中,它在" clock_gen"和" gen_and_check"附近。
模拟执行脚本
我已经在
在(TOPLEVEL)中指定DUT顶层层次结构,然后在(MODULE)中输入Python脚本名称。
生成文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | TOPLEVEL := dff TOPLEVEL_LANG ?= verilog PWD=$(shell pwd) COCOTB=$(PWD)/../../.. ifeq ($(OS),Msys) WPWD=$(shell sh -c 'pwd -W') PYTHONPATH := $(WPWD)/../model;$(PYTHONPATH) else WPWD=$(shell pwd) PYTHONPATH := $(WPWD)/../model:$(PYTHONPATH) endif export PYTHONPATH VERILOG_SOURCES = $(WPWD)/../rtl/dff.v GPI_IMPL := vpi export TOPLEVEL_LANG MODULE ?= tests include $(COCOTB)/makefiles/Makefile.inc include $(COCOTB)/makefiles/Makefile.sim |
执行结果?波形
如下所示,可以从初始化阶段转到重置发行,输出值检查和仿真结束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | TESTCASE= TOPLEVEL=dff \ vvp -M /tmp/cocotb/build/libs/x86_64 -m gpivpi sim_build/sim.vvp -.--ns INFO cocotb.gpi GpiCommon.cpp:47 in gpi_print_registered_impl VPI registered 0.00ns INFO cocotb.gpi gpi_embed.c:229 in embed_sim_init Running on Icarus Verilog version 0.9.6 0.00ns INFO cocotb.gpi gpi_embed.c:230 in embed_sim_init Python interpreter initialised and cocotb loaded! 0.00ns INFO cocotb.gpi __init__.py:103 in _initialise_testbench Running tests with Cocotb v1.0 from /tmp/cocotb 0.00ns INFO cocotb.gpi __init__.py:119 in _initialise_testbench Seeding Python random module with 1430897996 0.00ns INFO cocotb.regression regression.py:153 in initialise Found test tests.basic_test 0.00ns INFO cocotb.regression regression.py:254 in execute Running test 1/1: basic_test 0.00ns INFO ..routine.basic_test.0x7f2a3156ffd0 decorators.py:186 in send Starting test: "basic_test" Description: basic_test VCD info: dumpfile dump.vcd opened for output. 5.00ns INFO cocotb.dff tests.py:14 in reset Resetting DUT 15.00ns INFO cocotb.dff tests.py:20 in reset Out of reset 25.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK] 35.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK] (中略) 315.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK] 315.00ns INFO cocotb.regression regression.py:201 in handle_result Test Passed: basic_test 315.00ns INFO cocotb.regression regression.py:162 in tear_down Passed 1 tests (0 skipped) 315.00ns INFO cocotb.regression regression.py:168 in tear_down Shutting down... |
波形如下。您可以看到它已用RST_N初始化,然后输入了一个随机值。
结论。
我的印象是,如果您具有Python的知识,则可以相对轻松地构建验证环境。
但是,尽管我可能不太理解,但是文档不是很完整。另外,教程开始时的Endian Swapper感觉门槛太高。
但是,在SystemVerilog中,很容易理解很难调试的测试部分是Python,而且我认为这次使用诸如random这样的Python库在成本和许多用户方面都具有很大的优势,我会的。
1.0刚刚发布,我对它寄予厚望。