cocotb 1.9.2__cp313-cp313-win_amd64.whl → 2.0.0b1__cp313-cp313-win_amd64.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.

Potentially problematic release.


This version of cocotb might be problematic. Click here for more details.

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