1 from abc
import ABCMeta
, abstractmethod
5 from collections
import OrderedDict
6 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
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",
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 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
147 def __init__(self
, *, src_loc_at
=0):
149 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
152 raise TypeError("Attempted to convert nMigen value to Python boolean")
154 def __invert__(self
):
155 return Operator("~", [self
])
157 return Operator("-", [self
])
159 def __add__(self
, other
):
160 return Operator("+", [self
, other
])
161 def __radd__(self
, other
):
162 return Operator("+", [other
, self
])
163 def __sub__(self
, other
):
164 return Operator("-", [self
, other
])
165 def __rsub__(self
, other
):
166 return Operator("-", [other
, self
])
168 def __mul__(self
, other
):
169 return Operator("*", [self
, other
])
170 def __rmul__(self
, other
):
171 return Operator("*", [other
, self
])
173 def __check_divisor(self
):
174 width
, signed
= self
.shape()
176 # Python's division semantics and Verilog's division semantics differ for negative
177 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
178 # completely by prohibiting such division operations.
179 raise NotImplementedError("Division by a signed value is not supported")
180 def __mod__(self
, other
):
181 other
= Value
.cast(other
)
182 other
.__check
_divisor
()
183 return Operator("%", [self
, other
])
184 def __rmod__(self
, other
):
185 self
.__check
_divisor
()
186 return Operator("%", [other
, self
])
187 def __floordiv__(self
, other
):
188 other
= Value
.cast(other
)
189 other
.__check
_divisor
()
190 return Operator("//", [self
, other
])
191 def __rfloordiv__(self
, other
):
192 self
.__check
_divisor
()
193 return Operator("//", [other
, self
])
195 def __check_shamt(self
):
196 width
, signed
= self
.shape()
198 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
199 # by a signed value to make sure the shift amount can always be interpreted as
201 raise TypeError("Shift amount must be unsigned")
202 def __lshift__(self
, other
):
203 other
= Value
.cast(other
)
204 other
.__check
_shamt
()
205 return Operator("<<", [self
, other
])
206 def __rlshift__(self
, other
):
208 return Operator("<<", [other
, self
])
209 def __rshift__(self
, other
):
210 other
= Value
.cast(other
)
211 other
.__check
_shamt
()
212 return Operator(">>", [self
, other
])
213 def __rrshift__(self
, other
):
215 return Operator(">>", [other
, self
])
217 def __and__(self
, other
):
218 return Operator("&", [self
, other
])
219 def __rand__(self
, other
):
220 return Operator("&", [other
, self
])
221 def __xor__(self
, other
):
222 return Operator("^", [self
, other
])
223 def __rxor__(self
, other
):
224 return Operator("^", [other
, self
])
225 def __or__(self
, other
):
226 return Operator("|", [self
, other
])
227 def __ror__(self
, other
):
228 return Operator("|", [other
, self
])
230 def __eq__(self
, other
):
231 return Operator("==", [self
, other
])
232 def __ne__(self
, other
):
233 return Operator("!=", [self
, other
])
234 def __lt__(self
, other
):
235 return Operator("<", [self
, other
])
236 def __le__(self
, other
):
237 return Operator("<=", [self
, other
])
238 def __gt__(self
, other
):
239 return Operator(">", [self
, other
])
240 def __ge__(self
, other
):
241 return Operator(">=", [self
, other
])
244 width
, signed
= self
.shape()
246 return Mux(self
>= 0, self
, -self
)
251 return self
.shape().width
253 def __getitem__(self
, key
):
255 if isinstance(key
, int):
256 if key
not in range(-n
, n
):
257 raise IndexError("Cannot index {} bits into {}-bit value".format(key
, n
))
260 return Slice(self
, key
, key
+ 1)
261 elif isinstance(key
, slice):
262 start
, stop
, step
= key
.indices(n
)
264 return Cat(self
[i
] for i
in range(start
, stop
, step
))
265 return Slice(self
, start
, stop
)
267 raise TypeError("Cannot index value with {}".format(repr(key
)))
269 def as_unsigned(self
):
270 """Conversion to unsigned.
275 This ``Value`` reinterpreted as a unsigned integer.
277 return Operator("u", [self
])
280 """Conversion to signed.
285 This ``Value`` reinterpreted as a signed integer.
287 return Operator("s", [self
])
290 """Conversion to boolean.
295 ``1`` if any bits are set, ``0`` otherwise.
297 return Operator("b", [self
])
300 """Check if any bits are ``1``.
305 ``1`` if any bits are set, ``0`` otherwise.
307 return Operator("r|", [self
])
310 """Check if all bits are ``1``.
315 ``1`` if all bits are set, ``0`` otherwise.
317 return Operator("r&", [self
])
320 """Compute pairwise exclusive-or of every bit.
325 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
327 return Operator("r^", [self
])
329 def implies(premise
, conclusion
):
335 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
337 return ~premise | conclusion
339 def bit_select(self
, offset
, width
):
340 """Part-select with bit granularity.
342 Selects a constant width but variable offset part of a ``Value``, such that successive
343 parts overlap by all but 1 bit.
348 Index of first selected bit.
350 Number of selected bits.
355 Selected part of the ``Value``
357 offset
= Value
.cast(offset
)
358 if type(offset
) is Const
and isinstance(width
, int):
359 return self
[offset
.value
:offset
.value
+ width
]
360 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
362 def word_select(self
, offset
, width
):
363 """Part-select with word granularity.
365 Selects a constant width but variable offset part of a ``Value``, such that successive
366 parts do not overlap.
371 Index of first selected word.
373 Number of selected bits.
378 Selected part of the ``Value``
380 offset
= Value
.cast(offset
)
381 if type(offset
) is Const
and isinstance(width
, int):
382 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
383 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
385 def matches(self
, *patterns
):
388 Matches against a set of patterns, which may be integers or bit strings, recognizing
389 the same grammar as ``Case()``.
393 patterns : int or str
394 Patterns to match against.
399 ``1`` if any pattern matches the value, ``0`` otherwise.
402 for pattern
in patterns
:
403 if not isinstance(pattern
, (int, str, Enum
)):
404 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
407 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
408 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
409 "bits, and may include whitespace"
411 if (isinstance(pattern
, str) and
412 len("".join(pattern
.split())) != len(self
)):
413 raise SyntaxError("Match pattern '{}' must have the same width as match value "
415 .format(pattern
, len(self
)))
416 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
417 warnings
.warn("Match pattern '{:b}' is wider than match value "
418 "(which has width {}); comparison will never be true"
419 .format(pattern
, len(self
)),
420 SyntaxWarning, stacklevel
=3)
422 if isinstance(pattern
, str):
423 pattern
= "".join(pattern
.split()) # remove whitespace
424 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
425 pattern
= int(pattern
.replace("-", "0"), 2)
426 matches
.append((self
& mask
) == pattern
)
427 elif isinstance(pattern
, int):
428 matches
.append(self
== pattern
)
429 elif isinstance(pattern
, Enum
):
430 matches
.append(self
== pattern
.value
)
435 elif len(matches
) == 1:
438 return Cat(*matches
).any()
440 def shift_left(self
, amount
):
441 """Shift left by constant amount.
451 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
453 if not isinstance(amount
, int):
454 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
456 return self
.shift_right(-amount
)
457 if self
.shape().signed
:
458 return Cat(Const(0, amount
), self
).as_signed()
460 return Cat(Const(0, amount
), self
) # unsigned
462 def shift_right(self
, amount
):
463 """Shift right by constant amount.
473 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
475 if not isinstance(amount
, int):
476 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
478 return self
.shift_left(-amount
)
479 if self
.shape().signed
:
480 return self
[amount
:].as_signed()
482 return self
[amount
:] # unsigned
484 def rotate_left(self
, amount
):
485 """Rotate left by constant amount.
495 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
497 if not isinstance(amount
, int):
498 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
500 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
502 def rotate_right(self
, amount
):
503 """Rotate right by constant amount.
513 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
515 if not isinstance(amount
, int):
516 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
518 return Cat(self
[amount
:], self
[:amount
])
526 Value to be assigned.
531 Assignment statement that can be used in combinatorial or synchronous context.
533 return Assign(self
, value
, src_loc_at
=1)
537 """Bit width and signedness of a value.
546 >>> Signal(8).shape()
547 Shape(width=8, signed=False)
548 >>> Const(0xaa).shape()
549 Shape(width=8, signed=False)
553 def _lhs_signals(self
):
554 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
557 def _rhs_signals(self
):
561 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
568 """A constant, literal integer value.
573 shape : int or tuple or None
574 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
575 in this constant and whether it is signed (can represent negative values).
576 ``shape`` defaults to the minimum possible width and signedness of ``value``.
586 def normalize(value
, shape
):
587 width
, signed
= shape
588 mask
= (1 << width
) - 1
590 if signed
and value
>> (width
- 1):
594 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
595 # We deliberately do not call Value.__init__ here.
596 self
.value
= int(value
)
598 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
599 elif isinstance(shape
, int):
600 shape
= Shape(shape
, signed
=self
.value
< 0)
602 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
603 self
.width
, self
.signed
= shape
604 self
.value
= self
.normalize(self
.value
, shape
)
607 return Shape(self
.width
, self
.signed
)
609 def _rhs_signals(self
):
616 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
619 C
= Const
# shorthand
622 class AnyValue(Value
, DUID
):
623 def __init__(self
, shape
, *, src_loc_at
=0):
624 super().__init
__(src_loc_at
=src_loc_at
)
625 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
626 if not isinstance(self
.width
, int) or self
.width
< 0:
627 raise TypeError("Width must be a non-negative integer, not {!r}"
631 return Shape(self
.width
, self
.signed
)
633 def _rhs_signals(self
):
638 class AnyConst(AnyValue
):
640 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
644 class AnySeq(AnyValue
):
646 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
650 class Operator(Value
):
651 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
652 super().__init
__(src_loc_at
=1 + src_loc_at
)
653 self
.operator
= operator
654 self
.operands
= [Value
.cast(op
) for op
in operands
]
657 def _bitwise_binary_shape(a_shape
, b_shape
):
658 a_bits
, a_sign
= a_shape
659 b_bits
, b_sign
= b_shape
660 if not a_sign
and not b_sign
:
661 # both operands unsigned
662 return Shape(max(a_bits
, b_bits
), False)
663 elif a_sign
and b_sign
:
664 # both operands signed
665 return Shape(max(a_bits
, b_bits
), True)
666 elif not a_sign
and b_sign
:
667 # first operand unsigned (add sign bit), second operand signed
668 return Shape(max(a_bits
+ 1, b_bits
), True)
670 # first signed, second operand unsigned (add sign bit)
671 return Shape(max(a_bits
, b_bits
+ 1), True)
673 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
674 if len(op_shapes
) == 1:
675 (a_width
, a_signed
), = op_shapes
676 if self
.operator
in ("+", "~"):
677 return Shape(a_width
, a_signed
)
678 if self
.operator
== "-":
679 return Shape(a_width
+ 1, True)
680 if self
.operator
in ("b", "r|", "r&", "r^"):
681 return Shape(1, False)
682 if self
.operator
== "u":
683 return Shape(a_width
, False)
684 if self
.operator
== "s":
685 return Shape(a_width
, True)
686 elif len(op_shapes
) == 2:
687 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
688 if self
.operator
in ("+", "-"):
689 width
, signed
= _bitwise_binary_shape(*op_shapes
)
690 return Shape(width
+ 1, signed
)
691 if self
.operator
== "*":
692 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
693 if self
.operator
in ("//", "%"):
695 return Shape(a_width
, a_signed
)
696 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
697 return Shape(1, False)
698 if self
.operator
in ("&", "^", "|"):
699 return _bitwise_binary_shape(*op_shapes
)
700 if self
.operator
== "<<":
702 extra
= 2 ** (b_width
- 1) - 1
704 extra
= 2 ** (b_width
) - 1
705 return Shape(a_width
+ extra
, a_signed
)
706 if self
.operator
== ">>":
708 extra
= 2 ** (b_width
- 1)
711 return Shape(a_width
+ extra
, a_signed
)
712 elif len(op_shapes
) == 3:
713 if self
.operator
== "m":
714 s_shape
, a_shape
, b_shape
= op_shapes
715 return _bitwise_binary_shape(a_shape
, b_shape
)
716 raise NotImplementedError("Operator {}/{} not implemented"
717 .format(self
.operator
, len(op_shapes
))) # :nocov:
719 def _rhs_signals(self
):
720 return union(op
._rhs
_signals
() for op
in self
.operands
)
723 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
726 def Mux(sel
, val1
, val0
):
727 """Choose between two values.
740 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
742 sel
= Value
.cast(sel
)
745 return Operator("m", [sel
, val1
, val0
])
750 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
751 if not isinstance(start
, int):
752 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
753 if not isinstance(stop
, int):
754 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
757 if start
not in range(-(n
+1), n
+1):
758 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
761 if stop
not in range(-(n
+1), n
+1):
762 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
766 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
768 super().__init
__(src_loc_at
=src_loc_at
)
769 self
.value
= Value
.cast(value
)
774 return Shape(self
.stop
- self
.start
)
776 def _lhs_signals(self
):
777 return self
.value
._lhs
_signals
()
779 def _rhs_signals(self
):
780 return self
.value
._rhs
_signals
()
783 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
788 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
789 if not isinstance(width
, int) or width
< 0:
790 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
791 if not isinstance(stride
, int) or stride
<= 0:
792 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
794 super().__init
__(src_loc_at
=src_loc_at
)
796 self
.offset
= Value
.cast(offset
)
801 return Shape(self
.width
)
803 def _lhs_signals(self
):
804 return self
.value
._lhs
_signals
()
806 def _rhs_signals(self
):
807 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
810 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
811 self
.width
, self
.stride
)
816 """Concatenate values.
818 Form a compound ``Value`` from several smaller ones by concatenation.
819 The first argument occupies the lower bits of the result.
820 The return value can be used on either side of an assignment, that
821 is, the concatenated value can be used as an argument on the RHS or
822 as a target on the LHS. If it is used on the LHS, it must solely
823 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
824 meeting these properties. The bit length of the return value is the sum of
825 the bit lengths of the arguments::
827 len(Cat(args)) == sum(len(arg) for arg in args)
831 *args : Values or iterables of Values, inout
832 ``Value`` s to be concatenated.
837 Resulting ``Value`` obtained by concatentation.
839 def __init__(self
, *args
, src_loc_at
=0):
840 super().__init
__(src_loc_at
=src_loc_at
)
841 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
844 return Shape(sum(len(part
) for part
in self
.parts
))
846 def _lhs_signals(self
):
847 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
849 def _rhs_signals(self
):
850 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
854 for part
in reversed(self
.parts
):
856 value |
= part
._as
_const
()
860 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
867 An input value is replicated (repeated) several times
868 to be used on the RHS of assignments::
870 len(Repl(s, n)) == len(s) * n
875 Input value to be replicated.
877 Number of replications.
884 def __init__(self
, value
, count
, *, src_loc_at
=0):
885 if not isinstance(count
, int) or count
< 0:
886 raise TypeError("Replication count must be a non-negative integer, not {!r}"
889 super().__init
__(src_loc_at
=src_loc_at
)
890 self
.value
= Value
.cast(value
)
894 return Shape(len(self
.value
) * self
.count
)
896 def _rhs_signals(self
):
897 return self
.value
._rhs
_signals
()
900 return "(repl {!r} {})".format(self
.value
, self
.count
)
904 class Signal(Value
, DUID
):
905 """A varying integer value.
909 shape : ``Shape``-castable object or None
910 Specification for the number of bits in this ``Signal`` and its signedness (whether it
911 can represent negative values). See ``Shape.cast`` for details.
912 If not specified, ``shape`` defaults to 1-bit and non-signed.
914 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
915 name this ``Signal`` is assigned to.
916 reset : int or integral Enum
917 Reset (synchronous) or default (combinatorial) value.
918 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
919 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
920 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
921 assumes its ``reset`` value. Defaults to 0.
923 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
924 The ``reset`` value is only used as a combinatorial default or as the initial value.
925 Defaults to ``False``.
927 Dictionary of synthesis attributes.
928 decoder : function or Enum
929 A function converting integer signal values to human-readable strings (e.g. FSM state
930 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
931 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
945 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
946 attrs
=None, decoder
=None, src_loc_at
=0):
947 super().__init
__(src_loc_at
=src_loc_at
)
949 if name
is not None and not isinstance(name
, str):
950 raise TypeError("Name must be a string, not {!r}".format(name
))
951 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
955 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
957 if isinstance(reset
, Enum
):
959 if not isinstance(reset
, int):
960 raise TypeError("Reset value has to be an int or an integral Enum")
962 reset_width
= bits_for(reset
, self
.signed
)
963 if reset
!= 0 and reset_width
> self
.width
:
964 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
966 .format(reset
, reset_width
, self
.width
),
967 SyntaxWarning, stacklevel
=2 + src_loc_at
)
970 self
.reset_less
= bool(reset_less
)
972 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
974 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
976 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
977 def enum_decoder(value
):
979 return "{0.name:}/{0.value:}".format(decoder(value
))
982 self
.decoder
= enum_decoder
983 self
._enum
_class
= decoder
985 self
.decoder
= decoder
986 self
._enum
_class
= None
988 # Not a @classmethod because nmigen.compat requires it.
990 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
991 """Create Signal based on another.
996 Object to base this Signal on.
1000 elif name_suffix
is not None:
1001 new_name
= other
.name
+ str(name_suffix
)
1003 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1004 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1005 if isinstance(other
, Signal
):
1006 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1007 attrs
=other
.attrs
, decoder
=other
.decoder
)
1009 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1012 return Shape(self
.width
, self
.signed
)
1014 def _lhs_signals(self
):
1015 return SignalSet((self
,))
1017 def _rhs_signals(self
):
1018 return SignalSet((self
,))
1021 return "(sig {})".format(self
.name
)
1025 class ClockSignal(Value
):
1026 """Clock signal for a clock domain.
1028 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1029 All of these signals ultimately refer to the same signal, but they can be manipulated
1030 independently of the clock domain, even before the clock domain is created.
1035 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1037 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1038 super().__init
__(src_loc_at
=src_loc_at
)
1039 if not isinstance(domain
, str):
1040 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1041 if domain
== "comb":
1042 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1043 self
.domain
= domain
1048 def _lhs_signals(self
):
1049 return SignalSet((self
,))
1051 def _rhs_signals(self
):
1052 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1055 return "(clk {})".format(self
.domain
)
1059 class ResetSignal(Value
):
1060 """Reset signal for a clock domain.
1062 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1063 All of these signals ultimately refer to the same signal, but they can be manipulated
1064 independently of the clock domain, even before the clock domain is created.
1069 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1070 allow_reset_less : bool
1071 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1073 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1074 super().__init
__(src_loc_at
=src_loc_at
)
1075 if not isinstance(domain
, str):
1076 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1077 if domain
== "comb":
1078 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1079 self
.domain
= domain
1080 self
.allow_reset_less
= allow_reset_less
1085 def _lhs_signals(self
):
1086 return SignalSet((self
,))
1088 def _rhs_signals(self
):
1089 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1092 return "(rst {})".format(self
.domain
)
1095 class Array(MutableSequence
):
1096 """Addressable multiplexer.
1098 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
1101 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1102 assignments, provided that all elements of the array are values. The array proxy also supports
1103 attribute access and further indexing, each returning another array proxy; this means that
1104 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1105 be used as first-class values.
1107 It is an error to change an array or any of its elements after an array proxy was created.
1108 Changing the array directly will raise an exception. However, it is not possible to detect
1109 the elements being modified; if an element's attribute or element is modified after the proxy
1110 for it has been created, the proxy will refer to stale data.
1117 gpios = Array(Signal() for _ in range(10))
1119 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1121 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1123 Multidimensional array::
1125 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1126 a = Signal.range(10)
1127 b = Signal.range(10)
1129 m.d.comb += r.eq(mult[a][b])
1137 buses = Array(Record(layout) for busno in range(4))
1138 master = Record(layout)
1140 buses[sel].r_en.eq(master.r_en),
1141 master.r_data.eq(buses[sel].r_data),
1144 def __init__(self
, iterable
=()):
1145 self
._inner
= list(iterable
)
1146 self
._proxy
_at
= None
1147 self
._mutable
= True
1149 def __getitem__(self
, index
):
1150 if isinstance(index
, Value
):
1152 self
._proxy
_at
= tracer
.get_src_loc()
1153 self
._mutable
= False
1154 return ArrayProxy(self
, index
)
1156 return self
._inner
[index
]
1159 return len(self
._inner
)
1161 def _check_mutability(self
):
1162 if not self
._mutable
:
1163 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1164 "at {}:{}".format(*self
._proxy
_at
))
1166 def __setitem__(self
, index
, value
):
1167 self
._check
_mutability
()
1168 self
._inner
[index
] = value
1170 def __delitem__(self
, index
):
1171 self
._check
_mutability
()
1172 del self
._inner
[index
]
1174 def insert(self
, index
, value
):
1175 self
._check
_mutability
()
1176 self
._inner
.insert(index
, value
)
1179 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1180 ", ".join(map(repr, self
._inner
)))
1184 class ArrayProxy(Value
):
1185 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1186 super().__init
__(src_loc_at
=1 + src_loc_at
)
1188 self
.index
= Value
.cast(index
)
1190 def __getattr__(self
, attr
):
1191 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1193 def __getitem__(self
, index
):
1194 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1196 def _iter_as_values(self
):
1197 return (Value
.cast(elem
) for elem
in self
.elems
)
1200 unsigned_width
= signed_width
= 0
1201 has_unsigned
= has_signed
= False
1202 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1205 signed_width
= max(signed_width
, elem_width
)
1208 unsigned_width
= max(unsigned_width
, elem_width
)
1209 # The shape of the proxy must be such that it preserves the mathematical value of the array
1210 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1211 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1212 # that every unsigned value is zero-extended by at least one bit.
1213 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1214 # Array contains both signed and unsigned values, and at least one of the unsigned
1215 # values won't be zero-extended otherwise.
1216 return signed(unsigned_width
+ 1)
1218 # Array contains values of the same signedness, or else all of the unsigned values
1219 # are zero-extended.
1220 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1222 def _lhs_signals(self
):
1223 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1227 def _rhs_signals(self
):
1228 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1230 return self
.index
._rhs
_signals
() | signals
1233 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1236 class UserValue(Value
):
1237 """Value with custom lowering.
1239 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1240 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1241 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1242 value when required.
1244 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1245 nMigen's view of representation of all values stays internally consistent. If the class
1246 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1247 it is not mutated in a way that changes its representation.
1249 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1250 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1251 * Querying the shape using ``.shape()`` or ``len()``;
1252 * Creating a similarly shaped signal using ``Signal.like``;
1253 * Indexing or iterating through individual bits;
1254 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1256 def __init__(self
, *, src_loc_at
=0):
1257 super().__init
__(src_loc_at
=1 + src_loc_at
)
1258 self
.__lowered
= None
1262 """Conversion to a concrete representation."""
1265 def _lazy_lower(self
):
1266 if self
.__lowered
is None:
1267 lowered
= self
.lower()
1268 if isinstance(lowered
, UserValue
):
1269 lowered
= lowered
._lazy
_lower
()
1270 self
.__lowered
= Value
.cast(lowered
)
1271 return self
.__lowered
1274 return self
._lazy
_lower
().shape()
1276 def _lhs_signals(self
):
1277 return self
._lazy
_lower
()._lhs
_signals
()
1279 def _rhs_signals(self
):
1280 return self
._lazy
_lower
()._rhs
_signals
()
1284 class Sample(Value
):
1285 """Value from the past.
1287 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1288 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1289 to the value of the expression calculated as if each signal had its reset value.
1291 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1292 super().__init
__(src_loc_at
=1 + src_loc_at
)
1293 self
.value
= Value
.cast(expr
)
1294 self
.clocks
= int(clocks
)
1295 self
.domain
= domain
1296 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1297 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1298 .format(self
.value
))
1300 raise ValueError("Cannot sample a value {} cycles in the future"
1301 .format(-self
.clocks
))
1302 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1303 raise TypeError("Domain name must be a string or None, not {!r}"
1304 .format(self
.domain
))
1307 return self
.value
.shape()
1309 def _rhs_signals(self
):
1310 return SignalSet((self
,))
1313 return "(sample {!r} @ {}[{}])".format(
1314 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1317 def Past(expr
, clocks
=1, domain
=None):
1318 return Sample(expr
, clocks
, domain
)
1321 def Stable(expr
, clocks
=0, domain
=None):
1322 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1325 def Rose(expr
, clocks
=0, domain
=None):
1326 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1329 def Fell(expr
, clocks
=0, domain
=None):
1330 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1334 class Initial(Value
):
1335 """Start indicator, for model checking.
1337 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1339 def __init__(self
, *, src_loc_at
=0):
1340 super().__init
__(src_loc_at
=src_loc_at
)
1345 def _rhs_signals(self
):
1346 return SignalSet((self
,))
1352 class _StatementList(list):
1354 return "({})".format(" ".join(map(repr, self
)))
1358 def __init__(self
, *, src_loc_at
=0):
1359 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1363 if isinstance(obj
, Iterable
):
1364 return _StatementList(sum((Statement
.cast(e
) for e
in obj
), []))
1366 if isinstance(obj
, Statement
):
1367 return _StatementList([obj
])
1369 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1373 class Assign(Statement
):
1374 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1375 super().__init
__(src_loc_at
=src_loc_at
)
1376 self
.lhs
= Value
.cast(lhs
)
1377 self
.rhs
= Value
.cast(rhs
)
1379 def _lhs_signals(self
):
1380 return self
.lhs
._lhs
_signals
()
1382 def _rhs_signals(self
):
1383 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1386 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1389 class UnusedProperty(UnusedMustUse
):
1393 class Property(Statement
, MustUse
):
1394 _MustUse__warning
= UnusedProperty
1396 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1397 super().__init
__(src_loc_at
=src_loc_at
)
1398 self
.test
= Value
.cast(test
)
1399 self
._check
= _check
1401 if self
._check
is None:
1402 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1403 self
._check
.src_loc
= self
.src_loc
1405 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1406 self
._en
.src_loc
= self
.src_loc
1408 def _lhs_signals(self
):
1409 return SignalSet((self
._en
, self
._check
))
1411 def _rhs_signals(self
):
1412 return self
.test
._rhs
_signals
()
1415 return "({} {!r})".format(self
._kind
, self
.test
)
1419 class Assert(Property
):
1424 class Assume(Property
):
1429 class Cover(Property
):
1434 class Switch(Statement
):
1435 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1437 super().__init
__(src_loc_at
=src_loc_at
)
1439 # Switch is a bit special in terms of location tracking because it is usually created
1440 # long after the control has left the statement that directly caused its creation.
1441 self
.src_loc
= src_loc
1442 # Switch is also a bit special in that its parts also have location information. It can't
1443 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1444 self
.case_src_locs
= {}
1446 self
.test
= Value
.cast(test
)
1447 self
.cases
= OrderedDict()
1448 for orig_keys
, stmts
in cases
.items():
1449 # Map: None -> (); key -> (key,); (key...) -> (key...)
1453 if not isinstance(keys
, tuple):
1455 # Map: 2 -> "0010"; "0010" -> "0010"
1458 if isinstance(key
, str):
1459 key
= "".join(key
.split()) # remove whitespace
1460 elif isinstance(key
, int):
1461 key
= format(key
, "b").rjust(len(self
.test
), "0")
1462 elif isinstance(key
, Enum
):
1463 key
= format(key
.value
, "b").rjust(len(self
.test
), "0")
1465 raise TypeError("Object {!r} cannot be used as a switch key"
1467 assert len(key
) == len(self
.test
)
1468 new_keys
= (*new_keys
, key
)
1469 if not isinstance(stmts
, Iterable
):
1471 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1472 if orig_keys
in case_src_locs
:
1473 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1475 def _lhs_signals(self
):
1476 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1480 def _rhs_signals(self
):
1481 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1483 return self
.test
._rhs
_signals
() | signals
1486 def case_repr(keys
, stmts
):
1487 stmts_repr
= " ".join(map(repr, stmts
))
1489 return "(default {})".format(stmts_repr
)
1490 elif len(keys
) == 1:
1491 return "(case {} {})".format(keys
[0], stmts_repr
)
1493 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1494 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1495 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1498 class _MappedKeyCollection(metaclass
=ABCMeta
):
1500 def _map_key(self
, key
):
1504 def _unmap_key(self
, key
):
1508 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1509 def __init__(self
, pairs
=()):
1510 self
._storage
= OrderedDict()
1511 for key
, value
in pairs
:
1514 def __getitem__(self
, key
):
1515 key
= None if key
is None else self
._map
_key
(key
)
1516 return self
._storage
[key
]
1518 def __setitem__(self
, key
, value
):
1519 key
= None if key
is None else self
._map
_key
(key
)
1520 self
._storage
[key
] = value
1522 def __delitem__(self
, key
):
1523 key
= None if key
is None else self
._map
_key
(key
)
1524 del self
._storage
[key
]
1527 for key
in self
._storage
:
1531 yield self
._unmap
_key
(key
)
1533 def __eq__(self
, other
):
1534 if not isinstance(other
, type(self
)):
1536 if len(self
) != len(other
):
1538 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1541 if self
._storage
[ak
] != other
._storage
[bk
]:
1546 return len(self
._storage
)
1549 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1550 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1554 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1555 def __init__(self
, elements
=()):
1556 self
._storage
= OrderedDict()
1557 for elem
in elements
:
1560 def add(self
, value
):
1561 self
._storage
[self
._map
_key
(value
)] = None
1563 def update(self
, values
):
1564 for value
in values
:
1567 def discard(self
, value
):
1569 del self
._storage
[self
._map
_key
(value
)]
1571 def __contains__(self
, value
):
1572 return self
._map
_key
(value
) in self
._storage
1575 for key
in [k
for k
in self
._storage
]:
1576 yield self
._unmap
_key
(key
)
1579 return len(self
._storage
)
1582 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1583 ", ".join(repr(x
) for x
in self
))
1587 def __init__(self
, value
):
1588 self
.value
= Value
.cast(value
)
1589 if isinstance(self
.value
, Const
):
1590 self
._hash
= hash(self
.value
.value
)
1591 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1592 self
._hash
= hash(self
.value
.duid
)
1593 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1594 self
._hash
= hash(self
.value
.domain
)
1595 elif isinstance(self
.value
, Operator
):
1596 self
._hash
= hash((self
.value
.operator
,
1597 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1598 elif isinstance(self
.value
, Slice
):
1599 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1600 elif isinstance(self
.value
, Part
):
1601 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1602 self
.value
.width
, self
.value
.stride
))
1603 elif isinstance(self
.value
, Cat
):
1604 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1605 elif isinstance(self
.value
, ArrayProxy
):
1606 self
._hash
= hash((ValueKey(self
.value
.index
),
1607 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1608 elif isinstance(self
.value
, Sample
):
1609 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1610 elif isinstance(self
.value
, Initial
):
1613 raise TypeError("Object {!r} cannot be used as a key in value collections"
1614 .format(self
.value
))
1619 def __eq__(self
, other
):
1620 if type(other
) is not ValueKey
:
1622 if type(self
.value
) is not type(other
.value
):
1625 if isinstance(self
.value
, Const
):
1626 return self
.value
.value
== other
.value
.value
1627 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1628 return self
.value
is other
.value
1629 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1630 return self
.value
.domain
== other
.value
.domain
1631 elif isinstance(self
.value
, Operator
):
1632 return (self
.value
.operator
== other
.value
.operator
and
1633 len(self
.value
.operands
) == len(other
.value
.operands
) and
1634 all(ValueKey(a
) == ValueKey(b
)
1635 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1636 elif isinstance(self
.value
, Slice
):
1637 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1638 self
.value
.start
== other
.value
.start
and
1639 self
.value
.stop
== other
.value
.stop
)
1640 elif isinstance(self
.value
, Part
):
1641 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1642 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1643 self
.value
.width
== other
.value
.width
and
1644 self
.value
.stride
== other
.value
.stride
)
1645 elif isinstance(self
.value
, Cat
):
1646 return all(ValueKey(a
) == ValueKey(b
)
1647 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1648 elif isinstance(self
.value
, ArrayProxy
):
1649 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1650 len(self
.value
.elems
) == len(other
.value
.elems
) and
1651 all(ValueKey(a
) == ValueKey(b
)
1652 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1653 other
.value
._iter
_as
_values
())))
1654 elif isinstance(self
.value
, Sample
):
1655 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1656 self
.value
.clocks
== other
.value
.clocks
and
1657 self
.value
.domain
== self
.value
.domain
)
1658 elif isinstance(self
.value
, Initial
):
1661 raise TypeError("Object {!r} cannot be used as a key in value collections"
1662 .format(self
.value
))
1664 def __lt__(self
, other
):
1665 if not isinstance(other
, ValueKey
):
1667 if type(self
.value
) != type(other
.value
):
1670 if isinstance(self
.value
, Const
):
1671 return self
.value
< other
.value
1672 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1673 return self
.value
.duid
< other
.value
.duid
1674 elif isinstance(self
.value
, Slice
):
1675 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1676 self
.value
.start
< other
.value
.start
and
1677 self
.value
.end
< other
.value
.end
)
1679 raise TypeError("Object {!r} cannot be used as a key in value collections")
1682 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1685 class ValueDict(_MappedKeyDict
):
1687 _unmap_key
= lambda self
, key
: key
.value
1690 class ValueSet(_MappedKeySet
):
1692 _unmap_key
= lambda self
, key
: key
.value
1696 def __init__(self
, signal
):
1697 self
.signal
= signal
1698 if isinstance(signal
, Signal
):
1699 self
._intern
= (0, signal
.duid
)
1700 elif type(signal
) is ClockSignal
:
1701 self
._intern
= (1, signal
.domain
)
1702 elif type(signal
) is ResetSignal
:
1703 self
._intern
= (2, signal
.domain
)
1705 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1708 return hash(self
._intern
)
1710 def __eq__(self
, other
):
1711 if type(other
) is not SignalKey
:
1713 return self
._intern
== other
._intern
1715 def __lt__(self
, other
):
1716 if type(other
) is not SignalKey
:
1717 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1718 return self
._intern
< other
._intern
1721 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1724 class SignalDict(_MappedKeyDict
):
1725 _map_key
= SignalKey
1726 _unmap_key
= lambda self
, key
: key
.signal
1729 class SignalSet(_MappedKeySet
):
1730 _map_key
= SignalKey
1731 _unmap_key
= lambda self
, key
: key
.signal