cocotb 2.0.1__cp38-cp38-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cocotb/_ANSI.py +65 -0
- cocotb/__init__.py +127 -0
- cocotb/_base_triggers.py +515 -0
- cocotb/_bridge.py +186 -0
- cocotb/_decorators.py +515 -0
- cocotb/_deprecation.py +36 -0
- cocotb/_exceptions.py +7 -0
- cocotb/_extended_awaitables.py +419 -0
- cocotb/_gpi_triggers.py +385 -0
- cocotb/_init.py +301 -0
- cocotb/_outcomes.py +54 -0
- cocotb/_profiling.py +46 -0
- cocotb/_py_compat.py +150 -0
- cocotb/_scheduler.py +448 -0
- cocotb/_test.py +248 -0
- cocotb/_test_factory.py +312 -0
- cocotb/_test_functions.py +42 -0
- cocotb/_typing.py +7 -0
- cocotb/_utils.py +274 -0
- cocotb/_version.py +4 -0
- cocotb/_xunit_reporter.py +103 -0
- cocotb/clock.py +419 -0
- cocotb/debug.py +24 -0
- cocotb/handle.py +1752 -0
- cocotb/libs/cocotb.dll +0 -0
- cocotb/libs/cocotb.exp +0 -0
- cocotb/libs/cocotb.lib +0 -0
- cocotb/libs/cocotbfli_modelsim.dll +0 -0
- cocotb/libs/cocotbfli_modelsim.exp +0 -0
- cocotb/libs/cocotbfli_modelsim.lib +0 -0
- cocotb/libs/cocotbutils.dll +0 -0
- cocotb/libs/cocotbutils.exp +0 -0
- cocotb/libs/cocotbutils.lib +0 -0
- cocotb/libs/cocotbvhpi_aldec.dll +0 -0
- cocotb/libs/cocotbvhpi_aldec.exp +0 -0
- cocotb/libs/cocotbvhpi_aldec.lib +0 -0
- cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
- cocotb/libs/cocotbvhpi_nvc.dll +0 -0
- cocotb/libs/cocotbvhpi_nvc.exp +0 -0
- cocotb/libs/cocotbvhpi_nvc.lib +0 -0
- cocotb/libs/cocotbvpi_aldec.dll +0 -0
- cocotb/libs/cocotbvpi_aldec.exp +0 -0
- cocotb/libs/cocotbvpi_aldec.lib +0 -0
- cocotb/libs/cocotbvpi_ghdl.dll +0 -0
- cocotb/libs/cocotbvpi_ghdl.exp +0 -0
- cocotb/libs/cocotbvpi_ghdl.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.exp +0 -0
- cocotb/libs/cocotbvpi_icarus.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.vpl +0 -0
- cocotb/libs/cocotbvpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvpi_modelsim.lib +0 -0
- cocotb/libs/embed.dll +0 -0
- cocotb/libs/embed.exp +0 -0
- cocotb/libs/embed.lib +0 -0
- cocotb/libs/gpi.dll +0 -0
- cocotb/libs/gpi.exp +0 -0
- cocotb/libs/gpi.lib +0 -0
- cocotb/libs/gpilog.dll +0 -0
- cocotb/libs/gpilog.exp +0 -0
- cocotb/libs/gpilog.lib +0 -0
- cocotb/libs/pygpilog.dll +0 -0
- cocotb/libs/pygpilog.exp +0 -0
- cocotb/libs/pygpilog.lib +0 -0
- cocotb/logging.py +417 -0
- cocotb/py.typed +0 -0
- cocotb/queue.py +235 -0
- cocotb/regression.py +900 -0
- cocotb/result.py +38 -0
- cocotb/share/def/.gitignore +2 -0
- cocotb/share/def/README.md +4 -0
- cocotb/share/def/aldec.def +61 -0
- cocotb/share/def/aldec.exp +0 -0
- cocotb/share/def/aldec.lib +0 -0
- cocotb/share/def/ghdl.def +43 -0
- cocotb/share/def/ghdl.exp +0 -0
- cocotb/share/def/ghdl.lib +0 -0
- cocotb/share/def/icarus.def +43 -0
- cocotb/share/def/icarus.exp +0 -0
- cocotb/share/def/icarus.lib +0 -0
- cocotb/share/def/modelsim.def +138 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/def/nvcvhpi.def +18 -0
- cocotb/share/def/nvcvhpi.exp +0 -0
- cocotb/share/def/nvcvhpi.lib +0 -0
- cocotb/share/include/cocotb_utils.h +70 -0
- cocotb/share/include/embed.h +33 -0
- cocotb/share/include/exports.h +20 -0
- cocotb/share/include/gpi.h +459 -0
- cocotb/share/include/gpi_logging.h +291 -0
- cocotb/share/include/py_gpi_logging.h +33 -0
- cocotb/share/include/vhpi_user_ext.h +26 -0
- cocotb/share/include/vpi_user_ext.h +33 -0
- cocotb/share/lib/verilator/verilator.cpp +209 -0
- cocotb/simtime.py +238 -0
- cocotb/simulator.cp38-win32.exp +0 -0
- cocotb/simulator.cp38-win32.lib +0 -0
- cocotb/simulator.cp38-win32.pyd +0 -0
- cocotb/simulator.cp38-win32.pyd.2.config +8 -0
- cocotb/simulator.pyi +107 -0
- cocotb/task.py +590 -0
- cocotb/triggers.py +67 -0
- cocotb/types/__init__.py +31 -0
- cocotb/types/_abstract_array.py +151 -0
- cocotb/types/_array.py +297 -0
- cocotb/types/_indexing.py +17 -0
- cocotb/types/_logic.py +333 -0
- cocotb/types/_logic_array.py +884 -0
- cocotb/types/_range.py +197 -0
- cocotb/types/_resolve.py +76 -0
- cocotb/utils.py +110 -0
- cocotb-2.0.1.dist-info/LICENSE +29 -0
- cocotb-2.0.1.dist-info/METADATA +44 -0
- cocotb-2.0.1.dist-info/RECORD +152 -0
- cocotb-2.0.1.dist-info/WHEEL +5 -0
- cocotb-2.0.1.dist-info/entry_points.txt +2 -0
- cocotb-2.0.1.dist-info/top_level.txt +18 -0
- cocotb_tools/__init__.py +0 -0
- cocotb_tools/_coverage.py +33 -0
- cocotb_tools/_vendor/__init__.py +3 -0
- cocotb_tools/_vendor/distutils_version.py +346 -0
- cocotb_tools/check_results.py +65 -0
- cocotb_tools/combine_results.py +152 -0
- cocotb_tools/config.py +242 -0
- cocotb_tools/ipython_support.py +99 -0
- cocotb_tools/makefiles/Makefile.deprecations +27 -0
- cocotb_tools/makefiles/Makefile.inc +198 -0
- cocotb_tools/makefiles/Makefile.sim +96 -0
- cocotb_tools/makefiles/simulators/Makefile.activehdl +72 -0
- cocotb_tools/makefiles/simulators/Makefile.cvc +61 -0
- cocotb_tools/makefiles/simulators/Makefile.dsim +39 -0
- cocotb_tools/makefiles/simulators/Makefile.ghdl +84 -0
- cocotb_tools/makefiles/simulators/Makefile.icarus +80 -0
- cocotb_tools/makefiles/simulators/Makefile.ius +93 -0
- cocotb_tools/makefiles/simulators/Makefile.modelsim +9 -0
- cocotb_tools/makefiles/simulators/Makefile.nvc +60 -0
- cocotb_tools/makefiles/simulators/Makefile.questa +29 -0
- cocotb_tools/makefiles/simulators/Makefile.questa-compat +143 -0
- cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun +149 -0
- cocotb_tools/makefiles/simulators/Makefile.riviera +144 -0
- cocotb_tools/makefiles/simulators/Makefile.vcs +65 -0
- cocotb_tools/makefiles/simulators/Makefile.verilator +79 -0
- cocotb_tools/makefiles/simulators/Makefile.xcelium +104 -0
- cocotb_tools/py.typed +0 -0
- cocotb_tools/runner.py +2001 -0
- cocotb_tools/sim_versions.py +140 -0
- pygpi/__init__.py +0 -0
- pygpi/entry.py +42 -0
- pygpi/py.typed +0 -0
cocotb/_deprecation.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
2
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
3
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
import warnings
|
|
7
|
+
from typing import Callable, Type, TypeVar
|
|
8
|
+
|
|
9
|
+
AnyCallableT = TypeVar("AnyCallableT", bound=Callable[..., object])
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def deprecated(
|
|
13
|
+
msg: str, category: Type[Warning] = DeprecationWarning
|
|
14
|
+
) -> Callable[[AnyCallableT], AnyCallableT]:
|
|
15
|
+
"""Emits a DeprecationWarning when the decorated function is called.
|
|
16
|
+
|
|
17
|
+
This decorator works on normal functions, methods, and properties.
|
|
18
|
+
Usage on properties requires the ``@property`` decorator to appear outside the
|
|
19
|
+
``@deprecated`` decorator.
|
|
20
|
+
Concrete classes can be deprecated by decorating their ``__init__`` or ``__new__``
|
|
21
|
+
method.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
msg: the deprecation message
|
|
25
|
+
category: the warning class to use
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def decorator(f: AnyCallableT) -> AnyCallableT:
|
|
29
|
+
@functools.wraps(f)
|
|
30
|
+
def wrapper(*args: object, **kwargs: object) -> object:
|
|
31
|
+
warnings.warn(msg, category=category, stacklevel=2)
|
|
32
|
+
return f(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
return wrapper # type: ignore[return-value] # type checkers get confused about this
|
|
35
|
+
|
|
36
|
+
return decorator
|
cocotb/_exceptions.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
2
|
+
# Copyright (c) 2013 Potential Ventures Ltd
|
|
3
|
+
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
4
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
5
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
6
|
+
|
|
7
|
+
"""A collection of triggers which a testbench can :keyword:`await`."""
|
|
8
|
+
|
|
9
|
+
from abc import abstractmethod
|
|
10
|
+
from decimal import Decimal
|
|
11
|
+
from typing import (
|
|
12
|
+
Any,
|
|
13
|
+
Awaitable,
|
|
14
|
+
Coroutine,
|
|
15
|
+
Generator,
|
|
16
|
+
List,
|
|
17
|
+
Optional,
|
|
18
|
+
Type,
|
|
19
|
+
TypeVar,
|
|
20
|
+
Union,
|
|
21
|
+
cast,
|
|
22
|
+
overload,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
import cocotb.handle
|
|
26
|
+
from cocotb._base_triggers import NullTrigger, Trigger, _InternalEvent
|
|
27
|
+
from cocotb._gpi_triggers import FallingEdge, RisingEdge, Timer, ValueChange
|
|
28
|
+
from cocotb._typing import RoundMode, TimeUnit
|
|
29
|
+
from cocotb.task import Task
|
|
30
|
+
|
|
31
|
+
T = TypeVar("T")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Waitable(Awaitable[T]):
|
|
35
|
+
"""A Trigger-like object that can be implemented using coroutines.
|
|
36
|
+
|
|
37
|
+
This converts a ``_wait`` abstract method into a suitable ``__await__``.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def _wait(self) -> T:
|
|
42
|
+
"""The coroutine function which implements the functionality of the Waitable."""
|
|
43
|
+
|
|
44
|
+
def __await__(self) -> Generator[Trigger, None, T]:
|
|
45
|
+
return self._wait().__await__()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class _AggregateWaitable(Waitable[T]):
|
|
49
|
+
"""Base class for :class:`Combine` and :class:`First`."""
|
|
50
|
+
|
|
51
|
+
def __init__(self, *trigger: Union[Trigger, Waitable[Any], Task[Any]]) -> None:
|
|
52
|
+
self._triggers = trigger
|
|
53
|
+
|
|
54
|
+
# Do some basic type-checking up front, rather than waiting until we
|
|
55
|
+
# await them.
|
|
56
|
+
allowed_types = (Trigger, Waitable, Task)
|
|
57
|
+
for t in self._triggers:
|
|
58
|
+
if not isinstance(t, allowed_types):
|
|
59
|
+
raise TypeError(
|
|
60
|
+
f"All triggers must be instances of Trigger! Got: {type(t).__qualname__}"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
# no _pointer_str here, since this is not a trigger, so identity
|
|
65
|
+
# doesn't matter.
|
|
66
|
+
return "{}({})".format(
|
|
67
|
+
type(self).__qualname__,
|
|
68
|
+
", ".join(repr(t) for t in self._triggers),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def _wait_callback(trigger: Awaitable[T]) -> T:
|
|
73
|
+
return await trigger
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class Combine(_AggregateWaitable["Combine"]):
|
|
77
|
+
r"""Trigger that fires when all *triggers* have fired.
|
|
78
|
+
|
|
79
|
+
:keyword:`await`\ ing this returns the :class:`Combine` object.
|
|
80
|
+
This is similar to Verilog's ``join``.
|
|
81
|
+
See :ref:`combine-tutorial` for an example.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
trigger: One or more :keyword:`await`\ able objects.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
TypeError: When an unsupported *trigger* object is passed.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
async def _wait(self) -> "Combine":
|
|
91
|
+
if len(self._triggers) == 0:
|
|
92
|
+
await NullTrigger()
|
|
93
|
+
elif len(self._triggers) == 1:
|
|
94
|
+
await self._triggers[0]
|
|
95
|
+
else:
|
|
96
|
+
waiters: List[Task[object]] = []
|
|
97
|
+
completed: List[Task[object]] = []
|
|
98
|
+
done = _InternalEvent(self)
|
|
99
|
+
exception: Union[BaseException, None] = None
|
|
100
|
+
|
|
101
|
+
def on_done(
|
|
102
|
+
task: Task[object],
|
|
103
|
+
) -> None:
|
|
104
|
+
# have to check cancelled first otherwise exception() will throw
|
|
105
|
+
if task.cancelled():
|
|
106
|
+
completed.append(task)
|
|
107
|
+
if len(completed) == len(waiters):
|
|
108
|
+
done.set()
|
|
109
|
+
return
|
|
110
|
+
e = task.exception()
|
|
111
|
+
if e is not None:
|
|
112
|
+
nonlocal exception
|
|
113
|
+
exception = e
|
|
114
|
+
done.set()
|
|
115
|
+
else:
|
|
116
|
+
completed.append(task)
|
|
117
|
+
if len(completed) == len(waiters):
|
|
118
|
+
done.set()
|
|
119
|
+
|
|
120
|
+
# start a parallel task for each trigger
|
|
121
|
+
for t in self._triggers:
|
|
122
|
+
task = Task[object](_wait_callback(t))
|
|
123
|
+
task._add_done_callback(on_done)
|
|
124
|
+
cocotb.start_soon(task)
|
|
125
|
+
waiters.append(task)
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
# wait for the last waiter to complete
|
|
129
|
+
await done
|
|
130
|
+
finally:
|
|
131
|
+
# kill remaining waiters
|
|
132
|
+
for w in waiters:
|
|
133
|
+
w.cancel()
|
|
134
|
+
|
|
135
|
+
if exception is not None:
|
|
136
|
+
raise exception
|
|
137
|
+
|
|
138
|
+
return self
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class First(_AggregateWaitable[object]):
|
|
142
|
+
r"""Fires when the first trigger in *triggers* fires.
|
|
143
|
+
|
|
144
|
+
:keyword:`await`\ ing this object returns the result of the first trigger that fires.
|
|
145
|
+
This is similar to Verilog's ``join_any``.
|
|
146
|
+
See :ref:`first-tutorial` for an example.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
trigger: One or more :keyword:`await`\ able objects.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
TypeError: When an unsupported *trigger* object is passed.
|
|
153
|
+
ValueError: When no triggers are passed.
|
|
154
|
+
|
|
155
|
+
.. note::
|
|
156
|
+
The event loop is single threaded, so while events may be simultaneous
|
|
157
|
+
in simulation time, they can never be simultaneous in real time.
|
|
158
|
+
For this reason, the value of ``t_ret is t1`` in the following example
|
|
159
|
+
is implementation-defined, and will vary by simulator::
|
|
160
|
+
|
|
161
|
+
t1 = Timer(10, unit="ps")
|
|
162
|
+
t2 = Timer(10, unit="ps")
|
|
163
|
+
t_ret = await First(t1, t2)
|
|
164
|
+
|
|
165
|
+
.. note::
|
|
166
|
+
In the old-style :ref:`generator-based coroutines <yield-syntax>`, ``t = yield [a, b]`` was another spelling of
|
|
167
|
+
``t = yield First(a, b)``. This spelling is no longer available when using :keyword:`await`-based
|
|
168
|
+
coroutines.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(self, *trigger: Union[Trigger, Waitable[Any], Task[Any]]) -> None:
|
|
172
|
+
if not trigger:
|
|
173
|
+
raise ValueError("First() requires at least one Trigger or Task argument")
|
|
174
|
+
super().__init__(*trigger)
|
|
175
|
+
|
|
176
|
+
async def _wait(self) -> object:
|
|
177
|
+
if len(self._triggers) == 1:
|
|
178
|
+
return await self._triggers[0]
|
|
179
|
+
|
|
180
|
+
waiters: List[Task[object]] = []
|
|
181
|
+
done = _InternalEvent(self)
|
|
182
|
+
completed: List[Task[object]] = []
|
|
183
|
+
|
|
184
|
+
def on_done(task: Task[object]) -> None:
|
|
185
|
+
completed.append(task)
|
|
186
|
+
done.set()
|
|
187
|
+
|
|
188
|
+
# start a parallel task for each trigger
|
|
189
|
+
for t in self._triggers:
|
|
190
|
+
task = Task[object](_wait_callback(t))
|
|
191
|
+
task._add_done_callback(on_done)
|
|
192
|
+
cocotb.start_soon(task)
|
|
193
|
+
waiters.append(task)
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
# wait for a waiter to complete
|
|
197
|
+
await done
|
|
198
|
+
finally:
|
|
199
|
+
# kill all the other waiters
|
|
200
|
+
for w in waiters:
|
|
201
|
+
w.cancel()
|
|
202
|
+
|
|
203
|
+
return completed[0].result()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class ClockCycles(Waitable["ClockCycles"]):
|
|
207
|
+
r"""Finishes after *num_cycles* transitions of *signal*.
|
|
208
|
+
|
|
209
|
+
:keyword:`await`\ ing this Trigger returns the :class:`!ClockCycles` object.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
signal: The signal to monitor.
|
|
213
|
+
num_cycles: The number of cycles to count.
|
|
214
|
+
rising: If ``True``, count rising edges; if ``False``, count falling edges.
|
|
215
|
+
edge_type: The kind of :ref:`edge-triggers` to count.
|
|
216
|
+
|
|
217
|
+
.. warning::
|
|
218
|
+
On many simulators transitions occur when the signal changes value from non-``0`` to ``0`` or non-``1`` to ``1``,
|
|
219
|
+
not just from ``1`` to ``0`` or ``0`` to ``1``.
|
|
220
|
+
|
|
221
|
+
.. versionadded:: 2.0
|
|
222
|
+
Passing the edge trigger type: :class:`.RisingEdge`, :class:`.FallingEdge`, or :class:`.ValueChange`
|
|
223
|
+
as the third positional argument or by the keyword *edge_type*.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
@overload
|
|
227
|
+
def __init__(
|
|
228
|
+
self,
|
|
229
|
+
signal: "cocotb.handle.LogicObject",
|
|
230
|
+
num_cycles: int,
|
|
231
|
+
) -> None: ...
|
|
232
|
+
|
|
233
|
+
@overload
|
|
234
|
+
def __init__(
|
|
235
|
+
self,
|
|
236
|
+
signal: "cocotb.handle.LogicObject",
|
|
237
|
+
num_cycles: int,
|
|
238
|
+
edge_type: Union[
|
|
239
|
+
Type[RisingEdge], Type[FallingEdge], Type[ValueChange], None
|
|
240
|
+
] = None,
|
|
241
|
+
) -> None: ...
|
|
242
|
+
|
|
243
|
+
@overload
|
|
244
|
+
def __init__(
|
|
245
|
+
self, signal: "cocotb.handle.LogicObject", num_cycles: int, *, rising: bool
|
|
246
|
+
) -> None: ...
|
|
247
|
+
|
|
248
|
+
def __init__(
|
|
249
|
+
self,
|
|
250
|
+
signal: "cocotb.handle.LogicObject",
|
|
251
|
+
num_cycles: int,
|
|
252
|
+
edge_type: Union[
|
|
253
|
+
bool, Type[RisingEdge], Type[FallingEdge], Type[ValueChange], None
|
|
254
|
+
] = None,
|
|
255
|
+
*,
|
|
256
|
+
rising: Union[bool, None] = None,
|
|
257
|
+
) -> None:
|
|
258
|
+
self._signal = signal
|
|
259
|
+
self._num_cycles = num_cycles
|
|
260
|
+
self._edge_type: Union[Type[RisingEdge], Type[FallingEdge], Type[ValueChange]]
|
|
261
|
+
if edge_type is not None and rising is not None:
|
|
262
|
+
raise TypeError("Passed more than one edge selection argument.")
|
|
263
|
+
elif edge_type is True:
|
|
264
|
+
self._edge_type = RisingEdge
|
|
265
|
+
elif edge_type is False:
|
|
266
|
+
self._edge_type = FallingEdge
|
|
267
|
+
elif edge_type is not None:
|
|
268
|
+
self._edge_type = edge_type
|
|
269
|
+
elif rising is not None:
|
|
270
|
+
self._edge_type = RisingEdge if rising else FallingEdge
|
|
271
|
+
else:
|
|
272
|
+
# default if no argument is passed
|
|
273
|
+
self._edge_type = RisingEdge
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def signal(self) -> "cocotb.handle.LogicObject":
|
|
277
|
+
"""The signal being monitored."""
|
|
278
|
+
return self._signal
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def num_cycles(self) -> int:
|
|
282
|
+
"""The number of cycles to wait."""
|
|
283
|
+
return self._num_cycles
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def edge_type(
|
|
287
|
+
self,
|
|
288
|
+
) -> Union[Type[RisingEdge], Type[FallingEdge], Type[ValueChange]]:
|
|
289
|
+
"""The type of edge trigger used."""
|
|
290
|
+
return self._edge_type
|
|
291
|
+
|
|
292
|
+
async def _wait(self) -> "ClockCycles":
|
|
293
|
+
trigger = self._edge_type(self._signal)
|
|
294
|
+
for _ in range(self._num_cycles):
|
|
295
|
+
await trigger
|
|
296
|
+
return self
|
|
297
|
+
|
|
298
|
+
def __repr__(self) -> str:
|
|
299
|
+
return f"{type(self).__qualname__}({self._signal._path}, {self._num_cycles}, {self._edge_type.__qualname__})"
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class SimTimeoutError(TimeoutError):
|
|
303
|
+
"""Exception thrown when a timeout, in terms of simulation time, occurs."""
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
TriggerT = TypeVar("TriggerT", bound=Trigger)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@overload
|
|
310
|
+
async def with_timeout(
|
|
311
|
+
trigger: TriggerT,
|
|
312
|
+
timeout_time: Union[float, Decimal],
|
|
313
|
+
timeout_unit: TimeUnit = "step",
|
|
314
|
+
round_mode: Optional[RoundMode] = None,
|
|
315
|
+
) -> TriggerT: ...
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@overload
|
|
319
|
+
async def with_timeout(
|
|
320
|
+
trigger: Waitable[T],
|
|
321
|
+
timeout_time: Union[float, Decimal],
|
|
322
|
+
timeout_unit: TimeUnit = "step",
|
|
323
|
+
round_mode: Optional[RoundMode] = None,
|
|
324
|
+
) -> T: ...
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
@overload
|
|
328
|
+
async def with_timeout(
|
|
329
|
+
trigger: Task[T],
|
|
330
|
+
timeout_time: Union[float, Decimal],
|
|
331
|
+
timeout_unit: TimeUnit = "step",
|
|
332
|
+
round_mode: Optional[RoundMode] = None,
|
|
333
|
+
) -> T: ...
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
@overload
|
|
337
|
+
async def with_timeout(
|
|
338
|
+
trigger: Coroutine[Trigger, None, T],
|
|
339
|
+
timeout_time: Union[float, Decimal],
|
|
340
|
+
timeout_unit: TimeUnit = "step",
|
|
341
|
+
round_mode: Optional[RoundMode] = None,
|
|
342
|
+
) -> T: ...
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
async def with_timeout(
|
|
346
|
+
trigger: Union[TriggerT, Waitable[T], Task[T], Coroutine[Trigger, None, T]],
|
|
347
|
+
timeout_time: Union[float, Decimal],
|
|
348
|
+
timeout_unit: TimeUnit = "step",
|
|
349
|
+
round_mode: Optional[RoundMode] = None,
|
|
350
|
+
) -> Union[T, TriggerT]:
|
|
351
|
+
r"""Wait on triggers or coroutines, throw an exception if it waits longer than the given time.
|
|
352
|
+
|
|
353
|
+
When a :term:`python:coroutine` is passed,
|
|
354
|
+
the callee coroutine is started,
|
|
355
|
+
the caller blocks until the callee completes,
|
|
356
|
+
and the callee's result is returned to the caller.
|
|
357
|
+
If timeout occurs, the callee is killed
|
|
358
|
+
and :exc:`SimTimeoutError` is raised.
|
|
359
|
+
|
|
360
|
+
When a :term:`task` is passed,
|
|
361
|
+
the caller blocks until the callee completes
|
|
362
|
+
and the callee's result is returned to the caller.
|
|
363
|
+
If timeout occurs, the callee `continues to run`
|
|
364
|
+
and :exc:`SimTimeoutError` is raised.
|
|
365
|
+
|
|
366
|
+
If a :class:`~cocotb.triggers.Trigger` or :class:`~cocotb.triggers.Waitable` is passed,
|
|
367
|
+
the caller blocks until the trigger fires,
|
|
368
|
+
and the trigger is returned to the caller.
|
|
369
|
+
If timeout occurs, the trigger is cancelled
|
|
370
|
+
and :exc:`SimTimeoutError` is raised.
|
|
371
|
+
|
|
372
|
+
Usage:
|
|
373
|
+
.. code-block:: python
|
|
374
|
+
|
|
375
|
+
await with_timeout(coro, 100, "ns")
|
|
376
|
+
await with_timeout(First(coro, event.wait()), 100, "ns")
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
trigger:
|
|
380
|
+
A single object that could be right of an :keyword:`await` expression in cocotb.
|
|
381
|
+
timeout_time:
|
|
382
|
+
Simulation time duration before timeout occurs.
|
|
383
|
+
timeout_unit:
|
|
384
|
+
Unit of timeout_time, accepts any unit that :class:`~cocotb.triggers.Timer` does.
|
|
385
|
+
round_mode:
|
|
386
|
+
String specifying how to handle time values that sit between time steps
|
|
387
|
+
(one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``).
|
|
388
|
+
A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`.
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
First trigger that completed if timeout did not occur.
|
|
392
|
+
|
|
393
|
+
Raises:
|
|
394
|
+
:exc:`SimTimeoutError`: If timeout occurs.
|
|
395
|
+
|
|
396
|
+
.. versionadded:: 1.3
|
|
397
|
+
|
|
398
|
+
.. versionchanged:: 1.7
|
|
399
|
+
Support passing :term:`python:coroutine`\ s.
|
|
400
|
+
|
|
401
|
+
.. versionchanged:: 2.0
|
|
402
|
+
Passing ``None`` as the *timeout_unit* argument was removed, use ``'step'`` instead.
|
|
403
|
+
|
|
404
|
+
"""
|
|
405
|
+
if isinstance(trigger, Coroutine):
|
|
406
|
+
trigger = cocotb.start_soon(trigger)
|
|
407
|
+
shielded = False
|
|
408
|
+
else:
|
|
409
|
+
shielded = True
|
|
410
|
+
timeout_timer = Timer(timeout_time, timeout_unit, round_mode=round_mode)
|
|
411
|
+
res = await First(timeout_timer, trigger)
|
|
412
|
+
if res is timeout_timer:
|
|
413
|
+
if not shielded:
|
|
414
|
+
# shielded = False only when trigger is a Task created to wrap a Coroutine
|
|
415
|
+
task = cast("Task[object]", trigger)
|
|
416
|
+
task.cancel()
|
|
417
|
+
raise SimTimeoutError
|
|
418
|
+
else:
|
|
419
|
+
return cast("T | TriggerT", res)
|