cocotb 1.9.2__cp36-cp36m-win32.whl → 2.0.0rc2__cp36-cp36m-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.

Potentially problematic release.


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

Files changed (149) hide show
  1. cocotb/_ANSI.py +65 -0
  2. cocotb/__init__.py +81 -327
  3. cocotb/_base_triggers.py +515 -0
  4. cocotb/_bridge.py +186 -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 +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 +114 -29
  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 +3 -7
  21. cocotb/_xunit_reporter.py +66 -0
  22. cocotb/clock.py +353 -108
  23. cocotb/debug.py +24 -0
  24. cocotb/handle.py +1370 -793
  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/cocotbvpi_aldec.dll +0 -0
  41. cocotb/libs/cocotbvpi_aldec.exp +0 -0
  42. cocotb/libs/cocotbvpi_aldec.lib +0 -0
  43. cocotb/libs/cocotbvpi_ghdl.dll +0 -0
  44. cocotb/libs/cocotbvpi_ghdl.exp +0 -0
  45. cocotb/libs/cocotbvpi_ghdl.lib +0 -0
  46. cocotb/libs/cocotbvpi_icarus.exp +0 -0
  47. cocotb/libs/cocotbvpi_icarus.lib +0 -0
  48. cocotb/libs/cocotbvpi_icarus.vpl +0 -0
  49. cocotb/libs/cocotbvpi_modelsim.dll +0 -0
  50. cocotb/libs/cocotbvpi_modelsim.exp +0 -0
  51. cocotb/libs/cocotbvpi_modelsim.lib +0 -0
  52. cocotb/libs/embed.dll +0 -0
  53. cocotb/libs/embed.exp +0 -0
  54. cocotb/libs/embed.lib +0 -0
  55. cocotb/libs/gpi.dll +0 -0
  56. cocotb/libs/gpi.exp +0 -0
  57. cocotb/libs/gpi.lib +0 -0
  58. cocotb/libs/gpilog.dll +0 -0
  59. cocotb/libs/gpilog.exp +0 -0
  60. cocotb/libs/gpilog.lib +0 -0
  61. cocotb/libs/pygpilog.dll +0 -0
  62. cocotb/libs/pygpilog.exp +0 -0
  63. cocotb/libs/pygpilog.lib +0 -0
  64. cocotb/logging.py +424 -0
  65. cocotb/queue.py +103 -57
  66. cocotb/regression.py +680 -717
  67. cocotb/result.py +17 -188
  68. cocotb/share/def/modelsim.def +1 -0
  69. cocotb/share/include/cocotb_utils.h +9 -32
  70. cocotb/share/include/embed.h +7 -30
  71. cocotb/share/include/gpi.h +331 -137
  72. cocotb/share/include/gpi_logging.h +221 -142
  73. cocotb/share/include/py_gpi_logging.h +8 -5
  74. cocotb/share/include/vpi_user_ext.h +4 -26
  75. cocotb/share/lib/verilator/verilator.cpp +80 -67
  76. cocotb/simtime.py +230 -0
  77. cocotb/simulator.cp36-win32.exp +0 -0
  78. cocotb/simulator.cp36-win32.lib +0 -0
  79. cocotb/simulator.cp36-win32.pyd +0 -0
  80. cocotb/task.py +478 -213
  81. cocotb/triggers.py +55 -1092
  82. cocotb/types/__init__.py +28 -47
  83. cocotb/types/_abstract_array.py +151 -0
  84. cocotb/types/_array.py +295 -0
  85. cocotb/types/_indexing.py +17 -0
  86. cocotb/types/_logic.py +333 -0
  87. cocotb/types/_logic_array.py +868 -0
  88. cocotb/types/{range.py → _range.py} +47 -48
  89. cocotb/types/_resolve.py +76 -0
  90. cocotb/utils.py +58 -646
  91. {cocotb-1.9.2.dist-info → cocotb-2.0.0rc2.dist-info}/LICENSE +1 -0
  92. cocotb-2.0.0rc2.dist-info/METADATA +48 -0
  93. cocotb-2.0.0rc2.dist-info/RECORD +134 -0
  94. cocotb-2.0.0rc2.dist-info/entry_points.txt +3 -0
  95. {cocotb-1.9.2.dist-info → cocotb-2.0.0rc2.dist-info}/top_level.txt +1 -0
  96. cocotb_tools/_coverage.py +33 -0
  97. cocotb_tools/_vendor/__init__.py +3 -0
  98. cocotb_tools/check_results.py +65 -0
  99. cocotb_tools/combine_results.py +152 -0
  100. cocotb_tools/config.py +241 -0
  101. {cocotb → cocotb_tools}/ipython_support.py +29 -22
  102. cocotb_tools/makefiles/Makefile.deprecations +27 -0
  103. {cocotb/share → cocotb_tools}/makefiles/Makefile.inc +77 -55
  104. {cocotb/share → cocotb_tools}/makefiles/Makefile.sim +16 -33
  105. {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.activehdl +9 -16
  106. cocotb_tools/makefiles/simulators/Makefile.cvc +61 -0
  107. cocotb_tools/makefiles/simulators/Makefile.dsim +39 -0
  108. {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.ghdl +13 -42
  109. cocotb_tools/makefiles/simulators/Makefile.icarus +80 -0
  110. cocotb_tools/makefiles/simulators/Makefile.ius +93 -0
  111. cocotb_tools/makefiles/simulators/Makefile.modelsim +9 -0
  112. cocotb_tools/makefiles/simulators/Makefile.nvc +60 -0
  113. cocotb_tools/makefiles/simulators/Makefile.questa +29 -0
  114. cocotb/share/makefiles/simulators/Makefile.questa → cocotb_tools/makefiles/simulators/Makefile.questa-compat +26 -54
  115. cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun +149 -0
  116. {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.riviera +17 -56
  117. cocotb_tools/makefiles/simulators/Makefile.vcs +65 -0
  118. {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.verilator +15 -22
  119. {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.xcelium +20 -52
  120. cocotb_tools/runner.py +1868 -0
  121. cocotb/_sim_versions.py → cocotb_tools/sim_versions.py +16 -21
  122. pygpi/entry.py +34 -18
  123. cocotb/ANSI.py +0 -92
  124. cocotb/binary.py +0 -858
  125. cocotb/config.py +0 -289
  126. cocotb/decorators.py +0 -332
  127. cocotb/log.py +0 -303
  128. cocotb/memdebug.py +0 -35
  129. cocotb/outcomes.py +0 -56
  130. cocotb/runner.py +0 -1400
  131. cocotb/scheduler.py +0 -1099
  132. cocotb/share/makefiles/Makefile.deprecations +0 -12
  133. cocotb/share/makefiles/simulators/Makefile.cvc +0 -94
  134. cocotb/share/makefiles/simulators/Makefile.icarus +0 -111
  135. cocotb/share/makefiles/simulators/Makefile.ius +0 -125
  136. cocotb/share/makefiles/simulators/Makefile.modelsim +0 -32
  137. cocotb/share/makefiles/simulators/Makefile.nvc +0 -64
  138. cocotb/share/makefiles/simulators/Makefile.vcs +0 -98
  139. cocotb/types/array.py +0 -309
  140. cocotb/types/logic.py +0 -292
  141. cocotb/types/logic_array.py +0 -298
  142. cocotb/wavedrom.py +0 -199
  143. cocotb/xunit_reporter.py +0 -80
  144. cocotb-1.9.2.dist-info/METADATA +0 -170
  145. cocotb-1.9.2.dist-info/RECORD +0 -113
  146. cocotb-1.9.2.dist-info/entry_points.txt +0 -3
  147. {cocotb-1.9.2.dist-info → cocotb-2.0.0rc2.dist-info}/WHEEL +0 -0
  148. {cocotb/_vendor → cocotb_tools}/__init__.py +0 -0
  149. {cocotb → cocotb_tools}/_vendor/distutils_version.py +0 -0
@@ -0,0 +1,868 @@
1
+ # Copyright cocotb contributors
2
+ # Licensed under the Revised BSD License, see LICENSE for details.
3
+ # SPDX-License-Identifier: BSD-3-Clause
4
+ import copy
5
+ import warnings
6
+ from math import ceil
7
+ from typing import (
8
+ Any,
9
+ Dict,
10
+ Iterable,
11
+ Iterator,
12
+ List,
13
+ Union,
14
+ cast,
15
+ overload,
16
+ )
17
+
18
+ from cocotb._deprecation import deprecated
19
+ from cocotb._py_compat import Literal, TypeAlias
20
+ from cocotb.types._abstract_array import AbstractMutableArray
21
+ from cocotb.types._indexing import IndexingChangedWarning
22
+ from cocotb.types._logic import Logic, LogicConstructibleT
23
+ from cocotb.types._range import Range
24
+ from cocotb.types._resolve import RESOLVE_X, ResolverLiteral, get_str_resolver
25
+
26
+ _resolve_lh_table = str.maketrans({"L": "0", "H": "1"})
27
+ _str_literals = frozenset("uUxX01zZwWlLhH-")
28
+
29
+
30
+ ByteOrder: TypeAlias = Literal["big", "little"]
31
+
32
+
33
+ class LogicArray(AbstractMutableArray[Logic]):
34
+ r"""Fixed-sized, arbitrarily-indexed, :class:`.Array` of :class:`.Logic`\ s.
35
+
36
+ An :class:`!Array`, where all elements are enforced to be :class:`!Logic`.
37
+ This allows the additional of bit-wise logical operators, conversions to integers and bytes, and ``X`` testing and mapping.
38
+
39
+ :class:`!LogicArray`\ s can be constructed from an iterable of :class:`!Logic`\ s,
40
+ or values constructible into :class:`!Logic`, like :class:`bool`, :class:`str`, or :class:`int`.
41
+ Alternatively, they can be constructed from :class:`!str` or :class:`!int` literals.
42
+
43
+ Like :class:`!Array`, if *range* is not given, the range ``Range(len(value)-1, "downto", 0)`` is used;
44
+ and if an :class:`int` is passed for *range*, the range ``Range(range-1, "downto", 0)`` is used.
45
+
46
+ .. code-block:: pycon3
47
+
48
+ >>> LogicArray(0b0111, 4)
49
+ LogicArray('0111', Range(3, 'downto', 0))
50
+
51
+ >>> LogicArray("01XZ", Range(0, "to", 3))
52
+ LogicArray('01XZ', Range(0, 'to', 3))
53
+
54
+ >>> LogicArray([0, True, "X", Logic("-")])
55
+ LogicArray('01X-', Range(3, 'downto', 0))
56
+
57
+ .. note::
58
+ If constructing from an unsigned :class:`!int` literal, *range* `must` be given.
59
+
60
+ :class:`!LogicArray`\ s can be constructed from :class:`int`\ s using :meth:`from_unsigned` or :meth:`from_signed`.
61
+
62
+ .. code-block:: pycon3
63
+
64
+ >>> LogicArray.from_unsigned(0xA, 4)
65
+ LogicArray('1010', Range(3, 'downto', 0))
66
+
67
+ >>> LogicArray.from_signed(-4, Range(0, "to", 3)) # will sign-extend
68
+ LogicArray('1100', Range(0, 'to', 3))
69
+
70
+ :class:`!LogicArray`\ s can be constructed from :class:`bytes` or :class:`bytearray` using :meth:`from_bytes`.
71
+ Use the *byteorder* argument to control endianness.
72
+
73
+ .. code-block:: pycon3
74
+
75
+ >>> LogicArray.from_bytes(b"1n", byteorder="big")
76
+ LogicArray('0011000101101110', Range(15, 'downto', 0))
77
+
78
+ >>> LogicArray.from_bytes(b"1n", byteorder="little")
79
+ LogicArray('0110111000110001', Range(15, 'downto', 0))
80
+
81
+ :class:`!LogicArray`\ s support the same :class:`list`-like operations as :class:`!Array`;
82
+ however, it enforces the condition that all elements must be a :class:`!Logic`.
83
+
84
+ .. code-block:: pycon3
85
+
86
+ >>> array = LogicArray("1010")
87
+ >>> array[0] # is indexable
88
+ Logic('0')
89
+
90
+ >>> array[1:] # is slice-able
91
+ LogicArray('10', Range(1, 'downto', 0))
92
+
93
+ >>> Logic("0") in array # is a collection
94
+ True
95
+
96
+ >>> list(array) # is an iterable
97
+ [Logic('1'), Logic('0'), Logic('1'), Logic('0')]
98
+
99
+ When setting an element or slice, the *value* is first constructed into a :class:`!Logic`.
100
+
101
+ .. code-block:: pycon3
102
+
103
+ >>> array = LogicArray("1010")
104
+ >>> array[3] = "Z"
105
+ >>> array[3]
106
+ Logic('Z')
107
+
108
+ >>> array[2:] = ["X", True, 0]
109
+ >>> array
110
+ LogicArray('ZX10', Range(3, 'downto', 0))
111
+
112
+ >>> array[:] = 0b0101
113
+ >>> array
114
+ LogicArray('0101', Range(3, 'downto', 0))
115
+
116
+ :class:`!LogicArray`\ s can be converted into their :class:`str` or :class:`int` literal values using casts.
117
+ They can also be used in conditionals.
118
+
119
+ .. code-block:: pycon3
120
+
121
+ >>> value = LogicArray("1010")
122
+ >>> str(value)
123
+ '1010'
124
+
125
+ >>> int(value)
126
+ 10
127
+ >>> if value:
128
+ ... print("Not 0!")
129
+ Not 0!
130
+
131
+ .. warning::
132
+ The :class:`int` cast, :class:`bool` cast, and use in conditionals assumes the
133
+ value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise.
134
+
135
+ The :meth:`to_unsigned`, :meth:`to_signed`, and :meth:`to_bytes` methods can be used to convert
136
+ the value into an unsigned or signed integer, or bytes, respectively.
137
+
138
+ .. code-block:: pycon3
139
+
140
+ >>> value = LogicArray("1010")
141
+ >>> value.to_unsigned()
142
+ 10
143
+
144
+ >>> value.to_signed()
145
+ -6
146
+
147
+ >>> value.to_bytes(byteorder="big")
148
+ b'\n'
149
+
150
+ .. warning::
151
+ These operations assume the value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise.
152
+
153
+ You can also convert :class:`!LogicArray`\ s to hexadecimal or binary strings using
154
+ the built-ins :func:`hex` and :func:`bin`, respectively.
155
+
156
+ .. code-block:: pycon3
157
+
158
+ >>> value = LogicArray("01111010")
159
+ >>> hex(value)
160
+ '0x7a'
161
+
162
+ >>> bin(value)
163
+ '0b1111010'
164
+
165
+ .. warning::
166
+ Using :func:`hex` or :func:`bin` first turns the :class:`!LogicArray` into an :class:`int`.
167
+ This means the exact length of the :class:`!LogicArray` is lost.
168
+ It also means that these expressions will raise an exception if the value is not entirely ``0``, ``1``, ``L``, or ``H``.
169
+
170
+ :class:`!LogicArray`\ s also support element-wise logical operations: ``&``, ``|``,
171
+ ``^``, and ``~``.
172
+
173
+ .. code-block:: pycon3
174
+
175
+ >>> def big_mux(a: LogicArray, b: LogicArray, sel: Logic) -> LogicArray:
176
+ ... s = LogicArray([sel] * len(a))
177
+ ... return (a & ~s) | (b & s)
178
+
179
+ >>> a = LogicArray("0110")
180
+ >>> b = LogicArray("1110")
181
+ >>> sel = Logic("1") # choose second option
182
+ >>> big_mux(a, b, sel)
183
+ LogicArray('1110', Range(3, 'downto', 0))
184
+
185
+ Args:
186
+ value: Initial value for the :class:`!LogicArray`.
187
+ range: The indexing scheme of the :class:`!LogicArray`.
188
+
189
+ Raises:
190
+ TypeError: When invalid argument types are used.
191
+ ValueError: When *value* will not fit in a :class:`!LogicArray` of the given *range*.
192
+ """
193
+
194
+ # These three attribute contain the current value of the array in one or more of
195
+ # three different implementations. This is done for performance reasons, as certain
196
+ # implementations are faster for particular operations.
197
+ # Each implementation can be present, or None if the implementation has not been
198
+ # computed or has been invalidated by a mutating operation.
199
+ _value_as_array: Union[List[Logic], None]
200
+ _value_as_int: Union[int, None]
201
+ _value_as_str: Union[str, None]
202
+ _range: Range
203
+ _warn_indexing: bool
204
+
205
+ __slots__ = (
206
+ "_value_as_array",
207
+ "_value_as_int",
208
+ "_value_as_str",
209
+ "_range",
210
+ "_warn_indexing",
211
+ )
212
+
213
+ def __init__(
214
+ self,
215
+ value: Union[int, str, Iterable[LogicConstructibleT]],
216
+ range: Union[Range, int, None] = None,
217
+ ) -> None:
218
+ self._value_as_array = None
219
+ self._value_as_int = None
220
+ self._value_as_str = None
221
+ self._warn_indexing = False
222
+
223
+ if isinstance(range, int):
224
+ range = Range(range - 1, "downto", 0)
225
+ elif range is not None and not isinstance(range, Range):
226
+ raise TypeError(
227
+ f"Expected Range or int for parameter 'range', not {type(range).__qualname__}"
228
+ )
229
+
230
+ if isinstance(value, str):
231
+ if not (set(value) <= _str_literals):
232
+ raise ValueError("Invalid str literal")
233
+ self._value_as_str = value.upper()
234
+ if range is not None:
235
+ if len(value) != len(range):
236
+ raise ValueError(
237
+ f"Value of length {len(self._value_as_str)} will not fit in {range!r}"
238
+ )
239
+ self._range = range
240
+ else:
241
+ self._range = Range(len(self._value_as_str) - 1, "downto", 0)
242
+ elif isinstance(value, int):
243
+ value = int(value) # force bool to int
244
+ if value < 0:
245
+ raise ValueError("Invalid int literal")
246
+ if range is None:
247
+ raise TypeError("Missing required arguments: 'range'")
248
+ bitlen = max(1, int.bit_length(value))
249
+ if bitlen > len(range):
250
+ raise ValueError(
251
+ f"{value!r} will not fit in a LogicArray with bounds: {range!r}"
252
+ )
253
+ self._value_as_int = value
254
+ self._range = range
255
+ else:
256
+ self._value_as_array = [Logic(v) for v in value]
257
+ if range is not None:
258
+ if len(self._value_as_array) != len(range):
259
+ raise ValueError(
260
+ f"Value of length {len(self._value_as_array)} will not fit in {range!r}"
261
+ )
262
+ self._range = range
263
+ else:
264
+ self._range = Range(len(self._value_as_array) - 1, "downto", 0)
265
+
266
+ def _get_array(self) -> List[Logic]:
267
+ if self._value_as_array is None:
268
+ # May convert int to str before to converting to array.
269
+ self._value_as_array = [Logic(v) for v in self._get_str()]
270
+ return self._value_as_array
271
+
272
+ def _get_str(self) -> str:
273
+ if self._value_as_str is None:
274
+ if self._value_as_int is not None:
275
+ self._value_as_str = format(self._value_as_int, f"0{len(self)}b")
276
+ else:
277
+ self._value_as_str = "".join(
278
+ str(v) for v in cast("List[Logic]", self._value_as_array)
279
+ )
280
+ return self._value_as_str
281
+
282
+ def _get_int(self) -> int:
283
+ if self._value_as_int is None:
284
+ # May convert list to str before converting to int.
285
+ value_as_str = self._get_str()
286
+
287
+ # always resolve L and H to 0 and 1
288
+ value_as_str = value_as_str.translate(_resolve_lh_table)
289
+
290
+ try:
291
+ self._value_as_int = int(value_as_str, 2)
292
+ except ValueError:
293
+ if RESOLVE_X is None:
294
+ raise ValueError(
295
+ f"Can't convert {type(self).__qualname__} to int: it contains non-0/1 values"
296
+ ) from None
297
+ else:
298
+ value_as_str = RESOLVE_X(value_as_str)
299
+ return int(value_as_str, 2)
300
+
301
+ return self._value_as_int
302
+
303
+ @classmethod
304
+ def from_unsigned(
305
+ cls,
306
+ value: int,
307
+ range: Union[Range, int],
308
+ ) -> "LogicArray":
309
+ """Construct a :class:`!LogicArray` from an :class:`int` with unsigned representation.
310
+
311
+ The :class:`int` is treated as an arbitrary-length bit vector with unsigned representation where the left-most bit is the most significant bit.
312
+ This bit vector is then constructed into a :class:`!LogicArray`.
313
+
314
+ Args:
315
+ value: The integer to convert.
316
+ range: Indexing scheme for the :class:`!LogicArray`.
317
+
318
+ Returns:
319
+ A :class:`!LogicArray` equivalent to the *value*.
320
+
321
+ Raises:
322
+ TypeError: When invalid argument types are used.
323
+ ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*, or *value* is negative.
324
+ """
325
+ if value < 0:
326
+ raise ValueError("Expected unsigned integer, got negative value")
327
+ return LogicArray(value, range)
328
+
329
+ @classmethod
330
+ def from_signed(
331
+ cls,
332
+ value: int,
333
+ range: Union[Range, int],
334
+ ) -> "LogicArray":
335
+ """Construct a :class:`!LogicArray` from an :class:`int` with two's complement representation.
336
+
337
+ The :class:`int` is treated as an arbitrary-length bit vector with two's complement representation where the left-most bit is the most significant bit.
338
+ This bit vector is then constructed into a :class:`!LogicArray`.
339
+
340
+ Args:
341
+ value: The integer to convert.
342
+ range: Indexing scheme for the :class:`!LogicArray`.
343
+
344
+ Returns:
345
+ A :class:`!LogicArray` equivalent to the *value*.
346
+
347
+ Raises:
348
+ TypeError: When invalid argument types are used.
349
+ ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*.
350
+ """
351
+ if isinstance(range, int):
352
+ range = Range(range - 1, "downto", 0)
353
+ elif not isinstance(range, Range):
354
+ raise TypeError(
355
+ f"Expected Range or int for parameter 'range', not {type(range).__qualname__}"
356
+ )
357
+
358
+ # Prevent null range from blowing up the below code.
359
+ if len(range) == 0:
360
+ raise ValueError(
361
+ f"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}"
362
+ )
363
+
364
+ limit = 1 << (len(range) - 1)
365
+ if value < -limit or limit <= value:
366
+ raise ValueError(
367
+ f"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}"
368
+ )
369
+ value %= 2 * limit
370
+
371
+ return LogicArray(value, range)
372
+
373
+ @classmethod
374
+ def from_bytes(
375
+ cls,
376
+ value: Union[bytes, bytearray],
377
+ range: Union[Range, int, None] = None,
378
+ *,
379
+ byteorder: ByteOrder,
380
+ ) -> "LogicArray":
381
+ """Construct a :class:`!LogicArray` from :class:`bytes`.
382
+
383
+ The :class:`bytes` is first converted to an unsigned integer using *byteorder*-endian representation,
384
+ then is converted to a :class:`!LogicArray` as in :meth:`from_unsigned`.
385
+
386
+ Args:
387
+ value: The bytes to convert.
388
+ range: Indexing scheme for the :class:`!LogicArray`.
389
+ byteorder: The endianness used to construct the intermediate integer, either ``"big"`` or ``"little"``.
390
+
391
+ Returns:
392
+ A :class:`!LogicArray` equivalent to the *value*.
393
+
394
+ Raises:
395
+ ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*.
396
+ """
397
+ if range is None:
398
+ range = Range(len(value) * 8 - 1, "downto", 0)
399
+ else:
400
+ if isinstance(range, int):
401
+ range = Range(range - 1, "downto", 0)
402
+ if len(value) * 8 != len(range):
403
+ raise ValueError(
404
+ f"Value of length {len(value)} will not fit in a LogicArray with bounds: {range!r}"
405
+ )
406
+ value_as_int = int.from_bytes(value, byteorder=byteorder, signed=False)
407
+ return LogicArray(value_as_int, range)
408
+
409
+ @classmethod
410
+ def _from_handle(cls, value: str, warn_indexing: bool) -> "LogicArray":
411
+ # Used by cocotb.handle classes to make LogicArray from values gotten from the
412
+ # simulator which we expect to be well-formed.
413
+ # Values are required to be uppercase.
414
+ self = cls.__new__(cls)
415
+ self._value_as_array = None
416
+ self._value_as_int = None
417
+ self._value_as_str = value
418
+ self._range = Range(len(value) - 1, "downto", 0)
419
+ self._warn_indexing = warn_indexing
420
+ return self
421
+
422
+ @property
423
+ def range(self) -> Range:
424
+ """:class:`Range` of the indexes of the array."""
425
+ return self._range
426
+
427
+ @range.setter
428
+ def range(self, new_range: Range) -> None:
429
+ """Set a new indexing scheme on the array. Must be the same size."""
430
+ if not isinstance(new_range, Range):
431
+ raise TypeError("range argument must be of type 'Range'")
432
+ if len(new_range) != len(self):
433
+ raise ValueError(
434
+ f"{new_range!r} not the same length as old range: {self._range!r}"
435
+ )
436
+ self._range = new_range
437
+
438
+ def __iter__(self) -> Iterator[Logic]:
439
+ return iter(self._get_array())
440
+
441
+ def __reversed__(self) -> Iterator[Logic]:
442
+ return reversed(self._get_array())
443
+
444
+ def __contains__(self, item: object) -> bool:
445
+ return item in self._get_array()
446
+
447
+ def __eq__(
448
+ self,
449
+ other: object,
450
+ ) -> bool:
451
+ if isinstance(other, int):
452
+ if len(self) == 0:
453
+ # Null arrays don't have a value and thus always compare False.
454
+ return False
455
+ try:
456
+ return self.to_unsigned() == other
457
+ except ValueError:
458
+ return False
459
+ elif isinstance(other, str):
460
+ return str(self) == other.upper()
461
+ elif isinstance(other, LogicArray):
462
+ if len(self) != len(other):
463
+ return False
464
+ # Complex, but efficient chain of checking logic.
465
+ # Avoid conversions if it can help it at first.
466
+ # Prefers checking against str vs any type since that is going to be the
467
+ # most common type and also the "middle" type for conversions.
468
+ # Always converts away from ints to prevent issues with non-0/1 data.
469
+ if self._value_as_str is not None and other._value_as_str is not None:
470
+ # (STR, STR)
471
+ return self._value_as_str == other._value_as_str
472
+ elif self._value_as_array is not None and other._value_as_array is not None:
473
+ # (ARRAY, ARRAY)
474
+ return self._value_as_array == other._value_as_array
475
+ elif self._value_as_int is not None and other._value_as_int is not None:
476
+ # (INT, INT)
477
+ return self._value_as_int == other._value_as_int
478
+ elif self._value_as_str is not None:
479
+ # (STR, INT)
480
+ # (STR, ARRAY)
481
+ return self._value_as_str == other._get_str()
482
+ elif other._value_as_str is not None:
483
+ # (INT, STR)
484
+ # (ARRAY, STR)
485
+ return self._get_str() == other._value_as_str
486
+ elif self._value_as_array is not None:
487
+ # (ARRAY, INT)
488
+ return self._value_as_array == other._get_array()
489
+ else:
490
+ # (INT, ARRAY)
491
+ return self._get_array() == other._value_as_array
492
+ elif isinstance(other, (list, tuple)):
493
+ try:
494
+ other = LogicArray(other)
495
+ except ValueError:
496
+ return False
497
+ return self == other
498
+ else:
499
+ return NotImplemented
500
+
501
+ @property
502
+ @deprecated(
503
+ "`logic_array.binstr` getter is deprecated. Use `str(logic_array)` instead."
504
+ )
505
+ def binstr(self) -> str:
506
+ """The :class:`!LogicArray`'s value in :class:`str` literal representation.
507
+
508
+ :getter:
509
+ Return the :class:`!LogicArray`'s value in :class:`str` literal representation.
510
+
511
+ .. deprecated:: 2.0
512
+ Use ``str(logic_array)`` instead.
513
+
514
+ :setter:
515
+ Set the :class:`!LogicArray`'s value using a :class:`str` literal representation.
516
+
517
+ .. deprecated:: 2.0
518
+ Use ``logic_array[:] = value`` instead.
519
+ """
520
+ return str(self)
521
+
522
+ @binstr.setter
523
+ @deprecated(
524
+ "`logic_array.binstr = value` setter is deprecated. Use `logic_array[:] = value` instead."
525
+ )
526
+ def binstr(self, value: str) -> None:
527
+ self[:] = value
528
+
529
+ @property
530
+ def is_resolvable(self) -> bool:
531
+ """``True`` if all elements are ``0``, ``1``, ``L``, ``H``."""
532
+ return all(bit.is_resolvable for bit in self)
533
+
534
+ @property
535
+ @deprecated(
536
+ "`logic_array.integer` getter is deprecated. Use `logic_array.to_unsigned()` instead."
537
+ )
538
+ def integer(self) -> int:
539
+ """The :class:`!LogicArray`'s value as an unsigned :class:`int`.
540
+
541
+ The :class:`!LogicArray` is treated as an arbitrary-length vector of bits
542
+ with the left-most bit being the most significant bit in the integer value.
543
+ The bit vector is then interpreted as an integer using unsigned representation.
544
+
545
+ :getter:
546
+ Return the :class:`!LogicArray`'s value as an unsigned integer.
547
+
548
+ .. deprecated:: 2.0
549
+ Use :meth:`logic_array.to_unsigned() <cocotb.types.LogicArray.to_unsigned>` instead.
550
+
551
+ :setter:
552
+ Set the :class:`!LogicArray`'s value using an unsigned integer.
553
+
554
+ .. deprecated:: 2.0
555
+ Use ``logic_array[:] = value`` instead.
556
+ """
557
+ return self.to_unsigned()
558
+
559
+ @integer.setter
560
+ @deprecated(
561
+ "`logic_array.integer = value` setter is deprecated. Use `logic_array[:] = value` instead."
562
+ )
563
+ def integer(self, value: int) -> None:
564
+ self[:] = value
565
+
566
+ @property
567
+ @deprecated(
568
+ "`logic_array.signed_integer` getter is deprecated. Use `logic_array.to_signed()` instead."
569
+ )
570
+ def signed_integer(self) -> int:
571
+ """The :class:`!LogicArray`'s value as a signed :class:`int`.
572
+
573
+ The :class:`!LogicArray` is treated as an arbitrary-length vector of bits
574
+ with the left-most bit being the most significant bit in the integer value.
575
+ The bit vector is then interpreted as an integer using two's complement representation.
576
+
577
+ :getter:
578
+ Return the :class:`!LogicArray`'s value as a signed integer.
579
+
580
+ .. deprecated:: 2.0
581
+ Use :meth:`logic_array.to_signed() <cocotb.types.LogicArray.to_signed>` instead.
582
+
583
+ :setter:
584
+ Set the :class:`!LogicArray`'s value using a signed integer.
585
+
586
+ .. deprecated:: 2.0
587
+ Use ``logic_array[:] = LogicArray.from_signed(value, len(logic_array))`` instead.
588
+ """
589
+ return self.to_signed()
590
+
591
+ @signed_integer.setter
592
+ @deprecated(
593
+ "`logic_array.signed_integer = value` setter is deprecated. "
594
+ "Use `logic_array[:] = LogicArray.from_signed(value, len(logic_array))` instead."
595
+ )
596
+ def signed_integer(self, value: int) -> None:
597
+ self[:] = LogicArray.from_signed(value, len(self))
598
+
599
+ @property
600
+ @deprecated(
601
+ "`logic_array.buff` getter is deprecated. "
602
+ 'Use `logic_array.to_bytes(byteorder="big")` instead.'
603
+ )
604
+ def buff(self) -> bytes:
605
+ """The :class:`!LogicArray`'s value as :class:`bytes`.
606
+
607
+ The object is first converted to an :class:`int` as in :meth:`to_unsigned`.
608
+ Then the object is converted to :class:`bytes` by converting the resulting integer value as in :meth:`int.to_bytes`.
609
+ This assumes big-endian byte order and the minimal number of bytes necessary to hold any value of the current object.
610
+
611
+ :getter:
612
+ Return the :class:`!LogicArray`'s value as :class:`bytes`.
613
+
614
+ .. deprecated:: 2.0
615
+ Use :meth:`logic_array.to_bytes(byteorder="big") <cocotb.types.LogicArray.to_bytes>` instead.
616
+
617
+ :setter:
618
+ Set the :class:`!LogicArray`'s value using :class:`bytes`.
619
+
620
+ .. deprecated:: 2.0
621
+ Use ``logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder="big")`` instead.
622
+ """
623
+ return self.to_bytes(byteorder="big")
624
+
625
+ @buff.setter
626
+ @deprecated(
627
+ "`logic_array.buff = value` setter is deprecated. "
628
+ 'Use `logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder="big")` instead.'
629
+ )
630
+ def buff(self, value: bytes) -> None:
631
+ self[:] = LogicArray.from_bytes(value, len(self), byteorder="big")
632
+
633
+ def to_unsigned(self) -> int:
634
+ """Convert the value to an integer by interpreting it using unsigned representation.
635
+
636
+ The :class:`!LogicArray` is treated as an arbitrary-length vector of bits
637
+ with the left-most bit being the most significant bit in the integer value.
638
+ The bit vector is then interpreted as an integer using unsigned representation.
639
+
640
+ Returns:
641
+ An integer equivalent to the value by interpreting it using unsigned representation.
642
+ """
643
+ if len(self) == 0:
644
+ raise ValueError("Cannot convert null vector to integer")
645
+ return self._get_int()
646
+
647
+ def to_signed(self) -> int:
648
+ """Convert the value to an integer by interpreting it using two's complement representation.
649
+
650
+ The :class:`!LogicArray` is treated as an arbitrary-length vector of bits
651
+ with the left-most bit being the most significant bit in the integer value.
652
+ The bit vector is then interpreted as an integer using two's complement representation.
653
+
654
+ Returns:
655
+ An integer equivalent to the value by interpreting it using two's complement representation.
656
+ """
657
+ if len(self) == 0:
658
+ raise ValueError("Cannot convert null vector to integer")
659
+ value = self._get_int()
660
+ limit = 1 << (len(self) - 1)
661
+ if value >= limit:
662
+ value -= 2 * limit
663
+ return value
664
+
665
+ def to_bytes(
666
+ self,
667
+ *,
668
+ byteorder: ByteOrder,
669
+ ) -> bytes:
670
+ """Convert the value to bytes.
671
+
672
+ The :class:`!LogicArray` is converted to an unsigned integer as in :meth:`to_unsigned`,
673
+ then is converted to :class:`bytes` using *byteorder*-endian representation
674
+ with the minimum number of bytes which can store all the bits in the original :class:`!LogicArray`.
675
+
676
+ Args:
677
+ byteorder: The endianness used to construct the intermediate integer, either ``"big"`` or ``"little"``.
678
+
679
+ Returns:
680
+ :class:`bytes` equivalent to the value.
681
+ """
682
+ return self.to_unsigned().to_bytes(ceil(len(self) / 8), byteorder=byteorder)
683
+
684
+ @overload
685
+ def __getitem__(self, item: int) -> Logic: ...
686
+
687
+ @overload
688
+ def __getitem__(self, item: slice) -> "LogicArray": ...
689
+
690
+ def __getitem__(self, item: Union[int, slice]) -> Union[Logic, "LogicArray"]:
691
+ array = self._get_array()
692
+ if isinstance(item, int):
693
+ if self._warn_indexing:
694
+ warnings.warn(
695
+ f"Update index {item} to {self.range[item]}",
696
+ IndexingChangedWarning,
697
+ stacklevel=2,
698
+ )
699
+ idx = self._translate_index(item)
700
+ return array[idx]
701
+ elif isinstance(item, slice):
702
+ if self._warn_indexing:
703
+ start = item.start if item.start is not None else 0
704
+ stop = item.stop if item.stop is not None else len(self) - 1
705
+ warnings.warn(
706
+ f"Update slice {start}:{stop} to {self.range[start]}:{self.range[stop]}",
707
+ IndexingChangedWarning,
708
+ stacklevel=2,
709
+ )
710
+ start = item.start if item.start is not None else self.left
711
+ stop = item.stop if item.stop is not None else self.right
712
+ if item.step is not None:
713
+ raise IndexError("do not specify step")
714
+ start_i = self._translate_index(start)
715
+ stop_i = self._translate_index(stop)
716
+ if start_i > stop_i:
717
+ raise IndexError(
718
+ f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]"
719
+ )
720
+ value = array[start_i : stop_i + 1]
721
+ range = Range(start, self.direction, stop)
722
+ return LogicArray(value=value, range=range)
723
+ raise TypeError(f"indexes must be ints or slices, not {type(item).__name__}")
724
+
725
+ @overload
726
+ def __setitem__(self, item: int, value: LogicConstructibleT) -> None: ...
727
+
728
+ @overload
729
+ def __setitem__(
730
+ self, item: slice, value: Union[str, Iterable[LogicConstructibleT], int]
731
+ ) -> None: ...
732
+
733
+ def __setitem__(
734
+ self,
735
+ item: Union[int, slice],
736
+ value: Union[LogicConstructibleT, Iterable[LogicConstructibleT]],
737
+ ) -> None:
738
+ array = self._get_array()
739
+ # invalid other impls
740
+ self._value_as_str = None
741
+ self._value_as_int = None
742
+ if isinstance(item, int):
743
+ idx = self._translate_index(item)
744
+ array[idx] = Logic(cast("LogicConstructibleT", value))
745
+ elif isinstance(item, slice):
746
+ start = item.start if item.start is not None else self.left
747
+ stop = item.stop if item.stop is not None else self.right
748
+ if item.step is not None:
749
+ raise IndexError("do not specify step")
750
+ start_i = self._translate_index(start)
751
+ stop_i = self._translate_index(stop)
752
+ if start_i > stop_i:
753
+ raise IndexError(
754
+ f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]"
755
+ )
756
+ value = cast("str | int | Iterable[LogicConstructibleT]", value)
757
+ value_as_logics = LogicArray(value, stop_i - start_i + 1)
758
+ array[start_i : stop_i + 1] = value_as_logics
759
+ else:
760
+ raise TypeError(
761
+ f"indexes must be ints or slices, not {type(item).__name__}"
762
+ )
763
+
764
+ def _translate_index(self, item: int) -> int:
765
+ try:
766
+ return self._range.index(item)
767
+ except ValueError:
768
+ raise IndexError(f"index {item} out of range") from None
769
+
770
+ def __repr__(self) -> str:
771
+ return f"{type(self).__qualname__}({str(self)!r}, {self.range!r})"
772
+
773
+ def __str__(self) -> str:
774
+ return self._get_str()
775
+
776
+ def __int__(self) -> int:
777
+ return self.to_unsigned()
778
+
779
+ def __index__(self) -> int:
780
+ return int(self)
781
+
782
+ def __and__(self, other: "LogicArray") -> "LogicArray":
783
+ if not isinstance(other, LogicArray):
784
+ return NotImplemented
785
+ if len(self) != len(other):
786
+ raise ValueError(
787
+ f"cannot perform bitwise & "
788
+ f"between {type(self).__qualname__} of length {len(self)} "
789
+ f"and {type(other).__qualname__} of length {len(other)}"
790
+ )
791
+ return LogicArray(a & b for a, b in zip(self, other))
792
+
793
+ def __or__(self, other: "LogicArray") -> "LogicArray":
794
+ if not isinstance(other, LogicArray):
795
+ return NotImplemented
796
+ if len(self) != len(other):
797
+ raise ValueError(
798
+ f"cannot perform bitwise | "
799
+ f"between {type(self).__qualname__} of length {len(self)} "
800
+ f"and {type(other).__qualname__} of length {len(other)}"
801
+ )
802
+ return LogicArray(a | b for a, b in zip(self, other))
803
+
804
+ def __xor__(self, other: "LogicArray") -> "LogicArray":
805
+ if not isinstance(other, LogicArray):
806
+ return NotImplemented
807
+ if len(self) != len(other):
808
+ raise ValueError(
809
+ f"cannot perform bitwise ^ "
810
+ f"between {type(self).__qualname__} of length {len(self)} "
811
+ f"and {type(other).__qualname__} of length {len(other)}"
812
+ )
813
+ return LogicArray(a ^ b for a, b in zip(self, other))
814
+
815
+ def __invert__(self) -> "LogicArray":
816
+ return LogicArray(~v for v in self)
817
+
818
+ if RESOLVE_X is None:
819
+
820
+ def __bool__(self) -> bool:
821
+ if len(self) == 0:
822
+ return False
823
+ return bool(int(self))
824
+
825
+ else:
826
+
827
+ def __bool__(self) -> bool:
828
+ if len(self) == 0:
829
+ return False
830
+ return any(bool(bit) for bit in self)
831
+
832
+ def resolve(self, resolver: ResolverLiteral) -> "LogicArray":
833
+ """Resolves non-0/1 values to 0/1.
834
+
835
+ The possible values of the *resolver* argument are:
836
+
837
+ * ``"weak"``:
838
+ Weak values are resolved to their strong-valued equivalents.
839
+
840
+ * ``"zeros"``:
841
+ ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.
842
+ Remaining non-``0``/``1`` values are resolved to ``0``.
843
+
844
+ * ``"ones"``:
845
+ ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.
846
+ Remaining non-``0``/``1`` values are resolved to ``1``.
847
+
848
+ * ``"random"``:
849
+ ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.
850
+ Remaining non-``0``/``1`` values are randomly resolved to either ``0`` or ``1``.
851
+
852
+ Args:
853
+ resolver: How to resolve non-``0``/``1`` values. See possible values above.
854
+
855
+ Returns:
856
+ The resolved Logic.
857
+
858
+ Raises:
859
+ ValueError: Invalid *resolver* value.
860
+ TypeError: Unsupported *value* type.
861
+ """
862
+ return LogicArray(get_str_resolver(resolver)(str(self)), self.range)
863
+
864
+ def __copy__(self) -> "LogicArray":
865
+ raise NotImplementedError("`copy.copy` on LogicArray is not supported")
866
+
867
+ def __deepcopy__(self, memo: Dict[int, Any]) -> "LogicArray":
868
+ return LogicArray(self._get_str(), copy.deepcopy(self._range, memo=memo))