1 from abc
import ABCMeta
, abstractmethod
4 from collections
import OrderedDict
5 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
7 from itertools
import chain
10 from .._utils
import *
11 from .._unused
import *
15 "Shape", "signed", "unsigned",
16 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
17 "Array", "ArrayProxy",
18 "Signal", "ClockSignal", "ResetSignal",
19 "UserValue", "ValueCastable",
20 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
21 "Statement", "Switch",
22 "Property", "Assign", "Assert", "Assume", "Cover",
23 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
28 """Deterministic Unique IDentifier."""
31 self
.duid
= DUID
.__next
_uid
36 """Bit width and signedness of a value.
38 A ``Shape`` can be constructed using:
39 * explicit bit width and signedness;
40 * aliases :func:`signed` and :func:`unsigned`;
41 * casting from a variety of objects.
43 A ``Shape`` can be cast from:
44 * an integer, where the integer specifies the bit width;
45 * a range, where the result is wide enough to represent any element of the range, and is
46 signed if any element of the range is signed;
47 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
48 enough to represent any member of the enumeration, and is signed if any member of
49 the enumeration is signed.
54 The number of bits in the representation, including the sign bit (if any).
56 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
58 def __init__(self
, width
=1, signed
=False):
59 if not isinstance(width
, int) or width
< 0:
60 raise TypeError("Width must be a non-negative integer, not {!r}"
66 return iter((self
.width
, self
.signed
))
69 def cast(obj
, *, src_loc_at
=0):
70 if isinstance(obj
, Shape
):
72 if isinstance(obj
, int):
74 if isinstance(obj
, tuple):
76 warnings
.warn("instead of `{tuple}`, use `{constructor}({width})`"
77 .format(constructor
="signed" if signed
else "unsigned", width
=width
,
79 DeprecationWarning, stacklevel
=2 + src_loc_at
)
80 return Shape(width
, signed
)
81 if isinstance(obj
, range):
83 return Shape(0, obj
.start
< 0)
84 signed
= obj
.start
< 0 or (obj
.stop
- obj
.step
) < 0
85 width
= max(bits_for(obj
.start
, signed
),
86 bits_for(obj
.stop
- obj
.step
, signed
))
87 return Shape(width
, signed
)
88 if isinstance(obj
, type) and issubclass(obj
, Enum
):
89 min_value
= min(member
.value
for member
in obj
)
90 max_value
= max(member
.value
for member
in obj
)
91 if not isinstance(min_value
, int) or not isinstance(max_value
, int):
92 raise TypeError("Only enumerations with integer values can be used "
94 signed
= min_value
< 0 or max_value
< 0
95 width
= max(bits_for(min_value
, signed
), bits_for(max_value
, signed
))
96 return Shape(width
, signed
)
97 raise TypeError("Object {!r} cannot be used as value shape".format(obj
))
101 return "signed({})".format(self
.width
)
103 return "unsigned({})".format(self
.width
)
105 def __eq__(self
, other
):
106 if isinstance(other
, tuple) and len(other
) == 2:
107 width
, signed
= other
108 if isinstance(width
, int) and isinstance(signed
, bool):
109 return self
.width
== width
and self
.signed
== signed
111 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
114 if not isinstance(other
, Shape
):
115 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
118 return self
.width
== other
.width
and self
.signed
== other
.signed
122 """Shorthand for ``Shape(width, signed=False)``."""
123 return Shape(width
, signed
=False)
127 """Shorthand for ``Shape(width, signed=True)``."""
128 return Shape(width
, signed
=True)
131 class Value(metaclass
=ABCMeta
):
134 """Converts ``obj`` to an nMigen value.
136 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
137 all integers are converted to a :class:`Const` with a shape that fits every member.
139 if isinstance(obj
, Value
):
141 if isinstance(obj
, int):
143 if isinstance(obj
, Enum
):
144 return Const(obj
.value
, Shape
.cast(type(obj
)))
145 if isinstance(obj
, ValueCastable
):
146 return obj
.as_value()
147 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
149 def __init__(self
, *, src_loc_at
=0):
151 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
153 def __Mux__(self
, val1
, val0
):
154 return _InternalMux(self
, val1
, val0
)
157 raise TypeError("Attempted to convert nMigen value to Python boolean")
159 def __invert__(self
):
160 return Operator("~", [self
])
162 return Operator("-", [self
])
164 def __add__(self
, other
):
165 return Operator("+", [self
, other
])
166 def __radd__(self
, other
):
167 return Operator("+", [other
, self
])
168 def __sub__(self
, other
):
169 return Operator("-", [self
, other
])
170 def __rsub__(self
, other
):
171 return Operator("-", [other
, self
])
173 def __mul__(self
, other
):
174 return Operator("*", [self
, other
])
175 def __rmul__(self
, other
):
176 return Operator("*", [other
, self
])
178 def __check_divisor(self
):
179 width
, signed
= self
.shape()
181 # Python's division semantics and Verilog's division semantics differ for negative
182 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
183 # completely by prohibiting such division operations.
184 raise NotImplementedError("Division by a signed value is not supported")
185 def __mod__(self
, other
):
186 other
= Value
.cast(other
)
187 other
.__check
_divisor
()
188 return Operator("%", [self
, other
])
189 def __rmod__(self
, other
):
190 self
.__check
_divisor
()
191 return Operator("%", [other
, self
])
192 def __floordiv__(self
, other
):
193 other
= Value
.cast(other
)
194 other
.__check
_divisor
()
195 return Operator("//", [self
, other
])
196 def __rfloordiv__(self
, other
):
197 self
.__check
_divisor
()
198 return Operator("//", [other
, self
])
200 def __check_shamt(self
):
201 width
, signed
= self
.shape()
203 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
204 # by a signed value to make sure the shift amount can always be interpreted as
206 raise TypeError("Shift amount must be unsigned")
207 def __lshift__(self
, other
):
208 other
= Value
.cast(other
)
209 other
.__check
_shamt
()
210 return Operator("<<", [self
, other
])
211 def __rlshift__(self
, other
):
213 return Operator("<<", [other
, self
])
214 def __rshift__(self
, other
):
215 other
= Value
.cast(other
)
216 other
.__check
_shamt
()
217 return Operator(">>", [self
, other
])
218 def __rrshift__(self
, other
):
220 return Operator(">>", [other
, self
])
222 def __and__(self
, other
):
223 return Operator("&", [self
, other
])
224 def __rand__(self
, other
):
225 return Operator("&", [other
, self
])
226 def __xor__(self
, other
):
227 return Operator("^", [self
, other
])
228 def __rxor__(self
, other
):
229 return Operator("^", [other
, self
])
230 def __or__(self
, other
):
231 return Operator("|", [self
, other
])
232 def __ror__(self
, other
):
233 return Operator("|", [other
, self
])
235 def __eq__(self
, other
):
236 return Operator("==", [self
, other
])
237 def __ne__(self
, other
):
238 return Operator("!=", [self
, other
])
239 def __lt__(self
, other
):
240 return Operator("<", [self
, other
])
241 def __le__(self
, other
):
242 return Operator("<=", [self
, other
])
243 def __gt__(self
, other
):
244 return Operator(">", [self
, other
])
245 def __ge__(self
, other
):
246 return Operator(">=", [self
, other
])
249 width
, signed
= self
.shape()
251 return Mux(self
>= 0, self
, -self
)
256 return self
.shape().width
258 def __getitem__(self
, key
):
260 if isinstance(key
, int):
261 if key
not in range(-n
, n
):
262 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
265 return Slice(self
, key
, key
+ 1)
266 elif isinstance(key
, slice):
267 start
, stop
, step
= key
.indices(n
)
269 return Cat(self
[i
] for i
in range(start
, stop
, step
))
270 return Slice(self
, start
, stop
)
272 raise TypeError("Cannot index value with {}".format(repr(key
)))
274 def as_unsigned(self
):
275 """Conversion to unsigned.
280 This ``Value`` reinterpreted as a unsigned integer.
282 return Operator("u", [self
])
285 """Conversion to signed.
290 This ``Value`` reinterpreted as a signed integer.
292 return Operator("s", [self
])
295 """Conversion to boolean.
300 ``1`` if any bits are set, ``0`` otherwise.
302 return Operator("b", [self
])
305 """Check if any bits are ``1``.
310 ``1`` if any bits are set, ``0`` otherwise.
312 return Operator("r|", [self
])
315 """Check if all bits are ``1``.
320 ``1`` if all bits are set, ``0`` otherwise.
322 return Operator("r&", [self
])
325 """Compute pairwise exclusive-or of every bit.
330 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
332 return Operator("r^", [self
])
334 def implies(premise
, conclusion
):
340 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
342 return ~premise | conclusion
344 def bit_select(self
, offset
, width
):
345 """Part-select with bit granularity.
347 Selects a constant width but variable offset part of a ``Value``, such that successive
348 parts overlap by all but 1 bit.
353 Index of first selected bit.
355 Number of selected bits.
360 Selected part of the ``Value``
362 offset
= Value
.cast(offset
)
363 if type(offset
) is Const
and isinstance(width
, int):
364 return self
[offset
.value
:offset
.value
+ width
]
365 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
367 def word_select(self
, offset
, width
):
368 """Part-select with word granularity.
370 Selects a constant width but variable offset part of a ``Value``, such that successive
371 parts do not overlap.
376 Index of first selected word.
378 Number of selected bits.
383 Selected part of the ``Value``
385 offset
= Value
.cast(offset
)
386 if type(offset
) is Const
and isinstance(width
, int):
387 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
388 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
390 def matches(self
, *patterns
):
393 Matches against a set of patterns, which may be integers or bit strings, recognizing
394 the same grammar as ``Case()``.
398 patterns : int or str
399 Patterns to match against.
404 ``1`` if any pattern matches the value, ``0`` otherwise.
407 for pattern
in patterns
:
408 if not isinstance(pattern
, (int, str, Enum
)):
409 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
412 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
413 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
414 "bits, and may include whitespace"
416 if (isinstance(pattern
, str) and
417 len("".join(pattern
.split())) != len(self
)):
418 raise SyntaxError("Match pattern '{}' must have the same width as match value "
420 .format(pattern
, len(self
)))
421 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
422 warnings
.warn("Match pattern '{:b}' is wider than match value "
423 "(which has width {}); comparison will never be true"
424 .format(pattern
, len(self
)),
425 SyntaxWarning, stacklevel
=3)
427 if isinstance(pattern
, str):
428 pattern
= "".join(pattern
.split()) # remove whitespace
429 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
430 pattern
= int(pattern
.replace("-", "0"), 2)
431 matches
.append((self
& mask
) == pattern
)
432 elif isinstance(pattern
, int):
433 matches
.append(self
== pattern
)
434 elif isinstance(pattern
, Enum
):
435 matches
.append(self
== pattern
.value
)
440 elif len(matches
) == 1:
443 return Cat(*matches
).any()
445 def shift_left(self
, amount
):
446 """Shift left by constant amount.
456 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
458 if not isinstance(amount
, int):
459 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
461 return self
.shift_right(-amount
)
462 if self
.shape().signed
:
463 return Cat(Const(0, amount
), self
).as_signed()
465 return Cat(Const(0, amount
), self
) # unsigned
467 def shift_right(self
, amount
):
468 """Shift right by constant amount.
478 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
480 if not isinstance(amount
, int):
481 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
483 return self
.shift_left(-amount
)
484 if self
.shape().signed
:
485 return self
[amount
:].as_signed()
487 return self
[amount
:] # unsigned
489 def rotate_left(self
, amount
):
490 """Rotate left by constant amount.
500 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
502 if not isinstance(amount
, int):
503 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
505 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
507 def rotate_right(self
, amount
):
508 """Rotate right by constant amount.
518 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
520 if not isinstance(amount
, int):
521 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
523 return Cat(self
[amount
:], self
[:amount
])
531 Value to be assigned.
536 Assignment statement that can be used in combinatorial or synchronous context.
538 return Assign(self
, value
, src_loc_at
=1)
542 """Bit width and signedness of a value.
551 >>> Signal(8).shape()
552 Shape(width=8, signed=False)
553 >>> Const(0xaa).shape()
554 Shape(width=8, signed=False)
558 def _lhs_signals(self
):
559 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
562 def _rhs_signals(self
):
566 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
573 """A constant, literal integer value.
578 shape : int or tuple or None
579 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
580 in this constant and whether it is signed (can represent negative values).
581 ``shape`` defaults to the minimum possible width and signedness of ``value``.
591 def normalize(value
, shape
):
592 width
, signed
= shape
593 mask
= (1 << width
) - 1
595 if signed
and value
>> (width
- 1):
599 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
600 # We deliberately do not call Value.__init__ here.
601 self
.value
= int(value
)
603 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
604 elif isinstance(shape
, int):
605 shape
= Shape(shape
, signed
=self
.value
< 0)
607 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
608 self
.width
, self
.signed
= shape
609 self
.value
= self
.normalize(self
.value
, shape
)
612 return Shape(self
.width
, self
.signed
)
614 def _rhs_signals(self
):
621 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
624 C
= Const
# shorthand
627 class AnyValue(Value
, DUID
):
628 def __init__(self
, shape
, *, src_loc_at
=0):
629 super().__init
__(src_loc_at
=src_loc_at
)
630 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
631 if not isinstance(self
.width
, int) or self
.width
< 0:
632 raise TypeError("Width must be a non-negative integer, not {!r}"
636 return Shape(self
.width
, self
.signed
)
638 def _rhs_signals(self
):
643 class AnyConst(AnyValue
):
645 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
649 class AnySeq(AnyValue
):
651 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
655 class Operator(Value
):
656 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
657 super().__init
__(src_loc_at
=1 + src_loc_at
)
658 self
.operator
= operator
659 self
.operands
= [Value
.cast(op
) for op
in operands
]
662 def _bitwise_binary_shape(a_shape
, b_shape
):
663 a_bits
, a_sign
= a_shape
664 b_bits
, b_sign
= b_shape
665 if not a_sign
and not b_sign
:
666 # both operands unsigned
667 return Shape(max(a_bits
, b_bits
), False)
668 elif a_sign
and b_sign
:
669 # both operands signed
670 return Shape(max(a_bits
, b_bits
), True)
671 elif not a_sign
and b_sign
:
672 # first operand unsigned (add sign bit), second operand signed
673 return Shape(max(a_bits
+ 1, b_bits
), True)
675 # first signed, second operand unsigned (add sign bit)
676 return Shape(max(a_bits
, b_bits
+ 1), True)
678 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
679 if len(op_shapes
) == 1:
680 (a_width
, a_signed
), = op_shapes
681 if self
.operator
in ("+", "~"):
682 return Shape(a_width
, a_signed
)
683 if self
.operator
== "-":
684 return Shape(a_width
+ 1, True)
685 if self
.operator
in ("b", "r|", "r&", "r^"):
686 return Shape(1, False)
687 if self
.operator
== "u":
688 return Shape(a_width
, False)
689 if self
.operator
== "s":
690 return Shape(a_width
, True)
691 elif len(op_shapes
) == 2:
692 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
693 if self
.operator
in ("+", "-"):
694 width
, signed
= _bitwise_binary_shape(*op_shapes
)
695 return Shape(width
+ 1, signed
)
696 if self
.operator
== "*":
697 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
698 if self
.operator
in ("//", "%"):
700 return Shape(a_width
, a_signed
)
701 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
702 return Shape(1, False)
703 if self
.operator
in ("&", "^", "|"):
704 return _bitwise_binary_shape(*op_shapes
)
705 if self
.operator
== "<<":
707 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
708 if self
.operator
== ">>":
710 return Shape(a_width
, a_signed
)
711 elif len(op_shapes
) == 3:
712 if self
.operator
== "m":
713 s_shape
, a_shape
, b_shape
= op_shapes
714 return _bitwise_binary_shape(a_shape
, b_shape
)
715 raise NotImplementedError("Operator {}/{} not implemented"
716 .format(self
.operator
, len(op_shapes
))) # :nocov:
718 def _rhs_signals(self
):
719 return union(op
._rhs
_signals
() for op
in self
.operands
)
722 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
725 def Mux(sel
, val1
, val0
):
726 sel
= Value
.cast(sel
)
729 return sel
.__Mux
__(val1
, val0
)
732 def _InternalMux(sel
, val1
, val0
):
733 """Choose between two values.
746 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
748 sel
= Value
.cast(sel
)
751 return Operator("m", [sel
, val1
, val0
])
756 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
757 if not isinstance(start
, int):
758 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
759 if not isinstance(stop
, int):
760 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
763 if start
not in range(-(n
+1), n
+1):
764 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
767 if stop
not in range(-(n
+1), n
+1):
768 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
772 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
774 super().__init
__(src_loc_at
=src_loc_at
)
775 self
.value
= Value
.cast(value
)
776 self
.start
= int(start
)
777 self
.stop
= int(stop
)
780 return Shape(self
.stop
- self
.start
)
782 def _lhs_signals(self
):
783 return self
.value
._lhs
_signals
()
785 def _rhs_signals(self
):
786 return self
.value
._rhs
_signals
()
789 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
794 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
795 if not isinstance(width
, int) or width
< 0:
796 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
797 if not isinstance(stride
, int) or stride
<= 0:
798 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
800 super().__init
__(src_loc_at
=src_loc_at
)
802 self
.offset
= Value
.cast(offset
)
807 return Shape(self
.width
)
809 def _lhs_signals(self
):
810 return self
.value
._lhs
_signals
()
812 def _rhs_signals(self
):
813 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
816 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
817 self
.width
, self
.stride
)
822 """Concatenate values.
824 Form a compound ``Value`` from several smaller ones by concatenation.
825 The first argument occupies the lower bits of the result.
826 The return value can be used on either side of an assignment, that
827 is, the concatenated value can be used as an argument on the RHS or
828 as a target on the LHS. If it is used on the LHS, it must solely
829 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
830 meeting these properties. The bit length of the return value is the sum of
831 the bit lengths of the arguments::
833 len(Cat(args)) == sum(len(arg) for arg in args)
837 *args : Values or iterables of Values, inout
838 ``Value`` s to be concatenated.
843 Resulting ``Value`` obtained by concatentation.
845 def __init__(self
, *args
, src_loc_at
=0):
846 super().__init
__(src_loc_at
=src_loc_at
)
847 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
850 return Shape(sum(len(part
) for part
in self
.parts
))
852 def _lhs_signals(self
):
853 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
855 def _rhs_signals(self
):
856 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
860 for part
in reversed(self
.parts
):
862 value |
= part
._as
_const
()
866 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
873 An input value is replicated (repeated) several times
874 to be used on the RHS of assignments::
876 len(Repl(s, n)) == len(s) * n
881 Input value to be replicated.
883 Number of replications.
890 def __init__(self
, value
, count
, *, src_loc_at
=0):
891 if not isinstance(count
, int) or count
< 0:
892 raise TypeError("Replication count must be a non-negative integer, not {!r}"
895 super().__init
__(src_loc_at
=src_loc_at
)
896 self
.value
= Value
.cast(value
)
900 return Shape(len(self
.value
) * self
.count
)
902 def _rhs_signals(self
):
903 return self
.value
._rhs
_signals
()
906 return "(repl {!r} {})".format(self
.value
, self
.count
)
910 class Signal(Value
, DUID
):
911 """A varying integer value.
915 shape : ``Shape``-castable object or None
916 Specification for the number of bits in this ``Signal`` and its signedness (whether it
917 can represent negative values). See ``Shape.cast`` for details.
918 If not specified, ``shape`` defaults to 1-bit and non-signed.
920 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
921 name this ``Signal`` is assigned to.
922 reset : int or integral Enum
923 Reset (synchronous) or default (combinatorial) value.
924 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
925 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
926 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
927 assumes its ``reset`` value. Defaults to 0.
929 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
930 The ``reset`` value is only used as a combinatorial default or as the initial value.
931 Defaults to ``False``.
933 Dictionary of synthesis attributes.
934 decoder : function or Enum
935 A function converting integer signal values to human-readable strings (e.g. FSM state
936 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
937 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
951 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
952 attrs
=None, decoder
=None, src_loc_at
=0):
953 super().__init
__(src_loc_at
=src_loc_at
)
955 if name
is not None and not isinstance(name
, str):
956 raise TypeError("Name must be a string, not {!r}".format(name
))
957 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
961 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
963 if isinstance(reset
, Enum
):
965 if not isinstance(reset
, int):
966 raise TypeError("Reset value has to be an int or an integral Enum")
968 reset_width
= bits_for(reset
, self
.signed
)
969 if reset
!= 0 and reset_width
> self
.width
:
970 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
972 .format(reset
, reset_width
, self
.width
),
973 SyntaxWarning, stacklevel
=2 + src_loc_at
)
976 self
.reset_less
= bool(reset_less
)
978 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
980 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
982 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
983 def enum_decoder(value
):
985 return "{0.name:}/{0.value:}".format(decoder(value
))
988 self
.decoder
= enum_decoder
989 self
._enum
_class
= decoder
991 self
.decoder
= decoder
992 self
._enum
_class
= None
994 # Not a @classmethod because nmigen.compat requires it.
996 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
997 """Create Signal based on another.
1002 Object to base this Signal on.
1004 if name
is not None:
1005 new_name
= str(name
)
1006 elif name_suffix
is not None:
1007 new_name
= other
.name
+ str(name_suffix
)
1009 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1010 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1011 if isinstance(other
, Signal
):
1012 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1013 attrs
=other
.attrs
, decoder
=other
.decoder
)
1015 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1018 return Shape(self
.width
, self
.signed
)
1020 def _lhs_signals(self
):
1021 return SignalSet((self
,))
1023 def _rhs_signals(self
):
1024 return SignalSet((self
,))
1027 return "(sig {})".format(self
.name
)
1031 class ClockSignal(Value
):
1032 """Clock signal for a clock domain.
1034 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1035 All of these signals ultimately refer to the same signal, but they can be manipulated
1036 independently of the clock domain, even before the clock domain is created.
1041 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1043 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1044 super().__init
__(src_loc_at
=src_loc_at
)
1045 if not isinstance(domain
, str):
1046 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1047 if domain
== "comb":
1048 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1049 self
.domain
= domain
1054 def _lhs_signals(self
):
1055 return SignalSet((self
,))
1057 def _rhs_signals(self
):
1058 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1061 return "(clk {})".format(self
.domain
)
1065 class ResetSignal(Value
):
1066 """Reset signal for a clock domain.
1068 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1069 All of these signals ultimately refer to the same signal, but they can be manipulated
1070 independently of the clock domain, even before the clock domain is created.
1075 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1076 allow_reset_less : bool
1077 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1079 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1080 super().__init
__(src_loc_at
=src_loc_at
)
1081 if not isinstance(domain
, str):
1082 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1083 if domain
== "comb":
1084 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1085 self
.domain
= domain
1086 self
.allow_reset_less
= allow_reset_less
1091 def _lhs_signals(self
):
1092 return SignalSet((self
,))
1094 def _rhs_signals(self
):
1095 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1098 return "(rst {})".format(self
.domain
)
1101 class Array(MutableSequence
):
1102 """Addressable multiplexer.
1104 An array is similar to a ``list`` that can also be indexed by ``Value``s; indexing by an integer or a slice works the same as for Python lists, but indexing by a ``Value`` results
1107 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1108 assignments, provided that all elements of the array are values. The array proxy also supports
1109 attribute access and further indexing, each returning another array proxy; this means that
1110 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1111 be used as first-class values.
1113 It is an error to change an array or any of its elements after an array proxy was created.
1114 Changing the array directly will raise an exception. However, it is not possible to detect
1115 the elements being modified; if an element's attribute or element is modified after the proxy
1116 for it has been created, the proxy will refer to stale data.
1123 gpios = Array(Signal() for _ in range(10))
1125 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1127 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1129 Multidimensional array::
1131 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1132 a = Signal.range(10)
1133 b = Signal.range(10)
1135 m.d.comb += r.eq(mult[a][b])
1143 buses = Array(Record(layout) for busno in range(4))
1144 master = Record(layout)
1146 buses[sel].r_en.eq(master.r_en),
1147 master.r_data.eq(buses[sel].r_data),
1150 def __init__(self
, iterable
=()):
1151 self
._inner
= list(iterable
)
1152 self
._proxy
_at
= None
1153 self
._mutable
= True
1155 def __getitem__(self
, index
):
1156 if isinstance(index
, Value
):
1158 self
._proxy
_at
= tracer
.get_src_loc()
1159 self
._mutable
= False
1160 return ArrayProxy(self
, index
)
1162 return self
._inner
[index
]
1165 return len(self
._inner
)
1167 def _check_mutability(self
):
1168 if not self
._mutable
:
1169 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1170 "at {}:{}".format(*self
._proxy
_at
))
1172 def __setitem__(self
, index
, value
):
1173 self
._check
_mutability
()
1174 self
._inner
[index
] = value
1176 def __delitem__(self
, index
):
1177 self
._check
_mutability
()
1178 del self
._inner
[index
]
1180 def insert(self
, index
, value
):
1181 self
._check
_mutability
()
1182 self
._inner
.insert(index
, value
)
1185 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1186 ", ".join(map(repr, self
._inner
)))
1190 class ArrayProxy(Value
):
1191 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1192 super().__init
__(src_loc_at
=1 + src_loc_at
)
1194 self
.index
= Value
.cast(index
)
1196 def __getattr__(self
, attr
):
1197 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1199 def __getitem__(self
, index
):
1200 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1202 def _iter_as_values(self
):
1203 return (Value
.cast(elem
) for elem
in self
.elems
)
1206 unsigned_width
= signed_width
= 0
1207 has_unsigned
= has_signed
= False
1208 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1211 signed_width
= max(signed_width
, elem_width
)
1214 unsigned_width
= max(unsigned_width
, elem_width
)
1215 # The shape of the proxy must be such that it preserves the mathematical value of the array
1216 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1217 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1218 # that every unsigned value is zero-extended by at least one bit.
1219 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1220 # Array contains both signed and unsigned values, and at least one of the unsigned
1221 # values won't be zero-extended otherwise.
1222 return signed(unsigned_width
+ 1)
1224 # Array contains values of the same signedness, or else all of the unsigned values
1225 # are zero-extended.
1226 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1228 def _lhs_signals(self
):
1229 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1233 def _rhs_signals(self
):
1234 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1236 return self
.index
._rhs
_signals
() | signals
1239 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1242 # TODO(nmigen-0.4): remove
1243 class UserValue(Value
):
1244 """Value with custom lowering.
1246 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1247 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1248 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1249 value when required.
1251 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1252 nMigen's view of representation of all values stays internally consistent. If the class
1253 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1254 it is not mutated in a way that changes its representation.
1256 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1257 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1258 * Querying the shape using ``.shape()`` or ``len()``;
1259 * Creating a similarly shaped signal using ``Signal.like``;
1260 * Indexing or iterating through individual bits;
1261 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1263 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
1264 def __init__(self
, *, src_loc_at
=0):
1265 super().__init
__(src_loc_at
=1 + src_loc_at
)
1266 self
.__lowered
= None
1270 """Conversion to a concrete representation."""
1273 def _lazy_lower(self
):
1274 if self
.__lowered
is None:
1275 lowered
= self
.lower()
1276 if isinstance(lowered
, UserValue
):
1277 lowered
= lowered
._lazy
_lower
()
1278 self
.__lowered
= Value
.cast(lowered
)
1279 return self
.__lowered
1282 return self
._lazy
_lower
().shape()
1284 def _lhs_signals(self
):
1285 return self
._lazy
_lower
()._lhs
_signals
()
1287 def _rhs_signals(self
):
1288 return self
._lazy
_lower
()._rhs
_signals
()
1291 class ValueCastable
:
1292 """Base class for classes which can be cast to Values.
1294 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1295 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1296 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1297 cast to a concrete nMigen value when required.
1299 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1300 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1301 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1302 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1303 it is up to the user to ensure that it is not mutated in a way that changes its representation
1304 after the first call to ``as_value``.
1306 def __new__(cls
, *args
, **kwargs
):
1307 self
= super().__new
__(cls
)
1308 if not hasattr(self
, "as_value"):
1309 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1310 "the `as_value` method")
1312 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1313 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1314 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1318 def lowermethod(func
):
1319 """Decorator to memoize lowering methods.
1321 Ensures the decorated method is called only once, with subsequent method calls returning the
1322 object returned by the first first method call.
1324 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1325 This is to ensure that nMigen's view of representation of all values stays internally
1328 @functools.wraps(func
)
1329 def wrapper_memoized(self
, *args
, **kwargs
):
1330 if not hasattr(self
, "_ValueCastable__lowered_to"):
1331 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1332 return self
.__lowered
_to
1333 wrapper_memoized
.__memoized
= True
1334 return wrapper_memoized
1338 class Sample(Value
):
1339 """Value from the past.
1341 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1342 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1343 to the value of the expression calculated as if each signal had its reset value.
1345 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1346 super().__init
__(src_loc_at
=1 + src_loc_at
)
1347 self
.value
= Value
.cast(expr
)
1348 self
.clocks
= int(clocks
)
1349 self
.domain
= domain
1350 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1351 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1352 .format(self
.value
))
1354 raise ValueError("Cannot sample a value {} cycles in the future"
1355 .format(-self
.clocks
))
1356 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1357 raise TypeError("Domain name must be a string or None, not {!r}"
1358 .format(self
.domain
))
1361 return self
.value
.shape()
1363 def _rhs_signals(self
):
1364 return SignalSet((self
,))
1367 return "(sample {!r} @ {}[{}])".format(
1368 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1371 def Past(expr
, clocks
=1, domain
=None):
1372 return Sample(expr
, clocks
, domain
)
1375 def Stable(expr
, clocks
=0, domain
=None):
1376 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1379 def Rose(expr
, clocks
=0, domain
=None):
1380 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1383 def Fell(expr
, clocks
=0, domain
=None):
1384 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1388 class Initial(Value
):
1389 """Start indicator, for model checking.
1391 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1393 def __init__(self
, *, src_loc_at
=0):
1394 super().__init
__(src_loc_at
=src_loc_at
)
1399 def _rhs_signals(self
):
1400 return SignalSet((self
,))
1406 class _StatementList(list):
1408 return "({})".format(" ".join(map(repr, self
)))
1412 def __init__(self
, *, src_loc_at
=0):
1413 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1417 if isinstance(obj
, Iterable
):
1418 return _StatementList(list(chain
.from_iterable(map(Statement
.cast
, obj
))))
1420 if isinstance(obj
, Statement
):
1421 return _StatementList([obj
])
1423 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1427 class Assign(Statement
):
1428 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1429 super().__init
__(src_loc_at
=src_loc_at
)
1430 self
.lhs
= Value
.cast(lhs
)
1431 self
.rhs
= Value
.cast(rhs
)
1433 def _lhs_signals(self
):
1434 return self
.lhs
._lhs
_signals
()
1436 def _rhs_signals(self
):
1437 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1440 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1443 class UnusedProperty(UnusedMustUse
):
1447 class Property(Statement
, MustUse
):
1448 _MustUse__warning
= UnusedProperty
1450 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1451 super().__init
__(src_loc_at
=src_loc_at
)
1452 self
.test
= Value
.cast(test
)
1453 self
._check
= _check
1455 if self
._check
is None:
1456 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1457 self
._check
.src_loc
= self
.src_loc
1459 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1460 self
._en
.src_loc
= self
.src_loc
1462 def _lhs_signals(self
):
1463 return SignalSet((self
._en
, self
._check
))
1465 def _rhs_signals(self
):
1466 return self
.test
._rhs
_signals
()
1469 return "({} {!r})".format(self
._kind
, self
.test
)
1473 class Assert(Property
):
1478 class Assume(Property
):
1483 class Cover(Property
):
1488 class Switch(Statement
):
1489 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1491 super().__init
__(src_loc_at
=src_loc_at
)
1493 # Switch is a bit special in terms of location tracking because it is usually created
1494 # long after the control has left the statement that directly caused its creation.
1495 self
.src_loc
= src_loc
1496 # Switch is also a bit special in that its parts also have location information. It can't
1497 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1498 self
.case_src_locs
= {}
1500 self
.test
= Value
.cast(test
)
1501 self
.cases
= OrderedDict()
1502 for orig_keys
, stmts
in cases
.items():
1503 # Map: None -> (); key -> (key,); (key...) -> (key...)
1507 if not isinstance(keys
, tuple):
1509 # Map: 2 -> "0010"; "0010" -> "0010"
1511 key_mask
= (1 << len(self
.test
)) - 1
1513 if isinstance(key
, str):
1514 key
= "".join(key
.split()) # remove whitespace
1515 elif isinstance(key
, int):
1516 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1517 elif isinstance(key
, Enum
):
1518 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1520 raise TypeError("Object {!r} cannot be used as a switch key"
1522 assert len(key
) == len(self
.test
)
1523 new_keys
= (*new_keys
, key
)
1524 if not isinstance(stmts
, Iterable
):
1526 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1527 if orig_keys
in case_src_locs
:
1528 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1530 def _lhs_signals(self
):
1531 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1535 def _rhs_signals(self
):
1536 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1538 return self
.test
._rhs
_signals
() | signals
1541 def case_repr(keys
, stmts
):
1542 stmts_repr
= " ".join(map(repr, stmts
))
1544 return "(default {})".format(stmts_repr
)
1545 elif len(keys
) == 1:
1546 return "(case {} {})".format(keys
[0], stmts_repr
)
1548 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1549 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1550 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1553 class _MappedKeyCollection(metaclass
=ABCMeta
):
1555 def _map_key(self
, key
):
1559 def _unmap_key(self
, key
):
1563 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1564 def __init__(self
, pairs
=()):
1565 self
._storage
= OrderedDict()
1566 for key
, value
in pairs
:
1569 def __getitem__(self
, key
):
1570 key
= None if key
is None else self
._map
_key
(key
)
1571 return self
._storage
[key
]
1573 def __setitem__(self
, key
, value
):
1574 key
= None if key
is None else self
._map
_key
(key
)
1575 self
._storage
[key
] = value
1577 def __delitem__(self
, key
):
1578 key
= None if key
is None else self
._map
_key
(key
)
1579 del self
._storage
[key
]
1582 for key
in self
._storage
:
1586 yield self
._unmap
_key
(key
)
1588 def __eq__(self
, other
):
1589 if not isinstance(other
, type(self
)):
1591 if len(self
) != len(other
):
1593 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1596 if self
._storage
[ak
] != other
._storage
[bk
]:
1601 return len(self
._storage
)
1604 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1605 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1609 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1610 def __init__(self
, elements
=()):
1611 self
._storage
= OrderedDict()
1612 for elem
in elements
:
1615 def add(self
, value
):
1616 self
._storage
[self
._map
_key
(value
)] = None
1618 def update(self
, values
):
1619 for value
in values
:
1622 def discard(self
, value
):
1624 del self
._storage
[self
._map
_key
(value
)]
1626 def __contains__(self
, value
):
1627 return self
._map
_key
(value
) in self
._storage
1630 for key
in [k
for k
in self
._storage
]:
1631 yield self
._unmap
_key
(key
)
1634 return len(self
._storage
)
1637 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1638 ", ".join(repr(x
) for x
in self
))
1642 def __init__(self
, value
):
1643 self
.value
= Value
.cast(value
)
1644 if isinstance(self
.value
, Const
):
1645 self
._hash
= hash(self
.value
.value
)
1646 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1647 self
._hash
= hash(self
.value
.duid
)
1648 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1649 self
._hash
= hash(self
.value
.domain
)
1650 elif isinstance(self
.value
, Operator
):
1651 self
._hash
= hash((self
.value
.operator
,
1652 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1653 elif isinstance(self
.value
, Slice
):
1654 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1655 elif isinstance(self
.value
, Part
):
1656 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1657 self
.value
.width
, self
.value
.stride
))
1658 elif isinstance(self
.value
, Cat
):
1659 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1660 elif isinstance(self
.value
, ArrayProxy
):
1661 self
._hash
= hash((ValueKey(self
.value
.index
),
1662 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1663 elif isinstance(self
.value
, Sample
):
1664 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1665 elif isinstance(self
.value
, Initial
):
1668 raise TypeError("Object {!r} cannot be used as a key in value collections"
1669 .format(self
.value
))
1674 def __eq__(self
, other
):
1675 if type(other
) is not ValueKey
:
1677 if type(self
.value
) is not type(other
.value
):
1680 if isinstance(self
.value
, Const
):
1681 return self
.value
.value
== other
.value
.value
1682 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1683 return self
.value
is other
.value
1684 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1685 return self
.value
.domain
== other
.value
.domain
1686 elif isinstance(self
.value
, Operator
):
1687 return (self
.value
.operator
== other
.value
.operator
and
1688 len(self
.value
.operands
) == len(other
.value
.operands
) and
1689 all(ValueKey(a
) == ValueKey(b
)
1690 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1691 elif isinstance(self
.value
, Slice
):
1692 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1693 self
.value
.start
== other
.value
.start
and
1694 self
.value
.stop
== other
.value
.stop
)
1695 elif isinstance(self
.value
, Part
):
1696 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1697 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1698 self
.value
.width
== other
.value
.width
and
1699 self
.value
.stride
== other
.value
.stride
)
1700 elif isinstance(self
.value
, Cat
):
1701 return all(ValueKey(a
) == ValueKey(b
)
1702 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1703 elif isinstance(self
.value
, ArrayProxy
):
1704 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1705 len(self
.value
.elems
) == len(other
.value
.elems
) and
1706 all(ValueKey(a
) == ValueKey(b
)
1707 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1708 other
.value
._iter
_as
_values
())))
1709 elif isinstance(self
.value
, Sample
):
1710 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1711 self
.value
.clocks
== other
.value
.clocks
and
1712 self
.value
.domain
== self
.value
.domain
)
1713 elif isinstance(self
.value
, Initial
):
1716 raise TypeError("Object {!r} cannot be used as a key in value collections"
1717 .format(self
.value
))
1719 def __lt__(self
, other
):
1720 if not isinstance(other
, ValueKey
):
1722 if type(self
.value
) != type(other
.value
):
1725 if isinstance(self
.value
, Const
):
1726 return self
.value
< other
.value
1727 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1728 return self
.value
.duid
< other
.value
.duid
1729 elif isinstance(self
.value
, Slice
):
1730 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1731 self
.value
.start
< other
.value
.start
and
1732 self
.value
.end
< other
.value
.end
)
1734 raise TypeError("Object {!r} cannot be used as a key in value collections")
1737 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1740 class ValueDict(_MappedKeyDict
):
1742 _unmap_key
= lambda self
, key
: key
.value
1745 class ValueSet(_MappedKeySet
):
1747 _unmap_key
= lambda self
, key
: key
.value
1751 def __init__(self
, signal
):
1752 self
.signal
= signal
1753 if isinstance(signal
, Signal
):
1754 self
._intern
= (0, signal
.duid
)
1755 elif type(signal
) is ClockSignal
:
1756 self
._intern
= (1, signal
.domain
)
1757 elif type(signal
) is ResetSignal
:
1758 self
._intern
= (2, signal
.domain
)
1760 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1763 return hash(self
._intern
)
1765 def __eq__(self
, other
):
1766 if type(other
) is not SignalKey
:
1768 return self
._intern
== other
._intern
1770 def __lt__(self
, other
):
1771 if type(other
) is not SignalKey
:
1772 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1773 return self
._intern
< other
._intern
1776 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1779 class SignalDict(_MappedKeyDict
):
1780 _map_key
= SignalKey
1781 _unmap_key
= lambda self
, key
: key
.signal
1784 class SignalSet(_MappedKeySet
):
1785 _map_key
= SignalKey
1786 _unmap_key
= lambda self
, key
: key
.signal