使用Python框架” cocotb”测试Verilog。


介绍。

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

这次,我在example目录中创建了一个新的工作目录,在其中创建了rtltests目录,并分别保存了DUT和test。

Icarus Verilog用于模拟器。将" icarus"放在makefiles目录中" Makefile.sim"的模拟器选择部分中。

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"附近。

模拟执行脚本

我已经在

tests目录中准备了一个Makefile。
在(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初始化,然后输入了一个随机值。

waves.png

结论。

我的印象是,如果您具有Python的知识,则可以相对轻松地构建验证环境。
但是,尽管我可能不太理解,但是文档不是很完整。另外,教程开始时的Endian Swapper感觉门槛太高。
但是,在SystemVerilog中,很容易理解很难调试的测试部分是Python,而且我认为这次使用诸如random这样的Python库在成本和许多用户方面都具有很大的优势,我会的。
1.0刚刚发布,我对它寄予厚望。