Giter VIP home page Giter VIP logo

cocotb / cocotb Goto Github PK

View Code? Open in Web Editor NEW
1.6K 105.0 478.0 7.56 MB

cocotb, a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python

Home Page: https://www.cocotb.org

License: BSD 3-Clause "New" or "Revised" License

Makefile 4.66% Verilog 1.92% C 25.19% C++ 20.56% VHDL 8.27% Python 37.18% SystemVerilog 2.19% PowerShell 0.03%
python vhdl verilog uvm verification test

cocotb's Introduction

cocotb is a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python.

Documentation Status CI PyPI Gitpod Ready-to-Code codecov

Note: The current master branch of the cocotb repository is expected to be released as cocotb 2.0, which contains API-breaking changes from previous 1.x releases. Please use the stable/1.8 branch if you're building cocotb from source, or just install it from PyPi.

Installation

The current stable version of cocotb requires:

After installing these dependencies, the latest stable version of cocotb can be installed with pip.

pip install cocotb

For more details on installation, including prerequisites, see the documentation.

For details on how to install the development version of cocotb, see the preliminary documentation of the future release.

Usage

As a first trivial introduction to cocotb, the following example "tests" a flip-flop.

First, we need a hardware design which we can test. For this example, create a file dff.sv with SystemVerilog code for a simple D flip-flop. You could also use any other language a cocotb-supported simulator understands, e.g. VHDL.

// dff.sv

`timescale 1us/1ns

module dff (
    output logic q,
    input logic clk, d
);

always @(posedge clk) begin
    q <= d;
end

endmodule

An example of a simple randomized cocotb testbench:

# test_dff.py

import random

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.types import LogicArray

@cocotb.test()
async def dff_simple_test(dut):
    """Test that d propagates to q"""

    # Assert initial output is unknown
    assert LogicArray(dut.q.value) == LogicArray("X")
    # Set initial input value to prevent it from floating
    dut.d.value = 0

    clock = Clock(dut.clk, 10, units="us")  # Create a 10us period clock on port clk
    # Start the clock. Start it low to avoid issues on the first RisingEdge
    cocotb.start_soon(clock.start(start_high=False))

    # Synchronize with the clock. This will regisiter the initial `d` value
    await RisingEdge(dut.clk)
    expected_val = 0  # Matches initial input value
    for i in range(10):
        val = random.randint(0, 1)
        dut.d.value = val  # Assign the random value val to the input port d
        await RisingEdge(dut.clk)
        assert dut.q.value == expected_val, f"output q was incorrect on the {i}th cycle"
        expected_val = val # Save random value for next RisingEdge

    # Check the final input on the next clock
    await RisingEdge(dut.clk)
    assert dut.q.value == expected_val, "output q was incorrect on the last cycle"

A simple Makefile:

# Makefile

TOPLEVEL_LANG = verilog
VERILOG_SOURCES = $(shell pwd)/dff.sv
TOPLEVEL = dff
MODULE = test_dff

include $(shell cocotb-config --makefiles)/Makefile.sim

In order to run the test with Icarus Verilog, execute:

make SIM=icarus

asciicast

For more information please see the cocotb documentation and our wiki.

Tutorials, examples and related projects

cocotb's People

Contributors

chiggs avatar cmarqu avatar dependabot[bot] avatar elgorwi avatar eric-wieser avatar fatsie avatar forensicgarlic avatar forty-bot avatar github-actions[bot] avatar imphil avatar jeroenvanstraten avatar jwrr avatar ktbarrett avatar leftink avatar lukedarnell avatar marlonjames avatar martoni avatar matthewar avatar mciepluc avatar nevsan avatar nickg avatar rw1nkler avatar sebastiancieslak avatar stuarthodgson avatar tc01 avatar themperek avatar tjora avatar toddstrader avatar tpambor avatar wallento avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cocotb's Issues

gpi_get_root_handle doesn't always return the root module

Packages etc. may be on the same level as the DUT so current implementation of gpi_get_root_handle may not work.

I think we have 2 options - either search for the first module instance, or search by name (makefiles already define a TOPLEVEL variable we could pass into GPI). Former is preferable if it works in every case but there may be examples with multiple modules at toplevel so latter is probably safer.

Scheduler should use coroutine.close() instead of coroutine.throw()

The scheduler needs to tear down coroutines, currently does this using coro.throw(StopIteration). Instead we should be using coroutine.close() which is intended for this purpose. From PEP342:

4. Add a close() method for generator-iterators, which raises
   GeneratorExit at the point where the generator was paused.  If
   the generator then raises StopIteration (by exiting normally, or
   due to already being closed) or GeneratorExit (by not catching
   the exception), close() returns to its caller.  If the generator
   yields a value, a RuntimeError is raised.  If the generator
   raises any other exception, it is propagated to the caller.
   close() does nothing if the generator has already exited due to
   an exception or normal exit.

TAR installation

Enable downloaded tar to be the installed location.

This should if running on a 64 bit machine also build the 32 bit libs as well.

Capability to integrate callable functions that aren't decorators into cocotb

It is necessary to provide a way for external code to integrate with cocotb without having to modify the external code. For this to work I think we have to assume that the external (non-coroutine) code is running in a separate thread. We can then block the external thread while cocotb and simulation time are advancing.

Propose the following:

  • a "callable" decorator to indicate that a method or function is callable from an external thread.
  • a ThreadCoroutineBridge base class that provides an interface between an external thread and a coroutine.

Take for example using a tool that reads and writes registers. It might use a library or base class that provides read/write methods that block until a result is returned from hardware. This capability would allow the same tool to run against the simulator without modification, by linking against a different library or picking up a different base class.

class HardwareInterface(ThreadCoroutineBridge):

    @callable
    def read(self, address):
        """Callable from an external thread, blocks while simulation time advances"""
        event = threading.Event()
        cocotb.scheduler.queue(self.read_sim(address, event))
        event.wait()
        return event.result

    @coroutine
    def read_sim(self, address, event):
        """Coroutine in cocotb context that performs the read, consuming simulation time"""
        yield self.driver.read(address)
        event.result = self.driver.result
        event.set()

NB The contents of the read call in the above example could actually be hidden in the "callable" decorator.

Documentation

Suggest create a "documentation" folder containing reStructuredText in sphinx format.

We can then set-up a post-commit hook to build the docs and host on readthedocs

Finer grained control over logging verbosity

We globally set the loglevel in cocotb.init.py:

log.setLevel(logging.INFO)

We've split the messages hierarchically using the standard python logging mechanism. It would be useful to provide and document a more convenient way to set up, for example all of the following can be different verbosity:

scheduler
drivers
monitors
scoreboard
coroutines

coroutine decorator needs to be a factory

The coroutine decorator currently wraps a function. When the function is called it assigns the self._coro member to be that instance.

This is broken - for example if we start 2 instances of coroutines from the same function we'll overwrite the _coro on the clock_gen coroutine instance:

clk1 = clock_gen(dut.clk1)      # clock_gen._coro = clk1
clk2 = clock_gen(dut.clk2)      # clock_gen._coro = clk2

The decorator should be a factory.

VCS core dump

Trying in a different environment (Python 2.7.1 that appears to be statically linked only - no libpython2.7.so just libpython.2.7.a

and a recent version of VCS ( Compiler version G-2012.09-SP1-3_Full64; Runtime version G-2012.09-SP1-3_Full64; Jul 9 14:08 2013 )

Any thoughts on the cause of the Interpreter not initialized error. Seen this before at all?

Compiler version G-2012.09-SP1-3_Full64; Runtime version G-2012.09-SP1-3_Full64;  Jul  9 14:08 2013
Fatal Python error: Interpreter not initialized (version mismatch?)

An unexpected termination has occurred in simv

During a VPI callback function for callback reason="cbStartOfSimulation"
Command line: simv +acc+1

--- Stack trace follows:
Dumping VCS Annotated Stack:
#0  0x00000031dfe99db5 in waitpid () from /lib64/libc.so.6
#1  0x00000031dfe3c761 in do_system () from /lib64/libc.so.6
#2  0x00002b01b4dbea34 in SNPSle_10ee25eff68cd8461c9146fa1d0b35e87067f3c8015b313e639d2928478c79b3f673f99203bcf8be646006121000822323a7337474f31850 () from pcie_tl_io_write_seq/amd64/lib/liberrorinf.so
#3  0x00002b01b4dc002d in SNPSle_10ee25eff68cd8461c9146fa1d0b35e87067f3c8015b313efba706aab251478fa49e66610e453774633a6c152e7ef778f2202cda681f3d4e () from /tools/vcs_linux64/amd64/lib/liberrorinf.so
#4  0x00002b01b4db8e96 in SNPSle_d35ca1ff70d465c24c71e1f0ad6ba632 () from /tools/vcs_linux64/amd64/lib/liberrorinf.so
#5  0x00002b01b6b0b3a9 in SNPSle_64133461705005bb725549e2e6fa1b3f () from /tools/vcs_linux64/amd64/lib/libvcsnew.so
#6  0x00002b01b69fad57 in SNPSle_82244d58c54c18c70d63edc9becab634 () from /tools/vcs_linux64/amd64/lib/libvcsnew.so
#8  0x00000031dfe30285 in raise () from /lib64/libc.so.6
#9  0x00000031dfe31d30 in abort () from /lib64/libc.so.6
#10 0x00002b01bf7c5379 in Py_FatalError (msg=<optimized out>) at Python/pythonrun.c:1670
#11 0x00002b01bf7c08c4 in Py_InitModule4_64 (name=0x2b01bf8042e2 "simulator", methods=0x2b01bfa3f060, doc=0x0, passthrough=0x0, module_api_version=1013) at Python/modsupport.c:38
#12 0x00002b01bf70762a in initsimulator () at simulatormodule.c:653
#13 0x00002b01b94dec39 in _PyImport_LoadDynamicModule (name=0x7fff87f9f0f7 "simulator", pathname=0x7fff87f9e030 "/home/gmcgregor/src/cocotb/build/libs/x86_64/simulator.so", fp=<optimized out>) at ./Python/importdl.c:53
#14 0x00002b01b94dc26d in load_module (name=0x7fff87f9f0f7 "simulator", fp=0x6, pathname=0x101010101010101 <Address 0x101010101010101 out of bounds>, type=8, loader=<optimized out>) at Python/import.c:1834
#15 0x00002b01b94dc69e in import_submodule (mod=0x2b01b9776b20, subname=0x7fff87f9f0f7 "simulator", fullname=0x7fff87f9f0f7 "simulator") at Python/import.c:2596
#16 0x00002b01b94dc944 in load_next (mod=0x1eca92b8, altmod=0x2b01b9776b20, p_name=<optimized out>, buf=0x7fff87f9f0f0 "cocotb.simulator", p_buflen=0x7fff87f9f0e8) at Python/import.c:2420
#17 0x00002b01b94dcdbd in import_module_level (name=<optimized out>, globals=<optimized out>, locals=<optimized out>, fromlist=0x2b01b9776b20, level=<optimized out>) at Python/import.c:2137
#19 0x00002b01b94b896d in builtin___import__ (self=<optimized out>, args=<optimized out>, kwds=<optimized out>) at Python/bltinmodule.c:49
#20 0x00002b01b943350d in PyObject_Call (func=0x2b01bde98dd0, arg=0x1f63d680, kw=0x0) at Objects/abstract.c:2529
#21 0x00002b01b94be3a1 in PyEval_CallObjectWithKeywords (func=0x2b01bde98dd0, arg=0x1f63d680, kw=0x0) at Python/ceval.c:3881
#22 0x00002b01b94c21a2 in PyEval_EvalFrameEx (f=0x1ecfd390, throwflag=<optimized out>) at Python/ceval.c:2332
#23 0x00002b01b94c6705 in PyEval_EvalCodeEx (co=0x1f671ab0, globals=<optimized out>, locals=<optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3252
#24 0x00002b01b94c68a2 in PyEval_EvalCode (co=0x1458, globals=0x1458, locals=0x6) at Python/ceval.c:666
#25 0x00002b01b94da98b in PyImport_ExecCodeModuleEx (name=0x7fff87fa27f0 "cocotb.handle", co=0x1f671ab0, pathname=<optimized out>) at Python/import.c:681
#26 0x00002b01b94daec5 in load_source_module (name=0x7fff87fa27f0 "cocotb.handle", pathname=0x7fff87fa1730 "/home/gmcgregor/src/cocotb/cocotb/handle.py", fp=<optimized out>) at Python/import.c:1021
#27 0x00002b01b94dc24d in load_module (name=0x7fff87fa27f0 "cocotb.handle", fp=0x6, pathname=0x101010101010101 <Address 0x101010101010101 out of bounds>, type=8, loader=<optimized out>) at Python/import.c:1825
#28 0x00002b01b94dc69e in import_submodule (mod=0x1eca92b8, subname=0x7fff87fa27f7 "handle", fullname=0x7fff87fa27f0 "cocotb.handle") at Python/import.c:2596
#29 0x00002b01b94dc902 in load_next (mod=0x1eca92b8, altmod=0x1eca92b8, p_name=<optimized out>, buf=0x7fff87fa27f0 "cocotb.handle", p_buflen=0x7fff87fa27e8) at Python/import.c:2416
#30 0x00002b01b94dcdef in import_module_level (name=0x0, globals=<optimized out>, locals=<optimized out>, fromlist=0x2b01b9776b20, level=<optimized out>) at Python/import.c:2145
#32 0x00002b01b94b896d in builtin___import__ (self=<optimized out>, args=<optimized out>, kwds=<optimized out>) at Python/bltinmodule.c:49
#33 0x00002b01b943350d in PyObject_Call (func=0x2b01bde98dd0, arg=0x2b01bf2aeaa0, kw=0x0) at Objects/abstract.c:2529
#34 0x00002b01b94be3a1 in PyEval_CallObjectWithKeywords (func=0x2b01bde98dd0, arg=0x2b01bf2aeaa0, kw=0x0) at Python/ceval.c:3881
#35 0x00002b01b94c21a2 in PyEval_EvalFrameEx (f=0x1ecfe1b0, throwflag=<optimized out>) at Python/ceval.c:2332
#36 0x00002b01b94c6705 in PyEval_EvalCodeEx (co=0x1ec959b0, globals=<optimized out>, locals=<optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3252
#37 0x00002b01b94c68a2 in PyEval_EvalCode (co=0x1458, globals=0x1458, locals=0x6) at Python/ceval.c:666
#38 0x00002b01b94da98b in PyImport_ExecCodeModuleEx (name=0x7fff87fa6f70 "cocotb", co=0x1ec959b0, pathname=<optimized out>) at Python/import.c:681
#39 0x00002b01b94daec5 in load_source_module (name=0x7fff87fa6f70 "cocotb", pathname=0x7fff87fa4e20 "/home/gmcgregor/src/cocotb/cocotb/__init__.py", fp=<optimized out>) at Python/import.c:1021
#40 0x00002b01b94dc24d in load_module (name=0x7fff87fa6f70 "cocotb", fp=0x6, pathname=0x101010101010101 <Address 0x101010101010101 out of bounds>, type=8, loader=<optimized out>) at Python/import.c:1825
#41 0x00002b01b94dc51c in load_package (name=0x7fff87fa6f70 "cocotb", pathname=<optimized out>) at Python/import.c:1077
#42 0x00002b01b94dc27a in load_module (name=0x7fff87fa6f70 "cocotb", fp=<optimized out>, pathname=0x101010101010101 <Address 0x101010101010101 out of bounds>, type=8, loader=<optimized out>) at Python/import.c:1839
#43 0x00002b01b94dc69e in import_submodule (mod=0x2b01b9776b20, subname=0x7fff87fa6f70 "cocotb", fullname=0x7fff87fa6f70 "cocotb") at Python/import.c:2596
#44 0x00002b01b94dc902 in load_next (mod=0x2b01b9776b20, altmod=0x2b01b9776b20, p_name=<optimized out>, buf=0x7fff87fa6f70 "cocotb", p_buflen=0x7fff87fa6f68) at Python/import.c:2416
#45 0x00002b01b94dcdbd in import_module_level (name=<optimized out>, globals=<optimized out>, locals=<optimized out>, fromlist=0x2b01bdea6bd8, level=<optimized out>) at Python/import.c:2137
#47 0x00002b01b94b896d in builtin___import__ (self=<optimized out>, args=<optimized out>, kwds=<optimized out>) at Python/bltinmodule.c:49
#48 0x00002b01b943350d in PyObject_Call (func=0x2b01bde98dd0, arg=0x2b01bf2a74d0, kw=0x0) at Objects/abstract.c:2529
#49 0x00002b01b9433640 in call_function_tail (callable=0x1458, args=0x2b01bf2a74d0) at Objects/abstract.c:2561
#51 0x00002b01b94dd7d7 in PyImport_Import (module_name=0x2b01bf115180) at Python/import.c:2774
#52 0x00002b01b942aa95 in embed_sim_init () at gpi_embed.c:99
#53 0x00002b01b8fe7ccf in handle_sim_init (gpi_cb_data=0x0) at gpi_vpi.c:716
#54 0x00002b01b8fe6d9b in handle_vpi_callback (cb_data=0x7fff87fa8250) at gpi_vpi.c:325

vpi_interator API needs to allow the full range of object types, not just vpiNet

One of the most useful features of pyHVL in large ASIC projects has been the simple access to the VPI iterators/ scan API.

For this to be useful though, it has to be more flexible than just vpiNet (e.g, vpiModule to walk the design hierarchy)

Ideally the full set of VPI constants would be accessible from Python and could be passed through the iterate_signals call (or probably a more generic 'iterate' API if you want to keep iterate_signals specific to vpiNets

PyHVL actually generated the defines dynamically by parsing the vpi_user.h - I could port that code over. It then populated the Python namespace with those vpi defines.

Make SimHandle iterable

We might want to iterate over all the signals/parameters of a module. We also might want to iterate over individual bits in a vector.

Should be able to do:

# Iterate over individual bits in a vector
for bit in signal:
     print bit

# Find all the signals/parameters/instantiations in a module
for thing in module:
     print thing

Python linking not very portable

From Gordon:

LIBS and INCLUDE paths in the Makefiles make a lot of assumptions about paths and settings that can be extracted using the python-config command.

The mix of libraries being pulled out of lib-dynload in makefiles/makefile.pylib It seems that the actual mix of dynamic vs statically linked libraries varies quite a bit between Python installs (It's controlled in the Modules/Setup file when building Python) so the actual dynamic libraries that can be used needs to be checked more thoroughly.

Commit e706b1e caused Icarus to spew warnings

VCS provides a signal value when registering a callback (see commit e706b1e). This causes the following warnings to pop out when using Icarus Verilog version 0.9.5:

vpi_callback: value format 151922824 not supported (fun_signal)
vpi_callback: value format 0 not supported (fun_signal)

Profiling capabilities

We want to know where all the time is going.

Initially, knowing how much time is spent in the simulator vs. how much time is spent in callback handlers would be a very useful indicator. This should be easy to do since all callbacks go through the same handler.

@test decorator

We should use an @test decorator to mark a function as a test.

Should provide some common test-like capabilities:

  • Test start/end message
  • Test description from function docstring
  • Duration / inactivity timeout
  • Kill all coroutines on completion
  • Mark as expected to fail

Questa build

Seeing the following shared library load error when trying to run on Questa. Any suggestions/ experience from running on VCS that you have to resolve? This looks similar to the dynload issues I'd mentioned with pyHVL

[gmcgregor@tesla cocotb]$ make test SIM=QUESTA
make -C lib/gpi
make[1]: Entering directory /home/gmcgregor/src/cocotb/lib/gpi' make[1]: Nothing to be done forall'.
make[1]: Leaving directory /home/gmcgregor/src/cocotb/lib/gpi' make -C lib/embed make[1]: Entering directory/home/gmcgregor/src/cocotb/lib/embed'
make[1]: Nothing to be done for all'. make[1]: Leaving directory/home/gmcgregor/src/cocotb/lib/embed'
make -C lib/vpi_shim
make[1]: Entering directory /home/gmcgregor/src/cocotb/lib/vpi_shim' make[1]: Nothing to be done forall'.
make[1]: Leaving directory /home/gmcgregor/src/cocotb/lib/vpi_shim' make -C lib/simulator make[1]: Entering directory/home/gmcgregor/src/cocotb/lib/simulator'
make[1]: Nothing to be done for all'. make[1]: Leaving directory/home/gmcgregor/src/cocotb/lib/simulator'
make -C examples
make[1]: Entering directory /home/gmcgregor/src/cocotb/examples' make[2]: Entering directory/home/gmcgregor/src/cocotb/examples/demo'
PYTHONPATH=/home/gmcgregor/src/cocotb/build/libs/x86_64:/home/gmcgregor/src/cocotb:/home/gmcgregor/src/cocotb/examples/demo:/home/gmcgregor/pyhvl LD_LIBRARY_PATH=/home/gmcgregor/src/cocotb/build/libs/x86_64:/usr/lib64:/usr/lib64/python2.6/lib-dynload/ MODULE=demo TESTCASE=
ncverilog +nc64bit +loadvpi=/home/gmcgregor/src/cocotb/build/libs/x86_64/libgpi.so:vlog_startup_routines_bootstrap +access+rw counter.v
ncverilog(64): 12.20-s003: (c) Copyright 1995-2013 Cadence Design Systems, Inc.
Loading snapshot worklib.first_counter:v .................... Done
Traceback (most recent call last):
File "/home/gmcgregor/src/cocotb/cocotb/init.py", line 33, in
import logging
File "/usr/lib64/python2.6/logging/init.py", line 34, in
import sys, os, types, time, string, cStringIO, traceback
ImportError: /usr/lib64/python2.6/lib-dynload/timemodule.so: undefined symbol: PyExc_ValueError
Failed to load "cocotb"
ncsim> source /our/.-ark-deploy/cadence-ius--12.20.003/tools/inca/files/ncsimrc
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit
-.--ns WARNING cocotb.gpi gpi_embed.c:177 in embed_sim_end Closing down cocotb at simulator request!
make[2]: Leaving directory /home/gmcgregor/src/cocotb/examples/demo' make[2]: Entering directory/home/gmcgregor/src/cocotb/examples/comb_seq'
PYTHONPATH=/home/gmcgregor/src/cocotb/build/libs/x86_64:/home/gmcgregor/src/cocotb:/home/gmcgregor/src/cocotb/examples/comb_seq:/home/gmcgregor/pyhvl LD_LIBRARY_PATH=/home/gmcgregor/src/cocotb/build/libs/x86_64:/usr/lib64:/usr/lib64/python2.6/lib-dynload/ MODULE=issue12 TESTCASE=
ncverilog +nc64bit +loadvpi=/home/gmcgregor/src/cocotb/build/libs/x86_64/libgpi.so:vlog_startup_routines_bootstrap +access+rw issue12.v
ncverilog(64): 12.20-s003: (c) Copyright 1995-2013 Cadence Design Systems, Inc.
Loading snapshot worklib.issue12:v .................... Done
Traceback (most recent call last):
File "/home/gmcgregor/src/cocotb/cocotb/init.py", line 33, in
import logging
File "/usr/lib64/python2.6/logging/init.py", line 34, in
import sys, os, types, time, string, cStringIO, traceback
ImportError: /usr/lib64/python2.6/lib-dynload/timemodule.so: undefined symbol: PyExc_ValueError
Failed to load "cocotb"
ncsim> source /our/.-ark-deploy/cadence-ius--12.20.003/tools/inca/files/ncsimrc
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit
-.--ns WARNING cocotb.gpi gpi_embed.c:177 in embed_sim_end Closing down cocotb at simulator request!
make[2]: Leaving directory /home/gmcgregor/src/cocotb/examples/comb_seq' make[1]: Leaving directory/home/gmcgregor/src/cocotb/examples'

Consolidate examples

The examples also double as a regression to ensure we don't break the APIs. We probably want only 2 examples in the repo:

1 - A set of separate tests that exercise all of the available features

  • Communication between coroutines using events
  • Fork/Join simultaneous execution
  • All the various trigger types
  • Combining triggers
  • Test timeout
  • Expected test failure etc
  • Use of Driver, Monitor, Scoreboard class etc

2 - An example of a verified block with a suite of tests

Example 1 ("features") would also work as a tutorial / introduction to cocotb.

coroutine.kill() does not work

This does not meet the semantics of cocotb currently.

Kill needs to schedule a function with the simulator that will run after the current co-routine has completed but before control is handled back to the simulator.

Support for stand-alone executable tests using a testmod() function

To maximise use of cocotbenv.py suggest we extend to provide more generic test-running support. When writing a file containing multiple tests I want to be able to add something like the following at the bottom of the file:

if __name__ == "__main__":
    cocotb.testmod()

This will find all the @test decorated coroutines in this module and run them consecutively. I can then chmod +x my_test and execute it.

This is similar to the way the Python doctest module works.

We might need to refactor cocotbenv.py slightly to achieve this.

unprime() on PythonTriggers doesn't do anything

We can therefore get in a mess when tearing down a test.

  • Something raises TestFailed
  • in cleanup we schedule a load of kills
  • we move to cleanup and call generator.close()
  • This causes the pending Join event to be scheduled which can then raise a TestSuccess.

RegressionManager masks errors in tests

Commit 80b3ac8 shows a problem with RegressionManager.

Running a test on its own fails with an exception:

make TESTCASE=test_adding_a_coroutine_without_starting
ERROR: called callback function returned NULL
Traceback (most recent call last):
  File "/home/ceh/code/cocotb/cocotb/scheduler.py", line 88, in react
    self.schedule(coroutine, trigger=trigger)
  File "/home/ceh/code/cocotb/cocotb/scheduler.py", line 204, in schedule
    result = coroutine.send(trigger)
  File "/home/ceh/code/cocotb/cocotb/decorators.py", line 232, in send
    return self._coro.send(value)
  File "/home/ceh/code/cocotb/examples/functionality/tests/test_cocotb.py", line 116, in test_adding_a_coroutine_without_starting
    forked = cocotb.fork(clock_gen)
  File "/home/ceh/code/cocotb/cocotb/scheduler.py", line 147, in add
    self.schedule(coroutine)
  File "/home/ceh/code/cocotb/cocotb/scheduler.py", line 204, in schedule
    result = coroutine.send(trigger)
  File "/home/ceh/code/cocotb/cocotb/decorators.py", line 126, in send
    self._pre_send()
  File "/home/ceh/code/cocotb/cocotb/decorators.py", line 119, in _pre_send
    if not hasattr(self._coro, "send"):
AttributeError: 'coroutine' object has no attribute '_coro'
Failed to execute callback

Running the regression passes (ish):

    12.70ns INFO    cocotb.regression                         regression.py:147  in test_runner                     Running test 5/8: test_adding_a_coroutine_without_starting
    12.70ns INFO    cocotb.test.test_adding_a_corouti..       decorators.py:228  in send                            Starting test: "test_adding_a_coroutine_without_starting"
                                                                                                                    Description: Catch (and provide useful error) for attempts to fork coroutines incorrectly     

but results.xml is trunctated.

RegressionManager seems to be masking the AttributeError exception.

Determine minimum required versions / dependencies and document

So far all development has been on Python 2.7. We probably don't work on < Python 2.5 although it would be worth auditing where/how we don't work. We might also have to do some things to get 2.5 to work. Can do things like:

from __future__ import with_statement

Note that RHEL 6 includes Python 2.6 so I don't think we need to worry too much about supporting earlier versions if it requires significant effort / ugliness.

Implement trigger.unprime() and update scheduler

There are occasions where we register a callback through GPI and yet want to deregister it before the callback is made.

For example, if a coroutine yields a list of triggers it expects to be resumed if any of the triggers fire. If/when one does, the remaining triggers that didn't fire should be de-registered, otherwise we may erroneously reschedule the coroutine at some point in the future when another trigger fires.

So in summary, triggers should only be primed if coroutines are actively blocked waiting for them to fire. If we schedule a coroutine we should un-prime any triggers that the coroutine is waiting on that didn't fire.

This should be done using the trigger.unprime() method.

VCS does not detect run time environment properly

VCS does not seem to detect that it is running on 32bit or 64bit correctly. So if run on a 64 bit system that does not have 32 bit libs then it fails to start. if there are 32 bit libs then when it links against libgpi.so it also fails on a mismatching elf class.

This is more a tracker as it is a problem that has been raised with VCS. But does prevent problems with installation.

Python threading exception

/usr/lib/python2.7/threading.py:827: RuntimeWarning: tp_compare didn't return -1 or -2 for exception
return _active[_get_ident()]
Command line: simv +acc+1

--- Stack trace follows:

Dumping VCS Annotated Stack:
No context available
VCS runtime internal error (core dumped) .
Please contact [email protected] or call 1-800-VERILOG
Note: Execution of simv exited with code 1
CPU time: .069 seconds to compile + .007 seconds to elab + .056 seconds to link + 418.870 seconds in simulation
make: *** [sim] Error 1

Add API to simulator.so to remove handles

When a Python handle is created it can create a handle from the sim, this takes user memory. When the object goes out of scope and is removed by the garbage collector it needs to call into the simulator library and remove the memory allocated to the handle as well.

VCS exits with code 72

Unsure if this is an issue cannot find a list of the error codes yet. Since fix up of the options this is at least consistent. May fix later if needed.

Seed random to ensure test repeatability

Need to ensure tests are repeatable, ideally even if order of creating coroutines varies etc.

To start with we should at least seed the Python random module and dump the seed in a log message...

cocotb screws up waveform viewer in VCS

It looks like cocotb runs before the GUI has a chance to register VPI hooks (for example for the waveform viewer etc). We then get lots of errors like this:

Error-[VPI-ITPTVOT] Illegal VPI tag
Unknown source file, unknown line number
In VPI call vpi_get, illegal type '28' was passed in for vpi object of type
'vpiParameter'
Please fix the VPI call in your PLI program by providing the legal type.

vpiSeverity - vpiError
PLI Routine - vpi_get
Reference Object - FILL_LEVEL_BITS
Reference Scope - sf_rhd_arb
Reference vpiType - vpiParameter
Path - > file.sv, 11
PLI Argument - 28 [vpiArray

Makefiles need refining to integrate well with existing build systems

People already have their own Makefiles - we don't want to try and replace them.

We need to think of a neat way for cocotb to slot into existing build systems. One way could be for cocotb to include another makefile which provides the rules required to build the binary. Another option might be to simply assign variables like VCS_ARGUMENTS which end-users can harmlessly insert into their existing makefile.

Either way needs some thought and decent documentation.

VPI layer can return misleading information

Attempting to get the value of a non-existent handle returns the string "UNKNOWN".

There are several issues here:

  • Shouldn't be possible to get a handle to an signal which doesn't exist, should have raised an AttributeError (according to existing code)

Need to make the following changes (at least):

  • Shouldn't fill "UNKNOWN" into a value if VPI returns NULL
  • Attempting to get the value with an invalid handle should raise an AttributeError

Not helped by VPI error messages being filtered due to issue #12

Call blocking functions from a test

This is the other half of issue #58.

We'd like to be able to call out to functions that may block. These blocking functions should ultimately interface with the ThreadCoroutineBridge defined in issue #58. Propose something like the following:

@cocotb.test()
def call_into_c_world(dut):
    result = yield threadify(external_lib.read( 0x1234)) 

Note that In this special case we pass the return value of the external lib call back into the coroutine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.