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
@@ -0,0 +1,385 @@
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
+ import warnings
10
+ from decimal import Decimal
11
+ from fractions import Fraction
12
+ from typing import (
13
+ TYPE_CHECKING,
14
+ Any,
15
+ Callable,
16
+ ClassVar,
17
+ Generic,
18
+ Optional,
19
+ TypeVar,
20
+ Union,
21
+ )
22
+
23
+ import cocotb
24
+ import cocotb.handle
25
+ from cocotb import simulator
26
+ from cocotb._base_triggers import Trigger
27
+ from cocotb._deprecation import deprecated
28
+ from cocotb._typing import RoundMode, TimeUnit
29
+ from cocotb._utils import pointer_str, singleton
30
+ from cocotb.utils import get_sim_steps, get_time_from_sim_steps
31
+
32
+ if TYPE_CHECKING:
33
+ from cocotb._py_compat import Self
34
+
35
+
36
+ class GPITrigger(Trigger):
37
+ """A trigger for a simulation event."""
38
+
39
+ def __init__(self) -> None:
40
+ super().__init__()
41
+ self._cbhdl: Optional[simulator.gpi_cb_hdl] = None
42
+
43
+ def _unprime(self) -> None:
44
+ """Disable a primed trigger, can be re-primed."""
45
+ if self._cbhdl is not None:
46
+ self._cbhdl.deregister()
47
+ return super()._unprime()
48
+
49
+ def _cleanup(self) -> None:
50
+ self._cbhdl = None
51
+ return super()._cleanup()
52
+
53
+
54
+ class Timer(GPITrigger):
55
+ r"""Fire after the specified simulation time period has elapsed.
56
+
57
+ This trigger will *always* consume some simulation time
58
+ and will return control to the :keyword:`await`\ ing task at the beginning of the time step.
59
+
60
+ Args:
61
+ time: The time value.
62
+
63
+ .. versionchanged:: 1.5
64
+ Previously this argument was misleadingly called `time_ps`.
65
+
66
+ unit: The unit of the time value.
67
+
68
+ One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``.
69
+ When *unit* is ``'step'``,
70
+ the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`).
71
+
72
+ .. versionchanged:: 2.0
73
+ Renamed from ``units``.
74
+
75
+ round_mode:
76
+
77
+ String specifying how to handle time values that sit between time steps
78
+ (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``).
79
+ A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`.
80
+
81
+ Raises:
82
+ ValueError: If a non-positive value is passed for Timer setup.
83
+
84
+ Usage:
85
+ >>> await Timer(100, unit="ps")
86
+
87
+ The time can also be a ``float``:
88
+
89
+ >>> await Timer(100e-9, unit="sec")
90
+
91
+ which is particularly convenient when working with frequencies:
92
+
93
+ >>> freq = 10e6 # 10 MHz
94
+ >>> await Timer(1 / freq, unit="sec")
95
+
96
+ Other built-in exact numeric types can be used too:
97
+
98
+ >>> from fractions import Fraction
99
+ >>> await Timer(Fraction(1, 10), unit="ns")
100
+
101
+ >>> from decimal import Decimal
102
+ >>> await Timer(Decimal("100e-9"), unit="sec")
103
+
104
+ These are most useful when using computed durations while
105
+ avoiding floating point inaccuracies.
106
+
107
+ .. versionchanged:: 1.5
108
+ Raise an exception when Timer uses a negative value as it is undefined behavior.
109
+ Warn for 0 as this will cause erratic behavior in some simulators as well.
110
+
111
+ .. versionchanged:: 1.5
112
+ Support ``'step'`` as the *unit* argument to mean "simulator time step".
113
+
114
+ .. versionchanged:: 1.6
115
+ Support rounding modes.
116
+
117
+ .. versionremoved:: 2.0
118
+ Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.
119
+
120
+ .. versionremoved:: 2.0
121
+ The ``time_ps`` parameter was removed, use the ``time`` parameter instead.
122
+
123
+ .. versionchanged:: 2.0
124
+ Passing ``0`` as the *time* argument now raises a :exc:`ValueError`.
125
+ """
126
+
127
+ round_mode: ClassVar[RoundMode] = "error"
128
+ """The default rounding mode."""
129
+
130
+ def __init__(
131
+ self,
132
+ time: Union[float, Fraction, Decimal],
133
+ unit: TimeUnit = "step",
134
+ *,
135
+ round_mode: Optional[RoundMode] = None,
136
+ units: None = None,
137
+ ) -> None:
138
+ super().__init__()
139
+ if time <= 0:
140
+ raise ValueError("Timer argument time must be positive")
141
+ if units is not None:
142
+ warnings.warn(
143
+ "The 'units' argument has been renamed to 'unit'.",
144
+ DeprecationWarning,
145
+ stacklevel=2,
146
+ )
147
+ unit = units
148
+ if round_mode is None:
149
+ round_mode = type(self).round_mode
150
+ self._sim_steps = get_sim_steps(time, unit, round_mode=round_mode)
151
+ # If we round to 0, we fix it up to 1 step as rounding is imprecise,
152
+ # and Timer(0) is invalid.
153
+ if self._sim_steps == 0:
154
+ self._sim_steps = 1
155
+
156
+ def _prime(self, callback: Callable[["Self"], None]) -> None:
157
+ """Register for a timed callback."""
158
+ if self._cbhdl is None:
159
+ self._cbhdl = simulator.register_timed_callback(
160
+ self._sim_steps, callback, self
161
+ )
162
+ if self._cbhdl is None:
163
+ raise RuntimeError(f"Unable set up {self!s} Trigger")
164
+ super()._prime(callback)
165
+
166
+ def __repr__(self) -> str:
167
+ return "<{} of {:1.2f}ps at {}>".format(
168
+ type(self).__qualname__,
169
+ get_time_from_sim_steps(self._sim_steps, unit="ps"),
170
+ pointer_str(self),
171
+ )
172
+
173
+
174
+ @singleton
175
+ class ReadOnly(GPITrigger):
176
+ """Fires when the current simulation timestep moves to the read-only phase.
177
+
178
+ The read-only phase is entered when the current timestep no longer has any further delta steps.
179
+ This will be a point where all the signal values are stable as there are no more RTL events scheduled for the timestep.
180
+ The simulator will not allow scheduling of more events in this timestep.
181
+ Useful for monitors which need to wait for all processes to execute (both RTL and cocotb) to ensure sampled signal values are final.
182
+ """
183
+
184
+ def _prime(self, callback: Callable[["Self"], None]) -> None:
185
+ if isinstance(current_gpi_trigger(), ReadOnly):
186
+ raise RuntimeError(
187
+ "Attempted illegal transition: awaiting ReadOnly in ReadOnly phase"
188
+ )
189
+ if self._cbhdl is None:
190
+ self._cbhdl = simulator.register_readonly_callback(callback, self)
191
+ if self._cbhdl is None:
192
+ raise RuntimeError(f"Unable set up {self!s} Trigger")
193
+ super()._prime(callback)
194
+
195
+ def __repr__(self) -> str:
196
+ return f"{type(self).__qualname__}()"
197
+
198
+
199
+ @singleton
200
+ class ReadWrite(GPITrigger):
201
+ """Fires when the read-write simulation phase is reached."""
202
+
203
+ def _prime(self, callback: Callable[["Self"], None]) -> None:
204
+ if isinstance(current_gpi_trigger(), ReadOnly):
205
+ raise RuntimeError(
206
+ "Attempted illegal transition: awaiting ReadWrite in ReadOnly phase"
207
+ )
208
+ if self._cbhdl is None:
209
+ self._cbhdl = simulator.register_rwsynch_callback(callback, self)
210
+ if self._cbhdl is None:
211
+ raise RuntimeError(f"Unable set up {self!s} Trigger")
212
+ super()._prime(callback)
213
+
214
+ def __repr__(self) -> str:
215
+ return f"{type(self).__qualname__}()"
216
+
217
+
218
+ @singleton
219
+ class NextTimeStep(GPITrigger):
220
+ """Fires when the next time step is started."""
221
+
222
+ def _prime(self, callback: Callable[["Self"], None]) -> None:
223
+ if self._cbhdl is None:
224
+ self._cbhdl = simulator.register_nextstep_callback(callback, self)
225
+ if self._cbhdl is None:
226
+ raise RuntimeError(f"Unable set up {self!s} Trigger")
227
+ super()._prime(callback)
228
+
229
+ def __repr__(self) -> str:
230
+ return f"{type(self).__qualname__}()"
231
+
232
+
233
+ _SignalType = TypeVar("_SignalType", bound="cocotb.handle.ValueObjectBase[Any, Any]")
234
+
235
+
236
+ class _EdgeBase(GPITrigger, Generic[_SignalType]):
237
+ """Internal base class that fires on a given edge of a signal."""
238
+
239
+ _edge_type: ClassVar[int]
240
+ signal: _SignalType
241
+
242
+ @classmethod
243
+ def _make(cls, signal: _SignalType) -> "Self":
244
+ self = GPITrigger.__new__(cls)
245
+ GPITrigger.__init__(self)
246
+ self.signal = signal
247
+ return self
248
+
249
+ def __init__(self, _: _SignalType) -> None:
250
+ pass
251
+
252
+ def _prime(self, callback: Callable[["Self"], None]) -> None:
253
+ if self._cbhdl is None:
254
+ self._cbhdl = simulator.register_value_change_callback(
255
+ self.signal._handle, callback, type(self)._edge_type, self
256
+ )
257
+ if self._cbhdl is None:
258
+ raise RuntimeError(f"Unable set up {self!s} Trigger")
259
+ super()._prime(callback)
260
+
261
+ def __repr__(self) -> str:
262
+ return f"{type(self).__qualname__}({self.signal!r})"
263
+
264
+
265
+ class RisingEdge(_EdgeBase["cocotb.handle.LogicObject"]):
266
+ """Fires on the rising edge of *signal*, on a transition to ``1``.
267
+
268
+ Only valid for scalar ``logic`` or ``bit``-typed signals.
269
+
270
+ Args:
271
+ signal: The signal upon which to wait for a rising edge.
272
+
273
+ Raises:
274
+ TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object.
275
+
276
+ .. note::
277
+ Prefer :attr:`await signal.rising_edge <cocotb.handle.LogicObject.rising_edge>` to ``await RisingEdge(signal)``.
278
+
279
+ .. warning::
280
+ On many simulators this will trigger on transitions from non-``0``/``1`` value to ``1``,
281
+ not just from ``0`` to ``1`` like the ``rising_edge`` function in VHDL.
282
+ """
283
+
284
+ _edge_type = simulator.RISING
285
+
286
+ def __new__(cls, signal: "cocotb.handle.LogicObject") -> "RisingEdge":
287
+ if not (isinstance(signal, cocotb.handle.LogicObject)):
288
+ raise TypeError(
289
+ f"{cls.__qualname__} requires a scalar LogicObject. Got {signal!r} of type {type(signal).__qualname__}"
290
+ )
291
+ return signal.rising_edge
292
+
293
+
294
+ class FallingEdge(_EdgeBase["cocotb.handle.LogicObject"]):
295
+ """Fires on the falling edge of *signal*, on a transition to ``0``.
296
+
297
+ Only valid for scalar ``logic`` or ``bit``-typed signals.
298
+
299
+ Args:
300
+ signal: The signal upon which to wait for a rising edge.
301
+
302
+ Raises:
303
+ TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object.
304
+
305
+ .. note::
306
+ Prefer :attr:`await signal.falling_edge <cocotb.handle.LogicObject.falling_edge>` to ``await FallingEdge(signal)``.
307
+
308
+ .. warning::
309
+ On many simulators this will trigger on transitions from non-``0``/``1`` value to ``0``,
310
+ not just from ``1`` to ``0`` like the ``falling_edge`` function in VHDL.
311
+ """
312
+
313
+ _edge_type = simulator.FALLING
314
+
315
+ def __new__(cls, signal: "cocotb.handle.LogicObject") -> "FallingEdge":
316
+ if not (isinstance(signal, cocotb.handle.LogicObject)):
317
+ raise TypeError(
318
+ f"{cls.__qualname__} requires a scalar LogicObject. Got {signal!r} of type {type(signal).__qualname__}"
319
+ )
320
+ return signal.falling_edge
321
+
322
+
323
+ class ValueChange(_EdgeBase["cocotb.handle._NonIndexableValueObjectBase[Any, Any]"]):
324
+ """Fires on any value change of *signal*.
325
+
326
+ Args:
327
+ signal: The signal upon which to wait for a value change.
328
+
329
+ Raises:
330
+ TypeError: If the signal is not an object which can change value.
331
+
332
+ .. note::
333
+ Prefer :attr:`await signal.value_change <cocotb.handle.NonArrayValueObject.value_change>` to ``await ValueChange(signal)``.
334
+
335
+ .. versionadded:: 2.0
336
+ """
337
+
338
+ _edge_type = simulator.VALUE_CHANGE
339
+
340
+ def __new__(
341
+ cls, signal: "cocotb.handle._NonIndexableValueObjectBase[Any, Any]"
342
+ ) -> "ValueChange":
343
+ if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase):
344
+ raise TypeError(
345
+ f"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. "
346
+ f"Got {signal!r} of type {type(signal).__qualname__}"
347
+ )
348
+ return signal.value_change
349
+
350
+
351
+ class Edge(ValueChange):
352
+ """Fires on any value change of *signal*.
353
+
354
+ Args:
355
+ signal: The signal upon which to wait for a value change.
356
+
357
+ Raises:
358
+ TypeError: If the signal is not an object which can change value.
359
+
360
+ .. deprecated:: 2.0
361
+
362
+ Use :attr:`signal.value_change <cocotb.handle.NonArrayValueObject.value_change>` instead.
363
+ """
364
+
365
+ @deprecated("Use `signal.value_change` instead.")
366
+ def __new__(
367
+ cls, signal: "cocotb.handle._NonIndexableValueObjectBase[Any, Any]"
368
+ ) -> "Edge":
369
+ if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase):
370
+ raise TypeError(
371
+ f"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. "
372
+ f"Got {signal!r} of type {type(signal).__qualname__}"
373
+ )
374
+ return signal._edge
375
+
376
+
377
+ # The initializer is a lie, but a useful one. Perhaps one day this can be something like `StartupTrigger`.`
378
+ _current_gpi_trigger = Timer(1, "step") # type: Union[None, GPITrigger]
379
+
380
+
381
+ def current_gpi_trigger() -> GPITrigger:
382
+ """Return the last GPITrigger that fired."""
383
+ if _current_gpi_trigger is None:
384
+ raise RuntimeError("No GPI trigger has fired.")
385
+ return _current_gpi_trigger
cocotb/_init.py ADDED
@@ -0,0 +1,301 @@
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
+ import ast
7
+ import logging
8
+ import os
9
+ import random
10
+ import sys
11
+ import time
12
+ import warnings
13
+ from pathlib import Path
14
+ from types import SimpleNamespace
15
+ from typing import Callable, List, cast
16
+
17
+ import cocotb
18
+ import cocotb._profiling
19
+ import cocotb.handle
20
+ import cocotb.logging
21
+ import cocotb.simtime
22
+ import cocotb.simulator
23
+ from cocotb._scheduler import Scheduler
24
+ from cocotb.regression import RegressionManager, RegressionMode
25
+
26
+ log: logging.Logger
27
+
28
+
29
+ def _setup_logging() -> None:
30
+ cocotb.log = logging.getLogger("test")
31
+ cocotb.log.setLevel(logging.INFO)
32
+
33
+ global log
34
+ log = logging.getLogger("cocotb")
35
+
36
+
37
+ _shutdown_callbacks: List[Callable[[], None]] = []
38
+ """List of callbacks to be called when cocotb shuts down."""
39
+
40
+
41
+ def _register_shutdown_callback(cb: Callable[[], None]) -> None:
42
+ """Register a callback to be called when cocotb shuts down."""
43
+ _shutdown_callbacks.append(cb)
44
+
45
+
46
+ def _shutdown_testbench() -> None:
47
+ """Call all registered shutdown callbacks."""
48
+ while _shutdown_callbacks:
49
+ cb = _shutdown_callbacks.pop(0)
50
+ cb()
51
+
52
+
53
+ def init_package_from_simulation(argv: List[str]) -> None:
54
+ """Initialize the cocotb package from a simulation context."""
55
+
56
+ # register a callback to be called if the simulation fails
57
+ cocotb.simulator.set_sim_event_callback(_sim_event)
58
+
59
+ cocotb.is_simulation = True
60
+
61
+ cocotb.argv = argv
62
+
63
+ # sys.path normally includes "" (the current directory), but does not appear to when python is embedded.
64
+ # Add it back because users expect to be able to import files in their test directory.
65
+ sys.path.insert(0, "")
66
+
67
+ cocotb.logging._init()
68
+ _setup_logging()
69
+
70
+ # From https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners
71
+ # If the user doesn't want to see these, they can always change the global
72
+ # warning settings in their test module.
73
+ if not sys.warnoptions:
74
+ warnings.simplefilter("default")
75
+
76
+ cocotb.SIM_NAME = cocotb.simulator.get_simulator_product().strip()
77
+ cocotb.SIM_VERSION = cocotb.simulator.get_simulator_version().strip()
78
+
79
+ log.info("Running on %s version %s", cocotb.SIM_NAME, cocotb.SIM_VERSION)
80
+
81
+ cocotb._profiling.initialize()
82
+ _register_shutdown_callback(cocotb._profiling.finalize)
83
+
84
+ _process_plusargs()
85
+ _process_packages()
86
+ _setup_random_seed()
87
+ _setup_root_handle()
88
+ _start_user_coverage()
89
+
90
+ cocotb.simtime._init()
91
+
92
+ log.info(
93
+ "Initialized cocotb v%s from %s",
94
+ cocotb.__version__,
95
+ Path(__file__).parent.absolute(),
96
+ )
97
+
98
+
99
+ def run_regression(_: object) -> None:
100
+ """Setup and run a regression."""
101
+
102
+ _setup_regression_manager()
103
+
104
+ # setup global scheduler system
105
+ cocotb._scheduler_inst = Scheduler()
106
+
107
+ # start Regression Manager
108
+ log.info("Running tests")
109
+ cocotb._regression_manager.start_regression()
110
+
111
+
112
+ def _sim_event(msg: str) -> None:
113
+ """Function that can be called externally to signal an event."""
114
+ # We simply return here as the simulator will exit
115
+ # so no cleanup is needed
116
+ if hasattr(cocotb, "_regression_manager"):
117
+ cocotb._regression_manager._fail_simulation(msg)
118
+ else:
119
+ log.error(msg)
120
+ _shutdown_testbench()
121
+
122
+
123
+ def _process_plusargs() -> None:
124
+ cocotb.plusargs = {}
125
+
126
+ for option in cocotb.argv:
127
+ if option.startswith("+"):
128
+ if option.find("=") != -1:
129
+ (name, value) = option[1:].split("=", 1)
130
+ cocotb.plusargs[name] = value
131
+ else:
132
+ cocotb.plusargs[option[1:]] = True
133
+
134
+
135
+ def _process_packages() -> None:
136
+ pkg_dict = {}
137
+
138
+ from cocotb import simulator # noqa: PLC0415
139
+
140
+ pkgs = simulator.package_iterate()
141
+ if pkgs is None:
142
+ cocotb.packages = SimpleNamespace()
143
+ return
144
+
145
+ for pkg in pkgs:
146
+ handle = cast(
147
+ "cocotb.handle.HierarchyObject", cocotb.handle._make_sim_object(pkg)
148
+ )
149
+ name = handle._name
150
+
151
+ # Icarus doesn't support named access to package objects:
152
+ # https://github.com/steveicarus/iverilog/issues/1038
153
+ # so we cannot lazily create handles
154
+ if cocotb.SIM_NAME == "Icarus Verilog":
155
+ handle._discover_all()
156
+ pkg_dict[name] = handle
157
+
158
+ cocotb.packages = SimpleNamespace(**pkg_dict)
159
+
160
+
161
+ def _start_user_coverage() -> None:
162
+ coverage_envvar = os.getenv("COCOTB_USER_COVERAGE")
163
+ if coverage_envvar is None:
164
+ coverage_envvar = os.getenv("COVERAGE")
165
+ if coverage_envvar is not None:
166
+ warnings.warn(
167
+ "COVERAGE is deprecated in favor of COCOTB_USER_COVERAGE",
168
+ DeprecationWarning,
169
+ stacklevel=2,
170
+ )
171
+ if coverage_envvar:
172
+ try:
173
+ import coverage # noqa: PLC0415
174
+ except ImportError:
175
+ raise RuntimeError(
176
+ "Coverage collection requested but coverage module not available. Install it using `pip install coverage`."
177
+ ) from None
178
+ else:
179
+ config_filepath = os.getenv("COVERAGE_RCFILE")
180
+ if config_filepath is None:
181
+ # Exclude cocotb itself from coverage collection.
182
+ log.info(
183
+ "Collecting coverage of user code. No coverage config file supplied via COVERAGE_RCFILE."
184
+ )
185
+ cocotb_package_dir = Path(__file__).parent.absolute()
186
+ user_coverage = coverage.coverage(
187
+ branch=True, omit=[f"{cocotb_package_dir}/*"]
188
+ )
189
+ else:
190
+ log.info(
191
+ "Collecting coverage of user code. Coverage config file supplied."
192
+ )
193
+ # Allow the config file to handle all configuration
194
+ user_coverage = coverage.coverage(config_file=config_filepath)
195
+ user_coverage.start()
196
+
197
+ def stop_user_coverage() -> None:
198
+ user_coverage.stop()
199
+ log.debug("Writing user coverage data")
200
+ user_coverage.save()
201
+
202
+ _register_shutdown_callback(stop_user_coverage)
203
+
204
+
205
+ def _setup_random_seed() -> None:
206
+ seed_envvar = os.getenv("COCOTB_RANDOM_SEED")
207
+ if seed_envvar is None:
208
+ seed_envvar = os.getenv("RANDOM_SEED")
209
+ if seed_envvar is not None:
210
+ warnings.warn(
211
+ "RANDOM_SEED is deprecated in favor of COCOTB_RANDOM_SEED",
212
+ DeprecationWarning,
213
+ )
214
+ if seed_envvar is None:
215
+ if "ntb_random_seed" in cocotb.plusargs:
216
+ warnings.warn(
217
+ "Passing +ntb_random_seed will not be used to seed Python's random number generator in the future. "
218
+ "Ensure you also set `COCOTB_RANDOM_SEED`.",
219
+ FutureWarning,
220
+ )
221
+ plusarg_seed = cocotb.plusargs["ntb_random_seed"]
222
+ if not isinstance(plusarg_seed, str):
223
+ raise TypeError("ntb_random_seed plusarg is not a valid seed value.")
224
+ seed = ast.literal_eval(plusarg_seed)
225
+ if not isinstance(seed, int):
226
+ raise TypeError("ntb_random_seed plusargs is not a valid seed value.")
227
+ cocotb.RANDOM_SEED = seed
228
+ elif "seed" in cocotb.plusargs:
229
+ warnings.warn(
230
+ "Passing +seed will not be used to seed Python's random number generator in the future. "
231
+ "Ensure you also set `COCOTB_RANDOM_SEED`.",
232
+ FutureWarning,
233
+ )
234
+ plusarg_seed = cocotb.plusargs["seed"]
235
+ if not isinstance(plusarg_seed, str):
236
+ raise TypeError("seed plusarg is not a valid seed value.")
237
+ seed = ast.literal_eval(plusarg_seed)
238
+ if not isinstance(seed, int):
239
+ raise TypeError("seed plusargs is not a valid seed value.")
240
+ cocotb.RANDOM_SEED = seed
241
+ else:
242
+ cocotb.RANDOM_SEED = int(time.time())
243
+ log.info("Seeding Python random module with %d", cocotb.RANDOM_SEED)
244
+ else:
245
+ cocotb.RANDOM_SEED = ast.literal_eval(seed_envvar)
246
+ log.info(
247
+ "Seeding Python random module with supplied seed %d", cocotb.RANDOM_SEED
248
+ )
249
+
250
+ random.seed(cocotb.RANDOM_SEED)
251
+
252
+
253
+ def _setup_root_handle() -> None:
254
+ root_name = os.getenv("COCOTB_TOPLEVEL")
255
+ if root_name is not None:
256
+ root_name = root_name.strip()
257
+ if root_name == "":
258
+ root_name = None
259
+ elif "." in root_name:
260
+ # Skip any library component of the toplevel
261
+ root_name = root_name.split(".", 1)[1]
262
+
263
+ from cocotb import simulator # noqa: PLC0415
264
+
265
+ handle = simulator.get_root_handle(root_name)
266
+ if not handle:
267
+ raise RuntimeError(f"Can not find root handle {root_name!r}")
268
+
269
+ cocotb.top = cocotb.handle._make_sim_object(handle)
270
+
271
+
272
+ def _setup_regression_manager() -> None:
273
+ cocotb._regression_manager = RegressionManager()
274
+
275
+ # discover tests
276
+ module_str = os.getenv("COCOTB_TEST_MODULES", "")
277
+ if not module_str:
278
+ raise RuntimeError(
279
+ "Environment variable COCOTB_TEST_MODULES, which defines the module(s) to execute, is not defined or empty."
280
+ )
281
+ modules = [s.strip() for s in module_str.split(",") if s.strip()]
282
+ cocotb._regression_manager.setup_pytest_assertion_rewriting()
283
+ cocotb._regression_manager.discover_tests(*modules)
284
+
285
+ # filter tests
286
+ testcase_str = os.getenv("COCOTB_TESTCASE", "").strip()
287
+ test_filter_str = os.getenv("COCOTB_TEST_FILTER", "").strip()
288
+ if testcase_str and test_filter_str:
289
+ raise RuntimeError("Specify only one of COCOTB_TESTCASE or COCOTB_TEST_FILTER")
290
+ elif testcase_str:
291
+ warnings.warn(
292
+ "COCOTB_TESTCASE is deprecated in favor of COCOTB_TEST_FILTER",
293
+ DeprecationWarning,
294
+ stacklevel=2,
295
+ )
296
+ filters = [f"{s.strip()}$" for s in testcase_str.split(",") if s.strip()]
297
+ cocotb._regression_manager.add_filters(*filters)
298
+ cocotb._regression_manager.set_mode(RegressionMode.TESTCASE)
299
+ elif test_filter_str:
300
+ cocotb._regression_manager.add_filters(test_filter_str)
301
+ cocotb._regression_manager.set_mode(RegressionMode.TESTCASE)