Beispiel #1
0
class ReadOnly(
        _py_compat.with_metaclass(_ParameterizedSingletonAndABC, GPITrigger)):
    """Fires when the current simulation timestep moves to the read-only phase.

    The read-only phase is entered when the current timestep no longer has any further delta steps.
    This will be a point where all the signal values are stable as there are no more RTL events scheduled for the timestep.
    The simulator will not allow scheduling of more events in this timestep.
    Useful for monitors which need to wait for all processes to execute (both RTL and cocotb) to ensure sampled signal values are final.
    """
    __slots__ = ()

    @classmethod
    def __singleton_key__(cls):
        return None

    def __init__(self):
        GPITrigger.__init__(self)

    def prime(self, callback):
        if self.cbhdl == 0:
            self.cbhdl = simulator.register_readonly_callback(callback, self)
            if self.cbhdl == 0:
                raise TriggerException("Unable set up %s Trigger" %
                                       (str(self)))
        GPITrigger.prime(self, callback)

    def __str__(self):
        return self.__class__.__name__ + "(readonly)"
Beispiel #2
0
class _EdgeBase(
        _py_compat.with_metaclass(_ParameterizedSingletonAndABC, GPITrigger)):
    """Internal base class that fires on a given edge of a signal."""
    __slots__ = ('signal', )

    @classmethod
    @property
    def _edge_type(self):
        """The edge type, as understood by the C code. Must be set in sub-classes."""
        raise NotImplementedError

    @classmethod
    def __singleton_key__(cls, signal):
        return signal

    def __init__(self, signal):
        super(_EdgeBase, self).__init__()
        self.signal = signal

    def prime(self, callback):
        """Register notification of a value change via a callback"""
        if self.cbhdl == 0:
            self.cbhdl = simulator.register_value_change_callback(
                self.signal._handle, callback,
                type(self)._edge_type, self)
            if self.cbhdl == 0:
                raise TriggerException("Unable set up %s Trigger" %
                                       (str(self)))
        super(_EdgeBase, self).prime(callback)

    def __str__(self):
        return self.__class__.__name__ + "(%s)" % self.signal._name
Beispiel #3
0
class test(_py_compat.with_metaclass(_decorator_helper, coroutine)):
    """Decorator to mark a function as a test.

    All tests are coroutines.  The test decorator provides
    some common reporting etc., a test timeout and allows
    us to mark tests as expected failures.

    Used as ``@cocotb.test(...)``.

    Args:
        timeout (int, optional):
            value representing simulation timeout (not implemented).
        expect_fail (bool, optional):
            Don't mark the result as a failure if the test fails.
        expect_error (bool or exception type or tuple of exception types, optional):
            If ``True``, consider this test passing if it raises *any* :class:`Exception`, and failing if it does not.
            If given an exception type or tuple of exception types, catching *only* a listed exception type is considered passing.
            This is primarily for cocotb internal regression use for when a simulator error is expected.

            Users are encouraged to use the following idiom instead::

                @cocotb.test()
                def my_test(dut):
                    try:
                        yield thing_that_should_fail()
                    except ExceptionIExpect:
                        pass
                    else:
                        assert False, "Exception did not occur"

            .. versionchanged:: 1.3
                Specific exception types can be expected
        skip (bool, optional):
            Don't execute this test as part of the regression.
        stage (int, optional)
            Order tests logically into stages, where multiple tests can share a stage.
    """
    def __init__(self,
                 f,
                 timeout=None,
                 expect_fail=False,
                 expect_error=False,
                 skip=False,
                 stage=None):
        super(test, self).__init__(f)

        self.timeout = timeout
        self.expect_fail = expect_fail
        if expect_error is True:
            expect_error = (Exception, )
        elif expect_error is False:
            expect_error = ()
        self.expect_error = expect_error
        self.skip = skip
        self.stage = stage
        self.im_test = True  # For auto-regressions
        self.name = self._func.__name__

    def __call__(self, *args, **kwargs):
        return RunningTest(self._func(*args, **kwargs), self)
Beispiel #4
0
class hook(_py_compat.with_metaclass(_decorator_helper, coroutine)):
    """Decorator to mark a function as a hook for cocotb.

    Used as ``@cocotb.hook()``.

    All hooks are run at the beginning of a cocotb test suite, prior to any
    test code being run."""
    def __init__(self, f):
        super(hook, self).__init__(f)
        self.im_hook = True
        self.name = self._func.__name__
Beispiel #5
0
class hook(_py_compat.with_metaclass(_decorator_helper, coroutine)):
    """Decorator to mark a function as a hook for cocotb.

    Used as ``@cocotb.hook()``.

    All hooks are run at the beginning of a cocotb test suite, prior to any
    test code being run."""
    def __init__(self, f):
        super(hook, self).__init__(f)
        self.im_hook = True
        self.name = self._func.__name__

    def __call__(self, *args, **kwargs):
        try:
            return RunningCoroutine(self._func(*args, **kwargs), self)
        except Exception as e:
            raise raise_error(self, "Hook raised exception:")
Beispiel #6
0
class test(_py_compat.with_metaclass(_decorator_helper, coroutine)):
    """Decorator to mark a function as a test.

    All tests are coroutines.  The test decorator provides
    some common reporting etc., a test timeout and allows
    us to mark tests as expected failures.

    Used as ``@cocotb.test(...)``.

    Args:
        timeout (int, optional):
            value representing simulation timeout (not implemented).
        expect_fail (bool, optional):
            Don't mark the result as a failure if the test fails.
        expect_error (bool, optional):
            Don't mark the result as an error if an error is raised.
            This is for cocotb internal regression use 
            when a simulator error is expected.
        skip (bool, optional):
            Don't execute this test as part of the regression.
        stage (int, optional)
            Order tests logically into stages, where multiple tests can share a stage.
    """
    def __init__(self,
                 f,
                 timeout=None,
                 expect_fail=False,
                 expect_error=False,
                 skip=False,
                 stage=None):
        super(test, self).__init__(f)

        self.timeout = timeout
        self.expect_fail = expect_fail
        self.expect_error = expect_error
        self.skip = skip
        self.stage = stage
        self.im_test = True  # For auto-regressions
        self.name = self._func.__name__

    def __call__(self, *args, **kwargs):
        return RunningTest(self._func(*args, **kwargs), self)
Beispiel #7
0
class NextTimeStep(_py_compat.with_metaclass(_ParameterizedSingletonAndABC, GPITrigger)):
    """Fires when the next time step is started."""
    __slots__ = ()

    @classmethod
    def __singleton_key__(cls):
        return None

    def __init__(self):
        GPITrigger.__init__(self)

    def prime(self, callback):
        if self.cbhdl == 0:
            self.cbhdl = simulator.register_nextstep_callback(callback, self)
            if self.cbhdl == 0:
                raise TriggerException("Unable set up %s Trigger" % (str(self)))
        GPITrigger.prime(self, callback)

    def __str__(self):
        return self.__class__.__name__ + "(nexttimestep)"
Beispiel #8
0
class ReadWrite(_py_compat.with_metaclass(_ParameterizedSingletonAndABC, GPITrigger)):
    """Fires when the read-write portion of the sim cycles is reached."""
    __slots__ = ()

    @classmethod
    def __singleton_key__(cls):
        return None

    def __init__(self):
        GPITrigger.__init__(self)

    def prime(self, callback):
        if self.cbhdl == 0:
            # import pdb
            # pdb.set_trace()
            self.cbhdl = simulator.register_rwsynch_callback(callback, self)
            if self.cbhdl == 0:
                raise TriggerException("Unable set up %s Trigger" % (str(self)))
        GPITrigger.prime(self, callback)

    def __str__(self):
        return self.__class__.__name__ + "(readwritesync)"
Beispiel #9
0
class test(_py_compat.with_metaclass(_decorator_helper, coroutine)):
    """Decorator to mark a function as a test.

    All tests are coroutines.  The test decorator provides
    some common reporting etc., a test timeout and allows
    us to mark tests as expected failures.

    Tests are evaluated in the order they are defined in a test module.

    Used as ``@cocotb.test(...)``.

    Args:
        timeout_time (int, optional):
            Value representing simulation timeout.

            .. versionadded:: 1.3
        timeout_unit (str, optional):
            Unit of timeout value, see :class:`~cocotb.triggers.Timer` for more info.

            .. versionadded:: 1.3
        expect_fail (bool, optional):
            Don't mark the result as a failure if the test fails.
        expect_error (bool or exception type or tuple of exception types, optional):
            If ``True``, consider this test passing if it raises *any* :class:`Exception`, and failing if it does not.
            If given an exception type or tuple of exception types, catching *only* a listed exception type is considered passing.
            This is primarily for cocotb internal regression use for when a simulator error is expected.

            Users are encouraged to use the following idiom instead::

                @cocotb.test()
                def my_test(dut):
                    try:
                        yield thing_that_should_fail()
                    except ExceptionIExpect:
                        pass
                    else:
                        assert False, "Exception did not occur"

            .. versionchanged:: 1.3
                Specific exception types can be expected
        skip (bool, optional):
            Don't execute this test as part of the regression.
        stage (int, optional)
            Order tests logically into stages, where multiple tests can share a stage.
    """

    _id_count = 0  # used by the RegressionManager to sort tests in definition order

    def __init__(self, f, timeout_time=None, timeout_unit=None,
                 expect_fail=False, expect_error=False,
                 skip=False, stage=None):

        self._id = self._id_count
        type(self)._id_count += 1

        if timeout_time is not None:
            co = coroutine(f)

            @functools.wraps(f)
            def f(*args, **kwargs):
                running_co = co(*args, **kwargs)
                try:
                    res = yield cocotb.triggers.with_timeout(running_co, self.timeout_time, self.timeout_unit)
                except cocotb.result.SimTimeoutError:
                    running_co.kill()
                    raise
                else:
                    raise ReturnValue(res)

        super(test, self).__init__(f)

        self.timeout_time = timeout_time
        self.timeout_unit = timeout_unit
        self.expect_fail = expect_fail
        if expect_error is True:
            expect_error = (Exception,)
        elif expect_error is False:
            expect_error = ()
        self.expect_error = expect_error
        self.skip = skip
        self.stage = stage
        self.im_test = True    # For auto-regressions
        self.name = self._func.__name__

    def __call__(self, *args, **kwargs):
        return RunningTest(self._func(*args, **kwargs), self)
Beispiel #10
0
class Trigger(_py_compat.with_metaclass(abc.ABCMeta)):
    """Base class to derive from."""

    # __dict__ is needed here for the `.log` lazy_property below to work.
    # The implementation of `_PyObject_GenericGetAttrWithDict` suggests that
    # despite its inclusion, __slots__ will overall give speed and memory
    # improvements:
    #  - the `__dict__` is not actually constructed until it's needed, and that
    #    only happens if the `.log` attribute is used, where performance
    #    concerns no longer matter.
    #  - Attribute setting and getting will still go through the slot machinery
    #    first, as "data descriptors" take priority over dict access
    __slots__ = ('primed', '__weakref__', '__dict__')

    def __init__(self):
        self.primed = False

    @lazy_property
    def log(self):
        return SimLog("cocotb.%s" % (self.__class__.__name__), id(self))

    @abc.abstractmethod
    def prime(self, callback):
        """Set a callback to be invoked when the trigger fires.

        The callback will be invoked with a single argument, `self`.

        Sub-classes must override this, but should end by calling the base class
        method.

        Do not call this directly within coroutines, it is intended to be used
        only by the scheduler.
        """
        self.primed = True

    def unprime(self):
        """Remove the callback, and perform cleanup if necessary.

        After being un-primed, a Trigger may be re-primed again in the future.
        Calling `unprime` multiple times is allowed, subsequent calls should be
        a no-op.

        Sub-classes may override this, but should end by calling the base class
        method.

        Do not call this directly within coroutines, it is intended to be used
        only by the scheduler.
        """
        self.primed = False

    def __del__(self):
        # Ensure if a trigger drops out of scope we remove any pending callbacks
        self.unprime()

    def __str__(self):
        return self.__class__.__name__

    @property
    def _outcome(self):
        """The result that `yield this_trigger` produces in a coroutine.

        The default is to produce the trigger itself, which is done for
        ease of use with :class:`~cocotb.triggers.First`.
        """
        return outcomes.Value(self)

    # Once Python 2.7 support is dropped, this can be run unconditionally
    if sys.version_info >= (3, 3):
        _py_compat.exec_(
            textwrap.dedent("""
        def __await__(self):
            # hand the trigger back to the scheduler trampoline
            return (yield self)
        """))
Beispiel #11
0
class Join(
        _py_compat.with_metaclass(_ParameterizedSingletonAndABC,
                                  PythonTrigger)):
    r"""Fires when a :func:`fork`\ ed coroutine completes

    The result of blocking on the trigger can be used to get the coroutine
    result::

        @cocotb.coroutine()
        def coro_inner():
            yield Timer(1)
            raise ReturnValue("Hello world")

        task = cocotb.fork(coro_inner())
        result = yield Join(task)
        assert result == "Hello world"

    Or using the syntax in Python 3.5 onwards:

    .. code-block:: python3

        @cocotb.coroutine()
        async def coro_inner():
            await Timer(1)
            return "Hello world"

        task = cocotb.fork(coro_inner())
        result = await Join(task)
        assert result == "Hello world"

    If the coroutine threw an exception, the :keyword:`await` or :keyword:`yield`
    will re-raise it.

    """
    __slots__ = ('_coroutine', )

    @classmethod
    def __singleton_key__(cls, coroutine):
        return coroutine

    def __init__(self, coroutine):
        super(Join, self).__init__()
        self._coroutine = coroutine

    @property
    def _outcome(self):
        return self._coroutine._outcome

    @property
    def retval(self):
        """The return value of the joined coroutine.

        .. note::
            Typically there is no need to use this attribute - the
            following code samples are equivalent::

                forked = cocotb.fork(mycoro())
                j = Join(forked)
                yield j
                result = j.retval

            ::

                forked = cocotb.fork(mycoro())
                result = yield Join(forked)
        """
        return self._coroutine.retval

    def prime(self, callback):
        if self._coroutine._finished:
            callback(self)
        else:
            super(Join, self).prime(callback)

    def __str__(self):
        return self.__class__.__name__ + "(%s)" % self._coroutine.__name__