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.
Files changed (152) hide show
  1. cocotb/_ANSI.py +65 -0
  2. cocotb/__init__.py +127 -0
  3. cocotb/_base_triggers.py +515 -0
  4. cocotb/_bridge.py +186 -0
  5. cocotb/_decorators.py +515 -0
  6. cocotb/_deprecation.py +36 -0
  7. cocotb/_exceptions.py +7 -0
  8. cocotb/_extended_awaitables.py +419 -0
  9. cocotb/_gpi_triggers.py +385 -0
  10. cocotb/_init.py +301 -0
  11. cocotb/_outcomes.py +54 -0
  12. cocotb/_profiling.py +46 -0
  13. cocotb/_py_compat.py +150 -0
  14. cocotb/_scheduler.py +448 -0
  15. cocotb/_test.py +248 -0
  16. cocotb/_test_factory.py +312 -0
  17. cocotb/_test_functions.py +42 -0
  18. cocotb/_typing.py +7 -0
  19. cocotb/_utils.py +274 -0
  20. cocotb/_version.py +4 -0
  21. cocotb/_xunit_reporter.py +103 -0
  22. cocotb/clock.py +419 -0
  23. cocotb/debug.py +24 -0
  24. cocotb/handle.py +1752 -0
  25. cocotb/libs/cocotb.dll +0 -0
  26. cocotb/libs/cocotb.exp +0 -0
  27. cocotb/libs/cocotb.lib +0 -0
  28. cocotb/libs/cocotbfli_modelsim.dll +0 -0
  29. cocotb/libs/cocotbfli_modelsim.exp +0 -0
  30. cocotb/libs/cocotbfli_modelsim.lib +0 -0
  31. cocotb/libs/cocotbutils.dll +0 -0
  32. cocotb/libs/cocotbutils.exp +0 -0
  33. cocotb/libs/cocotbutils.lib +0 -0
  34. cocotb/libs/cocotbvhpi_aldec.dll +0 -0
  35. cocotb/libs/cocotbvhpi_aldec.exp +0 -0
  36. cocotb/libs/cocotbvhpi_aldec.lib +0 -0
  37. cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
  38. cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
  39. cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
  40. cocotb/libs/cocotbvhpi_nvc.dll +0 -0
  41. cocotb/libs/cocotbvhpi_nvc.exp +0 -0
  42. cocotb/libs/cocotbvhpi_nvc.lib +0 -0
  43. cocotb/libs/cocotbvpi_aldec.dll +0 -0
  44. cocotb/libs/cocotbvpi_aldec.exp +0 -0
  45. cocotb/libs/cocotbvpi_aldec.lib +0 -0
  46. cocotb/libs/cocotbvpi_ghdl.dll +0 -0
  47. cocotb/libs/cocotbvpi_ghdl.exp +0 -0
  48. cocotb/libs/cocotbvpi_ghdl.lib +0 -0
  49. cocotb/libs/cocotbvpi_icarus.exp +0 -0
  50. cocotb/libs/cocotbvpi_icarus.lib +0 -0
  51. cocotb/libs/cocotbvpi_icarus.vpl +0 -0
  52. cocotb/libs/cocotbvpi_modelsim.dll +0 -0
  53. cocotb/libs/cocotbvpi_modelsim.exp +0 -0
  54. cocotb/libs/cocotbvpi_modelsim.lib +0 -0
  55. cocotb/libs/embed.dll +0 -0
  56. cocotb/libs/embed.exp +0 -0
  57. cocotb/libs/embed.lib +0 -0
  58. cocotb/libs/gpi.dll +0 -0
  59. cocotb/libs/gpi.exp +0 -0
  60. cocotb/libs/gpi.lib +0 -0
  61. cocotb/libs/gpilog.dll +0 -0
  62. cocotb/libs/gpilog.exp +0 -0
  63. cocotb/libs/gpilog.lib +0 -0
  64. cocotb/libs/pygpilog.dll +0 -0
  65. cocotb/libs/pygpilog.exp +0 -0
  66. cocotb/libs/pygpilog.lib +0 -0
  67. cocotb/logging.py +417 -0
  68. cocotb/py.typed +0 -0
  69. cocotb/queue.py +235 -0
  70. cocotb/regression.py +900 -0
  71. cocotb/result.py +38 -0
  72. cocotb/share/def/.gitignore +2 -0
  73. cocotb/share/def/README.md +4 -0
  74. cocotb/share/def/aldec.def +61 -0
  75. cocotb/share/def/aldec.exp +0 -0
  76. cocotb/share/def/aldec.lib +0 -0
  77. cocotb/share/def/ghdl.def +43 -0
  78. cocotb/share/def/ghdl.exp +0 -0
  79. cocotb/share/def/ghdl.lib +0 -0
  80. cocotb/share/def/icarus.def +43 -0
  81. cocotb/share/def/icarus.exp +0 -0
  82. cocotb/share/def/icarus.lib +0 -0
  83. cocotb/share/def/modelsim.def +138 -0
  84. cocotb/share/def/modelsim.exp +0 -0
  85. cocotb/share/def/modelsim.lib +0 -0
  86. cocotb/share/def/nvcvhpi.def +18 -0
  87. cocotb/share/def/nvcvhpi.exp +0 -0
  88. cocotb/share/def/nvcvhpi.lib +0 -0
  89. cocotb/share/include/cocotb_utils.h +70 -0
  90. cocotb/share/include/embed.h +33 -0
  91. cocotb/share/include/exports.h +20 -0
  92. cocotb/share/include/gpi.h +459 -0
  93. cocotb/share/include/gpi_logging.h +291 -0
  94. cocotb/share/include/py_gpi_logging.h +33 -0
  95. cocotb/share/include/vhpi_user_ext.h +26 -0
  96. cocotb/share/include/vpi_user_ext.h +33 -0
  97. cocotb/share/lib/verilator/verilator.cpp +209 -0
  98. cocotb/simtime.py +238 -0
  99. cocotb/simulator.cp38-win32.exp +0 -0
  100. cocotb/simulator.cp38-win32.lib +0 -0
  101. cocotb/simulator.cp38-win32.pyd +0 -0
  102. cocotb/simulator.cp38-win32.pyd.2.config +8 -0
  103. cocotb/simulator.pyi +107 -0
  104. cocotb/task.py +590 -0
  105. cocotb/triggers.py +67 -0
  106. cocotb/types/__init__.py +31 -0
  107. cocotb/types/_abstract_array.py +151 -0
  108. cocotb/types/_array.py +297 -0
  109. cocotb/types/_indexing.py +17 -0
  110. cocotb/types/_logic.py +333 -0
  111. cocotb/types/_logic_array.py +884 -0
  112. cocotb/types/_range.py +197 -0
  113. cocotb/types/_resolve.py +76 -0
  114. cocotb/utils.py +110 -0
  115. cocotb-2.0.1.dist-info/LICENSE +29 -0
  116. cocotb-2.0.1.dist-info/METADATA +44 -0
  117. cocotb-2.0.1.dist-info/RECORD +152 -0
  118. cocotb-2.0.1.dist-info/WHEEL +5 -0
  119. cocotb-2.0.1.dist-info/entry_points.txt +2 -0
  120. cocotb-2.0.1.dist-info/top_level.txt +18 -0
  121. cocotb_tools/__init__.py +0 -0
  122. cocotb_tools/_coverage.py +33 -0
  123. cocotb_tools/_vendor/__init__.py +3 -0
  124. cocotb_tools/_vendor/distutils_version.py +346 -0
  125. cocotb_tools/check_results.py +65 -0
  126. cocotb_tools/combine_results.py +152 -0
  127. cocotb_tools/config.py +242 -0
  128. cocotb_tools/ipython_support.py +99 -0
  129. cocotb_tools/makefiles/Makefile.deprecations +27 -0
  130. cocotb_tools/makefiles/Makefile.inc +198 -0
  131. cocotb_tools/makefiles/Makefile.sim +96 -0
  132. cocotb_tools/makefiles/simulators/Makefile.activehdl +72 -0
  133. cocotb_tools/makefiles/simulators/Makefile.cvc +61 -0
  134. cocotb_tools/makefiles/simulators/Makefile.dsim +39 -0
  135. cocotb_tools/makefiles/simulators/Makefile.ghdl +84 -0
  136. cocotb_tools/makefiles/simulators/Makefile.icarus +80 -0
  137. cocotb_tools/makefiles/simulators/Makefile.ius +93 -0
  138. cocotb_tools/makefiles/simulators/Makefile.modelsim +9 -0
  139. cocotb_tools/makefiles/simulators/Makefile.nvc +60 -0
  140. cocotb_tools/makefiles/simulators/Makefile.questa +29 -0
  141. cocotb_tools/makefiles/simulators/Makefile.questa-compat +143 -0
  142. cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun +149 -0
  143. cocotb_tools/makefiles/simulators/Makefile.riviera +144 -0
  144. cocotb_tools/makefiles/simulators/Makefile.vcs +65 -0
  145. cocotb_tools/makefiles/simulators/Makefile.verilator +79 -0
  146. cocotb_tools/makefiles/simulators/Makefile.xcelium +104 -0
  147. cocotb_tools/py.typed +0 -0
  148. cocotb_tools/runner.py +2001 -0
  149. cocotb_tools/sim_versions.py +140 -0
  150. pygpi/__init__.py +0 -0
  151. pygpi/entry.py +42 -0
  152. 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,7 @@
1
+ # Copyright cocotb contributors
2
+ # Licensed under the Revised BSD License, see LICENSE for details.
3
+ # SPDX-License-Identifier: BSD-3-Clause
4
+
5
+
6
+ class InternalError(BaseException):
7
+ """An error internal to scheduler. If you see this, report a bug!"""
@@ -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)