cocotb 1.7.2__cp39-cp39-win_amd64.whl → 1.8.0rc1__cp39-cp39-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 (83) hide show
  1. cocotb/__init__.py +7 -18
  2. cocotb/_sim_versions.py +16 -1
  3. cocotb/_version.py +1 -1
  4. cocotb/clock.py +8 -3
  5. cocotb/decorators.py +40 -318
  6. cocotb/ipython_support.py +3 -1
  7. cocotb/libs/cocotb.dll +0 -0
  8. cocotb/libs/cocotb.exp +0 -0
  9. cocotb/libs/cocotb.lib +0 -0
  10. cocotb/libs/cocotbfli_modelsim.dll +0 -0
  11. cocotb/libs/cocotbfli_modelsim.exp +0 -0
  12. cocotb/libs/cocotbfli_modelsim.lib +0 -0
  13. cocotb/libs/cocotbutils.dll +0 -0
  14. cocotb/libs/cocotbutils.exp +0 -0
  15. cocotb/libs/cocotbutils.lib +0 -0
  16. cocotb/libs/cocotbvhpi_aldec.dll +0 -0
  17. cocotb/libs/cocotbvhpi_aldec.exp +0 -0
  18. cocotb/libs/cocotbvhpi_aldec.lib +0 -0
  19. cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
  20. cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
  21. cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
  22. cocotb/libs/cocotbvpi_aldec.dll +0 -0
  23. cocotb/libs/cocotbvpi_aldec.exp +0 -0
  24. cocotb/libs/cocotbvpi_aldec.lib +0 -0
  25. cocotb/libs/cocotbvpi_ghdl.dll +0 -0
  26. cocotb/libs/cocotbvpi_ghdl.exp +0 -0
  27. cocotb/libs/cocotbvpi_ghdl.lib +0 -0
  28. cocotb/libs/cocotbvpi_icarus.exp +0 -0
  29. cocotb/libs/cocotbvpi_icarus.lib +0 -0
  30. cocotb/libs/cocotbvpi_icarus.vpl +0 -0
  31. cocotb/libs/cocotbvpi_modelsim.dll +0 -0
  32. cocotb/libs/cocotbvpi_modelsim.exp +0 -0
  33. cocotb/libs/cocotbvpi_modelsim.lib +0 -0
  34. cocotb/libs/embed.dll +0 -0
  35. cocotb/libs/embed.exp +0 -0
  36. cocotb/libs/embed.lib +0 -0
  37. cocotb/libs/gpi.dll +0 -0
  38. cocotb/libs/gpi.exp +0 -0
  39. cocotb/libs/gpi.lib +0 -0
  40. cocotb/libs/gpilog.dll +0 -0
  41. cocotb/libs/gpilog.exp +0 -0
  42. cocotb/libs/gpilog.lib +0 -0
  43. cocotb/libs/pygpilog.dll +0 -0
  44. cocotb/libs/pygpilog.exp +0 -0
  45. cocotb/libs/pygpilog.lib +0 -0
  46. cocotb/regression.py +32 -14
  47. cocotb/runner.py +538 -453
  48. cocotb/scheduler.py +35 -18
  49. cocotb/share/def/aldec.exp +0 -0
  50. cocotb/share/def/aldec.lib +0 -0
  51. cocotb/share/def/ghdl.exp +0 -0
  52. cocotb/share/def/ghdl.lib +0 -0
  53. cocotb/share/def/icarus.exp +0 -0
  54. cocotb/share/def/icarus.lib +0 -0
  55. cocotb/share/def/modelsim.def +2 -0
  56. cocotb/share/def/modelsim.exp +0 -0
  57. cocotb/share/def/modelsim.lib +0 -0
  58. cocotb/share/include/embed.h +1 -2
  59. cocotb/share/include/gpi.h +10 -15
  60. cocotb/share/include/vpi_user_ext.h +3 -0
  61. cocotb/share/lib/verilator/verilator.cpp +8 -4
  62. cocotb/share/makefiles/Makefile.inc +16 -4
  63. cocotb/share/makefiles/Makefile.sim +2 -2
  64. cocotb/share/makefiles/simulators/Makefile.icarus +19 -0
  65. cocotb/share/makefiles/simulators/Makefile.ius +12 -1
  66. cocotb/share/makefiles/simulators/Makefile.questa +2 -1
  67. cocotb/share/makefiles/simulators/Makefile.riviera +4 -0
  68. cocotb/share/makefiles/simulators/Makefile.vcs +4 -0
  69. cocotb/share/makefiles/simulators/Makefile.verilator +5 -1
  70. cocotb/share/makefiles/simulators/Makefile.xcelium +5 -1
  71. cocotb/simulator.cp39-win_amd64.exp +0 -0
  72. cocotb/simulator.cp39-win_amd64.lib +0 -0
  73. cocotb/simulator.cp39-win_amd64.pyd +0 -0
  74. cocotb/task.py +325 -0
  75. cocotb/triggers.py +23 -7
  76. cocotb/types/logic_array.py +34 -3
  77. {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/METADATA +24 -9
  78. cocotb-1.8.0rc1.dist-info/RECORD +120 -0
  79. {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/WHEEL +1 -1
  80. cocotb-1.7.2.dist-info/RECORD +0 -119
  81. {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/LICENSE +0 -0
  82. {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/entry_points.txt +0 -0
  83. {cocotb-1.7.2.dist-info → cocotb-1.8.0rc1.dist-info}/top_level.txt +0 -0
cocotb/task.py ADDED
@@ -0,0 +1,325 @@
1
+ # Copyright cocotb contributors
2
+ # Licensed under the Revised BSD License, see LICENSE for details.
3
+ # SPDX-License-Identifier: BSD-3-Clause
4
+ import collections.abc
5
+ import inspect
6
+ import os
7
+ import typing
8
+ import warnings
9
+ from asyncio import CancelledError, InvalidStateError
10
+
11
+ import cocotb
12
+ import cocotb.triggers
13
+ from cocotb import outcomes
14
+ from cocotb.log import SimLog
15
+ from cocotb.result import ReturnValue
16
+ from cocotb.utils import extract_coro_stack, lazy_property, remove_traceback_frames
17
+
18
+ T = typing.TypeVar("T")
19
+ Self = typing.TypeVar("Self")
20
+
21
+ # Sadly the Python standard logging module is very slow so it's better not to
22
+ # make any calls by testing a boolean flag first
23
+ _debug = "COCOTB_SCHEDULER_DEBUG" in os.environ
24
+
25
+
26
+ class Task(typing.Coroutine[typing.Any, typing.Any, T]):
27
+ """Concurrently executing task.
28
+
29
+ This class is not intended for users to directly instantiate.
30
+ Use :func:`cocotb.create_task` to create a Task object,
31
+ or use :func:`cocotb.start_soon` or :func:`cocotb.start` to
32
+ create a Task and schedule it to run.
33
+
34
+ .. versionchanged:: 1.8.0
35
+ Moved to the ``cocotb.task`` module.
36
+ """
37
+
38
+ _name: str = "Task" # class name of schedulable task
39
+ _id_count = 0 # used by the scheduler for debug
40
+
41
+ def __init__(self, inst):
42
+
43
+ if isinstance(inst, collections.abc.Coroutine):
44
+ self._natively_awaitable = True
45
+ elif inspect.isgenerator(inst):
46
+ self._natively_awaitable = False
47
+ elif inspect.iscoroutinefunction(inst):
48
+ raise TypeError(
49
+ "Coroutine function {} should be called prior to being "
50
+ "scheduled.".format(inst)
51
+ )
52
+ elif inspect.isasyncgen(inst):
53
+ raise TypeError(
54
+ "{} is an async generator, not a coroutine. "
55
+ "You likely used the yield keyword instead of await.".format(
56
+ inst.__qualname__
57
+ )
58
+ )
59
+ else:
60
+ raise TypeError(
61
+ f"{inst} isn't a valid coroutine! Did you forget to use the yield keyword?"
62
+ )
63
+ self._coro = inst
64
+ self._started = False
65
+ self._outcome: outcomes.Outcome = None
66
+ self._trigger: typing.Optional[cocotb.triggers.Trigger] = None
67
+ self._cancelled: typing.Optional[CancelledError] = None
68
+
69
+ self._task_id = self._id_count
70
+ type(self)._id_count += 1
71
+ self.__name__ = f"{type(self)._name} {self._task_id}"
72
+ self.__qualname__ = self.__name__
73
+
74
+ @lazy_property
75
+ def log(self) -> SimLog:
76
+ # Creating a logger is expensive, only do it if we actually plan to
77
+ # log anything
78
+ return SimLog(f"cocotb.{self.__qualname__}.{self._coro.__qualname__}")
79
+
80
+ @property
81
+ def retval(self) -> T:
82
+ """Return the result of the Task.
83
+
84
+ If the Task ran to completion, the result is returned.
85
+ If the Task failed with an exception, the exception is re-raised.
86
+ If the Task is not yet complete, a :exc:`RuntimeError` is raised.
87
+
88
+ .. deprecated:: 1.7.0
89
+ """
90
+ warnings.warn(
91
+ "Deprecated in favor of the result() method. "
92
+ "Replace `task.retval` with `task.result()`.",
93
+ DeprecationWarning,
94
+ stacklevel=2,
95
+ )
96
+ if self._outcome is None:
97
+ raise RuntimeError("coroutine is not complete")
98
+ return self._outcome.get()
99
+
100
+ @property
101
+ def _finished(self) -> bool:
102
+ """``True`` if the Task is finished executing.
103
+
104
+ .. deprecated:: 1.7.0
105
+ """
106
+ warnings.warn(
107
+ "Deprecated in favor of the done() method. "
108
+ "Replace `task._finished` with `task.done()`.",
109
+ DeprecationWarning,
110
+ stacklevel=2,
111
+ )
112
+ return self._outcome is not None
113
+
114
+ def __iter__(self: Self) -> Self:
115
+ # for use in "yield from" statements
116
+ return self
117
+
118
+ def __str__(self) -> str:
119
+ return f"<{self.__name__}>"
120
+
121
+ def _get_coro_stack(self) -> typing.Any:
122
+ """Get the coroutine callstack of this Task."""
123
+ coro_stack = extract_coro_stack(self._coro)
124
+
125
+ # Remove Trigger.__await__() from the stack, as it's not really useful
126
+ if self._natively_awaitable and len(coro_stack):
127
+ if coro_stack[-1].name == "__await__":
128
+ coro_stack.pop()
129
+
130
+ return coro_stack
131
+
132
+ def __repr__(self) -> str:
133
+ coro_stack = self._get_coro_stack()
134
+
135
+ if cocotb.scheduler._current_task is self:
136
+ fmt = "<{name} running coro={coro}()>"
137
+ elif self.done():
138
+ fmt = "<{name} finished coro={coro}() outcome={outcome}>"
139
+ elif self._trigger is not None:
140
+ fmt = "<{name} pending coro={coro}() trigger={trigger}>"
141
+ elif not self._started:
142
+ fmt = "<{name} created coro={coro}()>"
143
+ else:
144
+ fmt = "<{name} adding coro={coro}()>"
145
+
146
+ try:
147
+ coro_name = coro_stack[-1].name
148
+ # coro_stack may be empty if:
149
+ # - exhausted generator
150
+ # - finished coroutine
151
+ except IndexError:
152
+ coro_name = self._coro.__name__
153
+
154
+ repr_string = fmt.format(
155
+ name=self.__name__,
156
+ coro=coro_name,
157
+ trigger=self._trigger,
158
+ outcome=self._outcome,
159
+ )
160
+ return repr_string
161
+
162
+ def _advance(self, outcome: outcomes.Outcome) -> typing.Any:
163
+ """Advance to the next yield in this coroutine.
164
+
165
+ Args:
166
+ outcome: The :any:`outcomes.Outcome` object to resume with.
167
+
168
+ Returns:
169
+ The object yielded from the coroutine or None if coroutine finished
170
+
171
+ """
172
+ try:
173
+ self._started = True
174
+ return outcome.send(self._coro)
175
+ except ReturnValue as e:
176
+ self._outcome = outcomes.Value(e.retval)
177
+ except StopIteration as e:
178
+ self._outcome = outcomes.Value(e.value)
179
+ except BaseException as e:
180
+ self._outcome = outcomes.Error(
181
+ remove_traceback_frames(e, ["_advance", "send"])
182
+ )
183
+
184
+ def send(self, value: typing.Any) -> typing.Any:
185
+ return self._coro.send(value)
186
+
187
+ def throw(self, exc: BaseException) -> typing.Any:
188
+ return self._coro.throw(exc)
189
+
190
+ def close(self) -> None:
191
+ return self._coro.close()
192
+
193
+ def kill(self) -> None:
194
+ """Kill a coroutine."""
195
+ if self._outcome is not None:
196
+ # already finished, nothing to kill
197
+ return
198
+
199
+ if _debug:
200
+ self.log.debug("kill() called on coroutine")
201
+ # todo: probably better to throw an exception for anyone waiting on the coroutine
202
+ self._outcome = outcomes.Value(None)
203
+ cocotb.scheduler._unschedule(self)
204
+
205
+ def join(self) -> "cocotb.triggers.Join":
206
+ """Return a trigger that will fire when the wrapped coroutine exits."""
207
+ return cocotb.triggers.Join(self)
208
+
209
+ def has_started(self) -> bool:
210
+ """Return ``True`` if the Task has started executing."""
211
+ return self._started
212
+
213
+ def cancel(self, msg: typing.Optional[str] = None) -> None:
214
+ """Cancel a Task's further execution.
215
+
216
+ When a Task is cancelled, a :exc:`asyncio.CancelledError` is thrown into the Task.
217
+ """
218
+ self._cancelled = CancelledError(msg)
219
+ warnings.warn(
220
+ "Calling this method will cause a CancelledError to be thrown in the "
221
+ "Task sometime in the future.",
222
+ FutureWarning,
223
+ stacklevel=2,
224
+ )
225
+ self.kill()
226
+
227
+ def cancelled(self) -> bool:
228
+ """Return ``True`` if the Task was cancelled."""
229
+ return self._cancelled is not None
230
+
231
+ def done(self) -> bool:
232
+ """Return ``True`` if the Task has finished executing."""
233
+ return self._outcome is not None or self.cancelled()
234
+
235
+ def result(self) -> T:
236
+ """Return the result of the Task.
237
+
238
+ If the Task ran to completion, the result is returned.
239
+ If the Task failed with an exception, the exception is re-raised.
240
+ If the Task was cancelled, the CancelledError is re-raised.
241
+ If the coroutine is not yet complete, a :exc:`asyncio.InvalidStateError` is raised.
242
+ """
243
+ if not self.done():
244
+ raise InvalidStateError("result is not yet available")
245
+ elif self.cancelled():
246
+ raise self._cancelled
247
+ else:
248
+ return self._outcome.get()
249
+
250
+ def exception(self) -> typing.Optional[BaseException]:
251
+ """Return the exception of the Task.
252
+
253
+ If the Task ran to completion, ``None`` is returned.
254
+ If the Task failed with an exception, the exception is returned.
255
+ If the Task was cancelled, the CancelledError is re-raised.
256
+ If the coroutine is not yet complete, a :exc:`asyncio.InvalidStateError` is raised.
257
+ """
258
+ if not self.done():
259
+ raise InvalidStateError("result is not yet available")
260
+ elif self.cancelled():
261
+ raise self._cancelled
262
+ elif isinstance(self._outcome, outcomes.Error):
263
+ return self._outcome.error
264
+ else:
265
+ return None
266
+
267
+ def __bool__(self) -> bool:
268
+ """``True`` if Task is not done.
269
+
270
+ .. deprecated:: 1.7.0
271
+ """
272
+ warnings.warn(
273
+ "Deprecated in favor of the done() method. "
274
+ "Replace with `not task.done()`.",
275
+ DeprecationWarning,
276
+ stacklevel=2,
277
+ )
278
+ return not self.done()
279
+
280
+ def __await__(self) -> typing.Generator[typing.Any, typing.Any, T]:
281
+ # It's tempting to use `return (yield from self._coro)` here,
282
+ # which bypasses the scheduler. Unfortunately, this means that
283
+ # we can't keep track of the result or state of the coroutine,
284
+ # things which we expose in our public API. If you want the
285
+ # efficiency of bypassing the scheduler, remove the `@coroutine`
286
+ # decorator from your `async` functions.
287
+
288
+ # Hand the coroutine back to the scheduler trampoline.
289
+ return (yield self)
290
+
291
+
292
+ class _RunningCoroutine(Task[T]):
293
+ """
294
+ The result of calling a :any:`cocotb.coroutine` decorated coroutine.
295
+
296
+ All this class does is provide some extra attributes.
297
+
298
+ .. versionchanged:: 1.8.0
299
+ Moved to the ``cocotb.task`` module.
300
+ """
301
+
302
+ def __init__(self, inst, parent):
303
+ super().__init__(inst)
304
+ self._parent = parent
305
+ self.__doc__ = parent._func.__doc__
306
+ self.module = parent._func.__module__
307
+ self.funcname = parent._func.__name__
308
+
309
+
310
+ class _RunningTest(_RunningCoroutine[T]):
311
+ """
312
+ The result of calling a :class:`cocotb.test` decorated object.
313
+
314
+ All this class does is change ``__name__`` to show "Test" instead of "Task".
315
+
316
+ .. versionchanged:: 1.8.0
317
+ Moved to the ``cocotb.task`` module.
318
+ """
319
+
320
+ _name: str = "Test"
321
+
322
+ def __init__(self, inst, parent):
323
+ super().__init__(inst, parent)
324
+ self.__name__ = f"{type(self)._name} {self.funcname}"
325
+ self.__qualname__ = self.__name__
cocotb/triggers.py CHANGED
@@ -33,11 +33,12 @@ import warnings
33
33
  from collections.abc import Awaitable
34
34
  from decimal import Decimal
35
35
  from numbers import Real
36
- from typing import Optional, Union
36
+ from typing import Any, Coroutine, Optional, TypeVar, Union
37
37
 
38
38
  import cocotb
39
39
  from cocotb import outcomes, simulator
40
40
  from cocotb.log import SimLog
41
+ from cocotb.task import Task
41
42
  from cocotb.utils import (
42
43
  ParametrizedSingleton,
43
44
  get_sim_steps,
@@ -46,6 +47,8 @@ from cocotb.utils import (
46
47
  remove_traceback_frames,
47
48
  )
48
49
 
50
+ T = TypeVar("T")
51
+
49
52
 
50
53
  def _pointer_str(obj):
51
54
  """
@@ -189,6 +192,10 @@ class Timer(GPITrigger):
189
192
  When *units* is ``'step'``,
190
193
  the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`).
191
194
 
195
+ round_mode (str, optional):
196
+ String specifying how to handle time values that sit between time steps
197
+ (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``).
198
+
192
199
  Examples:
193
200
 
194
201
  >>> await Timer(100, units='ps')
@@ -778,7 +785,7 @@ class _AggregateWaitable(Waitable):
778
785
 
779
786
  # Do some basic type-checking up front, rather than waiting until we
780
787
  # await them.
781
- allowed_types = (Trigger, Waitable, cocotb.decorators.Task)
788
+ allowed_types = (Trigger, Waitable, Task)
782
789
  for trigger in self.triggers:
783
790
  if not isinstance(trigger, allowed_types):
784
791
  raise TypeError(
@@ -793,8 +800,7 @@ class _AggregateWaitable(Waitable):
793
800
  return "{}({})".format(
794
801
  type(self).__qualname__,
795
802
  ", ".join(
796
- repr(Join(t)) if isinstance(t, cocotb.decorators.Task) else repr(t)
797
- for t in self.triggers
803
+ repr(Join(t)) if isinstance(t, Task) else repr(t) for t in self.triggers
798
804
  ),
799
805
  )
800
806
 
@@ -934,7 +940,12 @@ class ClockCycles(Waitable):
934
940
  return fmt.format(type(self).__qualname__, self.signal, self.num_cycles)
935
941
 
936
942
 
937
- async def with_timeout(trigger, timeout_time, timeout_unit="step"):
943
+ async def with_timeout(
944
+ trigger: Union[Trigger, Waitable, Task, Coroutine[Any, Any, T]],
945
+ timeout_time: Union[float, Decimal],
946
+ timeout_unit: str = "step",
947
+ round_mode: Optional[str] = None,
948
+ ) -> T:
938
949
  r"""
939
950
  Waits on triggers or coroutines, throws an exception if it waits longer than the given time.
940
951
 
@@ -972,12 +983,15 @@ async def with_timeout(trigger, timeout_time, timeout_unit="step"):
972
983
  await with_timeout(First(coro, event.wait()), 100, 'ns')
973
984
 
974
985
  Args:
975
- trigger (:class:`~cocotb.triggers.Trigger`, :class:`~cocotb.triggers.Waitable`, :class:`~cocotb.decorators.Task`, or :term:`python:coroutine`):
986
+ trigger (:class:`~cocotb.triggers.Trigger`, :class:`~cocotb.triggers.Waitable`, :class:`~cocotb.task.Task`, or :term:`python:coroutine`):
976
987
  A single object that could be right of an :keyword:`await` expression in cocotb.
977
988
  timeout_time (numbers.Real or decimal.Decimal):
978
989
  Simulation time duration before timeout occurs.
979
990
  timeout_unit (str, optional):
980
991
  Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does.
992
+ round_mode (str, optional):
993
+ String specifying how to handle time values that sit between time steps
994
+ (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``).
981
995
 
982
996
  Returns:
983
997
  First trigger that completed if timeout did not occur.
@@ -1005,7 +1019,9 @@ async def with_timeout(trigger, timeout_time, timeout_unit="step"):
1005
1019
  shielded = False
1006
1020
  else:
1007
1021
  shielded = True
1008
- timeout_timer = cocotb.triggers.Timer(timeout_time, timeout_unit)
1022
+ timeout_timer = cocotb.triggers.Timer(
1023
+ timeout_time, timeout_unit, round_mode=round_mode
1024
+ )
1009
1025
  res = await First(timeout_timer, trigger)
1010
1026
  if res is timeout_timer:
1011
1027
  if not shielded:
@@ -28,6 +28,8 @@ class LogicArray(Array[Logic]):
28
28
  used.
29
29
  Like :class:`Array`, if no *range* argument is given, it is deduced from the length
30
30
  of the iterable or bit string used to initialize the variable.
31
+ If a *range* argument is given, but no value,
32
+ the array is filled with the default value of Logic().
31
33
 
32
34
  .. code-block:: python3
33
35
 
@@ -37,12 +39,15 @@ class LogicArray(Array[Logic]):
37
39
  >>> LogicArray([0, True, "X"])
38
40
  LogicArray('01X', Range(2, 'downto', 0))
39
41
 
40
- >>> LogicArray(0xA) # picks smallest range that can fit the value
42
+ >>> LogicArray(0xA) # picks smallest range that can fit the value
41
43
  LogicArray('1010', Range(3, 'downto', 0))
42
44
 
43
- >>> LogicArray(-4, Range(0, "to", 3)) # will sign-extend
45
+ >>> LogicArray(-4, Range(0, "to", 3)) # will sign-extend
44
46
  LogicArray('1100', Range(0, 'to', 3))
45
47
 
48
+ >>> LogicArray(range=Range(0, "to", 3)) # default values
49
+ LogicArray('XXXX', Range(0, 'to', 3))
50
+
46
51
  :class:`LogicArray`\ s support the same operations as :class:`Array`;
47
52
  however, it enforces the condition that all elements must be a :class:`Logic`.
48
53
 
@@ -115,12 +120,38 @@ class LogicArray(Array[Logic]):
115
120
 
116
121
  __slots__ = ()
117
122
 
123
+ @typing.overload
118
124
  def __init__(
119
125
  self,
120
126
  value: typing.Union[int, typing.Iterable[LogicConstructibleT], BinaryValue],
127
+ range: typing.Optional[Range],
128
+ ):
129
+ ...
130
+
131
+ @typing.overload
132
+ def __init__(
133
+ self,
134
+ value: typing.Union[
135
+ int, typing.Iterable[LogicConstructibleT], BinaryValue, None
136
+ ],
137
+ range: Range,
138
+ ):
139
+ ...
140
+
141
+ def __init__(
142
+ self,
143
+ value: typing.Union[
144
+ int, typing.Iterable[LogicConstructibleT], BinaryValue, None
145
+ ] = None,
121
146
  range: typing.Optional[Range] = None,
122
147
  ) -> None:
123
- if isinstance(value, int):
148
+ if value is None and range is None:
149
+ raise ValueError(
150
+ "at least one of the value and range input parameters must be given"
151
+ )
152
+ if value is None:
153
+ self._value = [Logic() for _ in range]
154
+ elif isinstance(value, int):
124
155
  if value < 0:
125
156
  bitlen = int.bit_length(value + 1) + 1
126
157
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cocotb
3
- Version: 1.7.2
3
+ Version: 1.8.0rc1
4
4
  Summary: cocotb is a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python.
5
5
  Home-page: https://www.cocotb.org
6
6
  Author: Chris Higgs, Stuart Hodgson
@@ -39,8 +39,7 @@ Requires-Dist: cocotb-bus ; extra == 'bus'
39
39
  * Read the [documentation](https://docs.cocotb.org)
40
40
  * Get involved:
41
41
  * [Raise a bug / request an enhancement](https://github.com/cocotb/cocotb/issues/new) (Requires a GitHub account)
42
- * [Join the mailing list](https://lists.librecores.org/listinfo/cocotb)
43
- * [Join the Gitter chat room](https://gitter.im/cocotb)
42
+ * [Join the Gitter chat room](https://gitter.im/cocotb/Lobby)
44
43
 
45
44
  ## Installation
46
45
 
@@ -98,22 +97,38 @@ An example of a simple randomized cocotb testbench:
98
97
  # test_dff.py
99
98
 
100
99
  import random
100
+
101
101
  import cocotb
102
102
  from cocotb.clock import Clock
103
- from cocotb.triggers import FallingEdge
103
+ from cocotb.triggers import RisingEdge
104
+ from cocotb.types import LogicArray
104
105
 
105
106
  @cocotb.test()
106
- async def test_dff_simple(dut):
107
- """ Test that d propagates to q """
107
+ async def dff_simple_test(dut):
108
+ """Test that d propagates to q"""
109
+
110
+ # Assert initial output is unknown
111
+ assert LogicArray(dut.q.value) == LogicArray("X")
112
+ # Set initial input value to prevent it from floating
113
+ dut.d.value = 0
108
114
 
109
115
  clock = Clock(dut.clk, 10, units="us") # Create a 10us period clock on port clk
110
- cocotb.start_soon(clock.start()) # Start the clock
116
+ # Start the clock. Start it low to avoid issues on the first RisingEdge
117
+ cocotb.start_soon(clock.start(start_high=False))
111
118
 
119
+ # Synchronize with the clock. This will regisiter the initial `d` value
120
+ await RisingEdge(dut.clk)
121
+ expected_val = 0 # Matches initial input value
112
122
  for i in range(10):
113
123
  val = random.randint(0, 1)
114
124
  dut.d.value = val # Assign the random value val to the input port d
115
- await FallingEdge(dut.clk)
116
- assert dut.q.value == val, "output q was incorrect on the {}th cycle".format(i)
125
+ await RisingEdge(dut.clk)
126
+ assert dut.q.value == expected_val, f"output q was incorrect on the {i}th cycle"
127
+ expected_val = val # Save random value for next RisingEdge
128
+
129
+ # Check the final input on the next clock
130
+ await RisingEdge(dut.clk)
131
+ assert dut.q.value == expected_val, "output q was incorrect on the last cycle"
117
132
  ```
118
133
 
119
134
  A simple Makefile:
@@ -0,0 +1,120 @@
1
+ cocotb/ANSI.py,sha256=BXtYyxla8R_bHRasjDyZGibYDNoh2deY8Snyre8YT54,3458
2
+ cocotb/__init__.py,sha256=_NKjtHVLsDKgFPI7oXqNPKxiHt7EO-0XmUkqSLgGI1A,11650
3
+ cocotb/_deprecation.py,sha256=zCaBqq6H9GRyKgSij9NvLs6Ku5CIdvKuGW6rLwi1Hhk,1189
4
+ cocotb/_py_compat.py,sha256=Z-6oewHZbG79nO_tILrRrClahxjYaeEShezbcLnJsc4,2754
5
+ cocotb/_sim_versions.py,sha256=sZWOj9odl_yPo92B9k_b1c2XHll4roD-oHnVSqY4VhE,3689
6
+ cocotb/_version.py,sha256=c_sANXIqez9-uHsDRjcYbiXfIEFV5fERPy-0EiPwtaw,306
7
+ cocotb/binary.py,sha256=YCaXafbR2xG8CFnnToELgPyfL3rc6vEYYctmwGDQb5o,26996
8
+ cocotb/clock.py,sha256=tyrtalfTCUiBTTfo_4kIGKG5mnCSCq3hLmAxwrmyQyM,6734
9
+ cocotb/config.py,sha256=fW8kdxRx6_1qcWzL8r5Xm1KrHec-kVZcBv7WzBixMXs,10142
10
+ cocotb/decorators.py,sha256=RmFedYm9gxIWIaeeADGHJCf9lvHHSbf0M6WN2KrfGG8,11802
11
+ cocotb/handle.py,sha256=A_DojPAu_qbcOFP9U_q3A-dKRvrpLhX6ZWdy3NEHenw,42787
12
+ cocotb/ipython_support.py,sha256=gon5kkyYVl2nJPHZmyo33vFkb0F9qEPMdPKh70WJx0g,3228
13
+ cocotb/log.py,sha256=_pq5KzdU3dbFdSmaJfu_GhLSmIQaGuNsXQkIulSZuT0,10746
14
+ cocotb/memdebug.py,sha256=UzsA9FtitLlxt-Y9pf_vlknKYX13mroVjZqvax9ddzs,1888
15
+ cocotb/outcomes.py,sha256=4khaKTI7dZWhIAH1vZ7XWejQtlSGWb1-ZuHvSRClK9w,1355
16
+ cocotb/queue.py,sha256=BoFIJ8tO2HGTPb_30I9Td7-W6VLQ54kquPrc5qLw2dk,5338
17
+ cocotb/regression.py,sha256=XdokhhpR3GjriV3Hx-ihIayyjVLUiN27MdHldXMr1JE,33905
18
+ cocotb/result.py,sha256=0B3i0wXair7gfKlelTrRSkFpPbyuhsW2kPtSvSasweo,6905
19
+ cocotb/runner.py,sha256=o3KB_uPh9uhrQajGDD_JkHpZO7DDsASRsPInmaQJWGk,36621
20
+ cocotb/scheduler.py,sha256=KxdMtIO_wOJrKYJRhC--QQuLoYmxr6h7uLofXxyKYQQ,42042
21
+ cocotb/simulator.cp39-win_amd64.exp,sha256=XcSsHKMWuGEd-Bc-asq_SMlPhPKxP99gY-kfG6Bgegg,755
22
+ cocotb/simulator.cp39-win_amd64.lib,sha256=LOndjeKVN49iA5q0N3RCxef8pBFYODkMP7Nj16GTmPk,2036
23
+ cocotb/simulator.cp39-win_amd64.pyd,sha256=ZHdJ1T9qbiqUDEVeRlVrlZKW_2G61rB8BzCzDW-ed_U,31744
24
+ cocotb/simulator.cp39-win_amd64.pyd.2.config,sha256=JGoavZmGw71REMRGu8DrBlQezZSCkQx7E3GOzGIf9_o,263
25
+ cocotb/task.py,sha256=l51CgFAzBfKQD0snRuROoU24g52fd91wZM8GfSc-CQA,11360
26
+ cocotb/triggers.py,sha256=l6jZ0rjnljCH_5iPOyoJ2uX6QC0AQn7JZdRB4vWeQtM,33259
27
+ cocotb/utils.py,sha256=JTc870duDxUtSIM_UxXhsW9DtBvz6ziTagpn5wQ2ryU,23762
28
+ cocotb/wavedrom.py,sha256=xQ_xG_cdUc4q4hju7Sjys-gFrJCg7RngCPFNI3A4KAA,6187
29
+ cocotb/xunit_reporter.py,sha256=DrRM7Fn9LBY2hmtWI0PNFkiULpdNtqNzAk-1aw8Zd80,3632
30
+ cocotb/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ cocotb/_vendor/distutils_version.py,sha256=k4Zipnnw88hyoE5MLBbgcXh9iu7iYGK3K5s97wVpOFE,13185
32
+ cocotb/libs/cocotb.dll,sha256=KMA6KMdwk7o0w9b5ul4xSaNHjC-e2lpwT1mnZ9WNuXw,20480
33
+ cocotb/libs/cocotb.exp,sha256=3xDzWQmxkfjBfgCUoqkeu9LzMki_5OI_1FA9ALAfTd0,1108
34
+ cocotb/libs/cocotb.lib,sha256=A88vdah7VfZ_ovV3stbSxhO-wfcGhWKaoHU15D29nHE,2358
35
+ cocotb/libs/cocotbfli_modelsim.dll,sha256=hjmWi2JHC32GcyHNnd2-vC9HI5D59pi3RnEGulE8DJ8,84992
36
+ cocotb/libs/cocotbfli_modelsim.exp,sha256=XNUdBMB2eVzsdmTAB3n716uR4gK1vHY9HVAWo8319aw,874
37
+ cocotb/libs/cocotbfli_modelsim.lib,sha256=fxQQiVJim1EAt5lafBwAXMzlJQfLnNjP_s8H_aA52c8,2176
38
+ cocotb/libs/cocotbutils.dll,sha256=nm-b_rAeyCXH54076_rhekB28V45K7oNIleIYtwJxeA,11776
39
+ cocotb/libs/cocotbutils.exp,sha256=SXET5oFO2PyqfPhVlJ7o61eDBWfnZYnx7dZmMBfcykg,973
40
+ cocotb/libs/cocotbutils.lib,sha256=wHZ1lC4WqttFoZBPIqP_mSIQ-9-RHmYGf3eQhhVvF0c,2146
41
+ cocotb/libs/cocotbvhpi_aldec.dll,sha256=s73fMOXTNklQZP9HxPKm4v-qOFrAh8-EAP4bVhEiEfA,77312
42
+ cocotb/libs/cocotbvhpi_aldec.exp,sha256=8yldTw605-Nk2lWfpvpF3_L_JLUK9g7ufP76L6dm-14,1072
43
+ cocotb/libs/cocotbvhpi_aldec.lib,sha256=MSQ9cgUHCu3cjNlr_4ZuoM-4TvbPrwov7h2XEhkoEAE,2442
44
+ cocotb/libs/cocotbvhpi_modelsim.dll,sha256=xpSLgVL_t3IhpwIFjkffRfLKRsd1cbF0kl6FGn_HLPI,77312
45
+ cocotb/libs/cocotbvhpi_modelsim.exp,sha256=Ymy4d86r_kUkFHHhzeUMFExXTLcwH2zdw9TI-Ttu_ks,1079
46
+ cocotb/libs/cocotbvhpi_modelsim.lib,sha256=-hHWTB-uD55isZLMHWtgTQG_2rhansUvfS6p8TlORvM,2484
47
+ cocotb/libs/cocotbvpi_aldec.dll,sha256=oVP1J7L72-alO4OpO67fkGQjlKQy7_a7ESOV-EvQMiQ,65024
48
+ cocotb/libs/cocotbvpi_aldec.exp,sha256=f9mwnBe5uw9R5IksCr_rZnvBxYzYotRDBICk4LRua1Y,1067
49
+ cocotb/libs/cocotbvpi_aldec.lib,sha256=oEliaWtpPQ-gycodC1W1KGatibwSpmye4iayZYPeVhg,2418
50
+ cocotb/libs/cocotbvpi_ghdl.dll,sha256=YZowCeBSGQ6R7MMqlWlL2G3TBci0dE39JP0aB_G3YrU,65024
51
+ cocotb/libs/cocotbvpi_ghdl.exp,sha256=XA57uf8P3hksnkwdDnJoOwhhxvYBz1Xn1k-Zm2_1P2A,1066
52
+ cocotb/libs/cocotbvpi_ghdl.lib,sha256=1vXhVqSQGfCouzo_wGxihm10-1OXBIHFhDvHA_NMDs0,2408
53
+ cocotb/libs/cocotbvpi_icarus.exp,sha256=gitCkT1fB_sJbhINm0TRYa3UMHd-NDcIXHT9MbrtrvU,1070
54
+ cocotb/libs/cocotbvpi_icarus.lib,sha256=rAmfB7yOVOpAbDSg1wdxnWEyDd4ZPmyLYGd1vLonHIY,2438
55
+ cocotb/libs/cocotbvpi_icarus.vpl,sha256=PzBAM6fp9NTPj7FONM7CVBYxxhwQTGL5OuwIZ4EEyf8,65024
56
+ cocotb/libs/cocotbvpi_modelsim.dll,sha256=Ehq4ATB8yzA8rGgZ8hyEQJtVIYNDO0f8YCJup_7bSxY,65024
57
+ cocotb/libs/cocotbvpi_modelsim.exp,sha256=T1vfx67Y7geY73QZRPzND4HUCFM2e6wbdITxACqCiSQ,1074
58
+ cocotb/libs/cocotbvpi_modelsim.lib,sha256=RxjB0vL84fbwRnAmp-RBVgRkkzVEALu9eQao4F1TPhI,2468
59
+ cocotb/libs/embed.dll,sha256=ka7KL8NlqWFoE9U4HrevMGT1X71fXc6HmfXNfcZhlrQ,11776
60
+ cocotb/libs/embed.exp,sha256=s4btJK1AFaXCe40Y1ZX_E6eRGDQAUcKBIf3rrFQ2s0Y,1095
61
+ cocotb/libs/embed.lib,sha256=wCHsyl4vxU3zN9KnNFS9h7n6MsO_RAWUs8t1LuD0-aU,2322
62
+ cocotb/libs/gpi.dll,sha256=VLbLIMUHuCrxEYwp2a-TT4uFKaNUXXZ6qYaSz5kTNdk,46592
63
+ cocotb/libs/gpi.exp,sha256=cb9FAQhy0YrvU_NX7p2rX8-5eLMFyUh2eXJI25wrS9Q,21030
64
+ cocotb/libs/gpi.lib,sha256=7XS-7w5dyoGRkxcSayKrcNnNm_J5S38C8vgmGLS90tc,34400
65
+ cocotb/libs/gpilog.dll,sha256=0Fc2GcXnW-zVFffI2vRsPkpCZfQXTyAObS70P21FL6c,16896
66
+ cocotb/libs/gpilog.exp,sha256=e-GjNZv5nLzQi2RVDCnVWuX0h-gSwXHc1xWXFd9aS1g,1631
67
+ cocotb/libs/gpilog.lib,sha256=TJd8hd0zQ7HHY866Ikkz4ShJOlKUH3SP5pqyAmL_fMI,3244
68
+ cocotb/libs/pygpilog.dll,sha256=OOxt07rNd3pycZyGgsZ5zZOyCtwhSzreHCEfGPKRqFM,18432
69
+ cocotb/libs/pygpilog.exp,sha256=tBu1X8o2T6O5ERz-heVEd7NtXh4wLuxKTLCGbsO06Wo,1042
70
+ cocotb/libs/pygpilog.lib,sha256=PExGeknZU_cAZBWRtIh7PW5sdzoyfUDaugN-Vh5y7tk,2272
71
+ cocotb/share/def/.gitignore,sha256=JYPaHghbqtLFl-9QtOWaAHvoDOhVxEewSYwHgoYYgf8,46
72
+ cocotb/share/def/README.md,sha256=dptv3zHQGzMqLt3Zv4XOd5IZeGqQS7Lwcq1XCs3BcR0,380
73
+ cocotb/share/def/aldec.def,sha256=ItgxVlRaVuD20jGTN3JpkbHEO8jPfU5XjFlUqDUXzlU,991
74
+ cocotb/share/def/aldec.exp,sha256=8lHsNJWemZl0PlHE4eb6lO-c0hag8RVA19bIOY3eVBw,7938
75
+ cocotb/share/def/aldec.lib,sha256=5SgA1bN6HOYnjFyc227WcHnCh4_y9v7L0-8T6PkfN3c,13498
76
+ cocotb/share/def/ghdl.def,sha256=ETQh5VI72dWSJi_ig5m163GfLrxScYUamt5BjHjoKsY,705
77
+ cocotb/share/def/ghdl.exp,sha256=z8xhuW5RPuSrQRlZm8uw6YJT11HJCLJ9vLSCqHqTeM0,5763
78
+ cocotb/share/def/ghdl.lib,sha256=CXA22OgCWOwj98gQbzPU6V68g_aSZoUrsUYCOCQ2Jy4,9974
79
+ cocotb/share/def/icarus.def,sha256=VRqkgUyzR2sa916Ra56cZVIb4kzbqDlJVWIOc3389qY,698
80
+ cocotb/share/def/icarus.exp,sha256=HB5ti73Fl04QuBS84qHD8tDBqgObuMgyFRRIWO51myY,5753
81
+ cocotb/share/def/icarus.lib,sha256=GoQf24LaehNbZafMuo-bzZ_ymmPAykEK5l9xgmEsi9I,9612
82
+ cocotb/share/def/modelsim.def,sha256=_6VexHTDM7geGOfedUCm6CLRpXS4DrcHUlP_BQxL1Nc,2389
83
+ cocotb/share/def/modelsim.exp,sha256=Ulv7Vy3ZBGsUxD1A8hPjfBabmiB0z9CKQTAAwKEbvkE,16913
84
+ cocotb/share/def/modelsim.lib,sha256=mE9E7Qu60ehm8eO95Za5l8zgc_awwsX7Kk1TT-r1KGU,28194
85
+ cocotb/share/include/cocotb_utils.h,sha256=v3byzF0uZbks5umkKBe-mgB9J3ShtKwam0_S2vIS10A,4091
86
+ cocotb/share/include/embed.h,sha256=Fw0szHcAsXyrK_APXxZE-t0ttqmA8IUC72XXYO5yPl8,2509
87
+ cocotb/share/include/exports.h,sha256=RRDg9diMCUUJxdzKX0B6TGmQBNttcoVMBVCCLUUKsrA,677
88
+ cocotb/share/include/gpi.h,sha256=FvlF0QQD1rfy_jZ6Q_EnUpymNz7BtrGCgunXV8hg40k,10264
89
+ cocotb/share/include/gpi_logging.h,sha256=_Z00YAtMqSr5Mk3WSQ0YjQ5nyPvsxA5vmou1G8lX-B4,10553
90
+ cocotb/share/include/py_gpi_logging.h,sha256=zuuDIsKCdLOfUwOMv5EzeQWHuM0PaHzYE1kIH6TSWys,672
91
+ cocotb/share/include/vhpi_user_ext.h,sha256=VLXbA-oeO83mL1vR0e4Ye0zMe5ijIaXnvT2FRFgsYDY,654
92
+ cocotb/share/include/vpi_user_ext.h,sha256=ofqT24X1KOLeIDowuZxKDYvCTgXAy_RzMz5-_LjSZas,2511
93
+ cocotb/share/lib/verilator/verilator.cpp,sha256=DKNqW8ZZV8Xeqsf0WW8YSe1LzT6ay70fSyiI2Lkj29M,4560
94
+ cocotb/share/makefiles/Makefile.deprecations,sha256=83TZ1sYlXpVL5erEAr1Y0ZknoX-3vVn5gcwHwaAf30k,428
95
+ cocotb/share/makefiles/Makefile.inc,sha256=uOtUkgAFhogYPU1gJ3Y1AKaV6s86EqFfsbLObSY7dKs,7212
96
+ cocotb/share/makefiles/Makefile.sim,sha256=mDZPxOw40n1oIYM2wQ-KNHw5Ws9xMW9NSexLWIOxLTM,5412
97
+ cocotb/share/makefiles/simulators/Makefile.activehdl,sha256=Y5mq84jkkUo0DFSOwaP99fdv06w8J5fdflOcnYAOHD8,2728
98
+ cocotb/share/makefiles/simulators/Makefile.cvc,sha256=wAf8qdHAeXckTixGmF5zAyWicCky5w0H41illxmD-NE,3995
99
+ cocotb/share/makefiles/simulators/Makefile.ghdl,sha256=f0EdUOiEjjCONvQawAmmWfigzEUCt9CaheYT3x_tKW0,3627
100
+ cocotb/share/makefiles/simulators/Makefile.icarus,sha256=N4n5-azl6YCGYsHwmVwUbN5rQ49Rl0XNt02BTiZYE50,4485
101
+ cocotb/share/makefiles/simulators/Makefile.ius,sha256=ikm-N_uvdpTw4cSNbVOXCV59o6ZeaOoXTfpx676CCwc,5090
102
+ cocotb/share/makefiles/simulators/Makefile.modelsim,sha256=MQYmRb59nvUkY_f7GXUQVEYXQnU4IWA2-_G0N08StuI,1938
103
+ cocotb/share/makefiles/simulators/Makefile.questa,sha256=tSEhEoWm-UN5QzrmVAoPqnQ-sxBXQytVHKBQjRIRXHI,6595
104
+ cocotb/share/makefiles/simulators/Makefile.riviera,sha256=GkMwjsvcTKJ-Dq_VFWFFCxio5E9Boo8uAis0TB8dSIk,6074
105
+ cocotb/share/makefiles/simulators/Makefile.vcs,sha256=P6t3hpAQoeurusymMmck71vj9p5V5Ordbi6wyghPdHo,3788
106
+ cocotb/share/makefiles/simulators/Makefile.verilator,sha256=gi6X6u7QqRNUPOCr_AT1iD6a_EeAGz2y0rkYwVz-2nY,2486
107
+ cocotb/share/makefiles/simulators/Makefile.xcelium,sha256=h6Cd_bXncZUfLlLnRbRMBWXxKZDumWVtMM2MscxbheY,5545
108
+ cocotb/types/__init__.py,sha256=-M5mR--OWtFZ7Y4pjxB9CF4kmFtroDR7kzz1ba6h0No,1853
109
+ cocotb/types/array.py,sha256=JAg5YB84WwERF7S5SK16HvmzCYJgmc5trLATJT3TIqo,11208
110
+ cocotb/types/logic.py,sha256=PH5zocv9SpJam9Scc8Cl3uiDtPdtixhbiVLXjJPsPW8,8791
111
+ cocotb/types/logic_array.py,sha256=0XpStXNA7qY8FIoamb-dnn-IbzIOXIBoxd0tiWMlhVE,10255
112
+ cocotb/types/range.py,sha256=f25nic3X8jpd14nFU61D3izEOT77zPF_txZkWNrZ7N8,6428
113
+ pygpi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
+ pygpi/entry.py,sha256=LDJ8WK-s9nY_A5GEvPUuJTvnGqZvkhOe7i_yGQmqrI0,972
115
+ cocotb-1.8.0rc1.dist-info/LICENSE,sha256=oBp8aKF9rhLjG78uW4zxmiVsjA8Viwwdyj3nSbEXpmc,1570
116
+ cocotb-1.8.0rc1.dist-info/METADATA,sha256=b8cIvlmErODaWdItPo-Yk3pSB-XQGY2WvRKsdzAmv5g,6956
117
+ cocotb-1.8.0rc1.dist-info/WHEEL,sha256=eep6QWEFiQfg2wcclssb_WY-D33AnLYLnEKGA9Rn-VU,100
118
+ cocotb-1.8.0rc1.dist-info/entry_points.txt,sha256=Z2JL-ZgU-G5au6uYpkWZz9Pfk7qnh4fcoQJmBxnHSZQ,53
119
+ cocotb-1.8.0rc1.dist-info/top_level.txt,sha256=w-hmA_Ca52PldJkt5ya7gRP9tpUXfeJUGLMfXdv5Ez4,393
120
+ cocotb-1.8.0rc1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: bdist_wheel (0.40.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp39-cp39-win_amd64
5
5