cocotb 2.0.1__cp38-cp38-win32.whl

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