Use the Python framework "cocotb" to test Verilog.

Introduction.

cocotb is an HDL testing framework that uses Python. I've been watching for a while, but since version 1.0 has been released, I decided to give it a try.

Features of cocotb.

cocotb is a lightweight testing framework for HDL developed by Potential Ventures, written in Python. It is published on GitHub under the BSD license. https://github.com/potentialventures/cocotb

The documentation is here. http://cocotb.readthedocs.org/en/latest/index.html

Aware of the rapid launch of a verification environment in FPGA development, it is much lighter than UVM written in SystemVerilog, and written in Python. Therefore, the description is simple and easy to read.

Compatible simulators are Icarus Verilog, VCS, Riviera-PRO, [Questa (ModelSim)](http://www.mentorg.co.jp/products/fv/ It supports questa /), Incisive. Especially Icarus and VCS seem to have a good affinity.

In addition, it has a file output function for xUnit, and it can be said that it is easy to link with the CI tool Jenkins.

Python generators, coroutines and decorator technology are used to access DUT (HDL). It is a mechanism to pause the simulator with a coroutine, insert the processing of cocotb, and restart the simulator. Some people who use Python are not familiar with it, but with cocotb, if you know how to use it, you don't need to be very conscious of it.

This time, using samples and documents as clues, I used cocotb to describe an environment for verifying Verilog's sequential circuit. The OS is CentOS 6.6.

Preparation

Download from GitHub.

git clone https://github.com/potentialventures/cocotb

This time, I created a new working directory in the ʻexample directory, created the rtlandtests` directories there, and saved the DUT and tests, respectively.

Icarus Verilog is used for the simulator. Put "icarus" in the simulator selection part of "Makefile.sim" in the makefiles directory.

# Default to Icarus if no simulator is defined
SIM ?= icarus

DUT It is an 8-bit sequential circuit. Inside, I am trying to output a vcd file for waveform acquisition.

dff.v



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

test

I put in a testbench environment (instance with DUT) and a simple driver checker because I only need one file. This is a scenario in which a random value is input and the output value from the DUT is checked after one cycle.

tests.py


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()

In cocotb, "dut" is a reserved word, which corresponds to the top level of DUT. For the sake of simplicity, only the instance of dut is described in the constructor of class so far, but we will add processing such as initialization of other verification modules and utilities.

The test scenario is written by decorating cocotb.test () as written at the end.

In performing the simulation, the main processing part is decorating coroutb.coroutine. In the above description, it is around "clock_gen" and "gen_and_check".

Simulation execution script

I have prepared a Makefile in the tests directory. Specify the DUT top hierarchy in (TOPLEVEL) and enter the Python script name in (MODULE).

Makefile


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

Execution result / waveform

As shown below, it was possible to flow from the initialization phase to reset issuance, output value check, and simulation end.

        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]

    (Omission)

   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...

The waveform is as follows. You can see that it is initialized with RST_N and then a random value is entered.

waves.png

in conclusion.

With some knowledge of Python, I get the impression that it is relatively easy to build a verification environment. However, although I may not understand it, the documentation is not very complete. Also, the Endian Swapper at the beginning of the Tutorial felt like the threshold was too high. However, in SystemVerilog, it is fairly easy to understand that the test part that is difficult to debug is Python, and I think that using a Python library like random this time has a big advantage in terms of cost and many users. I will. 1.0 has just come out, and I have high expectations for it in the future.

Recommended Posts

Use the Python framework "cocotb" to test Verilog.
How to use the C library in Python
Specify the Python executable to use with virtualenv
The easiest way to use OpenCV with python
[Algorithm x Python] How to use the list
Knowledge notes needed to understand the Python framework
How to use the Raspberry Pi relay module Python
[Python] How to use the graph creation library Altair
Specify MinGW as the compiler to use with Python
[Introduction to Udemy Python3 + Application] 27. How to use the dictionary
[Introduction to Udemy Python3 + Application] 30. How to use the set
How to use the model learned in Lobe in Python
I want to use the R dataset in python
How to use the generator
[Python] How to use list 1
How to use Python argparse
Python: How to use pydub
[Python] How to use checkio
[Python] How to use input ()
How to use the decorator
How to use Python lambda
[Python] How to use virtualenv
python3: How to use bottle (3)
python3: How to use bottle
How to use Python bytes
Design and test Verilog in Python only with Veriloggen and cocotb.
[python] How to use the library Matplotlib for drawing graphs
The first API to make with python Djnago REST framework
How to use the __call__ method in a Python class
[Hyperledger Iroha] Notes on how to use the Python SDK
[Python] I want to use the -h option with argparse
I didn't know how to use the [python] for statement
Tips for Python beginners to use the Scikit-image example for themselves
Python: How to use async with
How to use the zip function
How to use the optparse module
AtCoder: Python: Daddy the sample test.
How to use Requests (Python Library)
How to use SQLite in Python
In the python command python points to python3.8
How to get the Python version
[Python] How to import the library
[Introduction to Python] Let's use pandas
[Python] How to use list 3 Added
How to use Mysql in python
How to use OpenPose's Python API
Use the Flickr API from Python
How to use ChemSpider in Python
How to use FTP with Python
Python: How to use pydub (playback)
How to use PubChem in Python
Easy to use Jupyter notebook (Python3.5)
[Introduction to Python] Let's use pandas
How to use python zip function
Sakura Use Python on the Internet
How to use the ConfigParser module
[Introduction to Python] Let's use pandas
[Python] How to use Typetalk API
[Python] Change the alphabet to numbers
[September 2020 version] Explains the procedure to use Gmail API with Python
How to use Serverless Framework & Python environment variables and manage stages